diff options
author | Lucas Rocha <lucasr@gnome.org> | 2007-03-17 22:19:09 +0000 |
---|---|---|
committer | Lucas Almeida Rocha <lucasr@src.gnome.org> | 2007-03-17 22:19:09 +0000 |
commit | 9ac162fa8eddb77f2760a01b1b1315f202a8366c (patch) | |
tree | 450c0c5269b2befa452619293d801afdf0de9cc7 | |
parent | 4aaab084893195f2c8232475fbbbf9e83082d276 (diff) | |
download | eog-ng.tar.gz |
Restabilished ICC profiling functionality with full code refactoring.eog-ng
2007-03-18 Lucas Rocha <lucasr@gnome.org>
Restabilished ICC profiling functionality with full code refactoring.
* src/eog-debug.[ch] (eog_debug_init): added EOG_DEBUG_LCMS for ICC
profiles debugging.
* src/eog-image.[ch] (eog_image_get_profile,
eog_image_apply_display_profile, eog_image_set_icc_data,
eog_image_real_load): load embedded ICC profile from the image if
present.
* src/eog-metadata-reader.[ch] (eog_metadata_reader_get_icc_chunk,
eog_metadata_reader_get_icc_chunk_size): unify ICC functions for
consistency.
* src/eog-window.c (eog_job_load_cb, eog_window_init,
eog_job_model_cb, eog_window_dispose,
eog_window_get_display_profile): load and cache display profile
to be applied on images just after they are successfully loaded.
svn path=/branches/eog-ng/; revision=3650
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | src/eog-debug.c | 3 | ||||
-rw-r--r-- | src/eog-debug.h | 4 | ||||
-rw-r--r-- | src/eog-image.c | 167 | ||||
-rw-r--r-- | src/eog-image.h | 7 | ||||
-rw-r--r-- | src/eog-metadata-reader.c | 26 | ||||
-rw-r--r-- | src/eog-metadata-reader.h | 3 | ||||
-rw-r--r-- | src/eog-window.c | 94 |
8 files changed, 227 insertions, 95 deletions
@@ -1,3 +1,21 @@ +2007-03-18 Lucas Rocha <lucasr@gnome.org> + + Restabilished ICC profiling functionality with full code refactoring. + + * src/eog-debug.[ch] (eog_debug_init): added EOG_DEBUG_LCMS for ICC + profiles debugging. + * src/eog-image.[ch] (eog_image_get_profile, + eog_image_apply_display_profile, eog_image_set_icc_data, + eog_image_real_load): load embedded ICC profile from the image if + present. + * src/eog-metadata-reader.[ch] (eog_metadata_reader_get_icc_chunk, + eog_metadata_reader_get_icc_chunk_size): unify ICC functions for + consistency. + * src/eog-window.c (eog_job_load_cb, eog_window_init, + eog_job_model_cb, eog_window_dispose, + eog_window_get_display_profile): load and cache display profile + to be applied on images just after they are successfully loaded. + 2007-03-17 Lucas Rocha <lucasr@gnome.org> Restabilished move to trash functionality. Patch from Javier Sánchez diff --git a/src/eog-debug.c b/src/eog-debug.c index e54b0890..e86cc26a 100644 --- a/src/eog-debug.c +++ b/src/eog-debug.c @@ -82,6 +82,9 @@ eog_debug_init () if (g_getenv ("EOG_DEBUG_PRINTING") != NULL) debug = debug | EOG_DEBUG_PRINTING; + if (g_getenv ("EOG_DEBUG_LCMS") != NULL) + debug = debug | EOG_DEBUG_LCMS; + out: #ifdef ENABLE_PROFILING diff --git a/src/eog-debug.h b/src/eog-debug.h index ccdcdcfe..232a7e87 100644 --- a/src/eog-debug.h +++ b/src/eog-debug.h @@ -41,7 +41,8 @@ typedef enum { EOG_DEBUG_IMAGE_SAVE = 1 << 6, EOG_DEBUG_LIST_STORE = 1 << 7, EOG_DEBUG_PREFERENCES = 1 << 8, - EOG_DEBUG_PRINTING = 1 << 9 + EOG_DEBUG_PRINTING = 1 << 9, + EOG_DEBUG_LCMS = 1 << 10 } EogDebugSection; #define DEBUG_WINDOW EOG_DEBUG_WINDOW, __FILE__, __LINE__, G_STRFUNC @@ -54,6 +55,7 @@ typedef enum { #define DEBUG_LIST_STORE EOG_DEBUG_LIST_STORE, __FILE__, __LINE__, G_STRFUNC #define DEBUG_PREFERENCES EOG_DEBUG_PREFERENCES, __FILE__, __LINE__, G_STRFUNC #define DEBUG_PRINTING EOG_DEBUG_PRINTING, __FILE__, __LINE__, G_STRFUNC +#define DEBUG_LCMS EOG_DEBUG_LCMS, __FILE__, __LINE__, G_STRFUNC void eog_debug_init (void); diff --git a/src/eog-image.c b/src/eog-image.c index 108a643b..20200d7f 100644 --- a/src/eog-image.c +++ b/src/eog-image.c @@ -512,131 +512,165 @@ eog_image_apply_display_profile (EogImage *img, cmsHPROFILE screen) { EogImagePrivate *priv; cmsHTRANSFORM transform; - int row, width, rows, stride; + gint row, width, rows, stride; guchar *p; g_return_if_fail (img != NULL); - if (screen == NULL) - return; - priv = img->priv; - if (priv->profile == NULL) - return; - - transform = cmsCreateTransform(priv->profile, TYPE_RGB_8, screen, TYPE_RGB_8, INTENT_PERCEPTUAL, 0); + + if (screen == NULL || priv->profile == NULL) return; + + transform = cmsCreateTransform (priv->profile, + TYPE_RGB_8, + screen, + TYPE_RGB_8, + INTENT_PERCEPTUAL, + 0); rows = gdk_pixbuf_get_height(priv->image); width = gdk_pixbuf_get_width (priv->image); stride = gdk_pixbuf_get_rowstride (priv->image); p = gdk_pixbuf_get_pixels (priv->image); + for (row = 0; row < rows; ++row) { cmsDoTransform(transform, p, p, width); p += stride; } - cmsDeleteTransform(transform); - //cmsCloseProfile(screen); + + cmsDeleteTransform (transform); } static void -extract_profile (EogImage *img, EogMetadataReader *md_reader) +eog_image_set_icc_data (EogImage *img, EogMetadataReader *md_reader) { EogImagePrivate *priv = img->priv; + guchar *icc_chunk = NULL; + guint icc_chunk_len = 0; #ifdef HAVE_EXIF ExifEntry *entry; - const ExifByteOrder o = exif_data_get_byte_order (priv->exif); + ExifByteOrder o; + gint color_space; #endif + /* TODO: switch on format to specialised functions */ - /* Embedded ICC profiles rule over anything else */ - { - gpointer data = eog_metadata_reader_get_icc_chunk (md_reader); - if (data != NULL) { - cmsErrorAction (LCMS_ERROR_SHOW); - priv->profile = cmsOpenProfileFromMem(data, eog_metadata_reader_get_icc_chunk_size (md_reader)); - if (priv->profile) { - g_printerr("JPEG has ICC profile\n"); - } else { - g_printerr("JPEG has invalid ICC profile\n"); - } - return; + eog_metadata_reader_get_icc_chunk (md_reader, &icc_chunk, &icc_chunk_len); + + if (icc_chunk != NULL) { + cmsErrorAction (LCMS_ERROR_SHOW); + + priv->profile = cmsOpenProfileFromMem(icc_chunk, icc_chunk_len); + + if (priv->profile) { + eog_debug_message (DEBUG_LCMS, "JPEG has ICC profile"); + } else { + eog_debug_message (DEBUG_LCMS, "JPEG has invalid ICC profile"); } + + return; } + + return; + #ifdef HAVE_EXIF - /* No EXIF data, so can't do anything */ - if (priv->exif == NULL) - return; - - entry = exif_content_get_entry (priv->exif->ifd [EXIF_IFD_EXIF], EXIF_TAG_COLOR_SPACE); - if (entry == NULL) - return; + if (priv->exif == NULL) return; + + o = exif_data_get_byte_order (priv->exif); + + entry = exif_data_get_entry (priv->exif, EXIF_TAG_COLOR_SPACE); + + if (entry == NULL) return; + + color_space = exif_get_short (entry->data, o); + + switch (color_space) { + case 1: + eog_debug_message (DEBUG_LCMS, "JPEG is sRGB"); - if (exif_get_short (entry->data, o) == 1) { priv->profile = cmsCreate_sRGBProfile (); - //g_printerr ("JPEG is sRGB\n"); - } else if (exif_get_short (entry->data, o) == 2) { + + break; + + case 2: + eog_debug_message (DEBUG_LCMS, "JPEG is Adobe RGB (Disabled)"); + /* TODO: create Adobe RGB profile */ //priv->profile = cmsCreate_Adobe1998Profile (); - //g_printerr ("JPEG is Adobe RGB (NOT correcting for now!)\n"); - } else if (exif_get_short (entry->data, o) == 0xFFFF) { - double gammaValue; + + break; + + case 0xFFFF: + { cmsCIExyY whitepoint; cmsCIExyYTRIPLE primaries; LPGAMMATABLE gamma[3]; - - const int offset = exif_format_get_size (EXIF_FORMAT_RATIONAL); + double gammaValue; ExifRational r; + + const int offset = exif_format_get_size (EXIF_FORMAT_RATIONAL); - entry = exif_content_get_entry (priv->exif->ifd [EXIF_IFD_0], EXIF_TAG_WHITE_POINT); + entry = exif_data_get_entry (priv->exif, EXIF_TAG_WHITE_POINT); + if (entry && entry->components == 2) { r = exif_get_rational (entry->data, o); - whitepoint.x = (double)r.numerator/r.denominator; + whitepoint.x = (double) r.numerator / r.denominator; + r = exif_get_rational (entry->data + offset, o); - whitepoint.y = (double)r.numerator/r.denominator; + whitepoint.y = (double) r.numerator / r.denominator; whitepoint.Y = 1.0; } else { - g_printerr("No whitepoint found\n"); + eog_debug_message (DEBUG_LCMS, "No whitepoint found"); return; } - entry = exif_content_get_entry (priv->exif->ifd [EXIF_IFD_0], EXIF_TAG_PRIMARY_CHROMATICITIES); + entry = exif_data_get_entry (priv->exif, EXIF_TAG_PRIMARY_CHROMATICITIES); + if (entry && entry->components == 6) { r = exif_get_rational (entry->data + 0 * offset, o); - primaries.Red.x = (double)r.numerator/r.denominator; + primaries.Red.x = (double) r.numerator / r.denominator; + r = exif_get_rational (entry->data + 1 * offset, o); - primaries.Red.y = (double)r.numerator/r.denominator; + primaries.Red.y = (double) r.numerator / r.denominator; r = exif_get_rational (entry->data + 2 * offset, o); - primaries.Green.x = (double)r.numerator/r.denominator; + primaries.Green.x = (double) r.numerator / r.denominator; + r = exif_get_rational (entry->data + 3 * offset, o); - primaries.Green.y = (double)r.numerator/r.denominator; + primaries.Green.y = (double) r.numerator / r.denominator; r = exif_get_rational (entry->data + 4 * offset, o); - primaries.Blue.x = (double)r.numerator/r.denominator; + primaries.Blue.x = (double) r.numerator / r.denominator; + r = exif_get_rational (entry->data + 5 * offset, o); - primaries.Blue.y = (double)r.numerator/r.denominator; + primaries.Blue.y = (double) r.numerator / r.denominator; primaries.Red.Y = primaries.Green.Y = primaries.Blue.Y = 1.0; } else { - g_printerr("No primary chromaticities found\n"); + eog_debug_message (DEBUG_LCMS, "No primary chromaticities found"); return; } - entry = exif_content_get_entry (priv->exif->ifd [EXIF_IFD_EXIF], EXIF_TAG_GAMMA); + entry = exif_data_get_entry (priv->exif, EXIF_TAG_GAMMA); + if (entry) { r = exif_get_rational (entry->data, o); - gammaValue = (double)r.numerator/r.denominator; + gammaValue = (double) r.numerator / r.denominator; } else { - /* Assume 2.2 */ - g_printerr("No gamma found\n"); + eog_debug_message (DEBUG_LCMS, "No gamma found"); gammaValue = 2.2; } - gamma[0] = gamma[1] = gamma[2] = cmsBuildGamma(256, gammaValue); + gamma[0] = gamma[1] = gamma[2] = cmsBuildGamma (256, gammaValue); - priv->profile = cmsCreateRGBProfile(&whitepoint, &primaries, gamma); - //g_printerr ("JPEG is calibrated\n"); + priv->profile = cmsCreateRGBProfile (&whitepoint, &primaries, gamma); + cmsFreeGamma(gamma[0]); + + eog_debug_message (DEBUG_LCMS, "JPEG is calibrated"); + + break; + } } #endif } @@ -654,6 +688,7 @@ eog_image_set_orientation (EogImage *img) if (priv->exif != NULL) { ExifByteOrder o = exif_data_get_byte_order (priv->exif); + ExifEntry *entry = exif_data_get_entry (priv->exif, EXIF_TAG_ORIENTATION); @@ -769,7 +804,7 @@ eog_image_real_load (EogImage *img, guchar *buffer; gboolean failed = FALSE; gboolean first_run = TRUE; - gboolean set_exif_data = TRUE; + gboolean set_metadata = TRUE; gboolean read_image_data = (data2read & EOG_IMAGE_DATA_IMAGE); g_assert (error == NULL || *error == NULL); @@ -870,9 +905,13 @@ eog_image_real_load (EogImage *img, eog_metadata_reader_consume (md_reader, buffer, bytes_read); if (eog_metadata_reader_finished (md_reader)) { - if (set_exif_data) { + if (set_metadata) { eog_image_set_exif_data (img, md_reader); - set_exif_data = FALSE; + +#ifdef HAVE_LCMS + eog_image_set_icc_data (img, md_reader); +#endif + set_metadata = FALSE; } if (data2read == EOG_IMAGE_DATA_EXIF) @@ -927,12 +966,6 @@ eog_image_real_load (EogImage *img, priv->file_type = gdk_pixbuf_format_get_name (format); } } - -#ifdef HAVE_LCMS - if (md_reader != NULL) { - extract_profile (img, md_reader); - } -#endif } if (loader != NULL) { diff --git a/src/eog-image.h b/src/eog-image.h index 374b6d5f..0b145146 100644 --- a/src/eog-image.h +++ b/src/eog-image.h @@ -172,6 +172,13 @@ void eog_image_transform (EogImage *img, void eog_image_autorotate (EogImage *img); #endif +#ifdef HAVE_LCMS +cmsHPROFILE eog_image_get_profile (EogImage *img); + +void eog_image_apply_display_profile (EogImage *img, + cmsHPROFILE display_profile); +#endif + void eog_image_undo (EogImage *img); GList *eog_image_get_supported_mime_types (void); diff --git a/src/eog-metadata-reader.c b/src/eog-metadata-reader.c index b49d0b7c..c3223750 100644 --- a/src/eog-metadata-reader.c +++ b/src/eog-metadata-reader.c @@ -154,7 +154,7 @@ eog_metadata_reader_consume (EogMetadataReader *emr, guchar *buf, guint len) priv->size = 0; priv->state = EMR_READ_SIZE_HIGH_BYTE; - eog_debug_message (DEBUG_IMAGE_DATA, "APPx Marker Found: %x\n", priv->last_marker); + eog_debug_message (DEBUG_IMAGE_DATA, "APPx Marker Found: %x", priv->last_marker); } else { /* otherwise simply consume the byte */ @@ -342,20 +342,16 @@ eog_metadata_reader_get_exif_data (EogMetadataReader *emr) * parse the sections and construct a single memory chunk, or maybe even parse * the profile. */ - -gpointer -eog_metadata_reader_get_icc_chunk (EogMetadataReader *emr) +void +eog_metadata_reader_get_icc_chunk (EogMetadataReader *emr, guchar **data, guint *len) { - g_return_val_if_fail (EOG_IS_METADATA_READER (emr), NULL); - if (emr->priv->icc_chunk) - return emr->priv->icc_chunk + 14; - else - return NULL; -} + EogMetadataReaderPrivate *priv; + + g_return_if_fail (EOG_IS_METADATA_READER (emr)); + priv = emr->priv; -guint -eog_metadata_reader_get_icc_chunk_size (EogMetadataReader *emr) -{ - g_return_val_if_fail (EOG_IS_METADATA_READER (emr), -1); - return emr->priv->icc_len - 14; + if (priv->icc_chunk) { + *data = (guchar*) priv->icc_chunk + 14; + *len = priv->icc_len - 14; + } } diff --git a/src/eog-metadata-reader.h b/src/eog-metadata-reader.h index 406d1796..966e318d 100644 --- a/src/eog-metadata-reader.h +++ b/src/eog-metadata-reader.h @@ -49,8 +49,7 @@ gpointer eog_metadata_reader_get_iptc_chunk (EogMetadataReader *emr) IptcData* eog_metadata_reader_get_iptc_data (EogMetadataReader *emr); #endif -gpointer eog_metadata_reader_get_icc_chunk (EogMetadataReader *emr); -guint eog_metadata_reader_get_icc_chunk_size (EogMetadataReader *emr); +void eog_metadata_reader_get_icc_chunk (EogMetadataReader *emr, guchar **data, guint *len); G_END_DECLS diff --git a/src/eog-window.c b/src/eog-window.c index 7183bd68..33c91674 100644 --- a/src/eog-window.c +++ b/src/eog-window.c @@ -56,12 +56,21 @@ #include <glib-object.h> #include <glib/gi18n.h> #include <gdk/gdkkeysyms.h> +#ifdef GDK_WINDOWING_X11 +#include <gdk/gdkx.h> +#endif #include <gtk/gtk.h> #include <gtk/gtkprintunixdialog.h> #include <libgnomevfs/gnome-vfs-mime.h> #include <libgnomevfs/gnome-vfs-mime-handlers.h> #include <gconf/gconf-client.h> +#if HAVE_LCMS +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <lcms.h> +#endif + #define EOG_WINDOW_GET_PRIVATE(object) \ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOG_TYPE_WINDOW, EogWindowPrivate)) @@ -155,6 +164,10 @@ struct _EogWindowPrivate { guint open_with_menu_id; GList* mime_application_list; + +#ifdef HAVE_LCMS + cmsHPROFILE *display_profile; +#endif }; static void eog_window_cmd_fullscreen (GtkAction *action, gpointer user_data); @@ -484,6 +497,53 @@ eog_window_collection_mode_changed_cb (GConfClient *client, } } +#ifdef HAVE_LCMS +static cmsHPROFILE * +eog_window_get_display_profile (GdkScreen *screen) +{ + Display *dpy; + Atom icc_atom, type; + int format; + gulong nitems; + gulong bytes_after; + guchar *str; + int result; + cmsHPROFILE *profile; + + dpy = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); + + icc_atom = gdk_x11_get_xatom_by_name_for_display (gdk_screen_get_display (screen), + "_ICC_PROFILE"); + + result = XGetWindowProperty (dpy, + GDK_WINDOW_XID (gdk_screen_get_root_window (screen)), + icc_atom, + 0, + G_MAXLONG, + False, + XA_CARDINAL, + &type, + &format, + &nitems, + &bytes_after, + (guchar **)&str); + + /* TODO: handle bytes_after != 0 */ + + if (nitems) { + profile = cmsOpenProfileFromMem(str, nitems); + + XFree (str); + + return profile; + } else { + eog_debug_message (DEBUG_LCMS, "No profile, not correcting"); + + return NULL; + } +} +#endif + static void update_status_bar (EogWindow *window) { @@ -908,7 +968,8 @@ eog_window_update_openwith_menu (EogWindow *window, EogImage *image) GnomeVFSMimeApplication *app = iter->data; /* do not include eog itself */ - if (strcmp (gnome_vfs_mime_application_get_binary_name (app), g_get_prgname ()) == 0) { + if (g_ascii_strcasecmp (gnome_vfs_mime_application_get_binary_name (app), + g_get_prgname ()) == 0) { apps = g_list_remove_link (apps, iter); g_list_free1 (iter); gnome_vfs_mime_application_free (app); @@ -1159,6 +1220,11 @@ eog_job_load_cb (EogJobLoad *job, gpointer data) priv->image = g_object_ref (job->image); if (EOG_JOB (job)->error == NULL) { +#ifdef HAVE_LCMS + eog_image_apply_display_profile (job->image, + priv->display_profile); +#endif + eog_window_display_image (window, job->image); } else { GtkWidget *message_area; @@ -3493,12 +3559,15 @@ static void eog_window_init (EogWindow *window) { GdkGeometry hints; + GdkScreen *screen; eog_debug (DEBUG_WINDOW); hints.min_width = EOG_WINDOW_MIN_WIDTH; hints.min_height = EOG_WINDOW_MIN_HEIGHT; + screen = gtk_widget_get_screen (GTK_WIDGET (window)); + window->priv = EOG_WINDOW_GET_PRIVATE (window); window->priv->client = gconf_client_get_default (); @@ -3570,7 +3639,12 @@ eog_window_init (EogWindow *window) window->priv->status = EOG_WINDOW_STATUS_UNKNOWN; window->priv->recent_manager = - gtk_recent_manager_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window))); + gtk_recent_manager_get_for_screen (screen); + +#ifdef HAVE_LCMS + window->priv->display_profile = + eog_window_get_display_profile (screen); +#endif window->priv->recent_menu_id = 0; @@ -3676,6 +3750,13 @@ eog_window_dispose (GObject *object) priv->mime_application_list = NULL; } +#ifdef HAVE_LCMS + if (priv->display_profile != NULL) { + cmsCloseProfile (priv->display_profile); + priv->display_profile = NULL; + } +#endif + G_OBJECT_CLASS (eog_window_parent_class)->dispose (object); } @@ -4045,7 +4126,7 @@ eog_job_model_cb (EogJobModel *job, gpointer data) eog_debug (DEBUG_WINDOW); -#if defined(HAVE_LCMS) || defined(HAVE_EXIF) +#ifdef HAVE_EXIF int i; #endif @@ -4063,13 +4144,6 @@ eog_job_model_cb (EogJobModel *job, gpointer data) n_images = eog_list_store_length (EOG_LIST_STORE (priv->store)); -#ifdef HAVE_LCMS - for (i = 0; i < n_images; i++) { - //eog_image_apply_display_profile (eog_list_store_get_image_by_pos (priv->store, i), - // get_screen_profile (window)); - } -#endif - #ifdef HAVE_EXIF if (gconf_client_get_bool (priv->client, EOG_CONF_VIEW_AUTOROTATE, NULL)) { for (i = 0; i < n_images; i++) { |