...
 
Commits (2)
  • William Skaggs's avatar
    Bill Skaggs <weskaggs@primate.ucdavis.edu> · 7fbf1c61
    William Skaggs authored
    	Initiating "exif-testing" branch.  Testing to make sure commit
    	goes to the right branch, and not to HEAD.
    7fbf1c61
  • William Skaggs's avatar
    Bill Skaggs <weskaggs@primate.ucdavis.edu> · e04b8a9f
    William Skaggs authored
    	* libgthumb/gth-exif-utils.c
    	* libgthumb/gth-exif-utils.h
    	* libgthumb/jpegutils/.cvsignore
    	* libgthumb/jpegutils/Makefile.am
    	* libgthumb/jpegutils/README
    	* libgthumb/jpegutils/jpeg-data.c
    	* libgthumb/jpegutils/jpeg-data.h
    	* libgthumb/jpegutils/jpeg-marker.c
    	* libgthumb/jpegutils/jpeg-marker.h
    	* libgthumb/jpegutils/jpegtran.c
    	* libgthumb/jpegutils/jpegtran.h
    	* libgthumb/jpegutils/transupp.c
    	* libgthumb/jpegutils/transupp.h: new files
    
    	* configure.in
    	* components/catalog-view/Makefile.am
    	* components/image-viewer/Makefile.am
    	* data/gthumb.schemas.in
    	* data/glade/gthumb_preferences.glade
    	* data/glade/gthumb_tools.glade
    	* doc/C/gthumb.xml
    	* libgthumb/Makefile.am
    	* libgthumb/gthumb-module.c
    	* libgthumb/image-loader.c
    	* libgthumb/preferences.h
    	* src/Makefile.am
    	* src/dlg-jpegtran.c
    	* src/dlg-jpegtran.h
    	* src/dlg-photo-importer.c
    	* src/dlg-preferences.c
    	* src/gth-browser-ui.h
    	* src/gth-window-actions-callbacks.c
    	* src/gth-window-actions-callbacks.h
    	* src/gth-window-actions-entries.h
    	* src/rotation-utils.c
    	* src/rotation-utils.h: modified files.
    
    	Committed patches listed in comment #106 of bug #343867,
    	as follows:
    
    	patch -p0 < gthumb-exif-v3.patch
    	patch -p0 < gthumb_reset_exif_orientation_v2.patch
    	patch -p0 < importer.patch
    	patch -p0 < gthumb_rotate_v3.patch
    	patch -p1 < gthumb-20061006-exif-rotate.patch
    	patch -p1 < delete-checkbox-v2.patch
    
    	This is development aimed at improving gthumb's handling
    	of exif metadata.
    e04b8a9f
