245
253
gtk_widget_destroy(file_selector);
248
GdkPixbuf *img_load_pixbuf_from_file(gchar *filename)
250
GdkPixbuf *thumb = NULL;
252
thumb = gdk_pixbuf_new_from_file_at_scale(filename, 93, 70, TRUE, NULL);
256
slide_struct *img_set_slide_info(gint duration, guint speed, void (*render), gint transition_id, gchar *path, gchar *filename)
258
slide_struct *slide_info = NULL;
259
GdkPixbufFormat *pixbuf_format;
262
slide_info = g_new0(slide_struct,1);
265
slide_info->duration = duration;
266
slide_info->speed = speed;
267
slide_info->render = render;
268
slide_info->transition_id = transition_id;
269
slide_info->path = g_strdup( path );
270
slide_info->filename = g_strdup(filename);
271
pixbuf_format = gdk_pixbuf_get_file_info(filename,&width,&height);
272
slide_info->resolution = g_strdup_printf("%d x %d",width,height);
273
slide_info->type = gdk_pixbuf_format_get_name(pixbuf_format);
257
img_create_new_slide( void )
259
slide_struct *slide = NULL;
261
slide = g_slice_new0( slide_struct );
268
slide->path = g_strdup( "0" );
269
slide->transition_id = -1;
270
slide->speed = NORMAL;
273
slide->cur_point = -1;
276
slide->anim_duration = 1;
277
slide->position = IMG_SUB_POS_MIDDLE_CENTER;
278
slide->placing = IMG_REL_PLACING_EXPORTED_VIDEO;
279
slide->font_desc = pango_font_description_from_string( "Sans 12" );
280
slide->font_color[0] = 0; /* R */
281
slide->font_color[1] = 0; /* G */
282
slide->font_color[2] = 0; /* B */
283
slide->font_color[3] = 1; /* A */
290
img_set_slide_file_info( slide_struct *slide,
291
const gchar *filename )
293
GdkPixbufFormat *format;
297
format = gdk_pixbuf_get_file_info( filename, &width, &height );
299
slide->filename = g_strdup( filename );
300
slide->original_filename = NULL;
302
slide->resolution = g_strdup_printf( "%d x %d", width, height );
303
slide->type = gdk_pixbuf_format_get_name( format );
307
img_set_slide_gradient_info( slide_struct *slide,
309
gdouble *start_color,
311
gdouble *start_point,
312
gdouble *stop_point )
316
slide->gradient = gradient;
317
for( i = 0; i < 3; i++ )
319
slide->g_start_color[i] = start_color[i];
320
slide->g_stop_color[i] = stop_color[i];
322
for( i = 0; i < 2; i++ )
324
slide->g_start_point[i] = start_point[i];
325
slide->g_stop_point[i] = stop_point[i];
330
img_set_slide_still_info( slide_struct *slide,
332
img_window_struct *img )
334
if( slide->duration != duration )
336
slide->duration = duration;
338
if( ! img->total_dur_id )
340
g_idle_add( (GSourceFunc)img_set_total_slideshow_duration, img );
345
img_set_slide_transition_info( slide_struct *slide,
353
img_window_struct *img )
355
/* Set transition render. */
356
if( path && ( slide->transition_id != transition_id ) )
359
g_free( slide->path );
361
slide->path = g_strdup( path );
362
slide->transition_id = transition_id;
363
slide->render = render;
365
gtk_list_store_set( store, iter, 2, pix, -1 );
368
if( speed && ( slide->speed != speed ) )
370
slide->speed = speed;
372
if( ! img->total_dur_id )
374
g_idle_add( (GSourceFunc)img_set_total_slideshow_duration, img );
379
img_set_slide_ken_burns_info( slide_struct *slide,
388
if( slide->no_points )
390
g_list_free( slide->points );
391
slide->no_points = 0;
394
for( i = 0; i < length; i += 4 )
396
/* Create new point */
397
point = g_slice_new( ImgStopPoint );
398
point->time = (gint)( points[0 + i] + 0.5 );
399
point->offx = points[1 + i];
400
point->offy = points[2 + i];
401
point->zoom = points[3 + i];
403
/* Append it to the list */
404
slide->points = g_list_append( slide->points, point );
408
slide->cur_point = CLAMP( cur_point, -1, slide->no_points - 1 );
410
full = img_calc_slide_duration_points( slide->points,
413
slide->duration = full;
417
img_set_slide_text_info( slide_struct *slide,
420
const gchar *subtitle,
425
const gchar *font_desc,
427
img_window_struct *img )
429
/* Set the slide text info parameters */
434
if( slide->subtitle )
435
g_free( slide->subtitle );
436
slide->subtitle = g_strdup( subtitle );
438
flag = ( subtitle ? TRUE : FALSE );
439
gtk_list_store_set( store, iter, 3, flag, -1 );
442
if( ( anim_id > -1 ) && ( anim_id != slide->anim_id ) )
448
path = g_strdup_printf( "%d", anim_id );
449
model = gtk_combo_box_get_model( GTK_COMBO_BOX( img->sub_anim ) );
450
gtk_tree_model_get_iter_from_string( model, &iter, path );
453
slide->anim_id = anim_id;
454
gtk_tree_model_get( model, &iter, 1, &slide->anim, -1 );
457
img_sync_timings( slide, img );
460
if( ( anim_duration > 0 ) && ( anim_duration != slide->anim_duration ) )
462
slide->anim_duration = anim_duration;
464
/* Synchronize timings */
465
img_sync_timings( slide, img );
468
if( ( position > -1 ) && ( position != slide->position ) )
469
slide->position = position;
471
if( ( placing > -1 ) && ( placing != slide->placing ) )
472
slide->placing = placing;
476
if( slide->font_desc )
477
pango_font_description_free( slide->font_desc );
478
slide->font_desc = pango_font_description_from_string( font_desc );
483
slide->font_color[0] = font_color[0];
484
slide->font_color[1] = font_color[1];
485
slide->font_color[2] = font_color[2];
486
slide->font_color[3] = font_color[3];
491
img_free_slide_struct( slide_struct *entry )
495
if (entry->original_filename)
496
g_free(entry->original_filename);
497
g_free(entry->filename);
498
g_free(entry->resolution);
501
/* Free stop point list */
502
for( tmp = entry->points; tmp; tmp = g_list_next( tmp ) )
503
g_slice_free( ImgStopPoint, tmp->data );
504
g_list_free( entry->points );
506
g_slice_free( slide_struct, entry );
510
img_set_total_slideshow_duration( img_window_struct *img )
519
model = GTK_TREE_MODEL( img->thumbnail_model );
520
if( gtk_tree_model_get_iter_first( model, &iter ) )
524
gtk_tree_model_get( model, &iter, 1, &entry, -1 );
525
img->total_secs += entry->duration;
528
img->total_secs += entry->speed;
530
while( gtk_tree_model_iter_next( model, &iter ) );
532
/* Add time of last pseudo slide */
533
if( img->final_transition.render )
534
img->total_secs += img->final_transition.speed;
537
time = img_convert_seconds_to_time(img->total_secs);
538
gtk_label_set_text(GTK_LABEL (img->total_time_data),time);
541
/* This is here only to be able to add this to idle source. */
542
img->total_dur_id = 0;
547
img_calc_slide_duration_points( GList *list,
551
gint i, duration = 0;
554
/* If we have no points, return 0 */
558
/* Calculate length */
559
for( tmp = list, i = 0; i < length; tmp = g_list_next( tmp ), i++ )
561
point = (ImgStopPoint *)tmp->data;
562
duration += point->time;
571
* This function should be called for all image loading needs. It'll properly
572
* scale and trim loaded images, add borders if needed and return surface or
573
* pixbuf of requested size.
575
* If one of the size requests is 0, the other one will be calculated from
576
* first one with aspect ratio calculation. If both dimensions are 0, image
577
* will be loaded from disk at original size (this is mainly used for export,
578
* when we want to have images at their best quality).
580
* Return value: TRUE if image loading succeded, FALSE otherwise.
583
img_scale_image( const gchar *filename,
590
cairo_surface_t **surface )
592
GdkPixbuf *loader; /* Pixbuf used for loading */
593
gint i_width, i_height; /* Image dimensions */
594
gint offset_x, offset_y; /* Offset values for borders */
595
gdouble i_ratio; /* Export and image aspect ratios */
596
gdouble skew; /* Transformation between ratio and
598
gboolean transform = FALSE; /* Flag that controls scalling */
600
/* MAximal distortion values */
601
gdouble max_stretch = 0.1280;
602
gdouble max_crop = 0.8500;
604
/* Borderline skew values */
605
gdouble max_skew = ( 1 + max_stretch ) / max_crop;
606
gdouble min_skew = ( 1 - max_stretch ) * max_crop;
608
/* Obtain information about image being loaded */
609
if( ! gdk_pixbuf_get_file_info( filename, &i_width, &i_height ) )
612
/* How distorted images would be if we scaled them */
613
i_ratio = (gdouble)i_width / i_height;
614
skew = ratio / i_ratio;
616
/* Calculationg surface dimensions.
618
* In order to be as flexible as possible, this function can load images at
619
* various sizes, but at aspect ration that matches the aspect ratio of main
620
* preview area. How size is determined? If width argument is not -1, this
621
* is taken as a reference dimension from which height is calculated (if
622
* height argument also present, it's ignored). If width argument is -1,
623
* height is taken as a reference dimension. If both width and height are
624
* -1, surface dimensions are calculated to to fit original image.
628
/* Calculate height according to width */
629
height = width / ratio;
631
else if( height > 0 )
633
/* Calculate width from height */
634
width = height * ratio;
638
/* Load image at maximum quality
640
* If the user doesn't want to have distorted images, we create slightly
641
* bigger surface that will hold borders too.
643
* If images should be distorted, we first check if we're able to fit
644
* image without distorting it too much. If images would be largely
645
* distorted, we simply load them undistorted.
647
* If we came all the way to here, then we're able to distort image.
649
if( ( ! distort ) || /* Don't distort */
650
( skew > max_skew ) || /* Image is too wide */
651
( skew < min_skew ) ) /* Image is too tall */
653
/* User doesn't want images to be distorted or distortion would be
655
if( ratio < i_ratio )
657
/* Borders will be added on left and right */
659
height = width / ratio;
663
/* Borders will be added on top and bottom */
665
width = height * ratio;
670
/* User wants images to be distorted and we're able to do it
671
* without ruining images. */
672
if( ratio < i_ratio )
674
/* Image will be distorted horizontally */
676
width = height * ratio;
680
/* Image will be distorted vertically */
682
height = width / ratio;
687
/* Will image be disotrted?
690
* - user allows us to do it
691
* - skew is in sensible range
692
* - image is not smaller than exported wideo size
694
transform = distort && skew < max_skew && skew > min_skew &&
695
( i_width >= width || i_height >= height );
697
/* Load image into pixbuf at proper size */
702
/* Images will be loaded at slightly modified dimensions */
703
if( ratio < i_ratio )
705
/* Horizontal scaling */
706
lw = (gdouble)width / ( skew + 1 ) * 2;
711
/* Vertical scaling */
713
lh = (gdouble)height * ( skew + 1 ) / 2;
715
loader = gdk_pixbuf_new_from_file_at_scale( filename, lw, lh,
720
/* Simply load image into pixbuf at size */
721
loader = gdk_pixbuf_new_from_file_at_size( filename, width,
727
i_width = gdk_pixbuf_get_width( loader );
728
i_height = gdk_pixbuf_get_height( loader );
730
/* Calculate offsets */
731
offset_x = ( width - i_width ) / 2; /* CAN BE NEGATIVE!!! */
732
offset_y = ( height - i_height ) / 2; /* CAN BE NEGATIVE!!! */
736
* We can give two different output formats: cairo_surface_t and GdkPixbuf.
740
/* Create new pixbuf with loaded image */
741
GdkPixbuf *tmp_pix; /* Pixbuf used for loading */
742
guint32 tmp_color; /* Background color */
744
tmp_color = ( (gint)( color[0] * 0xff ) << 24 ) |
745
( (gint)( color[1] * 0xff ) << 16 ) |
746
( (gint)( color[2] * 0xff ) << 8 );
747
tmp_pix = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, width, height );
748
gdk_pixbuf_fill( tmp_pix, tmp_color );
749
gdk_pixbuf_composite( loader, tmp_pix,
750
MAX( 0, offset_x ), MAX( 0, offset_y ),
751
MIN( i_width, width ), MIN( i_height, height ),
752
offset_x, offset_y, 1, 1,
753
GDK_INTERP_BILINEAR, 255 );
759
/* Paint surface with loaded image
761
* If image cannot be scalled, transform is FALSE. In this case, just
762
* borders are added. If transform is not 0, than scale image before
764
cairo_t *cr; /* Cairo, used to transform image */
765
cairo_surface_t *tmp_surf; /* Surface to draw on */
767
/* Create image surface with proper dimensions */
768
tmp_surf = cairo_image_surface_create( CAIRO_FORMAT_RGB24,
771
cr = cairo_create( tmp_surf );
775
/* Fill with background color */
776
cairo_set_source_rgb( cr, color[0], color[1], color[2] );
781
gdk_cairo_set_source_pixbuf( cr, loader, offset_x, offset_y );
790
/* Free temporary pixbuf */
791
g_object_unref( G_OBJECT( loader ) );
797
img_set_project_mod_state( img_window_struct *img,
800
if( ( img->project_is_modified ? modified : ! modified ) )
803
img->project_is_modified = modified;
805
/* FIXME: Do any updates here (add "*" to window title, ...). */
809
img_sync_timings( slide_struct *slide,
810
img_window_struct *img )
812
/* If times are already synchronized, return */
813
if( slide->duration >= slide->anim_duration )
816
/* Do the right thing;) */
817
if( slide->no_points )
822
/* Calculate difference that we need to accomodate */
823
diff = slide->anim_duration - slide->duration;
825
/* Elongate last point */
826
point = (ImgStopPoint *)g_list_last( slide->points )->data;
829
/* Update Ken Burns display */
830
gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->ken_duration ),
835
gtk_spin_button_set_value( GTK_SPIN_BUTTON( img->duration ),
836
slide->anim_duration );
839
void img_select_nth_slide(img_window_struct *img, gint slide_to_select)
843
gtk_icon_view_unselect_all(GTK_ICON_VIEW (img->active_icon));
844
path = gtk_tree_path_new_from_indices(slide_to_select, -1);
845
gtk_icon_view_set_cursor (GTK_ICON_VIEW (img->active_icon), path, NULL, FALSE);
846
gtk_icon_view_select_path (GTK_ICON_VIEW (img->active_icon), path);
847
gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (img->active_icon), path, FALSE, 0, 0);
848
gtk_tree_path_free (path);
852
img_convert_surface_to_pixbuf( cairo_surface_t *surface )
855
gint w, h, ss, sp, row, col;
856
guchar *data_s, *data_p;
858
/* Information about surface */
859
w = cairo_image_surface_get_width( surface );
860
h = cairo_image_surface_get_height( surface );
861
ss = cairo_image_surface_get_stride( surface );
862
data_s = cairo_image_surface_get_data( surface );
864
/* Create new pixbuf according to upper specs */
865
pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, w, h );
867
/* Get info about new pixbuf */
868
sp = gdk_pixbuf_get_rowstride( pixbuf );
869
data_p = gdk_pixbuf_get_pixels( pixbuf );
872
for( row = 0; row < h; row++ )
874
for( col = 0; col < w; col++ )
876
gint index_s, index_p;
878
index_s = row * ss + col * 4;
879
index_p = row * sp + col * 3;
881
data_p[index_p + 0] = data_s[index_s + 2];
882
data_p[index_p + 1] = data_s[index_s + 1];
883
data_p[index_p + 2] = data_s[index_s + 0];
891
img_scale_gradient( gint gradient,
899
cairo_surface_t **surface )
903
cairo_pattern_t *pat;
904
gdouble diffx, diffy, radius;
906
sf = cairo_image_surface_create( CAIRO_FORMAT_RGB24, width, height );
907
cr = cairo_create( sf );
911
case 0: /* Solid color */
912
cairo_set_source_rgb( cr, c_start[0], c_start[1], c_start[2] );
916
case 1: /* Linear gradient */
917
pat = cairo_pattern_create_linear( p_start[0] * width,
920
p_stop[1] * height );
921
cairo_pattern_add_color_stop_rgb( pat, 0, c_start[0],
922
c_start[1], c_start[2] );
923
cairo_pattern_add_color_stop_rgb( pat, 1, c_stop[0],
924
c_stop[1], c_stop[2] );
925
cairo_set_source( cr, pat );
927
cairo_pattern_destroy( pat );
930
case 2: /* Radial gradient */
931
diffx = ABS( p_start[0] - p_stop[0] ) * width;
932
diffy = ABS( p_start[1] - p_stop[1] ) * height;
933
radius = sqrt( pow( diffx, 2 ) + pow( diffy, 2 ) );
935
pat = cairo_pattern_create_radial( p_start[0] * width,
936
p_start[1] * height, 0,
938
p_start[1] * height, radius );
939
cairo_pattern_add_color_stop_rgb( pat, 0, c_start[0],
940
c_start[1], c_start[2] );
941
cairo_pattern_add_color_stop_rgb( pat, 1, c_stop[0],
942
c_stop[1], c_stop[2] );
943
cairo_set_source( cr, pat );
945
cairo_pattern_destroy( pat );
954
*pixbuf = img_convert_surface_to_pixbuf( sf );
955
cairo_surface_destroy( sf );