00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024
00025 #include <iostream>
00026
00027
00028
00029 #include "image_filters.h"
00030 #include "error.h"
00031 #include "page_magick.h"
00032 #include "kino_extra.h"
00033
00034
00035
00036 #include <string.h>
00037 #include <stdio.h>
00038 #include <glade/glade.h>
00039
00040 extern "C"
00041 {
00042 #include "support.h"
00043 extern GladeXML* magick_glade;
00044 }
00045
00049 class ImageFilterKeep : public GDKImageFilter, public NullImageFilter
00050 {
00051 public:
00052 char *GetDescription( ) const
00053 {
00054 return _( "No Change" );
00055 }
00056
00057 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00058 {}
00059 }
00060 ;
00061
00065 class ImageFilterBlackWhite : public ImageFilter
00066 {
00067 public:
00068 char *GetDescription( ) const
00069 {
00070 return _( "Black & White" );
00071 }
00072
00073 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00074 {
00075 uint8_t r, g, b;
00076 uint8_t *p = pixels;
00077 while ( p < ( pixels + width * height * 3 ) )
00078 {
00079 r = *( p );
00080 g = *( p + 1 );
00081 b = *( p + 2 );
00082 r = ( uint8_t ) ( 0.299 * r + 0.587 * g + 0.114 * b );
00083 *p ++ = r;
00084 *p ++ = r;
00085 *p ++ = r;
00086 }
00087 }
00088 };
00089
00093 class ImageFilterFadeIn : public ImageFilter
00094 {
00095 public:
00096 char *GetDescription( ) const
00097 {
00098 return _( "Fade In" );
00099 }
00100
00101 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00102 {
00103 for ( uint8_t *p = pixels; p < ( pixels + width * height * 3 ); ++p )
00104 *p = uint8_t( *p * position + 0.5 );
00105 }
00106 };
00107
00111 class ImageFilterFadeOut : public ImageFilter
00112 {
00113 public:
00114 char *GetDescription( ) const
00115 {
00116 return _( "Fade Out" );
00117 }
00118
00119 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00120 {
00121 double r = ( 1.0 - position );
00122 for ( uint8_t *p = pixels; p < ( pixels + width * height * 3 ); ++p )
00123 *p = uint8_t( *p * r + 0.5 );
00124 }
00125 };
00126
00130 class ImageFilterSepia : public ImageFilter
00131 {
00132 public:
00133 char *GetDescription( ) const
00134 {
00135 return _( "Sepia" );
00136 }
00137
00138 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00139 {
00140 uint8_t r, g, b;
00141 uint8_t *p = pixels;
00142 while ( p < ( pixels + width * height * 3 ) )
00143 {
00144 r = *( p );
00145 g = *( p + 1 );
00146 b = *( p + 2 );
00147 r = ( uint8_t ) ( 0.299 * r + 0.587 * g + 0.114 * b );
00148 *p ++ = r < 225 ? ( int ) ( r + 30 ) : 0xff;
00149 *p ++ = r;
00150 *p ++ = r > 30 ? ( int ) ( r - 30 ) : 0;
00151 }
00152 }
00153 };
00154
00158 class ImageFilterMirror : public GDKImageFilter
00159 {
00160 private:
00161 GtkWidget *window;
00162 int type;
00163
00164 public:
00165 ImageFilterMirror()
00166 {
00167 window = glade_xml_get_widget( magick_glade, "image_filter_mirror" );
00168 GtkWidget* widget = glade_xml_get_widget( magick_glade, "optionmenu_mirror" );
00169 g_signal_connect( G_OBJECT( widget ), "changed", G_CALLBACK( Repaint ), 0 );
00170 }
00171
00172 virtual ~ImageFilterMirror()
00173 {
00174 gtk_widget_destroy( window );
00175 }
00176
00177 char *GetDescription( ) const
00178 {
00179 return _( "Mirror" );
00180 }
00181
00182 void LeftRight( uint8_t *pixels, int width, int height, double position )
00183 {
00184 uint8_t * p = pixels;
00185 for ( int y = 0; y < height; y ++ )
00186 {
00187 uint8_t *i = p + y * width * 3;
00188 uint8_t *o = p + ( y + 1 ) * width * 3 - 1;
00189 for ( ; o > i; o -= 3 )
00190 {
00191 *( o - 2 ) = *i ++;
00192 *( o - 1 ) = *i ++;
00193 *o = *i ++;
00194 }
00195 }
00196 }
00197
00198 void RightLeft( uint8_t *pixels, int width, int height, double position )
00199 {
00200 uint8_t * p = pixels;
00201 for ( int y = 0; y < height; y ++ )
00202 {
00203 uint8_t *o = p + y * width * 3;
00204 uint8_t *i = p + ( y + 1 ) * width * 3 - 1;
00205 for ( ; i > o; i -= 3 )
00206 {
00207 *o ++ = *( i - 2 );
00208 *o ++ = *( i - 1 );
00209 *o ++ = *i;
00210 }
00211 }
00212 }
00213
00214 void TopBottom( uint8_t *pixels, int width, int height, double position )
00215 {
00216 uint8_t * p = pixels;
00217 for ( int y = 0; y < height / 2; y ++ )
00218 {
00219 uint8_t *i = p + y * width * 3;
00220 uint8_t *o = p + ( height - y ) * width * 3;
00221 memcpy( o, i, width * 3 );
00222 }
00223 }
00224
00225 void BottomTop( uint8_t *pixels, int width, int height, double position )
00226 {
00227 uint8_t * p = pixels;
00228 for ( int y = 0; y < height / 2; y ++ )
00229 {
00230 uint8_t *i = p + ( height - y ) * width * 3;
00231 uint8_t *o = p + y * width * 3;
00232 memcpy( o, i, width * 3 );
00233 }
00234 }
00235
00236 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00237 {
00238 GtkMenu * menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( window, "optionmenu_mirror" ) ) ) );
00239 GtkWidget *active_item = gtk_menu_get_active( menu );
00240 type = g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item );
00241
00242 if ( type == 0 )
00243 LeftRight( pixels, width, height, position );
00244 else if ( type == 1 )
00245 RightLeft( pixels, width, height, position );
00246 else if ( type == 2 )
00247 TopBottom( pixels, width, height, position );
00248 else if ( type == 3 )
00249 BottomTop( pixels, width, height, position );
00250 }
00251
00252 void AttachWidgets( GtkBin *bin )
00253 {
00254 gtk_widget_reparent( ( GTK_BIN( window ) ) ->child, GTK_WIDGET( bin ) );
00255 }
00256
00257 void DetachWidgets( GtkBin *bin )
00258 {
00259 gtk_widget_reparent( ( GTK_BIN( bin ) ) ->child, GTK_WIDGET( window ) );
00260 }
00261 };
00262
00266 class ImageFilterKaleidoscope: public GDKImageFilter
00267 {
00268 private:
00269 GtkWidget *window;
00270 int type;
00271
00272 public:
00273 ImageFilterKaleidoscope()
00274 {
00275 window = glade_xml_get_widget( magick_glade, "image_filter_kaleidoscope" );
00276 GtkWidget* widget = glade_xml_get_widget( magick_glade, "optionmenu_kaleidoscope" );
00277 g_signal_connect( G_OBJECT( widget ), "changed", G_CALLBACK( Repaint ), 0 );
00278 }
00279
00280 virtual ~ImageFilterKaleidoscope()
00281 {
00282 gtk_widget_destroy( window );
00283 }
00284
00285 char *GetDescription( ) const
00286 {
00287 return _( "Kaleidoscope" );
00288 }
00289
00290 void TopLeft( uint8_t *pixels, int width, int height, double position )
00291 {
00292 uint8_t r, g, b;
00293 uint8_t *p = pixels;
00294 for ( int y = 0; y <= height / 2; y ++ )
00295 {
00296 uint8_t *i = p + y * width * 3;
00297 uint8_t *o = p + ( y + 1 ) * width * 3 - 1;
00298 uint8_t *o1 = p + ( height - y ) * width * 3;
00299 uint8_t *o2 = p + ( height - y + 1 ) * width * 3 - 1;
00300 while ( o > i )
00301 {
00302 r = *i ++;
00303 g = *i ++;
00304 b = *i ++;
00305 *o -- = b;
00306 *o -- = g;
00307 *o -- = r;
00308 *o1 ++ = r;
00309 *o1 ++ = g;
00310 *o1 ++ = b;
00311 *o2 -- = b;
00312 *o2 -- = g;
00313 *o2 -- = r;
00314 }
00315 }
00316 }
00317
00318 void TopRight( uint8_t *pixels, int width, int height, double position )
00319 {
00320 uint8_t r, g, b;
00321 uint8_t *p = pixels;
00322 for ( int y = 0; y <= height / 2; y ++ )
00323 {
00324 uint8_t *i = p + ( y + 1 ) * width * 3 - 1;
00325 uint8_t *o = p + y * width * 3;
00326 uint8_t *o1 = p + ( height - y ) * width * 3;
00327 uint8_t *o2 = p + ( height - y + 1 ) * width * 3 - 1;
00328 while ( i > o )
00329 {
00330 b = *i --;
00331 g = *i --;
00332 r = *i --;
00333 *o ++ = r;
00334 *o ++ = g;
00335 *o ++ = b;
00336 *o1 ++ = r;
00337 *o1 ++ = g;
00338 *o1 ++ = b;
00339 *o2 -- = b;
00340 *o2 -- = g;
00341 *o2 -- = r;
00342 }
00343 }
00344 }
00345
00346 void BottomLeft( uint8_t *pixels, int width, int height, double position )
00347 {
00348 uint8_t r, g, b;
00349 uint8_t *p = pixels;
00350 for ( int y = 0; y <= height / 2; y ++ )
00351 {
00352 uint8_t *o1 = p + y * width * 3;
00353 uint8_t *o2 = p + ( y + 1 ) * width * 3 - 1;
00354 uint8_t *i = p + ( height - y ) * width * 3;
00355 uint8_t *o = p + ( height - y + 1 ) * width * 3 - 1;
00356 while ( o > i )
00357 {
00358 r = *i ++;
00359 g = *i ++;
00360 b = *i ++;
00361 *o -- = b;
00362 *o -- = g;
00363 *o -- = r;
00364 *o1 ++ = r;
00365 *o1 ++ = g;
00366 *o1 ++ = b;
00367 *o2 -- = b;
00368 *o2 -- = g;
00369 *o2 -- = r;
00370 }
00371 }
00372 }
00373
00374 void BottomRight( uint8_t *pixels, int width, int height, double position )
00375 {
00376 uint8_t r, g, b;
00377 uint8_t *p = pixels;
00378 for ( int y = 0; y <= height / 2; y ++ )
00379 {
00380 uint8_t *o2 = p + ( y + 1 ) * width * 3 - 1;
00381 uint8_t *o1 = p + y * width * 3;
00382 uint8_t *o = p + ( height - y ) * width * 3;
00383 uint8_t *i = p + ( height - y + 1 ) * width * 3 - 1;
00384 while ( i > o )
00385 {
00386 b = *i --;
00387 g = *i --;
00388 r = *i --;
00389 *o ++ = r;
00390 *o ++ = g;
00391 *o ++ = b;
00392 *o1 ++ = r;
00393 *o1 ++ = g;
00394 *o1 ++ = b;
00395 *o2 -- = b;
00396 *o2 -- = g;
00397 *o2 -- = r;
00398 }
00399 }
00400 }
00401
00402 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00403 {
00404 GtkMenu * menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( window, "optionmenu_kaleidoscope" ) ) ) );
00405 GtkWidget *active_item = gtk_menu_get_active( menu );
00406 type = g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item );
00407
00408 if ( type == 0 )
00409 TopLeft( pixels, width, height, position );
00410 else if ( type == 1 )
00411 TopRight( pixels, width, height, position );
00412 else if ( type == 2 )
00413 BottomLeft( pixels, width, height, position );
00414 else if ( type == 3 )
00415 BottomRight( pixels, width, height, position );
00416 }
00417
00418 void AttachWidgets( GtkBin *bin )
00419 {
00420 gtk_widget_reparent( ( GTK_BIN( window ) ) ->child, GTK_WIDGET( bin ) );
00421 }
00422
00423 void DetachWidgets( GtkBin *bin )
00424 {
00425 gtk_widget_reparent( ( GTK_BIN( bin ) ) ->child, GTK_WIDGET( window ) );
00426 }
00427 };
00428
00432 class ImageFilterReverseVideo : public ImageFilter
00433 {
00434 public:
00435 char *GetDescription( ) const
00436 {
00437 return _( "Reverse Video" );
00438 }
00439
00440 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00441 {
00442 uint8_t r, g, b;
00443 uint8_t *p = pixels;
00444 while ( p < ( pixels + width * height * 3 ) )
00445 {
00446 r = *( p );
00447 g = *( p + 1 );
00448 b = *( p + 2 );
00449 *p ++ = 0xff - r;
00450 *p ++ = 0xff - g;
00451 *p ++ = 0xff - b;
00452 }
00453 }
00454 };
00455
00459 class ImageFilterSwap : public GDKImageFilter
00460 {
00461 private:
00462 GtkWidget *window;
00463 int type;
00464
00465 public:
00466 ImageFilterSwap()
00467 {
00468 window = glade_xml_get_widget( magick_glade, "image_filter_swap" );
00469 GtkWidget* widget = glade_xml_get_widget( magick_glade, "optionmenu_swap" );
00470 g_signal_connect( G_OBJECT( widget ), "changed", G_CALLBACK( Repaint ), 0 );
00471 }
00472
00473 virtual ~ImageFilterSwap()
00474 {
00475 gtk_widget_destroy( window );
00476 }
00477
00478 char *GetDescription( ) const
00479 {
00480 return _( "Flip" );
00481 }
00482
00483 void LeftRight( uint8_t *pixels, int width, int height, double position )
00484 {
00485 uint8_t r, g, b;
00486 uint8_t *p = pixels;
00487 for ( int y = 0; y < height; y ++ )
00488 {
00489 uint8_t *i = p + y * width * 3;
00490 uint8_t *o = p + ( y + 1 ) * width * 3 - 1;
00491 for ( int x = 0; x < width / 2; x ++ )
00492 {
00493 r = *i;
00494 g = *( i + 1 );
00495 b = *( i + 2 );
00496 *i ++ = *( o - 2 );
00497 *i ++ = *( o - 1 );
00498 *i ++ = *o;
00499 *o -- = b;
00500 *o -- = g;
00501 *o -- = r;
00502 }
00503 }
00504 }
00505
00506 void TopBottom( uint8_t *pixels, int width, int height, double position )
00507 {
00508 uint8_t * p = pixels;
00509 uint8_t keyFrame[ 720 * 3 ];
00510 for ( int y = 0; y < height / 2; y ++ )
00511 {
00512 uint8_t *i = p + y * width * 3;
00513 uint8_t *o = p + ( height - y - 1 ) * width * 3;
00514 memcpy( keyFrame, i, width * 3 );
00515 memcpy( i, o, width * 3 );
00516 memcpy( o, keyFrame, width * 3 );
00517 }
00518 }
00519
00520 void FilterFrame( uint8_t *pixels, int width, int height, double position, double frame_delta )
00521 {
00522 GtkMenu * menu = GTK_MENU( gtk_option_menu_get_menu( GTK_OPTION_MENU( lookup_widget( window, "optionmenu_swap" ) ) ) );
00523 GtkWidget *active_item = gtk_menu_get_active( menu );
00524 type = g_list_index ( GTK_MENU_SHELL ( menu ) ->children, active_item );
00525
00526 if ( type == 0 )
00527 LeftRight( pixels, width, height, position );
00528 else if ( type == 1 )
00529 TopBottom( pixels, width, height, position );
00530 }
00531
00532 void AttachWidgets( GtkBin *bin )
00533 {
00534 gtk_widget_reparent( ( GTK_BIN( window ) ) ->child, GTK_WIDGET( bin ) );
00535 }
00536
00537 void DetachWidgets( GtkBin *bin )
00538 {
00539 gtk_widget_reparent( ( GTK_BIN( bin ) ) ->child, GTK_WIDGET( window ) );
00540 }
00541 };
00542
00546 static void
00547 on_optionmenu_selected ( GtkMenuItem *menu_item, gpointer user_data )
00548 {
00549 ( ( GDKImageFilterRepository * ) user_data ) ->SelectionChange();
00550 }
00551
00557 GDKImageFilterRepository::GDKImageFilterRepository()
00558 : selected_filter( 0 )
00559 {
00560
00561 Register( new ImageFilterKeep() );
00562 Register( new GDKImageFilterAdapter( new ImageFilterBlackWhite() ) );
00563 Register( new ImageFilterKaleidoscope() );
00564 Register( new GDKImageFilterAdapter( new ImageFilterFadeIn() ) );
00565 Register( new GDKImageFilterAdapter( new ImageFilterFadeOut() ) );
00566 Register( new ImageFilterSwap() );
00567 Register( new ImageFilterMirror() );
00568 Register( new GDKImageFilterAdapter( new ImageFilterReverseVideo() ) );
00569 Register( new GDKImageFilterAdapter( new ImageFilterSepia() ) );
00570 }
00571
00575 GDKImageFilterRepository::~GDKImageFilterRepository()
00576 {
00577
00578 for ( unsigned int index = 0; index < filters.size(); index ++ )
00579 delete filters[ index ];
00580 }
00581
00585 void GDKImageFilterRepository::Register( GDKImageFilter *filter )
00586 {
00587 std::cerr << ">>> Image Filter: " << filter->GetDescription( ) << std::endl;
00588 filters.push_back( filter );
00589 }
00590
00594 void GDKImageFilterRepository::Initialise( GtkOptionMenu *menu, GtkBin *container )
00595 {
00596
00597 this->menu = menu;
00598 this->container = container;
00599
00600
00601 GtkMenu *menu_new = GTK_MENU( gtk_menu_new( ) );
00602 for ( unsigned int index = 0; index < filters.size(); index ++ )
00603 {
00604 GtkWidget *item = gtk_menu_item_new_with_label( filters[ index ] ->GetDescription( ) );
00605 gtk_widget_show( item );
00606 gtk_menu_append( menu_new, item );
00607 g_signal_connect( G_OBJECT( item ), "activate", G_CALLBACK( on_optionmenu_selected ), this );
00608 }
00609 gtk_menu_set_active( menu_new, 0 );
00610 gtk_option_menu_set_menu( menu, GTK_WIDGET( menu_new ) );
00611
00612
00613 SelectionChange();
00614 }
00615
00619 GDKImageFilter *GDKImageFilterRepository::Get( ) const
00620 {
00621 GtkMenu * filterMenu = GTK_MENU( gtk_option_menu_get_menu( menu ) );
00622 GtkWidget *active_item = gtk_menu_get_active( filterMenu );
00623 return filters[ g_list_index( GTK_MENU_SHELL( filterMenu ) ->children, active_item ) ];
00624 }
00625
00629 void GDKImageFilterRepository::SelectionChange( )
00630 {
00631 bool isPreviewing = false;
00632 PageMagick* magick = 0;
00633
00634 if ( common && common->getPageMagick( ) )
00635 magick = common->getPageMagick( );
00636 if ( magick && magick->IsPreviewing() )
00637 {
00638 isPreviewing = true;
00639 magick->StopPreview();
00640 }
00641
00642
00643 if ( selected_filter != NULL )
00644 selected_filter->DetachWidgets( container );
00645
00646 if ( magick )
00647 {
00648 magick->SetKeyFrameControllerClient(0);
00649 magick->ShowCurrentStatus( magick->GetCurrentPosition(), LOCKED_KEY, false, false );
00650 }
00651
00652
00653 selected_filter = Get();
00654
00655
00656 if ( selected_filter != NULL )
00657 selected_filter->AttachWidgets( container );
00658
00659 if ( magick )
00660 {
00661 if ( isPreviewing )
00662 magick->StartPreview();
00663 else
00664 magick->PreviewFrame();
00665 }
00666 }