2006-10-06 Bill Skaggs <weskaggs@primate.ucdavis.edu>
* libgthumb/gth-exif-utils.c
* libgthumb/gth-exif-utils.h
* libgthumb/jpegutils/.cvsignore
* libgthumb/jpegutils/Makefile.am
* libgthumb/jpegutils/README
* libgthumb/jpegutils/jpeg-data.c
* libgthumb/jpegutils/jpeg-data.h
* libgthumb/jpegutils/jpeg-marker.c
* libgthumb/jpegutils/jpeg-marker.h
* libgthumb/jpegutils/jpegtran.c
* libgthumb/jpegutils/jpegtran.h
* libgthumb/jpegutils/transupp.c
* libgthumb/jpegutils/transupp.h: new files
* configure.in
* components/catalog-view/Makefile.am
* components/image-viewer/Makefile.am
* data/gthumb.schemas.in
* data/glade/gthumb_preferences.glade
* data/glade/gthumb_tools.glade
* doc/C/gthumb.xml
* libgthumb/Makefile.am
* libgthumb/gthumb-module.c
* libgthumb/image-loader.c
* libgthumb/preferences.h
* src/Makefile.am
* src/dlg-jpegtran.c
* src/dlg-jpegtran.h
* src/dlg-photo-importer.c
* src/dlg-preferences.c
* src/gth-browser-ui.h
* src/gth-window-actions-callbacks.c
* src/gth-window-actions-callbacks.h
* src/gth-window-actions-entries.h
* src/rotation-utils.c
* src/rotation-utils.h: modified files.
Committed patches listed in comment #106 of bug #343867,
as follows:
patch -p0 < gthumb-exif-v3.patch
patch -p0 < gthumb_reset_exif_orientation_v2.patch
patch -p0 < importer.patch
patch -p0 < gthumb_rotate_v3.patch
patch -p1 < gthumb-20061006-exif-rotate.patch
patch -p1 < delete-checkbox-v2.patch
This is development aimed at improving gthumb's handling
of exif metadata.
2006-10-06 Bill Skaggs <weskaggs@primate.ucdavis.edu>
Initiating "exif-testing" branch. Testing to make sure commit
goes to the right branch, and not to HEAD.
2006-10-01 Paolo Bacchilega <paobac@cvs.gnome.org>
[ gthumb 2.7.9 released ]
......
......@@ -29,6 +29,7 @@ gthumb_catalog_view_SOURCES = \
gthumb_catalog_view_LDADD = \
$(COMPONENT_LIBS) \
$(EXIF_LIBS) \
$(JPEG_LIBS) \
$(IPTCDATA_LIBS) \
$(TIFF_LIBS) \
......
......@@ -34,6 +34,7 @@ gthumb_image_viewer_SOURCES = \
gthumb_image_viewer_LDADD = \
$(COMPONENT_LIBS) \
$(EXIF_LIBS) \
$(JPEG_LIBS) \
$(IPTCDATA_LIBS) \
$(TIFF_LIBS) \
......
......@@ -330,9 +330,9 @@ po/Makefile.in
libgthumb/Makefile
libgthumb/cursors/Makefile
libgthumb/icons/Makefile
libgthumb/jpegutils/Makefile
src/Makefile
src/icons/Makefile
src/jpegutils/Makefile
components/Makefile
components/image-viewer/Makefile
components/catalog-view/Makefile
......
......@@ -785,6 +785,147 @@
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox62">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkHBox" id="hbox122">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label189">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;To rotate images with Exif orientation tag support:&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox123">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkLabel" id="label190">
<property name="visible">True</property>
<property name="label" translatable="yes"> </property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox63">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkRadioButton" id="radio_exif_use_orientation_tag">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Adjust orientation tag. Leave image data unchanged.</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="radio_exif_use_image_transform">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Adjust image data. Reset orientation tag to top-left.</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<property name="group">radio_exif_use_orientation_tag</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="tab_expand">False</property>
......
......@@ -762,25 +762,6 @@
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="j_from_exif_checkbutton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Adjust photo _orientation</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
......
......@@ -95,7 +95,20 @@
</locale>
</schema>
<!-- Broswer -->
<schema>
<key>/schemas/apps/gthumb/general/use_exif_orientation</key>
<applyto>/apps/gthumb/general/use_exif_orientation</applyto>
<owner>gthumb</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short></short>
<long>
</long>
</locale>
</schema>
<!-- Browser -->
<schema>
<key>/schemas/apps/gthumb/browser/show_hidden_files</key>
......
......@@ -1988,13 +1988,6 @@
<para>
Click on <guibutton>Apply</guibutton> to apply the changes.
</para>
<para>
If you check the <guilabel>Adjust photo orientation</guilabel>
option, an attempt is done to read the current orientation from
the photo data embedded in the image, if the orientation data is
found an automatic rotation is applied to the image in order to
visualize the image in the right orientation.
</para>
<para>
If you check the <guilabel>Apply to all images</guilabel>
option, the rotation is applied to the
......
SUBDIRS = icons cursors
DIST_SUBDIRS = icons cursors
SUBDIRS = icons cursors jpegutils
DIST_SUBDIRS = icons cursors jpegutils
if ENABLE_DEPRECATIONS
DISABLE_DEPRECATED = -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGNOME_VFS_DISABLE_DEPRECATED -DGNOME_DISABLE_DEPRECATED -DBONOBO_DISABLE_DEPRECATED
......@@ -10,6 +10,7 @@ endif
gladedir = $(datadir)/gthumb/glade
INCLUDES = \
$(EXIF_CFLAGS) \
$(GTHUMB_CFLAGS) \
-DGTHUMB_MODULEDIR=\""$(libdir)/gthumb/modules"\" \
-DGTHUMB_GLADEDIR=\""$(gladedir)"\" \
......@@ -44,6 +45,7 @@ HEADER_FILES = \
gnome-print-font-picker.h \
gnome-print-font-dialog.h \
gstringlist.h \
gth-exif-utils.h \
gth-image-list.h \
gth-iviewer.h \
gth-file-list.h \
......@@ -100,6 +102,7 @@ libgthumb_la_SOURCES = \
gnome-print-font-picker.c \
gnome-print-font-dialog.c \
gstringlist.c \
gth-exif-utils.c \
gth-pixbuf-op.c \
gth-image-list.c \
gth-iviewer.c \
......@@ -129,9 +132,11 @@ libgthumb_la_SOURCES = \
thumb-loader.c
libgthumb_la_LIBADD = \
$(EXIF_LIBS) \
$(TIFF_LIBS) \
$(GTHUMB_LIBS) \
$(IPTCDATA_LIBS)
$(IPTCDATA_LIBS) \
$(top_builddir)/libgthumb/jpegutils/libgthumb-jpegutils.la
gthumb-marshal.h: gthumb-marshal.list $(GLIB_GENMARSHAL)
$(GLIB_GENMARSHAL) $(top_srcdir)/libgthumb/gthumb-marshal.list --header --prefix=gthumb_marshal > $(top_srcdir)/libgthumb/gthumb-marshal.h
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* GThumb
*
* Copyright (C) 2003 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*/
#include <config.h>
#ifdef HAVE_LIBEXIF
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <glib.h>
#include "file-utils.h"
#include "gth-exif-utils.h"
char *
get_exif_tag (const char *filename,
ExifTag etag)
{
ExifData *edata;
unsigned int i, j;
filename = get_file_path_from_uri (filename);
if (filename == NULL)
return g_strdup ("-");
edata = exif_data_new_from_file (filename);
if (edata == NULL)
return g_strdup ("-");
for (i = 0; i < EXIF_IFD_COUNT; i++) {
ExifContent *content = edata->ifd[i];
if (! edata->ifd[i] || ! edata->ifd[i]->count)
continue;
for (j = 0; j < content->count; j++) {
ExifEntry *e = content->entries[j];
if (! content->entries[j])
continue;
if (e->tag == etag) {
const char *value;
char *retval = NULL;
value = get_exif_entry_value (e);
if (value != NULL)
retval = g_locale_to_utf8 (value, -1, 0, 0, 0);
else
retval = g_strdup ("-");
exif_data_unref (edata);
return retval;
}
}
}
exif_data_unref (edata);
return g_strdup ("-");
}
ExifShort
get_exif_tag_short (const char *filename,
ExifTag etag)
{
ExifData *edata;
unsigned int i, j;
filename = get_file_path_from_uri (filename);
if (filename == NULL)
return 0;
edata = exif_data_new_from_file (filename);
if (edata == NULL)
return 0;
for (i = 0; i < EXIF_IFD_COUNT; i++) {
ExifContent *content = edata->ifd[i];
if (! edata->ifd[i] || ! edata->ifd[i]->count)
continue;
for (j = 0; j < content->count; j++) {
ExifEntry *e = content->entries[j];
if (! content->entries[j])
continue;
if (e->tag == etag) {
ExifByteOrder o;
ExifShort retval = 0;
o = exif_data_get_byte_order (e->parent->parent);
if (e->data != NULL)
retval = exif_get_short (e->data, o);
exif_data_unref (edata);
return retval;
}
}
}
exif_data_unref (edata);
return 0;
}
time_t
get_exif_time (const char *filename)
{
ExifData *edata;
unsigned int i, j;
time_t time = 0;
struct tm tm = { 0, };
filename = get_file_path_from_uri (filename);
if (filename == NULL)
return (time_t)0;
edata = exif_data_new_from_file (filename);
if (edata == NULL)
return (time_t)0;
for (i = 0; i < EXIF_IFD_COUNT; i++) {
ExifContent *content = edata->ifd[i];
if (! edata->ifd[i] || ! edata->ifd[i]->count)
continue;
for (j = 0; j < content->count; j++) {
ExifEntry *e = content->entries[j];
char *data;
if (! content->entries[j])
continue;
if ((e->tag != EXIF_TAG_DATE_TIME) &&
(e->tag != EXIF_TAG_DATE_TIME_ORIGINAL) &&
(e->tag != EXIF_TAG_DATE_TIME_DIGITIZED))
continue;
if (e->data == NULL)
continue;
if (strlen ((char*)e->data) < 10)
continue;
data = g_strdup ((char*)e->data);
data[4] = data[7] = data[10] = '\0';
tm.tm_year = atoi (data) - 1900;
tm.tm_mon = atoi (data + 5) - 1;
tm.tm_mday = atoi (data + 8);
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
if (strlen ((char*)e->data) > 10) {
data[13] = data[16] = '\0';
tm.tm_hour = atoi (data + 11);
tm.tm_min = atoi (data + 14);
tm.tm_sec = atoi (data + 17);
}
time = mktime (&tm);
g_free (data);
break;
}
}
exif_data_unref (edata);
return time;
}
char *
get_exif_aperture_value (const char *filename)
{
ExifData *edata;
unsigned int i, j;
filename = get_file_path_from_uri (filename);
if (filename == NULL)
return g_strdup ("-");
edata = exif_data_new_from_file (filename);
if (edata == NULL)
return g_strdup ("-");
for (i = 0; i < EXIF_IFD_COUNT; i++) {
ExifContent *content = edata->ifd[i];
if (! edata->ifd[i] || ! edata->ifd[i]->count)
continue;
for (j = 0; j < content->count; j++) {
ExifEntry *e = content->entries[j];
const char *value = NULL;
char *retval = NULL;
if (! content->entries[j])
continue;
if ((e->tag != EXIF_TAG_APERTURE_VALUE) &&
(e->tag != EXIF_TAG_FNUMBER))
continue;
value = get_exif_entry_value (e);
if (value)
retval = g_locale_to_utf8 (value, -1, 0, 0, 0);
else
retval = g_strdup ("-");
exif_data_unref (edata);
return retval;
}
}
exif_data_unref (edata);
return g_strdup ("-");
}
gboolean
have_exif_time (const char *filename)
{
return get_exif_time (filename) != (time_t)0;
}
#define VALUE_LEN 1024
const char *
get_exif_entry_value (ExifEntry *entry)
{
#ifdef HAVE_LIBEXIF_0_5
return exif_entry_get_value (entry);
#else
char value[VALUE_LEN + 1];
return exif_entry_get_value (entry, value, VALUE_LEN);
#endif
}
ExifData *
load_exif_data (const char *filename)
{
JPEGData *jdata = NULL;
ExifData *exif_data = NULL;
filename = get_file_path_from_uri (filename);
if (filename == NULL)
return NULL;
jdata = jpeg_data_new_from_file (filename);
if (jdata == NULL)
return NULL;
exif_data = jpeg_data_get_exif_data (jdata);
jpeg_data_unref (jdata);
return exif_data;
}
void
save_exif_data (const char *filename,
ExifData *edata)
{
JPEGData *jdata;
filename = get_file_path_from_uri (filename);
if (filename == NULL)
return;
jdata = jpeg_data_new_from_file (filename);
if (jdata == NULL)
return;
if (edata != NULL)
jpeg_data_set_exif_data (jdata, edata);
jpeg_data_save_file (jdata, filename);
jpeg_data_unref (jdata);
}
void
copy_exif_data (const char *src,
const char *dest)
{
ExifData *edata;
if (!image_is_jpeg (src) || !image_is_jpeg (dest))
return;
src = get_file_path_from_uri (src);
if (src == NULL)
return;
dest = get_file_path_from_uri (dest);
if (dest == NULL)
return;
edata = exif_data_new_from_file (src);
if (edata == NULL)
return;
save_exif_data (dest, edata);
exif_data_unref (edata);
}
#endif /* HAVE_LIBEXIF */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* GThumb
*
* Copyright (C) 2003 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*/
#ifndef EXIF_UTILS_H
#define EXIF_UTILS_H
#include <config.h>
#ifdef HAVE_LIBEXIF
#include <libexif/exif-data.h>
#include <libexif/exif-content.h>
#include <libexif/exif-entry.h>
#include <libexif/exif-utils.h>
#include "jpegutils/jpeg-data.h"
typedef enum { /*< skip >*/
GTH_EXIF_ORIENTATION_NONE = 0,
GTH_EXIF_ORIENTATION_TOP_LEFT,
GTH_EXIF_ORIENTATION_TOP_RIGHT,
GTH_EXIF_ORIENTATION_BOTTOM_RIGHT,
GTH_EXIF_ORIENTATION_BOTTOM_LEFT,
GTH_EXIF_ORIENTATION_LEFT_TOP,
GTH_EXIF_ORIENTATION_RIGHT_TOP,
GTH_EXIF_ORIENTATION_RIGHT_BOTTOM,
GTH_EXIF_ORIENTATION_LEFT_BOTTOM
} GthExifOrientation;
char * get_exif_tag (const char *filename,
ExifTag etag);
ExifShort get_exif_tag_short (const char *filename,
ExifTag etag);
time_t get_exif_time (const char *filename);
char * get_exif_aperture_value (const char *filename);
gboolean have_exif_time (const char *filename);
const char *get_exif_entry_value (ExifEntry *entry);
ExifData * load_exif_data (const char *filename);
void save_exif_data (const char *filename,
ExifData *edata);
void copy_exif_data (const char *src,
const char *dest);
#endif /* HAVE_LIBEXIF */
#endif /* EXIF_UTILS_H */
......@@ -36,7 +36,6 @@ static struct {
{ "search", "dlg_catalog_search" },
{ "jpegtran", "dlg_jpegtran" },
{ "jpegtran", "dlg_apply_jpegtran" },
{ "jpegtran", "dlg_apply_jpegtran_from_exif" },
{ "duplicates", "dlg_duplicates" },
{ "photoimporter", "dlg_photo_importer" },
{ NULL, NULL }
......
......@@ -37,6 +37,8 @@
#include "gthumb-marshal.h"
#include "file-utils.h"
#include "glib-utils.h"
#include "gth-exif-utils.h"
#include "pixbuf-utils.h"
#define REFRESH_RATE 5
......@@ -405,17 +407,77 @@ image_loader_set_pixbuf (ImageLoader *il,
g_mutex_unlock (priv->yes_or_no);
}
/*
* Returns an image, transformed according
* to the Exif orientation data.
*/
#ifdef HAVE_LIBEXIF
static GdkPixbuf *
_gdk_pixbuf_transform_exif_orientation (GdkPixbuf* src,
GthExifOrientation orientation)
{
GdkPixbuf *temp = NULL, *dest = NULL;
if (!src) return NULL;
switch (orientation) {
case GTH_EXIF_ORIENTATION_TOP_LEFT:
dest = src;
g_object_ref (dest);
break;
case GTH_EXIF_ORIENTATION_TOP_RIGHT:
dest = _gdk_pixbuf_copy_mirror (src, TRUE, FALSE);
break;
case GTH_EXIF_ORIENTATION_BOTTOM_RIGHT:
dest = _gdk_pixbuf_copy_mirror (src, TRUE, TRUE);
break;
case GTH_EXIF_ORIENTATION_BOTTOM_LEFT:
dest = _gdk_pixbuf_copy_mirror (src, FALSE, TRUE);
break;
case GTH_EXIF_ORIENTATION_LEFT_TOP:
temp = _gdk_pixbuf_copy_rotate_90 (src, FALSE);
dest = _gdk_pixbuf_copy_mirror (temp, TRUE, FALSE);
g_object_unref (temp);
break;
case GTH_EXIF_ORIENTATION_RIGHT_TOP:
dest = _gdk_pixbuf_copy_rotate_90 (src, FALSE);
break;
case GTH_EXIF_ORIENTATION_RIGHT_BOTTOM:
temp = _gdk_pixbuf_copy_rotate_90 (src, FALSE);
dest = _gdk_pixbuf_copy_mirror (temp, FALSE, TRUE);
g_object_unref (temp);
break;
case GTH_EXIF_ORIENTATION_LEFT_BOTTOM:
dest = _gdk_pixbuf_copy_rotate_90 (src, TRUE);
break;
default:
dest = src;
g_object_ref (dest);
break;
}
return dest;
}
#endif /* HAVE_LIBEXIF */
static void
image_loader_sync_pixbuf (ImageLoader *il)
{
GdkPixbuf *pixbuf;
GdkPixbuf *temp;
ImageLoaderPrivateData *priv;
#ifdef HAVE_LIBEXIF
GthExifOrientation orientation;
#endif
g_return_if_fail (il != NULL);
priv = il->priv;
#ifdef HAVE_LIBEXIF
orientation = get_exif_tag_short (image_loader_get_path(il), EXIF_TAG_ORIENTATION);
#endif
g_mutex_lock (priv->yes_or_no);
if (priv->animation == NULL) {
......@@ -426,8 +488,13 @@ image_loader_sync_pixbuf (ImageLoader *il)
return;
}
#ifdef HAVE_LIBEXIF
temp = gdk_pixbuf_animation_get_static_image (priv->animation);
pixbuf = _gdk_pixbuf_transform_exif_orientation (temp, orientation);
#else
pixbuf = gdk_pixbuf_animation_get_static_image (priv->animation);
g_object_ref (pixbuf);
#endif
if (priv->pixbuf == pixbuf) {
g_object_unref (pixbuf);
......
.deps
.libs
Makefile
Makefile.in
libgthumb-jpegutils.a
if ENABLE_DEPRECATIONS
DISABLE_DEPRECATED = -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGNOME_VFS_DISABLE_DEPRECATED -DGNOME_DISABLE_DEPRECATED -DBONOBO_DISABLE_DEPRECATED
else
DISABLE_DEPRECATED =
endif
INCLUDES = \
$(DISABLE_DEPRECATED) \
$(EXIF_CFLAGS) \
$(GTHUMB_CFLAGS) \
-I$(top_srcdir)/libgthumb
noinst_LTLIBRARIES = libgthumb-jpegutils.la
libgthumb_jpegutils_la_SOURCES = \
jpeg-data.c \
jpeg-data.h \
jpeg-marker.c \
jpeg-marker.h \
jpegtran.c \
jpegtran.h \
transupp.c \
transupp.h
EXTRA_DIST = README
This diff is collapsed.
/* jpeg-data.c
*
* Copyright 2001 Lutz Mller <lutz@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "jpeg-data.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* #define DEBUG */
#ifdef HAVE_LIBEXIF
struct _JPEGDataPrivate
{
unsigned int ref_count;
};
JPEGData *
jpeg_data_new (void)
{
JPEGData *data;
data = malloc (sizeof (JPEGData));
if (!data)
return (NULL);
memset (data, 0, sizeof (JPEGData));
data->priv = malloc (sizeof (JPEGDataPrivate));
if (!data->priv) {
free (data);
return (NULL);
}
memset (data->priv, 0, sizeof (JPEGDataPrivate));
data->priv->ref_count = 1;
return (data);
}
void
jpeg_data_append_section (JPEGData *data)
{
JPEGSection *s;
if (!data->count)
s = malloc (sizeof (JPEGSection));
else
s = realloc (data->sections,
sizeof (JPEGSection) * (data->count + 1));
if (!s)
return;
data->sections = s;
data->count++;
}
/* jpeg_data_save_file returns 1 on succes, 0 on failure */
int
jpeg_data_save_file (JPEGData *data, const char *path)
{
FILE *f;
unsigned char *d = NULL;
unsigned int size = 0, written;
jpeg_data_save_data (data, &d, &size);
if (!d)
return 0;
remove (path);
f = fopen (path, "wb");
if (!f) {
free (d);
return 0;
}
written = fwrite (d, 1, size, f);
fclose (f);
free (d);
if (written == size) {
return 1;
}
remove(path);
return 0;
}
void
jpeg_data_save_data (JPEGData *data, unsigned char **d, unsigned int *ds)
{
unsigned int i, eds = 0;
JPEGSection s;
unsigned char *ed = NULL;
if (!data)
return;
if (!d)
return;
if (!ds)
return;
for (*ds = i = 0; i < data->count; i++) {
s = data->sections[i];
#ifdef DEBUG
printf ("Writing marker 0x%x at position %i...\n",
s.marker, *ds);
#endif
/* Write the marker */
*d = realloc (*d, sizeof (char) * (*ds + 2));
(*d)[*ds + 0] = 0xff;
(*d)[*ds + 1] = s.marker;
*ds += 2;
switch (s.marker) {
case JPEG_MARKER_SOI:
case JPEG_MARKER_EOI:
break;
case JPEG_MARKER_APP1:
exif_data_save_data (s.content.app1, &ed, &eds);
if (!ed) break;
*d = realloc (*d, sizeof (char) * (*ds + 2));
(*d)[*ds + 0] = (eds + 2) >> 8;
(*d)[*ds + 1] = (eds + 2) >> 0;
*ds += 2;
*d = realloc (*d, sizeof (char) * (*ds + eds));
memcpy (*d + *ds, ed, eds);
*ds += eds;
free (ed);
break;
default:
*d = realloc (*d, sizeof (char) *
(*ds + s.content.generic.size + 2));
(*d)[*ds + 0] = (s.content.generic.size + 2) >> 8;
(*d)[*ds + 1] = (s.content.generic.size + 2) >> 0;
*ds += 2;
memcpy (*d + *ds, s.content.generic.data,
s.content.generic.size);
*ds += s.content.generic.size;
/* In case of SOS, we need to write the data. */
if (s.marker == JPEG_MARKER_SOS) {
*d = realloc (*d, *ds + data->size);
memcpy (*d + *ds, data->data, data->size);
*ds += data->size;
}
break;
}
}
}
JPEGData *
jpeg_data_new_from_data (const unsigned char *d,
unsigned int size)
{
JPEGData *data;
data = jpeg_data_new ();
jpeg_data_load_data (data, d, size);
return (data);
}
void
jpeg_data_load_data (JPEGData *data, const unsigned char *d,
unsigned int size)
{
unsigned int i, o, len;
JPEGSection *s;
JPEGMarker marker;
if (!data)
return;
if (!d)
return;
#ifdef DEBUG
printf ("Parsing %i bytes...\n", size);
#endif
for (o = 0; o < size;) {
/*
* JPEG sections start with 0xff. The first byte that is
* not 0xff is a marker (hopefully).
*/
for (i = 0; i < 7; i++)
if (d[o + i] != 0xff)
break;
if (!JPEG_IS_MARKER (d[o + i]))
return;
marker = d[o + i];
#ifdef DEBUG
printf ("Found marker 0x%x ('%s') at %i.\n", marker,
jpeg_marker_get_name (marker), o + i);
#endif
/* Append this section */
jpeg_data_append_section (data);
s = &data->sections[data->count - 1];
s->marker = marker;
s->content.generic.data = NULL;
o += i + 1;
switch (s->marker) {
case JPEG_MARKER_SOI:
case JPEG_MARKER_EOI:
break;
default:
/* Read the length of the section */
len = ((d[o] << 8) | d[o + 1]) - 2;
if (len > size) { o = size; break; }
o += 2;
if (o + len > size) { o = size; break; }
switch (s->marker) {
case JPEG_MARKER_APP1:
s->content.app1 = exif_data_new_from_data (
d + o - 4, len + 4);
break;
default:
s->content.generic.size = len;
s->content.generic.data =
malloc (sizeof (char) * len);
memcpy (s->content.generic.data, &d[o], len);
/* In case of SOS, image data will follow. */
if (s->marker == JPEG_MARKER_SOS) {
data->size = size - 2 - o - len;
data->data = malloc (
sizeof (char) * data->size);
memcpy (data->data, d + o + len,
data->size);
o += data->size;
}
break;
}
o += len;
break;
}
}
}
JPEGData *
jpeg_data_new_from_file (const char *path)
{
JPEGData *data;
data = jpeg_data_new ();
jpeg_data_load_file (data, path);
return (data);
}
void
jpeg_data_load_file (JPEGData *data, const char *path)
{
FILE *f;
unsigned char *d;
unsigned int size;
if (!data)
return;
if (!path)
return;
f = fopen (path, "rb");
if (!f)
return;
/* For now, we read the data into memory. Patches welcome... */
fseek (f, 0, SEEK_END);
size = ftell (f);
fseek (f, 0, SEEK_SET);
d = malloc (sizeof (char) * size);
if (!d) {
fclose (f);
return;
}
if (fread (d, 1, size, f) != size) {
free (d);
fclose (f);
return;
}
fclose (f);
jpeg_data_load_data (data, d, size);
free (d);
}
void
jpeg_data_ref (JPEGData *data)
{
if (!data)
return;
data->priv->ref_count++;
}
void
jpeg_data_unref (JPEGData *data)
{
if (!data)
return;
data->priv->ref_count--;
if (!data->priv->ref_count)
jpeg_data_free (data);
}
void
jpeg_data_free (JPEGData *data)
{
unsigned int i;
JPEGSection s;
if (!data)
return;
if (data->count) {
for (i = 0; i < data->count; i++) {
s = data->sections[i];
switch (s.marker) {
case JPEG_MARKER_SOI:
case JPEG_MARKER_EOI:
break;
case JPEG_MARKER_APP1:
exif_data_unref (s.content.app1);
break;
default:
free (s.content.generic.data);
break;
}
}
free (data->sections);
}
if (data->data)
free (data->data);
free (data->priv);
free (data);
}
static JPEGSection *
jpeg_data_get_section (JPEGData *data, JPEGMarker marker)
{
unsigned int i;
if (!data)
return (NULL);
for (i = 0; i < data->count; i++)
if (data->sections[i].marker == marker)
return (&data->sections[i]);
return (NULL);
}
void
jpeg_data_dump (JPEGData *data)
{
unsigned int i;
JPEGContent content;
JPEGMarker marker;
if (!data)
return;
printf ("Dumping JPEG data (%i bytes of data)...\n", data->size);
for (i = 0; i < data->count; i++) {
marker = data->sections[i].marker;
content = data->sections[i].content;
printf ("Section %i (marker 0x%x - %s):\n", i, marker,
jpeg_marker_get_name (marker));
printf (" Description: %s\n",
jpeg_marker_get_description (marker));
switch (marker) {
case JPEG_MARKER_SOI:
case JPEG_MARKER_EOI:
break;
case JPEG_MARKER_APP1:
exif_data_dump (content.app1);
break;
default:
printf (" Size: %i\n", content.generic.size);
printf (" Unknown content.\n");
break;
}
}
}
ExifData *
jpeg_data_get_exif_data (JPEGData *data)
{
JPEGSection *section;
if (!data)
return NULL;
section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
if (section) {
exif_data_ref (section->content.app1);
return (section->content.app1);
}
return (NULL);
}
void
jpeg_data_set_exif_data (JPEGData *data, ExifData *exif_data)
{
JPEGSection *section;
section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
if (!section) {
jpeg_data_append_section (data);
memmove (&data->sections[2], &data->sections[1],
sizeof (JPEGSection) * (data->count - 2));
section = &data->sections[1];
} else {
exif_data_unref (section->content.app1);
}
section->marker = JPEG_MARKER_APP1;
section->content.app1 = exif_data;
exif_data_ref (exif_data);
}
void
jpeg_data_set_header_data (JPEGData *data, JPEGMarker marker,
unsigned char *buf, unsigned int size)
{
JPEGSection *section;
int i;
section = jpeg_data_get_section (data, marker);
if (!section) {
jpeg_data_append_section (data);
for (i = 0; i < data->count - 1; i++) {
JPEGMarker m = data->sections[i].marker;
if (m != JPEG_MARKER_SOI &&
(m < JPEG_MARKER_APP0 ||
m > JPEG_MARKER_APP15)) {
memmove (&data->sections[i+1],
&data->sections[i],
sizeof (JPEGSection) *
(data->count - i - 1));
break;
}
}
section = &data->sections[i];
} else {
free (section->content.generic.data);
}
section->marker = marker;
section->content.generic.data = malloc (size);
memcpy (section->content.generic.data, buf, size);
section->content.generic.size = size;
}
#endif /* HAVE_LIBEXIF */
/* jpeg-data.h
*
* Copyright 2001 Lutz Mller <lutz@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __JPEG_DATA_H__
#define __JPEG_DATA_H__
#ifdef HAVE_LIBEXIF
#include "jpeg-marker.h"
#include <libexif/exif-data.h>
typedef ExifData * JPEGContentAPP1;
typedef struct _JPEGContentGeneric JPEGContentGeneric;
struct _JPEGContentGeneric
{
unsigned char *data;
unsigned int size;
};
typedef union _JPEGContent JPEGContent;
union _JPEGContent
{
JPEGContentGeneric generic;
JPEGContentAPP1 app1;
};
typedef struct _JPEGSection JPEGSection;
struct _JPEGSection
{
JPEGMarker marker;
JPEGContent content;
};
typedef struct _JPEGData JPEGData;
typedef struct _JPEGDataPrivate JPEGDataPrivate;
struct _JPEGData
{
JPEGSection *sections;
unsigned int count;
unsigned char *data;
unsigned int size;
JPEGDataPrivate *priv;
};
JPEGData *jpeg_data_new (void);
JPEGData *jpeg_data_new_from_file (const char *path);
JPEGData *jpeg_data_new_from_data (const unsigned char *data,
unsigned int size);
void jpeg_data_ref (JPEGData *data);
void jpeg_data_unref (JPEGData *data);
void jpeg_data_free (JPEGData *data);
void jpeg_data_load_data (JPEGData *data, const unsigned char *d,
unsigned int size);
void jpeg_data_save_data (JPEGData *data, unsigned char **d,
unsigned int *size);
void jpeg_data_load_file (JPEGData *data, const char *path);
int jpeg_data_save_file (JPEGData *data, const char *path);
void jpeg_data_set_exif_data (JPEGData *data, ExifData *exif_data);
ExifData *jpeg_data_get_exif_data (JPEGData *data);
void jpeg_data_set_header_data (JPEGData *data, JPEGMarker marker,
unsigned char * buf, unsigned int size);
void jpeg_data_dump (JPEGData *data);
void jpeg_data_append_section (JPEGData *data);
#endif /* HAVE_LIBEXIF */
#endif /* __JPEG_DATA_H__ */
/* jpeg-marker.c
*
* Copyright 2001 Lutz Mller <lutz@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "jpeg-marker.h"
#include <stdlib.h>
static struct {
JPEGMarker marker;
const char *name;
const char *description;
} JPEGMarkerTable[] = {
{JPEG_MARKER_SOF0, "SOF0", "Encoding (baseline)"},
{JPEG_MARKER_SOF1, "SOF1", "Encoding (extended sequential)"},
{JPEG_MARKER_SOF2, "SOF2", "Encoding (progressive)"},
{JPEG_MARKER_SOF3, "SOF3", "Encoding (lossless)"},
{JPEG_MARKER_SOF5, "SOF5", "Encoding (differential sequential)"},
{JPEG_MARKER_SOF6, "SOF6", "Encoding (differential progressive)"},
{JPEG_MARKER_SOF7, "SOF7", "Encoding (differential lossless)"},
{JPEG_MARKER_SOF9, "SOF9",
"Encoding (extended sequential, arithmetic)"},
{JPEG_MARKER_SOF10, "SOF10", "Encoding (progressive, arithmetic)"},
{JPEG_MARKER_SOF11, "SOF11", "Encoding (lossless, arithmetic)"},
{JPEG_MARKER_SOF13, "SOF13",
"Encoding (differential sequential, arithmetic)"},
{JPEG_MARKER_SOF14, "SOF14",
"Encoding (differential progressive, arithmetic)"},
{JPEG_MARKER_SOF15, "SOF15",
"Encoding (differential lossless, arithmetic)"},
{JPEG_MARKER_SOI, "SOI", "Start of image"},
{JPEG_MARKER_EOI, "EOI", "End of image"},
{JPEG_MARKER_SOS, "SOS", "Start of scan"},
{JPEG_MARKER_COM, "COM", "Comment"},
{JPEG_MARKER_DHT, "DHT", "Define Huffman table"},
{JPEG_MARKER_JPG, "JPG", "Extension"},
{JPEG_MARKER_DAC, "DAC", "Define arithmetic coding conditioning"},
{JPEG_MARKER_RST1, "RST1", "Restart 1"},
{JPEG_MARKER_RST2, "RST2", "Restart 2"},
{JPEG_MARKER_RST3, "RST3", "Restart 3"},
{JPEG_MARKER_RST4, "RST4", "Restart 4"},
{JPEG_MARKER_RST5, "RST5", "Restart 5"},
{JPEG_MARKER_RST6, "RST6", "Restart 6"},
{JPEG_MARKER_RST7, "RST7", "Restart 7"},
{JPEG_MARKER_DQT, "DQT", "Define quantization table"},
{JPEG_MARKER_DNL, "DNL", "Define number of lines"},
{JPEG_MARKER_DRI, "DRI", "Define restart interval"},
{JPEG_MARKER_DHP, "DHP", "Define hierarchical progression"},
{JPEG_MARKER_EXP, "EXP", "Expand reference component"},
{JPEG_MARKER_APP0, "APP0", "Application segment 0"},
{JPEG_MARKER_APP1, "APP1", "Application segment 1"},
{JPEG_MARKER_APP2, "APP2", "Application segment 2"},
{JPEG_MARKER_APP3, "APP3", "Application segment 3"},
{JPEG_MARKER_APP4, "APP4", "Application segment 4"},
{JPEG_MARKER_APP5, "APP5", "Application segment 5"},
{JPEG_MARKER_APP6, "APP6", "Application segment 6"},
{JPEG_MARKER_APP7, "APP7", "Application segment 7"},
{JPEG_MARKER_APP8, "APP8", "Application segment 8"},
{JPEG_MARKER_APP9, "APP9", "Application segment 9"},
{JPEG_MARKER_APP10, "APP10", "Application segment 10"},
{JPEG_MARKER_APP11, "APP11", "Application segment 11"},
{JPEG_MARKER_APP12, "APP12", "Application segment 12"},
{JPEG_MARKER_APP13, "APP13", "Application segment 13"},
{JPEG_MARKER_APP14, "APP14", "Application segment 14"},
{JPEG_MARKER_APP15, "APP15", "Application segment 15"},
{JPEG_MARKER_JPG0, "JPG0", "Extension 0"},
{JPEG_MARKER_JPG1, "JPG1", "Extension 1"},
{JPEG_MARKER_JPG2, "JPG2", "Extension 2"},
{JPEG_MARKER_JPG3, "JPG3", "Extension 3"},
{JPEG_MARKER_JPG4, "JPG4", "Extension 4"},
{JPEG_MARKER_JPG5, "JPG5", "Extension 5"},
{JPEG_MARKER_JPG6, "JPG6", "Extension 6"},
{JPEG_MARKER_JPG7, "JPG7", "Extension 7"},
{JPEG_MARKER_JPG8, "JPG8", "Extension 8"},
{JPEG_MARKER_JPG9, "JPG9", "Extension 9"},
{JPEG_MARKER_JPG10, "JPG10", "Extension 10"},
{JPEG_MARKER_JPG11, "JPG11", "Extension 11"},
{JPEG_MARKER_JPG12, "JPG12", "Extension 12"},
{JPEG_MARKER_JPG13, "JPG13", "Extension 13"},
{0, NULL, NULL}
};
const char *
jpeg_marker_get_name (JPEGMarker marker)
{
unsigned int i;
for (i = 0; JPEGMarkerTable[i].name; i++)
if (JPEGMarkerTable[i].marker == marker)
break;
return (JPEGMarkerTable[i].name);
}
const char *
jpeg_marker_get_description (JPEGMarker marker)
{
unsigned int i;
for (i = 0; JPEGMarkerTable[i].description; i++)
if (JPEGMarkerTable[i].marker == marker)
break;
return (JPEGMarkerTable[i].description);
}