* bar_exif.c, cache-loader.c, pan-view.c: Pass new arg for exif_read().
* color-man.[ch]: Add color_man_new_embedded for using in-memory color
profiles.
* exif.[ch]: Add support for extracting color profiles embedded in jpeg
and tiff images. This resulted in a rewrite of the jpeg parser; both
to allow searching for any marker type, and to make the code readable.
* format_raw.c: Add color profile tag to the debug code.
* image.c, layout.c: Use embedded color profiles when found and
enabled, also add toggle for the option in color profile menu.
+Mon Nov 27 01:23:23 2006 John Ellis <johne@verizon.net>
+
+ * bar_exif.c, cache-loader.c, pan-view.c: Pass new arg for exif_read().
+ * color-man.[ch]: Add color_man_new_embedded for using in-memory color
+ profiles.
+ * exif.[ch]: Add support for extracting color profiles embedded in jpeg
+ and tiff images. This resulted in a rewrite of the jpeg parser; both
+ to allow searching for any marker type, and to make the code readable.
+ * format_raw.c: Add color profile tag to the debug code.
+ * image.c, layout.c: Use embedded color profiles when found and
+ enabled, also add toggle for the option in color profile menu.
+
Fri Nov 24 21:37:01 2006 John Ellis <johne@verizon.net>
* configure.in: Add test for lcms (little cms).
> should honor enable_thumbnails setting
> color profiles:
- > support profiles embedded in images
+ d> support profiles embedded in images
+ > check if clamp arg is handled correct in post_process_*()
> add support in img-view.c
---
ExifData *exif;
gint len, i;
- exif = exif_read(eb->path);
+ exif = exif_read(eb->path, FALSE);
if (!exif)
{
time_t date = -1;
ExifData *exif;
- exif = exif_read(cl->path);
+ exif = exif_read(cl->path, FALSE);
if (exif)
{
gchar *text;
}
}
-static cmsHPROFILE color_man_cache_load_profile(ColorManProfileType type, const gchar *file)
+static cmsHPROFILE color_man_cache_load_profile(ColorManProfileType type, const gchar *file,
+ unsigned char *data, guint data_len)
{
cmsHPROFILE profile = NULL;
case COLOR_PROFILE_SRGB:
profile = cmsCreate_sRGBProfile();
break;
+ case COLOR_PROFILE_MEM:
+ if (data)
+ {
+ profile = cmsOpenProfileFromMem(data, data_len);
+ }
+ break;
case COLOR_PROFILE_NONE:
default:
break;
}
static ColorManCache *color_man_cache_new(ColorManProfileType in_type, const gchar *in_file,
+ unsigned char *in_data, guint in_data_len,
ColorManProfileType out_type, const gchar *out_file,
gint has_alpha)
{
cc->has_alpha = has_alpha;
- cc->profile_in = color_man_cache_load_profile(cc->profile_in_type, cc->profile_in_file);
- cc->profile_out = color_man_cache_load_profile(cc->profile_out_type, cc->profile_out_file);
+ cc->profile_in = color_man_cache_load_profile(cc->profile_in_type, cc->profile_in_file,
+ in_data, in_data_len);
+ cc->profile_out = color_man_cache_load_profile(cc->profile_out_type, cc->profile_out_file,
+ NULL, 0);
if (!cc->profile_in || !cc->profile_out)
{
return NULL;
}
- cm_cache_list = g_list_append(cm_cache_list, cc);
+ if (cc->profile_in_type != COLOR_PROFILE_MEM)
+ {
+ cm_cache_list = g_list_append(cm_cache_list, cc);
+ color_man_cache_ref(cc);
+ }
return cc;
}
}
static ColorManCache *color_man_cache_get(ColorManProfileType in_type, const gchar *in_file,
+ unsigned char *in_data, guint in_data_len,
ColorManProfileType out_type, const gchar *out_file,
gint has_alpha)
{
ColorManCache *cc;
cc = color_man_cache_find(in_type, in_file, out_type, out_file, has_alpha);
-
- if (!cc)
+ if (cc)
{
- cc = color_man_cache_new(in_type, in_file, out_type, out_file, has_alpha);
+ color_man_cache_ref(cc);
+ return cc;
}
- return cc;
+ return color_man_cache_new(in_type, in_file, in_data, in_data_len,
+ out_type, out_file, has_alpha);
}
return TRUE;
}
-ColorMan *color_man_new(ImageWindow *imd,
- ColorManProfileType input_type, const gchar *input_file,
- ColorManProfileType screen_type, const gchar *screen_file,
- ColorManDoneFunc done_func, gpointer done_data)
+static ColorMan *color_man_new_real(ImageWindow *imd,
+ 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)
{
ColorMan *cm;
GdkPixbuf *pixbuf;
gint has_alpha;
if (!imd) return NULL;
- if (input_type == COLOR_PROFILE_NONE || screen_type == COLOR_PROFILE_NONE) return NULL;
pixbuf = image_get_pixbuf(imd);
if (!pixbuf) return NULL;
cm->func_done_data = done_data;
has_alpha = gdk_pixbuf_get_has_alpha(pixbuf);
- cm->profile = color_man_cache_get(input_type, input_file, screen_type, screen_file, has_alpha);
+ cm->profile = color_man_cache_get(input_type, input_file, input_data, input_data_len,
+ screen_type, screen_file, has_alpha);
if (!cm->profile)
{
color_man_free(cm);
return NULL;
}
- color_man_cache_ref(cm->profile);
-
cm->idle_id = g_idle_add(color_man_idle_cb, cm);
return cm;
}
+ColorMan *color_man_new(ImageWindow *imd,
+ ColorManProfileType input_type, const gchar *input_file,
+ ColorManProfileType screen_type, const gchar *screen_file,
+ ColorManDoneFunc done_func, gpointer done_data)
+{
+ return color_man_new_real(imd,
+ input_type, input_file, NULL, 0,
+ screen_type, screen_file,
+ done_func, done_data);
+}
+
+ColorMan *color_man_new_embedded(ImageWindow *imd,
+ unsigned char *input_data, guint input_data_len,
+ ColorManProfileType screen_type, const gchar *screen_file,
+ ColorManDoneFunc done_func, gpointer done_data)
+{
+ return color_man_new_real(imd,
+ COLOR_PROFILE_MEM, NULL, input_data, input_data_len,
+ screen_type, screen_file,
+ done_func, done_data);
+}
+
void color_man_free(ColorMan *cm)
{
if (!cm) return;
COLOR_PROFILE_NONE = 0,
COLOR_PROFILE_FILE,
COLOR_PROFILE_SRGB,
+ COLOR_PROFILE_MEM
} ColorManProfileType;
typedef enum {
ColorManProfileType input_type, const gchar *input_file,
ColorManProfileType screen_type, const gchar *screen_file,
ColorManDoneFunc done_func, gpointer done_data);
+ColorMan *color_man_new_embedded(ImageWindow *imd,
+ unsigned char *input_data, guint input_data_len,
+ ColorManProfileType screen_type, const gchar *screen_file,
+ ColorManDoneFunc done_func, gpointer done_data);
void color_man_free(ColorMan *cm);
void color_man_update(void);
{ 0x828e, EXIF_FORMAT_BYTE_UNSIGNED, -1, "CFAPattern", NULL, NULL },
{ 0x828f, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "BatteryLevel", NULL, NULL },
{ 0x83bb, EXIF_FORMAT_LONG_UNSIGNED, -1, "IPTC/NAA", NULL, NULL },
-{ 0x8773, EXIF_FORMAT_UNDEFINED, -1, "InterColorProfile", NULL, NULL },
+{ 0x8773, EXIF_FORMAT_UNDEFINED, -1, "ColorProfile", NULL, NULL },
{ 0x8825, EXIF_FORMAT_LONG_UNSIGNED, 1, "GPSInfo", "SubIFD GPS offset", NULL },
{ 0x8829, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Interlace", NULL, NULL },
{ 0x882a, EXIF_FORMAT_SHORT, 1, "TimeZoneOffset", NULL, NULL },
return (brief) ? ExifFormatList[item->format].short_name : ExifFormatList[item->format].description;
}
-
-#define UNDEFINED_TEXT_BYTE_COUNT 16
-
static GString *string_append_raw_bytes(GString *string, gpointer data, gint ne)
{
gint i;
- for (i = 0 ; i < ne && i < UNDEFINED_TEXT_BYTE_COUNT; i++)
+ for (i = 0 ; i < ne; i++)
{
unsigned char c = ((char *)data)[i];
if (c < 32 || c > 127) c = '.';
g_string_append_printf(string, "%c", c);
}
string = g_string_append(string, " : ");
- for (i = 0 ; i < ne && i < UNDEFINED_TEXT_BYTE_COUNT; i++)
+ for (i = 0 ; i < ne; i++)
{
const gchar *spacer;
if (i > 0)
}
g_string_append_printf(string, "%s%02x", spacer, ((char *)data)[i]);
}
- if (i >= UNDEFINED_TEXT_BYTE_COUNT) g_string_append_printf(string, " (%d bytes)", ne);
return string;
}
*-------------------------------------------------------------------
*/
-#define MARKER_UNKNOWN 0x00
-#define MARKER_SOI 0xD8
-#define MARKER_APP1 0xE1
+#define JPEG_MARKER 0xFF
+#define JPEG_MARKER_SOI 0xD8
+#define JPEG_MARKER_EOI 0xD9
+#define JPEG_MARKER_APP1 0xE1
+#define JPEG_MARKER_APP2 0xE2
+
+/* jpeg container format:
+ all data markers start with 0XFF
+ 2 byte long file start and end markers: 0xFFD8(SOI) and 0XFFD9(EOI)
+ 4 byte long data segment markers in format: 0xFFTTSSSSNNN...
+ FF: 1 byte standard marker identifier
+ TT: 1 byte data type
+ SSSS: 2 bytes in Motorola byte alignment for length of the data.
+ This value includes these 2 bytes in the count, making actual
+ length of NN... == SSSS - 2.
+ NNN.: the data in this segment
+ */
-static gint jpeg_get_marker_size(unsigned char *data)
+static gint exif_jpeg_segment_find(unsigned char *data, guint size,
+ guchar app_marker, const gchar *magic, guint magic_len,
+ guint *seg_offset, guint *seg_length)
{
- /* Size is always in Motorola byte order */
- return exif_byte_get_int16(data + 2, EXIF_BYTE_ORDER_MOTOROLA);
-}
+ guchar marker = 0;
+ guint offset = 0;
+ guint length = 0;
-static gint jpeg_goto_next_marker(unsigned char **data, gint *size, gint *marker)
-{
- gint marker_size = 2;
+ while (marker != app_marker &&
+ marker != JPEG_MARKER_EOI)
+ {
+ offset += length;
+ length = 2;
- *marker = MARKER_UNKNOWN;
+ if (offset + 2 >= size ||
+ data[offset] != JPEG_MARKER) return FALSE;
- /* It is safe to access the marker and its size since we have checked
- * the SOI and this function guaranties the whole next marker is
- * available
- */
- if (*(*data + 1) != MARKER_SOI)
+ marker = data[offset + 1];
+ if (marker != JPEG_MARKER_SOI &&
+ marker != JPEG_MARKER_EOI)
+ {
+ if (offset + 4 >= size) return FALSE;
+ length += exif_byte_get_int16(data + offset + 2, EXIF_BYTE_ORDER_MOTOROLA);
+ }
+ }
+
+ if (marker == app_marker &&
+ offset + length < size &&
+ length >= 4 + magic_len &&
+ memcmp(data + offset + 4, magic, magic_len) == 0)
{
- marker_size += jpeg_get_marker_size(*data);
+ *seg_offset = offset + 4;
+ *seg_length = length - 4;
+ return TRUE;
}
- *size -= marker_size;
+ return FALSE;
+}
- /* size should be at least 4, so we can read the marker and its size
- * and check data are actually available
- */
- if (*size < 4) return -1;
+static ExifMarker jpeg_color_marker = { 0x8773, EXIF_FORMAT_UNDEFINED, -1, "ColorProfile", NULL, NULL };
- /* Jump to the next marker and be sure it begins with 0xFF
+static gint exif_jpeg_parse_color(ExifData *exif, unsigned char *data, guint size)
+{
+ guint seg_offset = 0;
+ guint seg_length = 0;
+ guint chunk_offset[255];
+ guint chunk_length[255];
+ guint chunk_count = 0;
+
+ /* For jpeg/jfif, ICC color profile data can be in more than one segment.
+ the data is in APP2 data segments that start with "ICC_PROFILE\x00\xNN\xTT"
+ NN = segment number for data
+ TT = total number of ICC segments (TT in each ICC segment should match)
*/
- *data += marker_size;
- if (**data != 0xFF) return -1;
- if (jpeg_get_marker_size(*data) + 2 > *size) return -1;
+ while (exif_jpeg_segment_find(data + seg_offset + seg_length,
+ size - seg_offset - seg_length,
+ JPEG_MARKER_APP2,
+ "ICC_PROFILE\x00", 12,
+ &seg_offset, &seg_length))
+ {
+ guchar chunk_num;
+ guchar chunk_tot;
- *marker = *(*data + 1);
+ if (seg_length < 14) return FALSE;
- return 0;
-}
+ chunk_num = data[seg_offset + 12];
+ chunk_tot = data[seg_offset + 13];
+ if (chunk_num == 0 || chunk_tot == 0) return FALSE;
-static gint exif_parse_JPEG(ExifData *exif, unsigned char *data, gint size, ExifMarker *list)
-{
- gint marker;
- gint marker_size;
+ if (chunk_count == 0)
+ {
+ guint i;
- if (size < 4 || *data != 0xFF || *(data + 1) != MARKER_SOI)
- {
- return -2;
+ chunk_count = (guint)chunk_tot;
+ for (i = 0; i < chunk_count; i++) chunk_offset[i] = 0;
+ for (i = 0; i < chunk_count; i++) chunk_length[i] = 0;
+ }
+
+ if (chunk_tot != chunk_count ||
+ chunk_num > chunk_count) return FALSE;
+
+ chunk_num--;
+ chunk_offset[chunk_num] = seg_offset + 14;
+ chunk_length[chunk_num] = seg_length - 14;
}
- do {
- if (jpeg_goto_next_marker(&data, &size, &marker) == -1)
+ if (chunk_count > 0)
+ {
+ ExifItem *item;
+ unsigned char *cp_data;
+ guint cp_length = 0;
+ guint i;
+
+ for (i = 0; i < chunk_count; i++) cp_length += chunk_length[i];
+ cp_data = g_malloc(cp_length);
+
+ for (i = 0; i < chunk_count; i++)
{
- break;
+ if (chunk_offset[i] == 0)
+ {
+ /* error, we never saw this chunk */
+ g_free(cp_data);
+ return FALSE;
+ }
+ memcpy(cp_data, data + chunk_offset[i], chunk_length[i]);
}
- } while (marker != MARKER_APP1);
- if (marker != MARKER_APP1)
+ item = exif_item_new(jpeg_color_marker.format, jpeg_color_marker.tag, 1,
+ &jpeg_color_marker);
+ g_free(item->data);
+ item->data = cp_data;
+ item->elements = cp_length;
+ item->data_len = cp_length;
+ exif->items = g_list_prepend(exif->items, item);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gint exif_jpeg_parse(ExifData *exif,
+ unsigned char *data, guint size,
+ ExifMarker *list, gint parse_color)
+{
+ guint seg_offset = 0;
+ guint seg_length = 0;
+ gint res = -1;
+
+ if (size < 4 ||
+ memcmp(data, "\xFF\xD8", 2) != 0)
{
return -2;
}
- marker_size = jpeg_get_marker_size(data) - 2;
-
- if (marker_size < 6 || memcmp(data + 4, "Exif\x00\x00", 6) != 0)
+ if (exif_jpeg_segment_find(data, size, JPEG_MARKER_APP1,
+ "Exif\x00\x00", 6,
+ &seg_offset, &seg_length))
{
- return -2;
+ res = exif_tiff_parse(exif, data + seg_offset + 6, seg_length - 6, list);
+ }
+
+ if (parse_color &&
+ exif_jpeg_parse_color(exif, data, size))
+ {
+ res = 0;
}
- return exif_tiff_parse(exif, data + 10, marker_size - 6, list);
+ return res;
}
+
/*
*-------------------------------------------------------------------
* misc
g_free(exif);
}
-ExifData *exif_read(const gchar *path)
+ExifData *exif_read(const gchar *path, gint parse_color_profile)
{
ExifData *exif;
void *f;
exif = g_new0(ExifData, 1);
exif->items = NULL;
- if ((res = exif_parse_JPEG(exif, (unsigned char *)f, size, ExifKnownMarkersList)) == -2)
+ if ((res = exif_jpeg_parse(exif, (unsigned char *)f, size,
+ ExifKnownMarkersList,
+ parse_color_profile)) == -2)
{
res = exif_tiff_parse(exif, (unsigned char *)f, size, ExifKnownMarkersList);
}
ExifKnownMarkersList);
break;
case FORMAT_RAW_EXIF_JPEG:
- res = exif_parse_JPEG(exif, (unsigned char*)f + offset, size - offset,
- ExifKnownMarkersList);
+ res = exif_jpeg_parse(exif, (unsigned char*)f + offset, size - offset,
+ ExifKnownMarkersList, FALSE);
break;
case FORMAT_RAW_EXIF_IFD_II:
case FORMAT_RAW_EXIF_IFD_MM:
return NULL;
}
+#define EXIF_DATA_AS_TEXT_MAX_COUNT 16
+
gchar *exif_item_get_data_as_text(ExifItem *item)
{
const ExifMarker *marker;
data = item->data;
ne = item->elements;
+ if (ne > EXIF_DATA_AS_TEXT_MAX_COUNT) ne = EXIF_DATA_AS_TEXT_MAX_COUNT;
string = g_string_new("");
switch (item->format)
{
break;
}
- text = g_strdup(string->str);
- g_string_free(string, TRUE);
+ if (item->elements > EXIF_DATA_AS_TEXT_MAX_COUNT &&
+ item->format != EXIF_FORMAT_STRING)
+ {
+ g_string_append(string, " ...");
+ }
+
+ text = string->str;
+ g_string_free(string, FALSE);
return text;
}
/*
* GQView
- * (C) 2004 John Ellis
+ * (C) 2006 John Ellis
*
* Authors:
* Support for Exif file format, originally written by Eric Swalens.
*-----------------------------------------------------------------------------
*/
-ExifData *exif_read(const gchar *path);
+ExifData *exif_read(const gchar *path, gint parse_color_profile);
void exif_free(ExifData *exif);
gchar *exif_get_data_as_text(ExifData *exif, const gchar *key);
format_debug_tiff_table(data, len, subset, bo, level + 1);
}
}
+ else if (tag == 0x8773 && type == EXIF_FORMAT_UNDEFINED)
+ {
+ printf("%*s~~~ found ICC color profile at offset %d, length %d\n", level, "", segment, seg_len);
+ }
else if (tag == 0x201 && (type == EXIF_FORMAT_LONG_UNSIGNED || type == EXIF_FORMAT_LONG))
{
guint subset = exif_byte_get_int32(data + segment, bo);
*-------------------------------------------------------------------
*/
-static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp, gint exif_rotated)
+static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
{
PixbufRenderer *pr;
GdkPixbuf *new = NULL;
+ gint exif_rotate;
gint x, y;
gint t;
pr = (PixbufRenderer *)imd->pr;
+ exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
imd->delay_alter_type = ALTER_NONE;
if (!pr->pixbuf) return;
if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
{
- if (exif_rotated)
+ if (exif_rotate)
{
switch (pr->scroll_reset)
{
}
}
+static void image_post_process_alter(ImageWindow *imd, gint clamp)
+{
+ if (imd->delay_alter_type != ALTER_NONE)
+ {
+ image_alter_real(imd, imd->delay_alter_type, clamp);
+ }
+}
+
static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
{
ImageWindow *imd = data;
if (type != COLOR_RETURN_IMAGE_CHANGED)
{
- image_post_process(imd, FALSE);
+ image_post_process_alter(imd, FALSE);
}
}
-static gint image_post_process_color(ImageWindow *imd, gint start_row)
+static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif)
{
ColorMan *cm;
ColorManProfileType input_type;
ColorManProfileType screen_type;
const gchar *input_file;
const gchar *screen_file;
+ ExifItem *item = NULL;
if (imd->cm) return FALSE;
return FALSE;
}
- cm = color_man_new(imd,
- input_type, input_file,
- screen_type, screen_file,
- image_post_process_color_cb, imd);
+ if (imd->color_profile_use_image && exif)
+ {
+ item = exif_get_item(exif, "ColorProfile");
+ }
+ if (item && item->format == EXIF_FORMAT_UNDEFINED)
+ {
+ if (debug) printf("Found embedded color profile\n");
+
+ cm = color_man_new_embedded(imd,
+ item->data, item->data_len,
+ screen_type, screen_file,
+ image_post_process_color_cb, imd);
+ }
+ else
+ {
+ cm = color_man_new(imd,
+ input_type, input_file,
+ screen_type, screen_file,
+ image_post_process_color_cb, imd);
+ }
+
if (cm)
{
if (start_row > 0) cm->row = start_row;
static void image_post_process(ImageWindow *imd, gint clamp)
{
- gint exif_rotated = FALSE;
+ ExifData *exif = NULL;
- if (imd->color_profile_enable &&
- !(imd->state & IMAGE_STATE_COLOR_ADJ))
- {
- if (image_post_process_color(imd, 0)) return;
+ if (!image_get_pixbuf(imd)) return;
- /* fixme: note error to user */
- imd->state |= IMAGE_STATE_COLOR_ADJ;
+ if (exif_rotate_enable ||
+ (imd->color_profile_enable && imd->color_profile_use_image) )
+ {
+ exif = exif_read(imd->image_path, (imd->color_profile_enable && imd->color_profile_use_image));
}
- if (exif_rotate_enable && image_get_pixbuf(imd))
+ if (exif_rotate_enable && exif)
{
- ExifData *ed;
gint orientation;
- ed = exif_read(imd->image_path);
- if (ed && exif_get_integer(ed, "Orientation", &orientation))
+ if (exif_get_integer(exif, "Orientation", &orientation))
{
+ gint rotate = TRUE;
+
/* see http://jpegclub.org/exif_orientation.html
1 2 3 4 5 6 7 8
88 88 88 88
88 88 888888 888888
*/
-
switch (orientation)
{
case EXIF_ORIENTATION_TOP_LEFT:
/* normal -- nothing to do */
+ rotate = FALSE;
break;
case EXIF_ORIENTATION_TOP_RIGHT:
/* mirrored */
imd->delay_alter_type = ALTER_MIRROR;
- exif_rotated = TRUE;
break;
case EXIF_ORIENTATION_BOTTOM_RIGHT:
/* upside down */
imd->delay_alter_type = ALTER_ROTATE_180;
- exif_rotated = TRUE;
break;
case EXIF_ORIENTATION_BOTTOM_LEFT:
/* flipped */
imd->delay_alter_type = ALTER_FLIP;
- exif_rotated = TRUE;
break;
case EXIF_ORIENTATION_LEFT_TOP:
/* not implemented -- too wacky to fix in one step */
+ rotate = FALSE;
break;
case EXIF_ORIENTATION_RIGHT_TOP:
/* rotated -90 (270) */
imd->delay_alter_type = ALTER_ROTATE_90;
- exif_rotated = TRUE;
break;
case EXIF_ORIENTATION_RIGHT_BOTTOM:
/* not implemented -- too wacky to fix in one step */
+ rotate = FALSE;
break;
case EXIF_ORIENTATION_LEFT_BOTTOM:
/* rotated 90 */
imd->delay_alter_type = ALTER_ROTATE_90_CC;
- exif_rotated = TRUE;
break;
default:
/* The other values are out of range */
+ rotate = FALSE;
break;
}
+
+ if (rotate) imd->state |= IMAGE_STATE_COLOR_ADJ;
}
- exif_free(ed);
}
- if (imd->delay_alter_type != ALTER_NONE)
+ if (imd->color_profile_enable)
{
- image_alter_real(imd, imd->delay_alter_type, clamp, exif_rotated);
+ if (!image_post_process_color(imd, 0, exif))
+ {
+ /* fixme: note error to user */
+ imd->state |= IMAGE_STATE_COLOR_ADJ;
+ }
}
+
+ if (!imd->cm) image_post_process_alter(imd, clamp);
+
+ exif_free(exif);
}
/*
image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
if (imd->prev_color_row >= 0)
{
- image_post_process_color(imd, imd->prev_color_row);
+ ExifData *exif = NULL;
+
+ if (imd->color_profile_use_image) exif = exif_read(imd->image_path, TRUE);
+ image_post_process_color(imd, imd->prev_color_row, exif);
+ exif_free(exif);
}
success = TRUE;
}
{
/* still loading, wait till done */
imd->delay_alter_type = type;
+ imd->state |= IMAGE_STATE_ROTATE_USER;
+
+ if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
+ {
+ imd->state &= ~IMAGE_STATE_ROTATE_AUTO;
+ }
return;
}
- image_alter_real(imd, type, TRUE, FALSE);
+ image_alter_real(imd, type, TRUE);
}
void image_zoom_adjust(ImageWindow *imd, gdouble increment)
layout_image_refresh(lw);
}
+static void layout_color_menu_use_image_cb(GtkWidget *widget, gpointer data)
+{
+ LayoutWindow *lw = data;
+ gint input, screen, use_image;
+
+ if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
+ layout_image_color_profile_set(lw, input, screen, !use_image);
+ layout_image_refresh(lw);
+}
+
#define COLOR_MENU_KEY "color_menu_key"
static void layout_color_menu_input_cb(GtkWidget *widget, gpointer data)
menu_item_add_divider(menu);
+ item = menu_item_add_check(menu, _("Use profile from _image"), use_image,
+ G_CALLBACK(layout_color_menu_use_image_cb), lw);
+ gtk_widget_set_sensitive(item, active);
+
front = g_strdup_printf(_("Input _%d:"), 0);
buf = g_strdup_printf("%s %s", front, "sRGB");
g_free(front);
gint i;
if (!fd) return;
- exif = exif_read(fd->path);
+ exif = exif_read(fd->path, FALSE);
if (!exif) return;
pan_text_alignment_add(ta, NULL, NULL);