# HG changeset patch # User nadvornik # Date 1208454294 0 # Node ID c4080362d61971a129b9c4d3c4fcc4bc9c9f4baa # Parent a7be56e8487034ecac866646c06e26a92ead9dff image post-processing (rotation and color management) moved to pixbuf-renderer diff -r a7be56e84870 -r c4080362d619 src/color-man.c --- a/src/color-man.c Thu Apr 17 17:35:51 2008 +0000 +++ b/src/color-man.c Thu Apr 17 17:44:54 2008 +0000 @@ -277,18 +277,22 @@ } } -static void color_man_correct_region(ColorMan *cm, gint x, gint y, gint w, gint h, - gint pixbuf_width, gint pixbuf_height) +void color_man_correct_region(ColorMan *cm, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h) { ColorManCache *cc; guchar *pix; gint rs; gint i; + gint pixbuf_width, pixbuf_height; + + + pixbuf_width = gdk_pixbuf_get_width(pixbuf); + pixbuf_height = gdk_pixbuf_get_height(pixbuf); cc = cm->profile; - pix = gdk_pixbuf_get_pixels(cm->pixbuf); - rs = gdk_pixbuf_get_rowstride(cm->pixbuf); + pix = gdk_pixbuf_get_pixels(pixbuf); + rs = gdk_pixbuf_get_rowstride(pixbuf); w = MIN(w, pixbuf_width - x); h = MIN(h, pixbuf_height - y); @@ -299,10 +303,10 @@ guchar *pbuf; pbuf = pix + ((y + i) * rs); + cmsDoTransform(cc->transform, pbuf, pbuf, w); } - if (cm->incremental_sync && cm->imd) image_area_changed(cm->imd, x, y, w, h); } static gint color_man_idle_cb(gpointer data) @@ -310,6 +314,7 @@ ColorMan *cm = data; gint width, height; gint rh; + if (!cm->pixbuf) return FALSE; if (cm->imd && cm->pixbuf != image_get_pixbuf(cm->imd)) @@ -335,7 +340,8 @@ } rh = COLOR_MAN_CHUNK_SIZE / width + 1; - color_man_correct_region(cm, 0, cm->row, width, rh, width, height); + color_man_correct_region(cm, cm->pixbuf, 0, cm->row, width, rh); + if (cm->incremental_sync && cm->imd) image_area_changed(cm->imd, 0, cm->row, width, rh); cm->row += rh; return TRUE; @@ -344,28 +350,24 @@ static ColorMan *color_man_new_real(ImageWindow *imd, GdkPixbuf *pixbuf, ColorManProfileType input_type, const gchar *input_file, unsigned char *input_data, guint input_data_len, - ColorManProfileType screen_type, const gchar *screen_file, - ColorManDoneFunc done_func, gpointer done_data) + ColorManProfileType screen_type, const gchar *screen_file) { ColorMan *cm; gint has_alpha; if (imd) pixbuf = image_get_pixbuf(imd); - if (!pixbuf) return NULL; cm = g_new0(ColorMan, 1); cm->imd = imd; cm->pixbuf = pixbuf; - g_object_ref(cm->pixbuf); + if (cm->pixbuf) g_object_ref(cm->pixbuf); cm->incremental_sync = FALSE; cm->row = 0; cm->idle_id = -1; - cm->func_done = done_func; - cm->func_done_data = done_data; + has_alpha = pixbuf ? gdk_pixbuf_get_has_alpha(pixbuf) : FALSE; - has_alpha = gdk_pixbuf_get_has_alpha(pixbuf); cm->profile = color_man_cache_get(input_type, input_file, input_data, input_data_len, screen_type, screen_file, has_alpha); if (!cm->profile) @@ -374,31 +376,32 @@ return NULL; } - cm->idle_id = g_idle_add(color_man_idle_cb, cm); - return cm; } ColorMan *color_man_new(ImageWindow *imd, GdkPixbuf *pixbuf, ColorManProfileType input_type, const gchar *input_file, - ColorManProfileType screen_type, const gchar *screen_file, - ColorManDoneFunc done_func, gpointer done_data) + ColorManProfileType screen_type, const gchar *screen_file) { return color_man_new_real(imd, pixbuf, input_type, input_file, NULL, 0, - screen_type, screen_file, - done_func, done_data); + screen_type, screen_file); +} + +void color_man_start_bg(ColorMan *cm, ColorManDoneFunc done_func, gpointer done_data) +{ + cm->func_done = done_func; + cm->func_done_data = done_data; + cm->idle_id = g_idle_add(color_man_idle_cb, cm); } ColorMan *color_man_new_embedded(ImageWindow *imd, GdkPixbuf *pixbuf, unsigned char *input_data, guint input_data_len, - ColorManProfileType screen_type, const gchar *screen_file, - ColorManDoneFunc done_func, gpointer done_data) + ColorManProfileType screen_type, const gchar *screen_file) { return color_man_new_real(imd, pixbuf, COLOR_PROFILE_MEM, NULL, input_data, input_data_len, - screen_type, screen_file, - done_func, done_data); + screen_type, screen_file); } void color_man_free(ColorMan *cm) @@ -424,8 +427,7 @@ ColorMan *color_man_new(ImageWindow *imd, GdkPixbuf *pixbuf, ColorManProfileType input_type, const gchar *input_file, - ColorManProfileType screen_type, const gchar *screen_file, - ColorManDoneFunc don_func, gpointer done_data) + ColorManProfileType screen_type, const gchar *screen_file) { /* no op */ return NULL; @@ -433,8 +435,7 @@ ColorMan *color_man_new_embedded(ImageWindow *imd, GdkPixbuf *pixbuf, unsigned char *input_data, guint input_data_len, - ColorManProfileType screen_type, const gchar *screen_file, - ColorManDoneFunc done_func, gpointer done_data) + ColorManProfileType screen_type, const gchar *screen_file) { /* no op */ return NULL; @@ -450,6 +451,15 @@ /* no op */ } +void color_man_correct_region(ColorMan *cm, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h) +{ + /* no op */ +} + +void color_man_start_bg(ColorMan *cm, ColorManDoneFunc done_func, gpointer done_data) +{ + /* no op */ +} #endif diff -r a7be56e84870 -r c4080362d619 src/color-man.h --- a/src/color-man.h Thu Apr 17 17:35:51 2008 +0000 +++ b/src/color-man.h Thu Apr 17 17:44:54 2008 +0000 @@ -47,16 +47,17 @@ ColorMan *color_man_new(ImageWindow *imd, GdkPixbuf *pixbuf, ColorManProfileType input_type, const gchar *input_file, - ColorManProfileType screen_type, const gchar *screen_file, - ColorManDoneFunc done_func, gpointer done_data); + ColorManProfileType screen_type, const gchar *screen_file); ColorMan *color_man_new_embedded(ImageWindow *imd, GdkPixbuf *pixbuf, unsigned char *input_data, guint input_data_len, - ColorManProfileType screen_type, const gchar *screen_file, - ColorManDoneFunc done_func, gpointer done_data); + ColorManProfileType screen_type, const gchar *screen_file); void color_man_free(ColorMan *cm); void color_man_update(void); +void color_man_correct_region(ColorMan *cm, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h); + +void color_man_start_bg(ColorMan *cm, ColorManDoneFunc don_func, gpointer done_data); #endif diff -r a7be56e84870 -r c4080362d619 src/image.c --- a/src/image.c Thu Apr 17 17:35:51 2008 +0000 +++ b/src/image.c Thu Apr 17 17:44:54 2008 +0000 @@ -36,7 +36,7 @@ #define IMAGE_THROTTLE_LARGER_IMAGES 1 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */ -#define IMAGE_THROTTLE_FACTOR 4 +#define IMAGE_THROTTLE_FACTOR 32 /* the file size at which throttling take place */ #define IMAGE_THROTTLE_THRESHOLD 1048576 @@ -201,6 +201,9 @@ *------------------------------------------------------------------- */ + +#if 0 + static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp) { PixbufRenderer *pr; @@ -300,6 +303,7 @@ } } + static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data) { ImageWindow *imd = data; @@ -319,8 +323,9 @@ image_read_ahead_start(imd); } +#endif -static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif) +static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg) { ColorMan *cm; ColorManProfileType input_type; @@ -395,17 +400,15 @@ data = (unsigned char *) exif_item_get_data(item, &data_len); - cm = color_man_new_embedded(imd, NULL, + cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL, data, data_len, - screen_type, screen_file, - image_post_process_color_cb, imd); + screen_type, screen_file); } else { - cm = color_man_new(imd, NULL, + cm = color_man_new(run_in_bg ? imd : NULL, NULL, input_type, input_file, - screen_type, screen_file, - image_post_process_color_cb, imd); + screen_type, screen_file); } if (cm) @@ -417,6 +420,9 @@ } imd->cm = (gpointer)cm; +#if 0 + if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd); +#endif return TRUE; } @@ -425,6 +431,7 @@ static void image_post_process(ImageWindow *imd, gint clamp) { +#if 0 ExifData *exif = NULL; if (!image_get_pixbuf(imd)) return; @@ -436,7 +443,6 @@ { exif = exif_read_fd(imd->image_fd, (imd->color_profile_enable && imd->color_profile_use_image)); } - if (options->image.exif_rotate_enable && exif) { gint orientation; @@ -497,21 +503,77 @@ if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO); } } - if (imd->color_profile_enable) { - if (!image_post_process_color(imd, 0, exif)) + if (!image_post_process_color(imd, 0, exif, TRUE)) { /* fixme: note error to user */ image_state_set(imd, IMAGE_STATE_COLOR_ADJ); } } + if (!imd->cm) image_post_process_alter(imd, clamp); exif_free(exif); +#endif } +static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h, gpointer data) +{ + ImageWindow *imd = (ImageWindow *)data; + if (imd->cm) color_man_correct_region(imd->cm, *pixbuf, x, y, w, h); + if (imd->desaturate) pixbuf_desaturate_rect(*pixbuf, x, y, w, h); + +} + +void image_alter(ImageWindow *imd, AlterType type) +{ + + const static gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1}; + const static gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3}; + const static gint rotate_180[] = {1, 3, 4, 1, 2, 7, 8, 5, 6}; + const static gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7}; + const static gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5}; + + + if (!imd || !imd->pr) return; + + if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1; + + switch (type) + { + case ALTER_ROTATE_90: + imd->orientation = rotate_90[imd->orientation]; + break; + case ALTER_ROTATE_90_CC: + imd->orientation = rotate_90_cc[imd->orientation]; + break; + case ALTER_ROTATE_180: + imd->orientation = rotate_180[imd->orientation]; + break; + case ALTER_MIRROR: + imd->orientation = mirror[imd->orientation]; + break; + case ALTER_FLIP: + imd->orientation = flip[imd->orientation]; + break; + case ALTER_DESATURATE: + imd->desaturate = !imd->desaturate; + break; + case ALTER_NONE: + default: + return; + break; + } + pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation); + if (imd->cm || imd->desaturate) + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) ); + else + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE); +} + + /* *------------------------------------------------------------------- * read ahead (prebuffer) @@ -565,7 +627,7 @@ if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return; /* still loading ?, do later */ - if (imd->il || imd->cm) return; + if (imd->il /*|| imd->cm*/) return; if (debug) printf("%s read ahead started for :%s\n", get_exec_time(), imd->read_ahead_fd->path); @@ -634,7 +696,7 @@ ExifData *exif = NULL; if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd, TRUE); - image_post_process_color(imd, imd->prev_color_row, exif); +// image_post_process_color(imd, imd->prev_color_row, exif, TRUE); exif_free(exif); } success = TRUE; @@ -1203,7 +1265,45 @@ void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom) { + + ExifData *exif = NULL; + gint orientation; + + if (options->image.exif_rotate_enable || + (imd->color_profile_enable && imd->color_profile_use_image) ) + { + exif = exif_read_fd(imd->image_fd, (imd->color_profile_enable && imd->color_profile_use_image)); + } + + if (options->image.exif_rotate_enable && exif && exif_get_integer(exif, "Exif.Image.Orientation", &orientation)) + imd->orientation = orientation; + else + imd->orientation = 1; + + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE); + if (imd->cm) + { + color_man_free(imd->cm); + imd->cm = NULL; + } + pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom); + pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation); + + if (imd->color_profile_enable) + { + if (!image_post_process_color(imd, 0, exif, FALSE)) + { + /* fixme: note error to user */ +// image_state_set(imd, IMAGE_STATE_COLOR_ADJ); + } + } + + exif_free(exif); + + if (imd->cm || imd->desaturate) + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) ); + image_state_set(imd, IMAGE_STATE_IMAGE); } @@ -1317,8 +1417,17 @@ imd->completed = source->completed; imd->state = source->state; source->state = IMAGE_STATE_NONE; + + imd->orientation = source->orientation; + imd->desaturate = source->desaturate; pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr)); + + if (imd->cm || imd->desaturate) + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) ); + else + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE); + } /* manipulation */ @@ -1357,7 +1466,7 @@ } - +#if 0 void image_alter(ImageWindow *imd, AlterType type) { if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return; @@ -1377,6 +1486,7 @@ image_alter_real(imd, type, TRUE); } +#endif void image_zoom_adjust(ImageWindow *imd, gdouble increment) { @@ -1889,6 +1999,8 @@ imd->func_button = NULL; imd->func_scroll = NULL; + + imd->orientation = 1; imd->pr = GTK_WIDGET(pixbuf_renderer_new()); diff -r a7be56e84870 -r c4080362d619 src/layout_util.c --- a/src/layout_util.c Thu Apr 17 17:35:51 2008 +0000 +++ b/src/layout_util.c Thu Apr 17 17:44:54 2008 +0000 @@ -1094,7 +1094,7 @@ { "Rotate180", NULL, N_("Rotate 1_80"), "R", NULL, CB(layout_menu_alter_180_cb) }, { "Mirror", NULL, N_("_Mirror"), "M", NULL, CB(layout_menu_alter_mirror_cb) }, { "Flip", NULL, N_("_Flip"), "F", NULL, CB(layout_menu_alter_flip_cb) }, - { "Grayscale", NULL, N_("_Grayscale"), "G", NULL, CB(layout_menu_alter_desaturate_cb) }, + { "Grayscale", NULL, N_("Toggle _grayscale"),"G", NULL, CB(layout_menu_alter_desaturate_cb) }, { "Properties",GTK_STOCK_PROPERTIES, N_("_Properties"), "P", NULL, CB(layout_menu_info_cb) }, { "SelectAll", NULL, N_("Select _all"), "A", NULL, CB(layout_menu_select_all_cb) }, { "SelectNone", NULL, N_("Select _none"), "A",NULL, CB(layout_menu_unselect_all_cb) }, diff -r a7be56e84870 -r c4080362d619 src/menu.c --- a/src/menu.c Thu Apr 17 17:35:51 2008 +0000 +++ b/src/menu.c Thu Apr 17 17:44:54 2008 +0000 @@ -213,7 +213,7 @@ return _("_Flip"); break; case ALTER_DESATURATE: - return _("_Grayscale"); + return _("Toggle _grayscale"); break; default: break; diff -r a7be56e84870 -r c4080362d619 src/pixbuf-renderer.c --- a/src/pixbuf-renderer.c Thu Apr 17 17:35:51 2008 +0000 +++ b/src/pixbuf-renderer.c Thu Apr 17 17:44:54 2008 +0000 @@ -63,6 +63,18 @@ */ #define PR_MIN_SCALE_SIZE 8 +typedef enum { + EXIF_ORIENTATION_UNKNOWN = 0, + EXIF_ORIENTATION_TOP_LEFT = 1, + EXIF_ORIENTATION_TOP_RIGHT = 2, + EXIF_ORIENTATION_BOTTOM_RIGHT = 3, + EXIF_ORIENTATION_BOTTOM_LEFT = 4, + EXIF_ORIENTATION_LEFT_TOP = 5, + EXIF_ORIENTATION_RIGHT_TOP = 6, + EXIF_ORIENTATION_RIGHT_BOTTOM = 7, + EXIF_ORIENTATION_LEFT_BOTTOM = 8 +} ExifOrientationType; + typedef enum { TILE_RENDER_NONE = 0, /* do nothing */ @@ -491,6 +503,8 @@ pr->source_tiles_enabled = FALSE; pr->source_tiles = NULL; + pr->orientation = 1; + gtk_widget_set_double_buffered(box, FALSE); g_signal_connect_after(G_OBJECT(box), "size_allocate", G_CALLBACK(pr_size_cb), pr); @@ -508,6 +522,7 @@ pr_tile_free_all(pr); if (pr->pixbuf) g_object_unref(pr->pixbuf); + if (pr->spare_tile) gdk_pixbuf_unref(pr->spare_tile); pr_scroller_timer_set(pr, FALSE); pr_overlay_list_clear(pr); @@ -2002,12 +2017,13 @@ pr->tile_cache_size += size; } - if ((pr->zoom != 1.0 || pr->source_tiles_enabled || (pr->pixbuf && gdk_pixbuf_get_has_alpha(pr->pixbuf)) ) && - !it->pixbuf) + if ((pr->zoom != 1.0 || pr->source_tiles_enabled || (pr->pixbuf && gdk_pixbuf_get_has_alpha(pr->pixbuf)) || + pr->orientation != EXIF_ORIENTATION_TOP_LEFT || pr->func_post_process) && !it->pixbuf) { GdkPixbuf *pixbuf; guint size; - +#if 0 +/* I don't think that we need a pixbuf with alpha channel here */ if (pr->pixbuf) { pixbuf = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pr->pixbuf), @@ -2016,6 +2032,7 @@ pr->tile_width, pr->tile_height); } else +#endif { pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, pr->tile_width, pr->tile_height); } @@ -2034,6 +2051,362 @@ * drawing *------------------------------------------------------------------- */ + + +static void pr_tile_coords_map_orientation(PixbufRenderer *pr, + double tile_x, double tile_y, /* coordinates of the tile */ + gint image_w, gint image_h, + double tile_w, double tile_h, + double *res_x, double *res_y) +{ + *res_x = tile_x; + *res_y = tile_y; + switch (pr->orientation) + { + case EXIF_ORIENTATION_TOP_LEFT: + /* normal -- nothing to do */ + break; + case EXIF_ORIENTATION_TOP_RIGHT: + /* mirrored */ + *res_x = image_w - tile_x - tile_w; + break; + case EXIF_ORIENTATION_BOTTOM_RIGHT: + /* upside down */ + *res_x = image_w - tile_x - tile_w; + *res_y = image_h - tile_y - tile_h; + break; + case EXIF_ORIENTATION_BOTTOM_LEFT: + /* flipped */ + *res_y = image_h - tile_y - tile_h; + break; + case EXIF_ORIENTATION_LEFT_TOP: + *res_x = tile_y; + *res_y = tile_x; + break; + case EXIF_ORIENTATION_RIGHT_TOP: + /* rotated -90 (270) */ + *res_x = tile_y; + *res_y = image_w - tile_x - tile_w; + break; + case EXIF_ORIENTATION_RIGHT_BOTTOM: + *res_x = image_h - tile_y - tile_h; + *res_y = image_w - tile_x - tile_w; + break; + case EXIF_ORIENTATION_LEFT_BOTTOM: + /* rotated 90 */ + *res_x = image_h - tile_y - tile_h; + *res_y = tile_x; + break; + default: + /* The other values are out of range */ + break; + } +// printf("tile coord y:%f, ih:%d, th:%f ry:%f\n", tile_y, image_h, tile_h, *res_x); +} + +static void pr_tile_region_map_orientation(PixbufRenderer *pr, + gint area_x, gint area_y, /* coordinates of the area inside tile */ + gint tile_w, gint tile_h, + gint area_w, gint area_h, + gint *res_x, gint *res_y, + gint *res_w, gint *res_h) +{ + *res_x = area_x; + *res_y = area_y; + *res_w = area_w; + *res_h = area_h; + + switch (pr->orientation) + { + case EXIF_ORIENTATION_TOP_LEFT: + /* normal -- nothing to do */ + break; + case EXIF_ORIENTATION_TOP_RIGHT: + /* mirrored */ + *res_x = tile_w - area_x - area_w; + break; + case EXIF_ORIENTATION_BOTTOM_RIGHT: + /* upside down */ + *res_x = tile_w - area_x - area_w; + *res_y = tile_h - area_y - area_h; + break; + case EXIF_ORIENTATION_BOTTOM_LEFT: + /* flipped */ + *res_y = tile_h - area_y - area_h; + break; + case EXIF_ORIENTATION_LEFT_TOP: + *res_x = area_y; + *res_y = area_x; + *res_w = area_h; + *res_h = area_w; + break; + case EXIF_ORIENTATION_RIGHT_TOP: + /* rotated -90 (270) */ + *res_x = area_y; + *res_y = tile_w - area_x - area_w; + *res_w = area_h; + *res_h = area_w; + break; + case EXIF_ORIENTATION_RIGHT_BOTTOM: + *res_x = tile_h - area_y - area_h; + *res_y = tile_w - area_x - area_w; + *res_w = area_h; + *res_h = area_w; + break; + case EXIF_ORIENTATION_LEFT_BOTTOM: + /* rotated 90 */ + *res_x = tile_h - area_y - area_h; + *res_y = area_x; + *res_w = area_h; + *res_h = area_w; + break; + default: + /* The other values are out of range */ + break; + } +// printf("inside y:%d, th:%d, ah:%d ry:%d\n", area_y, tile_h, area_h, *res_x); +} + +static void pr_coords_map_orientation_reverse(PixbufRenderer *pr, + gint area_x, gint area_y, + gint tile_w, gint tile_h, + gint area_w, gint area_h, + gint *res_x, gint *res_y, + gint *res_w, gint *res_h) +{ + *res_x = area_x; + *res_y = area_y; + *res_w = area_w; + *res_h = area_h; + + switch (pr->orientation) + { + case EXIF_ORIENTATION_TOP_LEFT: + /* normal -- nothing to do */ + break; + case EXIF_ORIENTATION_TOP_RIGHT: + /* mirrored */ + *res_x = tile_w - area_x - area_w; + break; + case EXIF_ORIENTATION_BOTTOM_RIGHT: + /* upside down */ + *res_x = tile_w - area_x - area_w; + *res_y = tile_h - area_y - area_h; + break; + case EXIF_ORIENTATION_BOTTOM_LEFT: + /* flipped */ + *res_y = tile_h - area_y - area_h; + break; + case EXIF_ORIENTATION_LEFT_TOP: + *res_x = area_y; + *res_y = area_x; + *res_w = area_h; + *res_h = area_w; + break; + case EXIF_ORIENTATION_RIGHT_TOP: + /* rotated -90 (270) */ + *res_x = tile_w - area_y - area_h; + *res_y = area_x; + *res_w = area_h; + *res_h = area_w; + break; + case EXIF_ORIENTATION_RIGHT_BOTTOM: + *res_x = tile_w - area_y - area_h; + *res_y = tile_h - area_x - area_w; + *res_w = area_h; + *res_h = area_w; + break; + case EXIF_ORIENTATION_LEFT_BOTTOM: + /* rotated 90 */ + *res_x = area_y; + *res_y = tile_h - area_x - area_w; + *res_w = area_h; + *res_h = area_w; + break; + default: + /* The other values are out of range */ + break; + } +} + + +static GdkPixbuf *pr_get_spare_tile(PixbufRenderer *pr) +{ + if (!pr->spare_tile) pr->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, pr->tile_width, pr->tile_height); + return pr->spare_tile; +} + +static void pr_tile_rotate_90(PixbufRenderer *pr, GdkPixbuf **tile, gint counter_clockwise, gint x, gint y, gint w, gint h) +{ + GdkPixbuf *src = *tile; + GdkPixbuf *dest; + gint srs; + gint drs; + guchar *s_pix; + guchar *d_pix; + guchar *sp; + guchar *dp; + gint i, j; + gint a = 3; + + gint tw = pr->tile_width; + gint th = pr->tile_height; + + + srs = gdk_pixbuf_get_rowstride(src); + s_pix = gdk_pixbuf_get_pixels(src); + + dest = pr_get_spare_tile(pr); + drs = gdk_pixbuf_get_rowstride(dest); + d_pix = gdk_pixbuf_get_pixels(dest); + + for (i = y; i < y + h; i++) + { + sp = s_pix + (i * srs) + (x * a); + for (j = x; j < x + w; j++) + { + if (counter_clockwise) + { + dp = d_pix + ((th - j - 1) * drs) + (i * a); + } + else + { + dp = d_pix + (j * drs) + ((tw - i - 1) * a); + } + + *(dp++) = *(sp++); /* r */ + *(dp++) = *(sp++); /* g */ + *(dp++) = *(sp++); /* b */ + } + } + + pr->spare_tile = src; + *tile = dest; +} + +/* + * Returns a copy of pixbuf mirrored and or flipped. + * TO do a 180 degree rotations set both mirror and flipped TRUE + * if mirror and flip are FALSE, result is a simple copy. + */ +static void pr_tile_mirror(PixbufRenderer *pr, GdkPixbuf **tile, gint mirror, gint flip, gint x, gint y, gint w, gint h) +{ + GdkPixbuf *src = *tile; + GdkPixbuf *dest; + gint srs; + gint drs; + guchar *s_pix; + guchar *d_pix; + guchar *sp; + guchar *dp; + gint i, j; + gint a = 3; + + gint tw = pr->tile_width; + gint th = pr->tile_height; + + srs = gdk_pixbuf_get_rowstride(src); + s_pix = gdk_pixbuf_get_pixels(src); + + dest = pr_get_spare_tile(pr); + drs = gdk_pixbuf_get_rowstride(dest); + d_pix = gdk_pixbuf_get_pixels(dest); + + for (i = y; i < y + h; i++) + { + sp = s_pix + (i * srs) + (x * a); + if (flip) + { + dp = d_pix + ((th - i - 1) * drs); + } + else + { + dp = d_pix + (i * drs); + } + if (mirror) + { + dp += (tw - x - 1) * a; + for (j = 0; j < w; j++) + { + *(dp++) = *(sp++); /* r */ + *(dp++) = *(sp++); /* g */ + *(dp++) = *(sp++); /* b */ + dp -= (a + 3); + } + } + else + { + dp += x * a; + for (j = 0; j < w; j++) + { + *(dp++) = *(sp++); /* r */ + *(dp++) = *(sp++); /* g */ + *(dp++) = *(sp++); /* b */ + } + } + } + + pr->spare_tile = src; + *tile = dest; +} + + +static void pr_tile_apply_orientation(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h) +{ + switch (pr->orientation) + { + case EXIF_ORIENTATION_TOP_LEFT: + /* normal -- nothing to do */ + break; + case EXIF_ORIENTATION_TOP_RIGHT: + /* mirrored */ + { + pr_tile_mirror(pr, pixbuf, TRUE, FALSE, x, y, w, h); + } + break; + case EXIF_ORIENTATION_BOTTOM_RIGHT: + /* upside down */ + { + pr_tile_mirror(pr, pixbuf, TRUE, TRUE, x, y, w, h); + } + break; + case EXIF_ORIENTATION_BOTTOM_LEFT: + /* flipped */ + { + pr_tile_mirror(pr, pixbuf, FALSE, TRUE, x, y, w, h); + } + break; + case EXIF_ORIENTATION_LEFT_TOP: + { + pr_tile_mirror(pr, pixbuf, FALSE, TRUE, x, y, w, h); + pr_tile_rotate_90(pr, pixbuf, FALSE, x, pr->tile_height - y - h, w, h); + } + break; + case EXIF_ORIENTATION_RIGHT_TOP: + /* rotated -90 (270) */ + { + pr_tile_rotate_90(pr, pixbuf, FALSE, x, y, w, h); + } + break; + case EXIF_ORIENTATION_RIGHT_BOTTOM: + { + pr_tile_mirror(pr, pixbuf, FALSE, TRUE, x, y, w, h); + pr_tile_rotate_90(pr, pixbuf, TRUE, x, pr->tile_height - y - h, w, h); + } + break; + case EXIF_ORIENTATION_LEFT_BOTTOM: + /* rotated 90 */ + { + pr_tile_rotate_90(pr, pixbuf, TRUE, x, y, w, h); + } + break; + default: + /* The other values are out of range */ + break; + } + +} + static void pr_tile_render(PixbufRenderer *pr, ImageTile *it, gint x, gint y, gint w, gint h, @@ -2084,36 +2457,80 @@ } else if (pr->zoom == 1.0 || pr->scale == 1.0) { + + double src_x, src_y; + gint pb_x, pb_y; + gint pb_w, pb_h; + pr_tile_coords_map_orientation(pr, it->x, it->y, + pr->image_width, pr->image_height, + pr->tile_width, pr->tile_height, + &src_x, &src_y); + pr_tile_region_map_orientation(pr, x, y, + pr->tile_width, pr->tile_height, + w, h, + &pb_x, &pb_y, + &pb_w, &pb_h); + if (has_alpha) { - gdk_pixbuf_composite_color(pr->pixbuf, it->pixbuf, x, y, w, h, - (double) 0.0 - it->x, - (double) 0.0 - it->y, + gdk_pixbuf_composite_color(pr->pixbuf, it->pixbuf, pb_x, pb_y, pb_w, pb_h, + (double) 0.0 - src_x, + (double) 0.0 - src_y, 1.0, 1.0, GDK_INTERP_NEAREST, - 255, it->x + x, it->y + y, + 255, it->x + pb_x, it->y + pb_y, PR_ALPHA_CHECK_SIZE, PR_ALPHA_CHECK1, PR_ALPHA_CHECK2); + pr_tile_apply_orientation(pr, &it->pixbuf, pb_x, pb_y, pb_w, pb_h); draw = TRUE; } else { - /* faster, simple */ - gdk_draw_pixbuf(it->pixmap, - box->style->fg_gc[GTK_WIDGET_STATE(box)], - pr->pixbuf, - it->x + x, it->y + y, - x, y, - w, h, - pr->dither_quality, it->x + x, it->y + y); + + + if (pr->orientation == EXIF_ORIENTATION_TOP_LEFT && !(pr->func_post_process && !(pr->post_process_slow && fast))) + { + /* faster, simple, base orientation, no postprocessing */ + gdk_draw_pixbuf(it->pixmap, + box->style->fg_gc[GTK_WIDGET_STATE(box)], + pr->pixbuf, + it->x + x, it->y + y, + x, y, + w, h, + pr->dither_quality, it->x + x, it->y + y); + } + else + { + gdk_pixbuf_copy_area(pr->pixbuf, + src_x + pb_x, src_y + pb_y, + pb_w, pb_h, + it->pixbuf, + pb_x, pb_y); + pr_tile_apply_orientation(pr, &it->pixbuf, pb_x, pb_y, pb_w, pb_h); + draw = TRUE; + } } } else { double scale_x, scale_y; + double src_x, src_y; + gint pb_x, pb_y; + gint pb_w, pb_h; if (pr->image_width == 0 || pr->image_height == 0) return; + scale_x = (double)pr->width / pr->image_width; scale_y = (double)pr->height / pr->image_height; + pr_tile_coords_map_orientation(pr, it->x / scale_x, it->y /scale_y , + pr->image_width, pr->image_height, + pr->tile_width / scale_x , pr->tile_height / scale_y, + &src_x, &src_y); + pr_tile_region_map_orientation(pr, x, y, + pr->tile_width, pr->tile_height, + w, h, + &pb_x, &pb_y, + &pb_w, &pb_h); + /* HACK: The pixbuf scalers get kinda buggy(crash) with extremely * small sizes for anything but GDK_INTERP_NEAREST */ @@ -2121,27 +2538,32 @@ if (!has_alpha) { - gdk_pixbuf_scale(pr->pixbuf, it->pixbuf, x, y, w, h, - (double) 0.0 - it->x, - (double) 0.0 - it->y, + gdk_pixbuf_scale(pr->pixbuf, it->pixbuf, pb_x, pb_y, pb_w, pb_h, + (double) 0.0 - src_x * scale_x, + (double) 0.0 - src_y * scale_y, scale_x, scale_y, (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality); } else { - gdk_pixbuf_composite_color(pr->pixbuf, it->pixbuf, x, y, w, h, - (double) 0.0 - it->x, - (double) 0.0 - it->y, + gdk_pixbuf_composite_color(pr->pixbuf, it->pixbuf, pb_x, pb_y, pb_w, pb_h, + (double) 0.0 - src_x * scale_x, + (double) 0.0 - src_y * scale_y, scale_x, scale_y, (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality, - 255, it->x + x, it->y + y, + 255, it->x + pb_x, it->y + pb_y, PR_ALPHA_CHECK_SIZE, PR_ALPHA_CHECK1, PR_ALPHA_CHECK2); } + pr_tile_apply_orientation(pr, &it->pixbuf, pb_x, pb_y, pb_w, pb_h); draw = TRUE; } if (draw && it->pixbuf && !it->blank) { + + if (pr->func_post_process && !(pr->post_process_slow && fast)) + pr->func_post_process(pr, &it->pixbuf, x, y, w, h, pr->post_process_user_data); + gdk_draw_pixbuf(it->pixmap, box->style->fg_gc[GTK_WIDGET_STATE(box)], it->pixbuf, @@ -2155,6 +2577,8 @@ /* enable this line for debugging the edges of tiles */ gdk_draw_rectangle(it->pixmap, box->style->white_gc, FALSE, 0, 0, it->w, it->h); + gdk_draw_rectangle(it->pixmap, box->style->white_gc, + FALSE, x, y, w, h); #endif } @@ -2214,7 +2638,7 @@ if (pr->draw_queue) { qd = pr->draw_queue->data; - fast = (pr->zoom_2pass && pr->zoom_quality != GDK_INTERP_NEAREST && pr->scale != 1.0); + fast = ((pr->zoom_2pass && pr->zoom_quality != GDK_INTERP_NEAREST && pr->scale != 1.0) || pr->post_process_slow); } else { @@ -3222,6 +3646,23 @@ * public *------------------------------------------------------------------- */ +static void pr_pixbuf_size_sync(PixbufRenderer *pr) +{ + if (!pr->pixbuf) return; + switch (pr->orientation) + { + case EXIF_ORIENTATION_LEFT_TOP: + case EXIF_ORIENTATION_RIGHT_TOP: + case EXIF_ORIENTATION_RIGHT_BOTTOM: + case EXIF_ORIENTATION_LEFT_BOTTOM: + pr->image_width = gdk_pixbuf_get_height(pr->pixbuf); + pr->image_height = gdk_pixbuf_get_width(pr->pixbuf); + break; + default: + pr->image_width = gdk_pixbuf_get_width(pr->pixbuf); + pr->image_height = gdk_pixbuf_get_height(pr->pixbuf); + } +} static void pr_pixbuf_sync(PixbufRenderer *pr, gdouble zoom) { @@ -3246,10 +3687,8 @@ return; } - - pr->image_width = gdk_pixbuf_get_width(pr->pixbuf); - pr->image_height = gdk_pixbuf_get_height(pr->pixbuf); - + + pr_pixbuf_size_sync(pr); pr_zoom_sync(pr, zoom, TRUE, TRUE, FALSE, 0, 0); } @@ -3280,6 +3719,33 @@ return pr->pixbuf; } +void pixbuf_renderer_set_orientation(PixbufRenderer *pr, gint orientation) +{ + g_return_if_fail(IS_PIXBUF_RENDERER(pr)); + + pr->orientation = orientation; + + pr_pixbuf_size_sync(pr); + pr_zoom_sync(pr, pr->zoom, TRUE, FALSE, FALSE, 0, 0); +} + +gint pixbuf_renderer_get_orientation(PixbufRenderer *pr) +{ + if (!pr) return 1; + return pr->orientation; +} + +void pixbuf_renderer_set_post_process_func(PixbufRenderer *pr, PixbufRendererPostProcessFunc func, gpointer user_data, gint slow) +{ + g_return_if_fail(IS_PIXBUF_RENDERER(pr)); + + pr->func_post_process = func; + pr->post_process_user_data = user_data; + pr->post_process_slow = func && slow; + +} + + void pixbuf_renderer_move(PixbufRenderer *pr, PixbufRenderer *source) { GObject *object; @@ -3304,6 +3770,11 @@ scroll_reset = pr->scroll_reset; pr->scroll_reset = PR_SCROLL_RESET_NOCHANGE; + pr->func_post_process = source->func_post_process; + pr->post_process_user_data = source->post_process_user_data; + pr->post_process_slow = source->post_process_slow; + pr->orientation = source->orientation; + if (source->source_tiles_enabled) { pr_source_tile_unset(pr); @@ -3337,12 +3808,19 @@ pr_tile_free_all(source); } -void pixbuf_renderer_area_changed(PixbufRenderer *pr, gint x, gint y, gint width, gint height) +void pixbuf_renderer_area_changed(PixbufRenderer *pr, gint src_x, gint src_y, gint src_w, gint src_h) { - gint x1, y1, x2, y2; + gint x, y, width, height, x1, y1, x2, y2; g_return_if_fail(IS_PIXBUF_RENDERER(pr)); + pr_coords_map_orientation_reverse(pr, + src_x, src_y, + pr->image_width, pr->image_height, + src_w, src_h, + &x, &y, + &width, &height); + if (pr->source_tiles_enabled) { pr_source_tile_changed(pr, x, y, width, height); diff -r a7be56e84870 -r c4080362d619 src/pixbuf-renderer.h --- a/src/pixbuf-renderer.h Thu Apr 17 17:35:51 2008 +0000 +++ b/src/pixbuf-renderer.h Thu Apr 17 17:44:54 2008 +0000 @@ -32,6 +32,10 @@ gint width, gint height, GdkPixbuf *pixbuf, gpointer user_data); typedef void (* PixbufRendererTileDisposeFunc)(PixbufRenderer *pr, gint x, gint y, gint width, gint height, GdkPixbuf *pixbuf, gpointer user_data); + +typedef void (* PixbufRendererPostProcessFunc)(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, + gint width, gint height, gpointer user_data); + typedef enum { PR_SCROLL_RESET_TOPLEFT = 0, PR_SCROLL_RESET_CENTER, @@ -119,8 +123,12 @@ PixbufRendererTileRequestFunc func_tile_request; PixbufRendererTileDisposeFunc func_tile_dispose; + + gpointer func_tile_data; - gpointer func_tile_data; + PixbufRendererPostProcessFunc func_post_process; + gpointer post_process_user_data; + gint post_process_slow; gboolean delay_flip; gboolean loading; @@ -138,6 +146,10 @@ GList *overlay_list; GdkPixmap *overlay_buffer; + + GdkPixbuf *spare_tile; + + gint orientation; }; struct _PixbufRendererClass @@ -165,6 +177,11 @@ void pixbuf_renderer_set_pixbuf(PixbufRenderer *pr, GdkPixbuf *pixbuf, gdouble zoom); GdkPixbuf *pixbuf_renderer_get_pixbuf(PixbufRenderer *pr); +void pixbuf_renderer_set_orientation(PixbufRenderer *pr, gint orientation); +gint pixbuf_renderer_get_orientation(PixbufRenderer *pr); + +void pixbuf_renderer_set_post_process_func(PixbufRenderer *pr, PixbufRendererPostProcessFunc func, gpointer user_data, gint slow); + /* display an on-request array of pixbuf tiles */ void pixbuf_renderer_set_tiles(PixbufRenderer *pr, gint width, gint height, diff -r a7be56e84870 -r c4080362d619 src/typedefs.h --- a/src/typedefs.h Thu Apr 17 17:35:51 2008 +0000 +++ b/src/typedefs.h Thu Apr 17 17:44:54 2008 +0000 @@ -379,6 +379,8 @@ gint auto_refresh_interval; gint delay_flip; + gint orientation; + gint desaturate; }; #define FILEDATA_MARKS_SIZE 6