#include "collect.h"
+#include "collect-table.h"
#include "color-man.h"
#include "exif.h"
#include "metadata.h"
#include "histogram.h"
+#include "history_list.h"
#include "image-load.h"
#include "image-overlay.h"
#include "layout.h"
static GList *image_list = NULL;
-static void image_update_title(ImageWindow *imd);
+void image_update_title(ImageWindow *imd);
static void image_read_ahead_start(ImageWindow *imd);
static void image_cache_set(ImageWindow *imd, FileData *fd);
+// For draw rectangle function
+static gint pixbuf_start_x;
+static gint pixbuf_start_y;
+static gint image_start_x;
+static gint image_start_y;
+static gint rect_x1, rect_x2, rect_y1, rect_y2;
+static gint rect_id = 0;
+
/*
*-------------------------------------------------------------------
* 'signals'
}
}
+static void switch_coords_orientation(ImageWindow *imd, gint x, gint y, gint width, gint height)
+{
+ switch (imd->orientation)
+ {
+ case EXIF_ORIENTATION_TOP_LEFT:
+ /* normal -- nothing to do */
+ rect_x1 = image_start_x;
+ rect_y1 = image_start_y;
+ rect_x2 = x;
+ rect_y2 = y;
+ break;
+ case EXIF_ORIENTATION_TOP_RIGHT:
+ /* mirrored */
+ rect_x1 = width - x;
+ rect_y1 = image_start_y;
+ rect_x2 = width - image_start_x;
+ rect_y2 = y;
+ break;
+ case EXIF_ORIENTATION_BOTTOM_RIGHT:
+ /* upside down */
+ rect_x1 = width - x;
+ rect_y1 = height - y;
+ rect_x2 = width - image_start_x;
+ rect_y2 = height - image_start_y;
+ break;
+ case EXIF_ORIENTATION_BOTTOM_LEFT:
+ /* flipped */
+ rect_x1 = image_start_x;
+ rect_y1 = height - y;
+ rect_x2 = x;
+ rect_y2 = height - image_start_y;
+ break;
+ case EXIF_ORIENTATION_LEFT_TOP:
+ /* left mirrored */
+ rect_x1 = image_start_y;
+ rect_y1 = image_start_x;
+ rect_x2 = y;
+ rect_y2 = x;
+ break;
+ case EXIF_ORIENTATION_RIGHT_TOP:
+ /* rotated -90 (270) */
+ rect_x1 = image_start_y;
+ rect_y1 = width - x;
+ rect_x2 = y;
+ rect_y2 = width - image_start_x;
+ break;
+ case EXIF_ORIENTATION_RIGHT_BOTTOM:
+ /* right mirrored */
+ rect_x1 = height - y;
+ rect_y1 = width - x;
+ rect_x2 = height - image_start_y;
+ rect_y2 = width - image_start_x;
+ break;
+ case EXIF_ORIENTATION_LEFT_BOTTOM:
+ /* rotated 90 */
+ rect_x1 = height - y;
+ rect_y1 = image_start_x;
+ rect_x2 = height - image_start_y;
+ rect_y2 = x;
+ break;
+ default:
+ /* The other values are out of range */
+ break;
+ }
+}
+
static void image_press_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
{
ImageWindow *imd = data;
LayoutWindow *lw;
+ gint x_pixel, y_pixel;
+
+ if(options->draw_rectangle)
+ {
+ pixbuf_renderer_get_mouse_position(pr, &x_pixel, &y_pixel);
+
+ pixbuf_start_x = event->x;
+ pixbuf_start_y = event->y;
+
+ if (x_pixel == -1)
+ {
+ image_start_x = 0;
+ }
+ else
+ {
+ image_start_x = x_pixel;
+ }
+
+ if (y_pixel == -1)
+ {
+ image_start_y = 0;
+ }
+ else
+ {
+ image_start_y = y_pixel;
+ }
+ }
+
+ if (rect_id)
+ {
+ pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, rect_id);
+ }
lw = layout_find_by_image(imd);
if (lw && event->button == MOUSE_BUTTON_LEFT && event->type == GDK_2BUTTON_PRESS
{
ImageWindow *imd = data;
gint width, height;
+ gint rect_width;
+ gint rect_height;
+ GdkPixbuf *rect_pixbuf;
+ gint x_pixel, y_pixel;
+ gint image_x_pixel, image_y_pixel;
+
+ if (options->draw_rectangle)
+ {
+ pixbuf_renderer_get_image_size(pr, &width, &height);
+ pixbuf_renderer_get_mouse_position(pr, &x_pixel, &y_pixel);
+
+ if (x_pixel == -1)
+ {
+ image_x_pixel = width;
+ }
+ else
+ {
+ image_x_pixel = x_pixel;
+ }
+
+ if (y_pixel == -1)
+ {
+ image_y_pixel = height;
+ }
+ else
+ {
+ image_y_pixel = y_pixel;
+ }
+
+ switch_coords_orientation(imd, image_x_pixel, image_y_pixel, width, height);
+ if (rect_id)
+ {
+ pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, rect_id);
+ }
+
+ rect_width = pr->drag_last_x - pixbuf_start_x;
+ if (rect_width <= 0)
+ {
+ rect_width = 1;
+ }
+ rect_height = pr->drag_last_y - pixbuf_start_y;
+ if (rect_height <= 0)
+ {
+ rect_height = 1;
+ }
+
+ rect_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, rect_width, rect_height);
+ pixbuf_set_rect_fill(rect_pixbuf, 0, 0, rect_width, rect_height, 255, 255, 255, 0);
+ pixbuf_set_rect(rect_pixbuf, 1, 1, rect_width-2, rect_height - 2, 0, 0, 0, 255, 1, 1, 1, 1);
+ pixbuf_set_rect(rect_pixbuf, 2, 2, rect_width-4, rect_height - 4, 255, 255, 255, 255, 1, 1, 1, 1);
+
+ rect_id = pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, rect_pixbuf, pixbuf_start_x, pixbuf_start_y, OVL_NORMAL);
+ }
pixbuf_renderer_get_scaled_size(pr, &width, &height);
*-------------------------------------------------------------------
*/
-static void image_update_title(ImageWindow *imd)
+void image_update_title(ImageWindow *imd)
{
gchar *title = NULL;
gchar *zoom = NULL;
gchar *collection = NULL;
+ LayoutWindow *lw;
+ gchar *lw_ident = NULL;
if (!imd->top_window) return;
g_free(buf);
}
- title = g_strdup_printf("%s%s%s%s%s%s",
+ lw = layout_find_by_image(imd);
+ if (lw)
+ {
+ lw_ident = g_strconcat(" (", lw->options.id, ")", NULL);
+ }
+
+ title = g_strdup_printf("%s%s%s%s%s%s%s",
imd->title ? imd->title : "",
imd->image_fd ? imd->image_fd->name : "",
zoom ? zoom : "",
collection ? collection : "",
imd->image_fd ? " - " : "",
- imd->title_right ? imd->title_right : "");
+ imd->title_right ? imd->title_right : "",
+ options->show_window_ids ? (lw_ident ? lw_ident : "") : ""
+ );
+ if (lw_ident)
+ {
+ g_free(lw_ident);
+ }
gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
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)
else
if (options->metadata.write_orientation)
{
- orientation = metadata_read_int(fd_n, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT);
+ if (g_strcmp0(imd->image_fd->format_name, "heif") == 0)
+ {
+ orientation = EXIF_ORIENTATION_TOP_LEFT;
+ }
+ else
+ {
+ orientation = metadata_read_int(fd_n, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT);
+ }
}
}
if (orientation != (fd_n->exif_orientation ? fd_n->exif_orientation : 1))
{
- if (!options->metadata.write_orientation)
+ if (g_strcmp0(fd_n->format_name, "heif") != 0)
+ {
+ if (!options->metadata.write_orientation)
+ {
+ /* user_orientation does not work together with options->metadata.write_orientation,
+ use either one or the other.
+ we must however handle switching metadata.write_orientation on and off, therefore
+ we just disable referencing new fd's, not unreferencing the old ones
+ */
+ if (fd_n->user_orientation == 0) file_data_ref(fd_n);
+ fd_n->user_orientation = orientation;
+ }
+ }
+ else
{
- /* user_orientation does not work together with options->metadata.write_orientation,
- use either one or the other.
- we must however handle switching metadata.write_orientation on and off, therefore
- we just disable referencing new fd's, not unreferencing the old ones
- */
if (fd_n->user_orientation == 0) file_data_ref(fd_n);
fd_n->user_orientation = orientation;
}
fd_n->user_orientation = 0;
}
- if (options->metadata.write_orientation)
+ if (g_strcmp0(fd_n->format_name, "heif") != 0)
{
- if (type == ALTER_NONE)
- {
- metadata_write_revert(fd_n, ORIENTATION_KEY);
- }
- else
+ if (options->metadata.write_orientation)
{
- metadata_write_int(fd_n, ORIENTATION_KEY, orientation);
+ if (type == ALTER_NONE)
+ {
+ metadata_write_revert(fd_n, ORIENTATION_KEY);
+ }
+ else
+ {
+ metadata_write_int(fd_n, ORIENTATION_KEY, orientation);
+ }
}
}
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;
+}
+
+void image_set_ignore_alpha(ImageWindow *imd, gboolean ignore_alpha)
+{
+ pixbuf_renderer_set_ignore_alpha((PixbufRenderer *)imd->pr, ignore_alpha);
+}
+
/*
*-------------------------------------------------------------------
* read ahead (prebuffer)
case FORMAT_CLASS_VIDEO:
pixbuf = pixbuf_inline(PIXBUF_INLINE_VIDEO);
break;
+ case FORMAT_CLASS_COLLECTION:
+ pixbuf = pixbuf_inline(PIXBUF_INLINE_COLLECTION);
+ break;
+ case FORMAT_CLASS_DOCUMENT:
+ pixbuf = pixbuf_inline(PIXBUF_INLINE_ICON_PDF);
+ break;
default:
pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
}
pr = PIXBUF_RENDERER(imd->pr);
pr->zoom = zoom; /* store the zoom, needed by the loader */
+ /* Disable 2-pass for GIFs. Animated GIFs can flicker when enabled
+ * Reduce quality to worst but fastest to avoid dropped frames */
+ if (g_ascii_strcasecmp(imd->image_fd->extension, ".GIF") == 0)
+ {
+ g_object_set(G_OBJECT(imd->pr), "zoom_2pass", FALSE, NULL);
+ g_object_set(G_OBJECT(imd->pr), "zoom_quality", GDK_INTERP_NEAREST, NULL);
+ }
+
+
if (image_load_begin(imd, imd->image_fd))
{
imd->unknown = FALSE;
static gboolean image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
{
ImageWindow *imd = data;
+ gboolean in_lw = FALSE;
+ gint i = 0;
+ LayoutWindow *lw = NULL;
- if (imd->func_scroll &&
- event && event->type == GDK_SCROLL)
+ if (imd->func_scroll && event && event->type == GDK_SCROLL)
{
- imd->func_scroll(imd, event, imd->data_scroll);
- return TRUE;
+ layout_valid(&lw);
+ /* check if the image is in a layout window */
+ for (i = 0; i < MAX_SPLIT_IMAGES; i++)
+ {
+ if (imd == lw->split_images[i])
+ {
+ in_lw = TRUE;
+ break;
+ }
+ }
+
+ if (in_lw)
+ {
+ if (lw->options.split_pane_sync)
+ {
+ for (i = 0; i < MAX_SPLIT_IMAGES; i++)
+ {
+ if (lw->split_images[i])
+ {
+ layout_image_activate(lw, i, FALSE);
+ imd->func_scroll(lw->split_images[i], event, lw->split_images[i]->data_scroll);
+ }
+ }
+ }
+ else
+ {
+ imd->func_scroll(imd, event, imd->data_scroll);
+ }
+ return TRUE;
+ }
+ else
+ {
+ imd->func_scroll(imd, event, imd->data_scroll);
+ return TRUE;
+ }
}
return FALSE;
void image_attach_window(ImageWindow *imd, GtkWidget *window,
const gchar *title, const gchar *title_right, gboolean show_zoom)
{
+ LayoutWindow *lw;
+
imd->top_window = window;
g_free(imd->title);
imd->title = g_strdup(title);
imd->title_right = g_strdup(title_right);
imd->title_show_zoom = show_zoom;
- if (!options->image.fit_window_to_image) window = NULL;
+ lw = layout_find_by_image(imd);
+
+ if (!(options->image.fit_window_to_image && lw && (lw->options.tools_float || lw->options.tools_hidden))) window = NULL;
pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom, gboolean lazy)
{
+ LayoutWindow *lw;
StereoPixbufData stereo_data = STEREO_PIXBUF_DEFAULT;
/* read_exif and similar functions can actually notice that the file has changed and trigger
a notification that removes the pixbuf from cache and unrefs it. Therefore we must ref it
}
else if (options->image.exif_rotate_enable)
{
- imd->orientation = metadata_read_int(imd->image_fd, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT);
- imd->image_fd->exif_orientation = imd->orientation;
+ if (g_strcmp0(imd->image_fd->format_name, "heif") == 0)
+ {
+ imd->orientation = EXIF_ORIENTATION_TOP_LEFT;
+ imd->image_fd->exif_orientation = imd->orientation;
+ }
+ else
+ {
+ imd->orientation = metadata_read_int(imd->image_fd, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT);
+ imd->image_fd->exif_orientation = imd->orientation;
+ }
}
}
if (pixbuf) g_object_unref(pixbuf);
- if (imd->color_profile_enable)
+ /* Color correction takes too much time for an animated gif */
+ lw = layout_find_by_image(imd);
+ if (imd->color_profile_enable && lw && !lw->animation)
{
- image_post_process_color(imd, 0, FALSE); /* TODO: error handling */
+ 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);
void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
{
+ CollectWindow *cw;
+
if (!cd || !info || !g_list_find(cd->list, info)) return;
image_change_real(imd, info->fd, cd, info, zoom);
+ cw = collection_window_find(cd);
+ if (cw)
+ {
+ collection_table_set_focus(cw->table, info);
+ collection_table_unselect_all(cw->table);
+ collection_table_select(cw->table,info);
+ }
+
+ if (info->fd)
+ {
+ image_chain_append_end(info->fd->path);
+ }
}
CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
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);
if ((type & NOTIFY_REREAD) && fd == imd->image_fd)
{
/* there is no need to reload on NOTIFY_CHANGE,
- modified files should be detacted anyway and NOTIFY_REREAD should be recieved
+ modified files should be detacted anyway and NOTIFY_REREAD should be received
or they are removed from the filelist completely on "move" and "delete"
*/
DEBUG_1("Notify image: %s %04x", fd->path, type);
if (frame)
{
imd->frame = gtk_frame_new(NULL);
+ DEBUG_NAME(imd->frame);
g_object_ref(imd->pr);
if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
imd->orientation = 1;
imd->pr = GTK_WIDGET(pixbuf_renderer_new());
+ DEBUG_NAME(imd->pr);
image_options_set(imd);
imd->widget = gtk_vbox_new(0, 0);
+ DEBUG_NAME(imd->widget);
image_set_frame(imd, frame);
return imd;
}
+
+void image_get_rectangle(gint *x1, gint *y1, gint *x2, gint *y2)
+{
+ *x1 = rect_x1;
+ *y1 = rect_y1;
+ *x2 = rect_x2;
+ *y2 = rect_y2;
+}
+
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */