<para>Toggles the full screen window display.</para>\r
</listitem>\r
</varlistentry>\r
+ <varlistentry>\r
+ <term>\r
+ <menuchoice>\r
+ <shortcut>\r
+ <keycombo>\r
+ <keycap>Shift</keycap>\r
+ <keycap>E</keycap>\r
+ </keycombo>\r
+ </shortcut>\r
+ <guimenu>Over/Under Exposure</guimenu>\r
+ </menuchoice>\r
+ </term>\r
+ <listitem>\r
+ <para>\r
+ Toggles highlighting of pixels that are either over or under exposed. This function operates on the displayed pixels. If a raw file is being displayed, the embedded jpeg data is being used. If the image is zoomed, the zoom type affects the results. Two-pass rendering also has some influence.\r
+ <para />\r
+ If a pixel has any channel at zero or full-scale, the pixel is displayed in red.\r
+ </para>\r
+ </listitem>\r
+ </varlistentry>\r
<varlistentry>\r
<term>\r
<guimenu>Keywords</guimenu>\r
<entry />\r
<entry>Toggle Keywords sidebar.</entry>\r
</row>\r
+ <row>\r
+ <entry>\r
+ <code>\r
+ Shift +\r
+ <keycap>E</keycap>\r
+ </code>\r
+ </entry>\r
+ <entry />\r
+ <entry>Toggle highlighting of pixels that are over or under exposed.</entry>\r
+ </row>\r
<row>\r
<entry>\r
<keycap>V</keycap>\r
icon_original.png \
icon_trash.png \
icon_heic.png \
- icon_grayscale.png
+ icon_grayscale.png \
+ icon_exposure.png
ICONS_INLINE_PAIRS = \
folder_closed $(srcdir)/folder_closed.png \
icon_original $(srcdir)/icon_original.png \
icon_trash $(srcdir)/icon_trash.png \
icon_heic $(srcdir)/icon_heic.png \
- icon_grayscale $(srcdir)/icon_grayscale.png
+ icon_grayscale $(srcdir)/icon_grayscale.png \
+ icon_exposure $(srcdir)/icon_exposure.png
icons_inline.h: $(ICONS_INLINE) Makefile.in
@sh -ec "echo '/* Auto generated file, do not edit */'; echo; \
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);
-
+ if (imd->overunderexposed) pixbuf_highlight_overunderexposed(*pixbuf, x, y, w, h);
}
void image_alter_orientation(ImageWindow *imd, FileData *fd_n, AlterType type)
void image_set_desaturate(ImageWindow *imd, gboolean desaturate)
{
imd->desaturate = desaturate;
- if (imd->cm || imd->desaturate)
+ if (imd->cm || imd->desaturate || imd->overunderexposed)
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);
return imd->desaturate;
}
+void image_set_overunderexposed(ImageWindow *imd, gboolean overunderexposed)
+{
+ imd->overunderexposed = overunderexposed;
+ if (imd->cm || imd->desaturate || imd->overunderexposed)
+ 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);
+ pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
+}
+
+gboolean image_get_overunderexposed(ImageWindow *imd)
+{
+ return imd->overunderexposed;
+}
+
/*
*-------------------------------------------------------------------
* read ahead (prebuffer)
image_post_process_color(imd, 0, FALSE); /* TODO: error handling */
}
- if (imd->cm || imd->desaturate)
+ if (imd->cm || imd->desaturate || imd->overunderexposed)
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);
pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
- if (imd->cm || imd->desaturate)
+ if (imd->cm || imd->desaturate || imd->overunderexposed)
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);
pixbuf_renderer_copy(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
- if (imd->cm || imd->desaturate)
+ if (imd->cm || imd->desaturate || imd->overunderexposed)
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);
void image_alter_orientation(ImageWindow *imd, FileData *fd, AlterType type);
void image_set_desaturate(ImageWindow *imd, gboolean desaturate);
gboolean image_get_desaturate(ImageWindow *imd);
+void image_set_overunderexposed(ImageWindow *imd, gboolean overunderexposed);
+gboolean image_get_overunderexposed(ImageWindow *imd);
/* zoom */
void image_zoom_adjust(ImageWindow *imd, gdouble increment);
return image_get_desaturate(lw->image);
}
+void layout_image_set_overunderexposed(LayoutWindow *lw, gboolean overunderexposed)
+{
+ if (!layout_valid(&lw)) return;
+
+ image_set_overunderexposed(lw->image, overunderexposed);
+}
+
+gboolean layout_image_get_overunderexposed(LayoutWindow *lw)
+{
+ if (!layout_valid(&lw)) return FALSE;
+
+ return image_get_overunderexposed(lw->image);
+}
+
/* stereo */
/*
gint layout_image_stereo_get(LayoutWindow *lw)
void layout_image_alter_orientation(LayoutWindow *lw, AlterType type);
void layout_image_set_desaturate(LayoutWindow *lw, gboolean desaturate);
gboolean layout_image_get_desaturate(LayoutWindow *lw);
+void layout_image_set_overunderexposed(LayoutWindow *lw, gboolean overunderexposed);
+gboolean layout_image_get_overunderexposed(LayoutWindow *lw);
void layout_image_rating(LayoutWindow *lw, const gchar *rating);
options->draw_rectangle = gtk_toggle_action_get_active(action);
}
+static void layout_menu_select_overunderexposed_cb(GtkToggleAction *action, gpointer data)
+{
+ LayoutWindow *lw = data;
+
+ layout_image_set_overunderexposed(lw, gtk_toggle_action_get_active(action));
+}
+
static void layout_menu_write_rotate(GtkToggleAction *action, gpointer data, gboolean keep_date)
{
LayoutWindow *lw = data;
{ "Animate", NULL, N_("GIF _animation"), "A", N_("Toggle GIF animation"), CB(layout_menu_animate_cb), FALSE },
{ "ExifRotate", GTK_STOCK_ORIENTATION_PORTRAIT, N_("_Exif rotate"), "<alt>X", N_("Exif rotate"), CB(layout_menu_exif_rotate_cb), FALSE },
{ "DrawRectangle", PIXBUF_INLINE_ICON_DRAW_RECTANGLE, N_("Draw Rectangle"), NULL, N_("Draw Rectangle"), CB(layout_menu_select_rectangle_cb), FALSE },
+ { "OverUnderExposed", PIXBUF_INLINE_ICON_EXPOSURE, N_("Over/Under Exposed"), "<shift>E", N_("Over/Under Exposed"), CB(layout_menu_select_overunderexposed_cb), FALSE },
};
static GtkRadioActionEntry menu_radio_entries[] = {
" <menuitem action='HistogramModeLog'/>"
" <menuitem action='HistogramModeCycle'/>"
" </menu>"
+" <menuitem action='OverUnderExposed'/>"
" <menuitem action='FullScreen'/>"
" <placeholder name='ViewSection'/>"
" <separator/>"
action = gtk_action_group_get_action(lw->action_group, "ExifRotate");
gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->image.exif_rotate_enable);
+ action = gtk_action_group_get_action(lw->action_group, "OverUnderExposed");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->overunderexposed);
+
action = gtk_action_group_get_action(lw->action_group, "DrawRectangle");
gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->draw_rectangle);
gboolean show_guidelines;
gboolean draw_rectangle;
gboolean show_predefined_keyword_tree;
+ gboolean overunderexposed;
/* various */
gboolean tree_descend_subdirs;
{ PIXBUF_INLINE_ICON_TRASH, icon_trash },
{ PIXBUF_INLINE_ICON_HEIF, icon_heic },
{ PIXBUF_INLINE_ICON_GRAYSCALE, icon_grayscale },
+ { PIXBUF_INLINE_ICON_EXPOSURE, icon_exposure },
{ NULL, NULL }
};
}
}
}
+
+/*
+ *-----------------------------------------------------------------------------
+ * pixbuf highlight under/over exposure *-----------------------------------------------------------------------------
+ */
+void pixbuf_highlight_overunderexposed(GdkPixbuf *pb, gint x, gint y, gint w, gint h)
+{
+ gboolean has_alpha;
+ gint pw, ph, prs;
+ guchar *p_pix;
+ guchar *pp;
+ gint i, j;
+
+ if (!pb) return;
+
+ pw = gdk_pixbuf_get_width(pb);
+ ph = gdk_pixbuf_get_height(pb);
+
+ if (x < 0 || x + w > pw) return;
+ if (y < 0 || y + h > ph) return;
+
+ has_alpha = gdk_pixbuf_get_has_alpha(pb);
+ prs = gdk_pixbuf_get_rowstride(pb);
+ p_pix = gdk_pixbuf_get_pixels(pb);
+
+ for (i = 0; i < h; i++)
+ {
+ pp = p_pix + (y + i) * prs + (x * (has_alpha ? 4 : 3));
+ for (j = 0; j < w; j++)
+ {
+ if (pp[0] == 255 || pp[1] == 255 || pp[2] == 255 || pp[0] == 0 || pp[1] == 0 || pp[2] == 0)
+ {
+ *pp = 255;
+ pp++;
+ *pp = 0;
+ pp++;
+ *pp = 0;
+ pp++;
+ if (has_alpha) pp++;
+ }
+ else
+ {
+ pp = pp + 3;
+ if (has_alpha) pp++;
+ }
+ }
+ }
+}
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
#define PIXBUF_INLINE_ICON_TRASH "icon_trash"
#define PIXBUF_INLINE_ICON_HEIF "icon_heic"
#define PIXBUF_INLINE_ICON_GRAYSCALE "icon_grayscale"
+#define PIXBUF_INLINE_ICON_EXPOSURE "icon_exposure"
#define PIXBUF_INLINE_ICON_CW "icon_rotate_clockwise"
#define PIXBUF_INLINE_ICON_CCW "icon_rotate_counter_clockwise"
void pixbuf_desaturate_rect(GdkPixbuf *pb,
gint x, gint y, gint w, gint h);
+void pixbuf_highlight_overunderexposed(GdkPixbuf *pb,
+ gint x, gint y, gint w, gint h);
/* clipping utils */
{"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
{"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
{"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
+ {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
{"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
{"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
{"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
gboolean delay_flip;
gint orientation;
gboolean desaturate;
+ gboolean overunderexposed;
gint user_stereo;
gboolean mouse_wheel_mode;