image post-processing (rotation and color management) moved to
authorVladimir Nadvornik <nadvornik@suse.cz>
Thu, 17 Apr 2008 17:44:54 +0000 (17:44 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Thu, 17 Apr 2008 17:44:54 +0000 (17:44 +0000)
pixbuf-renderer

src/color-man.c
src/color-man.h
src/image.c
src/layout_util.c
src/menu.c
src/pixbuf-renderer.c
src/pixbuf-renderer.h
src/typedefs.h

index 1bc8ceb..3e32233 100644 (file)
@@ -277,18 +277,22 @@ static void color_man_done(ColorMan *cm, ColorManReturnType type)
                }
 }
 
-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 @@ static void color_man_correct_region(ColorMan *cm, gint x, gint y, gint w, gint
                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 @@ static gint color_man_idle_cb(gpointer data)
        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 @@ static gint color_man_idle_cb(gpointer data)
                }
 
        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 gint color_man_idle_cb(gpointer data)
 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 @@ static ColorMan *color_man_new_real(ImageWindow *imd, GdkPixbuf *pixbuf,
                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 @@ void color_man_update(void)
 
 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(ImageWindow *imd, GdkPixbuf *pixbuf,
 
 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 @@ void color_man_update(void)
        /* 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
 
index 6e1518d..4dc4f04 100644 (file)
@@ -47,16 +47,17 @@ struct _ColorMan {
 
 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
 
index 69e8def..bf85ef6 100644 (file)
@@ -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 @@ static void image_update_title(ImageWindow *imd)
  *-------------------------------------------------------------------
  */
 
+
+#if 0
+
 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
 {
        PixbufRenderer *pr;
@@ -300,6 +303,7 @@ static void image_post_process_alter(ImageWindow *imd, gint clamp)
                }
 }
 
+
 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
 {
        ImageWindow *imd = data;
@@ -319,8 +323,9 @@ static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, g
 
        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 @@ static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData
                
                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 @@ static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData
                        }
 
                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 gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData
 
 static void image_post_process(ImageWindow *imd, gint clamp)
 {
+#if 0
        ExifData *exif = NULL;
 
        if (!image_get_pixbuf(imd)) return;
@@ -436,7 +443,6 @@ static void image_post_process(ImageWindow *imd, gint clamp)
                {
                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 @@ static void image_post_process(ImageWindow *imd, gint clamp)
                        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 @@ static void image_read_ahead_start(ImageWindow *imd)
        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 @@ static gint image_post_buffer_get(ImageWindow *imd)
                        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 @@ GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
 
 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 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source)
        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 @@ void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
 }
 
 
-
+#if 0
 void image_alter(ImageWindow *imd, AlterType type)
 {
        if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
@@ -1377,6 +1486,7 @@ void image_alter(ImageWindow *imd, AlterType type)
 
        image_alter_real(imd, type, TRUE);
 }
+#endif
 
 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
 {
@@ -1889,6 +1999,8 @@ ImageWindow *image_new(gint frame)
 
        imd->func_button = NULL;
        imd->func_scroll = NULL;
+       
+       imd->orientation = 1;
 
        imd->pr = GTK_WIDGET(pixbuf_renderer_new());
 
index 05b130c..f3c7cc6 100644 (file)
@@ -1094,7 +1094,7 @@ static GtkActionEntry menu_entries[] = {
   { "Rotate180",       NULL,           N_("Rotate 1_80"),      "<shift>R",     NULL,   CB(layout_menu_alter_180_cb) },
   { "Mirror",          NULL,           N_("_Mirror"),          "<shift>M",     NULL,   CB(layout_menu_alter_mirror_cb) },
   { "Flip",            NULL,           N_("_Flip"),            "<shift>F",     NULL,   CB(layout_menu_alter_flip_cb) },
-  { "Grayscale",       NULL,           N_("_Grayscale"),       "<shift>G",     NULL,   CB(layout_menu_alter_desaturate_cb) },
+  { "Grayscale",       NULL,           N_("Toggle _grayscale"),"<shift>G",     NULL,   CB(layout_menu_alter_desaturate_cb) },
   { "Properties",GTK_STOCK_PROPERTIES, N_("_Properties"),      "<control>P",   NULL,   CB(layout_menu_info_cb) },
   { "SelectAll",       NULL,           N_("Select _all"),      "<control>A",   NULL,   CB(layout_menu_select_all_cb) },
   { "SelectNone",      NULL,           N_("Select _none"), "<control><shift>A",NULL,   CB(layout_menu_unselect_all_cb) },
index 7f18019..c03d532 100644 (file)
@@ -213,7 +213,7 @@ gchar *alter_type_get_text(AlterType type)
                        return _("_Flip");
                        break;
                case ALTER_DESATURATE:
-                       return _("_Grayscale");
+                       return _("Toggle _grayscale");
                        break;
                default:
                        break;
index 749d745..fc3014a 100644 (file)
  */
 #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 @@ static void pixbuf_renderer_init(PixbufRenderer *pr)
        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 @@ static void pixbuf_renderer_finalize(GObject *object)
        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 @@ static void pr_tile_prepare(PixbufRenderer *pr, ImageTile *it)
                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 @@ static void pr_tile_prepare(PixbufRenderer *pr, ImageTile *it)
                                                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 @@ static void pr_tile_prepare(PixbufRenderer *pr, ImageTile *it)
  * 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 @@ static void pr_tile_render(PixbufRenderer *pr, ImageTile *it,
                }
        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 @@ static void pr_tile_render(PixbufRenderer *pr, ImageTile *it,
 
                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 @@ static void pr_tile_render(PixbufRenderer *pr, ImageTile *it,
        /* 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 @@ static gint pr_queue_draw_idle_cb(gpointer data)
        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 @@ static void pr_signals_connect(PixbufRenderer *pr)
  * 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 @@ static void pr_pixbuf_sync(PixbufRenderer *pr, gdouble zoom)
 
                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 @@ GdkPixbuf *pixbuf_renderer_get_pixbuf(PixbufRenderer *pr)
        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 @@ void pixbuf_renderer_move(PixbufRenderer *pr, PixbufRenderer *source)
        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 @@ void pixbuf_renderer_move(PixbufRenderer *pr, PixbufRenderer *source)
        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);
index 9c0f1c8..8dd4e67 100644 (file)
@@ -32,6 +32,10 @@ typedef gint (* PixbufRendererTileRequestFunc)(PixbufRenderer *pr, gint x, gint
                                               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,9 +123,13 @@ struct _PixbufRenderer
 
        PixbufRendererTileRequestFunc func_tile_request;
        PixbufRendererTileDisposeFunc func_tile_dispose;
-
+       
        gpointer func_tile_data;
 
+       PixbufRendererPostProcessFunc func_post_process;
+       gpointer post_process_user_data;
+       gint post_process_slow;
+
        gboolean delay_flip;
        gboolean loading;
        gboolean complete;
@@ -138,6 +146,10 @@ struct _PixbufRenderer
 
        GList *overlay_list;
        GdkPixmap *overlay_buffer;
+
+       GdkPixbuf *spare_tile;
+       
+       gint orientation;
 };
 
 struct _PixbufRendererClass
@@ -165,6 +177,11 @@ GtkWindow *pixbuf_renderer_get_parent(PixbufRenderer *pr);
 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,
index 61eadf6..7271c27 100644 (file)
@@ -379,6 +379,8 @@ struct _ImageWindow
        gint auto_refresh_interval;
 
        gint delay_flip;
+       gint orientation;
+       gint desaturate;
 };
 
 #define FILEDATA_MARKS_SIZE 6