7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
17 #include "image-load.h"
19 #include "color-man.h"
21 #include "pixbuf-renderer.h"
22 #include "pixbuf_util.h"
23 #include "ui_fileops.h"
30 /* size of the image loader buffer (512 bytes x defined number) */
31 #define IMAGE_LOAD_BUFFER_COUNT 8
33 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
34 #define IMAGE_THROTTLE_LARGER_IMAGES 1
36 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
37 #define IMAGE_THROTTLE_FACTOR 4
39 /* the file size at which throttling take place */
40 #define IMAGE_THROTTLE_THRESHOLD 1048576
42 #define IMAGE_AUTO_REFRESH_TIME 3000
45 static GList *image_list = NULL;
48 static void image_update_title(ImageWindow *imd);
49 static void image_post_process(ImageWindow *imd, gint clamp);
50 static void image_read_ahead_start(ImageWindow *imd);
53 *-------------------------------------------------------------------
55 *-------------------------------------------------------------------
58 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
60 ImageWindow *imd = data;
64 imd->func_button(imd, event->button, event->time,
65 event->x, event->y, event->state, imd->data_button);
69 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
71 ImageWindow *imd = data;
74 pixbuf_renderer_get_scaled_size(pr, &width, &height);
78 imd->func_drag(imd, event->button, event->time,
79 event->x, event->y, event->state,
80 (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
85 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
87 ImageWindow *imd = data;
89 if (imd->func_scroll_notify && pr->scale)
91 imd->func_scroll_notify(imd,
92 (gint)((gdouble)pr->x_scroll / pr->scale),
93 (gint)((gdouble)pr->y_scroll / pr->scale),
94 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
95 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
96 imd->data_scroll_notify);
100 static void image_update_util(ImageWindow *imd)
102 if (imd->func_update) imd->func_update(imd, imd->data_update);
105 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
107 ImageWindow *imd = data;
109 if (imd->title_show_zoom) image_update_title(imd);
110 image_update_util(imd);
113 static void image_complete_util(ImageWindow *imd, gint preload)
115 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
117 if (debug) printf("image load completed \"%s\" (%s)\n",
118 (preload) ? (imd->read_ahead_fd ? imd->read_ahead_fd->path : "null") :
119 (imd->image_fd ? imd->image_fd->path : "null"),
120 (preload) ? "preload" : "current");
122 if (!preload) imd->completed = TRUE;
123 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
126 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
128 ImageWindow *imd = data;
130 image_complete_util(imd, FALSE);
133 static void image_state_set(ImageWindow *imd, ImageState state)
135 if (state == IMAGE_STATE_NONE)
143 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
146 static void image_state_unset(ImageWindow *imd, ImageState state)
148 imd->state &= ~state;
149 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
153 *-------------------------------------------------------------------
155 *-------------------------------------------------------------------
158 static void image_update_title(ImageWindow *imd)
162 gchar *collection = NULL;
164 if (!imd->top_window) return;
166 if (imd->collection && collection_to_number(imd->collection) >= 0)
169 name = imd->collection->name;
170 if (!name) name = _("Untitled");
171 collection = g_strdup_printf(" (Collection %s)", name);
174 if (imd->title_show_zoom)
176 gchar *buf = image_zoom_get_as_text(imd);
177 zoom = g_strconcat(" [", buf, "]", NULL);
181 title = g_strdup_printf("%s%s%s%s%s%s",
182 imd->title ? imd->title : "",
183 imd->image_fd ? imd->image_fd->name : "",
185 collection ? collection : "",
186 imd->image_fd ? " - " : "",
187 imd->title_right ? imd->title_right : "");
189 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
197 *-------------------------------------------------------------------
198 * rotation, flip, etc.
199 *-------------------------------------------------------------------
202 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
205 GdkPixbuf *new = NULL;
210 pr = (PixbufRenderer *)imd->pr;
212 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
213 imd->delay_alter_type = ALTER_NONE;
215 if (!pr->pixbuf) return;
217 x = pr->x_scroll + (pr->vis_width / 2);
218 y = pr->y_scroll + (pr->vis_height / 2);
222 case ALTER_ROTATE_90:
223 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
228 case ALTER_ROTATE_90_CC:
229 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
234 case ALTER_ROTATE_180:
235 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
240 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
244 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
247 case ALTER_DESATURATE:
248 pixbuf_desaturate_rect(pr->pixbuf,
249 0, 0, pr->image_width, pr->image_height);
250 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
260 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
263 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
267 switch (pr->scroll_reset)
269 case PR_SCROLL_RESET_NOCHANGE:
271 case PR_SCROLL_RESET_CENTER:
272 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
273 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
275 case PR_SCROLL_RESET_TOPLEFT:
282 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
283 (gint)((gdouble)y / pr->scale),
287 if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
290 static void image_post_process_alter(ImageWindow *imd, gint clamp)
292 if (imd->delay_alter_type != ALTER_NONE)
294 image_alter_real(imd, imd->delay_alter_type, clamp);
298 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
300 ImageWindow *imd = data;
303 if (type == COLOR_RETURN_IMAGE_CHANGED)
305 if (cm == imd->cm) imd->cm = NULL;
310 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
312 image_post_process_alter(imd, FALSE);
314 image_read_ahead_start(imd);
317 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif)
320 ColorManProfileType input_type;
321 ColorManProfileType screen_type;
322 const gchar *input_file;
323 const gchar *screen_file;
324 ExifItem *item = NULL;
326 if (imd->cm) return FALSE;
328 if (imd->color_profile_input >= 1 &&
329 imd->color_profile_input <= COLOR_PROFILE_INPUTS)
333 n = imd->color_profile_input - 1;
334 if (!color_profile_input_file[n]) return FALSE;
336 input_type = COLOR_PROFILE_FILE;
337 input_file = color_profile_input_file[n];
339 else if (imd->color_profile_input == 0)
341 input_type = COLOR_PROFILE_SRGB;
349 if (imd->color_profile_screen == 1 &&
350 color_profile_screen_file)
352 screen_type = COLOR_PROFILE_FILE;
353 screen_file = color_profile_screen_file;
355 else if (imd->color_profile_screen == 0)
357 screen_type = COLOR_PROFILE_SRGB;
365 if (imd->color_profile_use_image && exif)
367 item = exif_get_item(exif, "ColorProfile");
372 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
373 if (exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs) &&
376 input_type = COLOR_PROFILE_SRGB;
379 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
384 if (item && exif_item_get_format_id(item) == EXIF_FORMAT_UNDEFINED)
388 if (debug) printf("Found embedded color profile\n");
390 data = exif_item_get_data(item, &data_len);
392 cm = color_man_new_embedded(imd, NULL,
394 screen_type, screen_file,
395 image_post_process_color_cb, imd);
399 cm = color_man_new(imd, NULL,
400 input_type, input_file,
401 screen_type, screen_file,
402 image_post_process_color_cb, imd);
410 cm->incremental_sync = TRUE;
413 imd->cm = (gpointer)cm;
420 static void image_post_process(ImageWindow *imd, gint clamp)
422 ExifData *exif = NULL;
424 if (!image_get_pixbuf(imd)) return;
426 if (exif_rotate_enable ||
427 (imd->color_profile_enable && imd->color_profile_use_image) )
429 exif = exif_read_fd(imd->image_fd, (imd->color_profile_enable && imd->color_profile_use_image));
432 if (exif_rotate_enable && exif)
436 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
440 /* see http://jpegclub.org/exif_orientation.html
443 888888 888888 88 88 8888888888 88 88 8888888888
444 88 88 88 88 88 88 88 88 88 88 88 88
445 8888 8888 8888 8888 88 8888888888 8888888888 88
451 case EXIF_ORIENTATION_TOP_LEFT:
452 /* normal -- nothing to do */
455 case EXIF_ORIENTATION_TOP_RIGHT:
457 imd->delay_alter_type = ALTER_MIRROR;
459 case EXIF_ORIENTATION_BOTTOM_RIGHT:
461 imd->delay_alter_type = ALTER_ROTATE_180;
463 case EXIF_ORIENTATION_BOTTOM_LEFT:
465 imd->delay_alter_type = ALTER_FLIP;
467 case EXIF_ORIENTATION_LEFT_TOP:
468 /* not implemented -- too wacky to fix in one step */
471 case EXIF_ORIENTATION_RIGHT_TOP:
472 /* rotated -90 (270) */
473 imd->delay_alter_type = ALTER_ROTATE_90;
475 case EXIF_ORIENTATION_RIGHT_BOTTOM:
476 /* not implemented -- too wacky to fix in one step */
479 case EXIF_ORIENTATION_LEFT_BOTTOM:
481 imd->delay_alter_type = ALTER_ROTATE_90_CC;
484 /* The other values are out of range */
489 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
493 if (imd->color_profile_enable)
495 if (!image_post_process_color(imd, 0, exif))
497 /* fixme: note error to user */
498 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
502 if (!imd->cm) image_post_process_alter(imd, clamp);
508 *-------------------------------------------------------------------
509 * read ahead (prebuffer)
510 *-------------------------------------------------------------------
513 static void image_read_ahead_cancel(ImageWindow *imd)
515 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
517 image_loader_free(imd->read_ahead_il);
518 imd->read_ahead_il = NULL;
520 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
521 imd->read_ahead_pixbuf = NULL;
523 file_data_unref(imd->read_ahead_fd);
524 imd->read_ahead_fd = NULL;
527 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
529 ImageWindow *imd = data;
531 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_fd->path);
533 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
534 if (imd->read_ahead_pixbuf)
536 g_object_ref(imd->read_ahead_pixbuf);
540 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
542 image_loader_free(imd->read_ahead_il);
543 imd->read_ahead_il = NULL;
545 image_complete_util(imd, TRUE);
548 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
550 /* we even treat errors as success, maybe at least some of the file was ok */
551 image_read_ahead_done_cb(il, data);
554 static void image_read_ahead_start(ImageWindow *imd)
556 /* already started ? */
557 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
559 /* still loading ?, do later */
560 if (imd->il || imd->cm) return;
562 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_fd->path);
564 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
566 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
567 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
569 image_read_ahead_cancel(imd);
570 image_complete_util(imd, TRUE);
574 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
576 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
578 image_read_ahead_cancel(imd);
580 imd->read_ahead_fd = file_data_ref(fd);
582 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_fd->path);
584 image_read_ahead_start(imd);
588 *-------------------------------------------------------------------
590 *-------------------------------------------------------------------
593 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
595 file_data_unref(imd->prev_fd);
596 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
600 imd->prev_fd = file_data_ref(fd);
602 g_object_ref(pixbuf);
603 imd->prev_pixbuf = pixbuf;
604 imd->prev_color_row = color_row;
609 imd->prev_pixbuf = NULL;
610 imd->prev_color_row = -1;
613 if (debug) printf("post buffer set: %s\n", fd ? fd->path : "null");
616 static gint image_post_buffer_get(ImageWindow *imd)
620 if (imd->prev_pixbuf &&
621 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
623 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
624 if (imd->prev_color_row >= 0)
626 ExifData *exif = NULL;
628 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd, TRUE);
629 image_post_process_color(imd, imd->prev_color_row, exif);
639 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
640 imd->prev_pixbuf = NULL;
642 file_data_unref(imd->prev_fd);
649 *-------------------------------------------------------------------
651 *-------------------------------------------------------------------
654 static void image_load_pixbuf_ready(ImageWindow *imd)
656 if (image_get_pixbuf(imd) || !imd->il) return;
658 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
661 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
663 ImageWindow *imd = data;
666 pr = (PixbufRenderer *)imd->pr;
668 if (imd->delay_flip &&
669 pr->pixbuf != image_loader_get_pixbuf(il))
674 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
676 pixbuf_renderer_area_changed(pr, x, y, w, h);
679 static void image_load_done_cb(ImageLoader *il, gpointer data)
681 ImageWindow *imd = data;
683 if (debug) printf ("image done\n");
685 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
686 image_state_unset(imd, IMAGE_STATE_LOADING);
688 if (imd->delay_flip &&
689 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
691 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
692 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
695 image_loader_free(imd->il);
698 image_post_process(imd, TRUE);
700 image_read_ahead_start(imd);
703 static void image_load_error_cb(ImageLoader *il, gpointer data)
705 if (debug) printf ("image error\n");
707 /* even on error handle it like it was done,
708 * since we have a pixbuf with _something_ */
710 image_load_done_cb(il, data);
713 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
714 static void image_load_buffer_throttle(ImageLoader *il)
716 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
718 /* Larger image files usually have larger chunks of data per pixel...
719 * So increase the buffer read size so that the rendering chunks called
723 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
727 /* this read ahead is located here merely for the callbacks, above */
729 static gint image_read_ahead_check(ImageWindow *imd)
731 if (!imd->read_ahead_fd) return FALSE;
732 if (imd->il) return FALSE;
734 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
736 image_read_ahead_cancel(imd);
740 if (imd->read_ahead_il)
742 imd->il = imd->read_ahead_il;
743 imd->read_ahead_il = NULL;
745 /* override the old signals */
746 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
747 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
748 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
750 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
751 image_load_buffer_throttle(imd->il);
754 /* do this one directly (probably should add a set func) */
755 imd->il->func_done = image_load_done_cb;
757 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
758 image_state_set(imd, IMAGE_STATE_LOADING);
760 if (!imd->delay_flip)
762 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
765 image_read_ahead_cancel(imd);
768 else if (imd->read_ahead_pixbuf)
770 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
771 g_object_unref(imd->read_ahead_pixbuf);
772 imd->read_ahead_pixbuf = NULL;
774 image_read_ahead_cancel(imd);
776 image_post_process(imd, FALSE);
780 image_read_ahead_cancel(imd);
784 static gint image_load_begin(ImageWindow *imd, FileData *fd)
786 if (debug) printf ("image begin \n");
788 if (imd->il) return FALSE;
790 imd->completed = FALSE;
791 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
793 if (image_post_buffer_get(imd))
795 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
799 if (image_read_ahead_check(imd))
801 if (debug) printf("from read ahead buffer: %s\n", imd->image_fd->path);
805 if (!imd->delay_flip && image_get_pixbuf(imd))
809 pr = PIXBUF_RENDERER(imd->pr);
810 if (pr->pixbuf) g_object_unref(pr->pixbuf);
814 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
816 imd->il = image_loader_new(fd);
818 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
819 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
820 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
822 if (!image_loader_start(imd->il, image_load_done_cb, imd))
824 if (debug) printf("image start error\n");
826 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
828 image_loader_free(imd->il);
831 image_complete_util(imd, FALSE);
836 image_state_set(imd, IMAGE_STATE_LOADING);
838 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
839 image_load_buffer_throttle(imd->il);
842 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
847 static void image_reset(ImageWindow *imd)
849 /* stops anything currently being done */
851 if (debug) printf("image reset\n");
853 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
855 image_loader_free(imd->il);
858 color_man_free((ColorMan *)imd->cm);
861 imd->delay_alter_type = ALTER_NONE;
863 image_state_set(imd, IMAGE_STATE_NONE);
867 *-------------------------------------------------------------------
869 *-------------------------------------------------------------------
872 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
876 if (imd->image_fd && isfile(imd->image_fd->path))
880 pr = PIXBUF_RENDERER(imd->pr);
881 pr->zoom = zoom; /* store the zoom, needed by the loader */
883 if (image_load_begin(imd, imd->image_fd))
885 imd->unknown = FALSE;
891 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
892 image_change_pixbuf(imd, pixbuf, zoom);
893 g_object_unref(pixbuf);
897 imd->size = filesize(imd->image_fd->path);
898 imd->mtime = filetime(imd->image_fd->path);
906 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
907 image_change_pixbuf(imd, pixbuf, zoom);
908 g_object_unref(pixbuf);
909 imd->mtime = filetime(imd->image_fd->path);
913 image_change_pixbuf(imd, NULL, zoom);
920 image_update_util(imd);
923 static void image_change_real(ImageWindow *imd, FileData *fd,
924 CollectionData *cd, CollectInfo *info, gdouble zoom)
927 GdkPixbuf *prev_pixbuf = NULL;
928 FileData *prev_fd = NULL;
929 gint prev_clear = FALSE;
930 gint prev_color_row = -1;
932 imd->collection = cd;
933 imd->collection_info = info;
935 pixbuf = image_get_pixbuf(imd);
937 if (enable_read_ahead && imd->image_fd && pixbuf)
941 /* current image is not finished */
946 prev_fd = file_data_ref(imd->image_fd);
947 prev_pixbuf = pixbuf;
948 g_object_ref(prev_pixbuf);
954 cm = (ColorMan *)imd->cm;
955 prev_color_row = cm->row;
960 file_data_unref(imd->image_fd);
961 imd->image_fd = file_data_ref(fd);
963 image_change_complete(imd, zoom, TRUE);
967 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
968 file_data_unref(prev_fd);
969 g_object_unref(prev_pixbuf);
973 image_post_buffer_set(imd, NULL, NULL, -1);
976 image_update_title(imd);
977 image_state_set(imd, IMAGE_STATE_IMAGE);
981 *-------------------------------------------------------------------
983 *-------------------------------------------------------------------
986 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
990 widget = imd->widget;
991 if (!widget->window) return;
995 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
996 area, widget, "image_window",
997 widget->allocation.x, widget->allocation.y,
998 widget->allocation.width - 1, widget->allocation.height - 1);
1002 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1003 area, widget, "image_window",
1004 widget->allocation.x, widget->allocation.y,
1005 widget->allocation.width - 1, widget->allocation.height - 1);
1009 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1011 ImageWindow *imd = data;
1013 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1017 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1019 ImageWindow *imd = data;
1021 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1022 image_focus_paint(imd, TRUE, NULL);
1027 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1029 ImageWindow *imd = data;
1031 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1032 image_focus_paint(imd, FALSE, NULL);
1037 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1038 gint relative, gint always)
1040 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1043 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1045 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1048 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1050 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1053 void image_overlay_remove(ImageWindow *imd, gint id)
1055 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1058 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1060 ImageWindow *imd = data;
1062 if (imd->func_scroll &&
1063 event && event->type == GDK_SCROLL)
1065 imd->func_scroll(imd, event->direction, event->time,
1066 event->x, event->y, event->state, imd->data_scroll);
1074 *-------------------------------------------------------------------
1076 *-------------------------------------------------------------------
1079 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1080 const gchar *title, const gchar *title_right, gint show_zoom)
1082 imd->top_window = window;
1084 imd->title = g_strdup(title);
1085 g_free(imd->title_right);
1086 imd->title_right = g_strdup(title_right);
1087 imd->title_show_zoom = show_zoom;
1089 if (!fit_window) window = NULL;
1091 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1093 image_update_title(imd);
1096 void image_set_update_func(ImageWindow *imd,
1097 void (*func)(ImageWindow *imd, gpointer data),
1100 imd->func_update = func;
1101 imd->data_update = data;
1104 void image_set_complete_func(ImageWindow *imd,
1105 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1108 imd->func_complete = func;
1109 imd->data_complete = data;
1112 void image_set_state_func(ImageWindow *imd,
1113 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1116 imd->func_state = func;
1117 imd->data_state = data;
1121 void image_set_button_func(ImageWindow *imd,
1122 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1125 imd->func_button = func;
1126 imd->data_button = data;
1129 void image_set_drag_func(ImageWindow *imd,
1130 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1133 imd->func_drag = func;
1134 imd->data_drag = data;
1137 void image_set_scroll_func(ImageWindow *imd,
1138 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1141 imd->func_scroll = func;
1142 imd->data_scroll = data;
1145 void image_set_scroll_notify_func(ImageWindow *imd,
1146 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1149 imd->func_scroll_notify = func;
1150 imd->data_scroll_notify = data;
1155 const gchar *image_get_path(ImageWindow *imd)
1157 if (imd->image_fd == NULL) return NULL;
1158 return imd->image_fd->path;
1161 const gchar *image_get_name(ImageWindow *imd)
1163 if (imd->image_fd == NULL) return NULL;
1164 return imd->image_fd->name;
1167 FileData *image_get_fd(ImageWindow *imd)
1169 return imd->image_fd;
1172 /* merely changes path string, does not change the image! */
1173 void image_set_fd(ImageWindow *imd, FileData *fd)
1175 file_data_unref(imd->image_fd);
1176 imd->image_fd = file_data_ref(fd);
1178 image_update_title(imd);
1179 image_state_set(imd, IMAGE_STATE_IMAGE);
1182 /* load a new image */
1184 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1186 if (imd->image_fd == fd) return;
1188 image_change_real(imd, fd, NULL, NULL, zoom);
1191 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1193 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1196 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1198 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1199 image_state_set(imd, IMAGE_STATE_IMAGE);
1202 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1204 if (!cd || !info || !g_list_find(cd->list, info)) return;
1206 image_change_real(imd, info->fd, cd, info, zoom);
1209 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1211 if (collection_to_number(imd->collection) >= 0)
1213 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1215 if (info) *info = imd->collection_info;
1219 if (info) *info = NULL;
1221 return imd->collection;
1224 if (info) *info = NULL;
1228 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1230 /* change data for the callbacks directly */
1232 il->data_area_ready = data;
1233 il->data_error = data;
1234 il->data_done = data;
1235 il->data_percent = data;
1238 /* this is more like a move function
1239 * it moves most data from source to imd
1241 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1243 if (imd == source) return;
1245 imd->unknown = source->unknown;
1247 imd->collection = source->collection;
1248 imd->collection_info = source->collection_info;
1249 imd->size = source->size;
1250 imd->mtime = source->mtime;
1252 image_set_fd(imd, image_get_fd(source));
1254 image_loader_free(imd->il);
1259 imd->il = source->il;
1262 image_loader_sync_data(imd->il, imd);
1264 imd->delay_alter_type = source->delay_alter_type;
1265 source->delay_alter_type = ALTER_NONE;
1268 imd->color_profile_enable = source->color_profile_enable;
1269 imd->color_profile_input = source->color_profile_input;
1270 imd->color_profile_screen = source->color_profile_screen;
1271 imd->color_profile_use_image = source->color_profile_use_image;
1272 color_man_free((ColorMan *)imd->cm);
1278 imd->cm = source->cm;
1281 cm = (ColorMan *)imd->cm;
1283 cm->func_done_data = imd;
1286 image_loader_free(imd->read_ahead_il);
1287 imd->read_ahead_il = source->read_ahead_il;
1288 source->read_ahead_il = NULL;
1289 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1291 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1292 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1293 source->read_ahead_pixbuf = NULL;
1295 file_data_unref(imd->read_ahead_fd);
1296 imd->read_ahead_fd = source->read_ahead_fd;
1297 source->read_ahead_fd = NULL;
1299 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1300 imd->prev_pixbuf = source->prev_pixbuf;
1301 source->prev_pixbuf = NULL;
1302 imd->prev_color_row = source->prev_color_row;
1303 source->prev_color_row = -1;
1305 file_data_unref(imd->prev_fd);
1306 imd->prev_fd = source->prev_fd;
1307 source->prev_fd = NULL;
1309 imd->completed = source->completed;
1310 imd->state = source->state;
1311 source->state = IMAGE_STATE_NONE;
1313 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1318 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1320 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1323 void image_reload(ImageWindow *imd)
1325 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1327 image_change_complete(imd, image_zoom_get(imd), FALSE);
1330 void image_scroll(ImageWindow *imd, gint x, gint y)
1332 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1335 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1336 gdouble x_align, gdouble y_align)
1338 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1341 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1343 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1346 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1348 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1353 void image_alter(ImageWindow *imd, AlterType type)
1355 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1357 if (imd->il || imd->cm)
1359 /* still loading, wait till done */
1360 imd->delay_alter_type = type;
1361 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1363 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1365 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1370 image_alter_real(imd, type, TRUE);
1373 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1375 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1378 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1380 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1383 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1385 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1388 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1390 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1393 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1399 pr = (PixbufRenderer *)imd->pr;
1401 if (!pixbuf_renderer_get_pixbuf(pr) ||
1402 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1406 zoom = (gdouble)pr->window_height / height;
1410 zoom = (gdouble)pr->window_width / width;
1415 zoom = 0.0 - 1.0 / zoom;
1418 pixbuf_renderer_zoom_set(pr, zoom);
1421 gdouble image_zoom_get(ImageWindow *imd)
1423 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1426 gdouble image_zoom_get_real(ImageWindow *imd)
1428 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1431 gchar *image_zoom_get_as_text(ImageWindow *imd)
1439 gchar *approx = " ";
1441 zoom = image_zoom_get(imd);
1442 scale = image_zoom_get_real(imd);
1448 else if (zoom < 0.0)
1452 else if (zoom == 0.0 && scale != 0.0)
1465 if (rint(l) != l) pl = 1;
1466 if (rint(r) != r) pr = 1;
1468 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1471 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1475 if (mode == ZOOM_RESET_ORIGINAL)
1479 else if (mode == ZOOM_RESET_FIT_WINDOW)
1487 zoom = image_zoom_get(imd);
1500 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1502 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1506 image_read_ahead_set(imd, fd);
1510 image_read_ahead_cancel(imd);
1514 static gint image_auto_refresh_cb(gpointer data)
1516 ImageWindow *imd = data;
1519 if (!imd || !image_get_pixbuf(imd) ||
1520 imd->il || !imd->image_fd ||
1521 !update_on_time_change) return TRUE;
1523 newtime = filetime(imd->image_fd->path);
1524 if (newtime > 0 && newtime != imd->mtime)
1526 imd->mtime = newtime;
1533 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1535 void image_auto_refresh(ImageWindow *imd, gint interval)
1538 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1540 if (imd->auto_refresh_id > -1)
1542 g_source_remove(imd->auto_refresh_id);
1543 imd->auto_refresh_id = -1;
1544 imd->auto_refresh_interval = -1;
1547 if (interval < 0) return;
1549 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1551 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1552 imd->auto_refresh_interval = interval;
1555 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1557 imd->top_window_sync = allow_sync;
1559 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1562 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1564 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1567 void image_color_profile_set(ImageWindow *imd,
1568 gint input_type, gint screen_type,
1573 if (input_type < 0 || input_type > COLOR_PROFILE_INPUTS ||
1574 screen_type < 0 || screen_type > 1)
1579 imd->color_profile_input = input_type;
1580 imd->color_profile_screen = screen_type;
1581 imd->color_profile_use_image = use_image;
1584 gint image_color_profile_get(ImageWindow *imd,
1585 gint *input_type, gint *screen_type,
1588 if (!imd) return FALSE;
1590 if (input_type) *input_type = imd->color_profile_input;
1591 if (screen_type) *screen_type = imd->color_profile_screen;
1592 if (use_image) *use_image = imd->color_profile_use_image;
1597 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1601 if (imd->color_profile_enable == enable) return;
1603 imd->color_profile_enable = enable;
1606 gint image_color_profile_get_use(ImageWindow *imd)
1608 if (!imd) return FALSE;
1610 return imd->color_profile_enable;
1613 void image_set_delay_flip(ImageWindow *imd, gint delay)
1616 imd->delay_flip == delay) return;
1618 imd->delay_flip = delay;
1620 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1622 if (!imd->delay_flip && imd->il)
1626 pr = PIXBUF_RENDERER(imd->pr);
1627 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1630 image_load_pixbuf_ready(imd);
1634 void image_to_root_window(ImageWindow *imd, gint scaled)
1637 GdkWindow *rootwindow;
1645 pixbuf = image_get_pixbuf(imd);
1646 if (!pixbuf) return;
1648 screen = gtk_widget_get_screen(imd->widget);
1649 rootwindow = gdk_screen_get_root_window(screen);
1650 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1654 width = gdk_screen_width();
1655 height = gdk_screen_height();
1659 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1662 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1664 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1665 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1666 gdk_window_clear(rootwindow);
1668 g_object_unref(pixmap);
1673 void image_select(ImageWindow *imd, gboolean select)
1679 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1680 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1683 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1689 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1695 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1696 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1700 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1701 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1707 *-------------------------------------------------------------------
1709 *-------------------------------------------------------------------
1712 static void image_options_set(ImageWindow *imd)
1714 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1715 "zoom_2pass", two_pass_zoom,
1716 "zoom_expand", zoom_to_fit_expands,
1717 "dither_quality", dither_quality,
1718 "scroll_reset", scroll_reset_method,
1719 "cache_display", tile_cache_max,
1720 "window_fit", (imd->top_window_sync && fit_window),
1721 "window_limit", limit_window_size,
1722 "window_limit_value", max_window_size,
1723 "autofit_limit", limit_autofit_size,
1724 "autofit_limit_value", max_autofit_size,
1728 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1731 void image_options_sync(void)
1743 image_options_set(imd);
1748 *-------------------------------------------------------------------
1750 *-------------------------------------------------------------------
1753 static void image_free(ImageWindow *imd)
1755 image_list = g_list_remove(image_list, imd);
1759 image_read_ahead_cancel(imd);
1760 image_post_buffer_set(imd, NULL, NULL, -1);
1761 image_auto_refresh(imd, -1);
1763 file_data_unref(imd->image_fd);
1765 g_free(imd->title_right);
1770 static void image_destroy_cb(GtkObject *widget, gpointer data)
1772 ImageWindow *imd = data;
1776 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1778 gtk_paint_flat_box(widget->style,
1781 GTK_FRAME (widget)->shadow_type,
1785 widget->allocation.x + 3, widget->allocation.y + 3,
1786 widget->allocation.width - 6, widget->allocation.height - 6);
1793 void image_set_frame(ImageWindow *imd, gboolean frame)
1797 if (frame == imd->has_frame) return;
1799 gtk_widget_hide(imd->pr);
1803 imd->frame = gtk_frame_new(NULL);
1804 gtk_widget_ref(imd->pr);
1805 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1806 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1807 gtk_widget_unref(imd->pr);
1808 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1809 G_CALLBACK (selectable_frame_expose_cb), NULL);
1811 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1812 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1813 G_CALLBACK(image_focus_in_cb), imd);
1814 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1815 G_CALLBACK(image_focus_out_cb), imd);
1817 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1818 G_CALLBACK(image_focus_expose), imd);
1821 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1822 gtk_widget_show(imd->frame);
1826 gtk_widget_ref(imd->pr);
1829 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1830 gtk_widget_destroy(imd->frame);
1833 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
1834 gtk_widget_unref(imd->pr);
1837 gtk_widget_show(imd->pr);
1839 imd->has_frame = frame;
1842 ImageWindow *image_new(gint frame)
1846 imd = g_new0(ImageWindow, 1);
1848 imd->top_window = NULL;
1850 imd->title_right = NULL;
1851 imd->title_show_zoom = FALSE;
1853 imd->unknown = TRUE;
1855 imd->has_frame = -1; /* not initialized; for image_set_frame */
1856 imd->top_window_sync = FALSE;
1858 imd->delay_alter_type = ALTER_NONE;
1860 imd->read_ahead_il = NULL;
1861 imd->read_ahead_pixbuf = NULL;
1862 imd->read_ahead_fd = NULL;
1864 imd->completed = FALSE;
1865 imd->state = IMAGE_STATE_NONE;
1867 imd->color_profile_enable = FALSE;
1868 imd->color_profile_input = 0;
1869 imd->color_profile_screen = 0;
1870 imd->color_profile_use_image = FALSE;
1872 imd->auto_refresh_id = -1;
1873 imd->auto_refresh_interval = -1;
1875 imd->delay_flip = FALSE;
1877 imd->func_update = NULL;
1878 imd->func_complete = NULL;
1879 imd->func_tile_request = NULL;
1880 imd->func_tile_dispose = NULL;
1882 imd->func_button = NULL;
1883 imd->func_scroll = NULL;
1885 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1887 image_options_set(imd);
1890 imd->widget = gtk_vbox_new(0, 0);
1892 image_set_frame(imd, frame);
1894 image_set_selectable(imd, 0);
1896 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1897 G_CALLBACK(image_click_cb), imd);
1898 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1899 G_CALLBACK(image_scroll_notify_cb), imd);
1901 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1902 G_CALLBACK(image_scroll_cb), imd);
1904 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1905 G_CALLBACK(image_destroy_cb), imd);
1907 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1908 G_CALLBACK(image_zoom_cb), imd);
1909 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1910 G_CALLBACK(image_render_complete_cb), imd);
1911 g_signal_connect(G_OBJECT(imd->pr), "drag",
1912 G_CALLBACK(image_drag_cb), imd);
1914 image_list = g_list_append(image_list, imd);