The attached patch a new snapshot on the work to support exif. Besides
coping exif to the output file, it replaces some of the old fields on
the RS_METADATA structure. The output file orientation is also correct
now :-)
Cheers,
Rafael
Index: configure.in
===================================================================
--- configure.in (revision 1849)
+++ configure.in (working copy)
@@ -54,7 +54,8 @@
fi
AC_SUBST(LIBTIFF)
-pkg_modules="gtk+-2.0 >= 2.8.0 libxml-2.0 >= 2.4 gconf-2.0 >= 2.0 lcms dbus-1"
+pkg_modules="gtk+-2.0 >= 2.8.0 libxml-2.0 >= 2.4 gconf-2.0 >= 2.0 lcms dbus-1 \
+ exiv2"
PKG_CHECK_MODULES(PACKAGE, [$pkg_modules])
AC_SUBST(PACKAGE_CFLAGS)
AC_SUBST(PACKAGE_LIBS)
Index: src/exif.cc
===================================================================
--- src/exif.cc (revision 0)
+++ src/exif.cc (revision 0)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2006-2008 Anders Brander <[EMAIL PROTECTED]> and
+ * Anders Kvist <[EMAIL PROTECTED]>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <iostream>
+#include <iomanip>
+#include <exiv2/image.hpp>
+#include <exiv2/exif.hpp>
+#include "exif.h"
+#include <assert.h>
+
+static float exif_float_value(rs_exif_data d, const gchar *s)
+{
+ Exiv2::ExifData *data = (Exiv2::ExifData *) d;
+ Exiv2::ExifData::iterator pos;
+
+ pos = data->findKey(Exiv2::ExifKey(s));
+ if (pos != data->end())
+ {
+ return pos->toFloat();
+ }
+
+ return 0.0;
+}
+
+static long exif_long_value(rs_exif_data d, const gchar *s)
+{
+ Exiv2::ExifData *data = (Exiv2::ExifData *) d;
+ Exiv2::ExifData::iterator pos;
+
+ pos = data->findKey(Exiv2::ExifKey(s));
+ if (pos != data->end())
+ {
+ return pos->toLong();
+ }
+
+ return 0;
+}
+
+extern "C" {
+
+rs_exif_data rs_exif_load(const gchar *filename)
+{
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename);
+ assert(image.get() != 0);
+ image->readMetadata();
+
+ return new Exiv2::ExifData(image->exifData());
+}
+
+void rs_exif_write(const gchar *filename, rs_exif_data d)
+{
+ Exiv2::ExifData *orig = (Exiv2::ExifData *) d;
+ Exiv2::ExifData data(*orig);
+ std::string s = "Exif.Image.Orientation";
+ Exiv2::ExifData::iterator pos = data.findKey(Exiv2::ExifKey(s));
+ data.erase(pos);
+
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(filename);
+ image->setExifData(data);
+ image->writeMetadata();
+}
+
+void rs_exif_free(rs_exif_data d)
+{
+ Exiv2::ExifData *data = (Exiv2::ExifData *) d;
+ delete data;
+}
+
+gfloat rs_exif_aperture(rs_exif_data d)
+{ /* Does any camera uses Exif.Photo.ApertureValue? */
+ return exif_float_value(d, "Exif.Photo.FNumber");
+}
+
+gfloat rs_exif_shutter_speed(rs_exif_data d)
+{
+ /* Does any camera uses Exif.Photo.ShutterSpeedValue? */
+ return 1/exif_float_value(d, "Exif.Photo.ExposureTime");
+}
+
+gshort rs_exif_focal_length(rs_exif_data d)
+{
+ return exif_float_value(d, "Exif.Photo.FocalLength");
+}
+
+gushort rs_exif_iso(rs_exif_data d)
+{
+ return exif_long_value(d, "Exif.Photo.ISOSpeedRatings");
+}
+
+gushort rs_exif_orientation(rs_exif_data d)
+{
+ long t = exif_long_value(d, "Exif.Image.Orientation");
+ std::cout << "foo = " << t << std::endl;
+ switch (t)
+ {
+ case 6: return 90;
+ case 8: return 270;
+ default: return 0;
+ }
+}
+
+}
Index: src/exif.h
===================================================================
--- src/exif.h (revision 0)
+++ src/exif.h (revision 0)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006-2008 Anders Brander <[EMAIL PROTECTED]> and
+ * Anders Kvist <[EMAIL PROTECTED]>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EXIF_H
+#define EXIF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <glib.h>
+
+typedef void* rs_exif_data;
+
+rs_exif_data rs_exif_load(const gchar *);
+void rs_exif_write(const gchar *filename, rs_exif_data);
+void rs_exif_free(rs_exif_data);
+gfloat rs_exif_aperture(rs_exif_data);
+gfloat rs_exif_shutter_speed(rs_exif_data);
+gshort rs_exif_focal_length(rs_exif_data);
+gushort rs_exif_iso(rs_exif_data);
+gushort rs_exif_orientation(rs_exif_data d);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: src/gtk-interface.c
===================================================================
--- src/gtk-interface.c (revision 1849)
+++ src/gtk-interface.c (working copy)
@@ -199,7 +199,8 @@
if (filetype->load_meta)
{
filetype->load_meta(name, photo->metadata);
- switch (photo->metadata->orientation)
+ gushort orientation = rs_exif_orientation(photo->metadata->exif);
+ switch (orientation)
{
case 90: ORIENTATION_90(photo->orientation);
break;
@@ -209,16 +210,20 @@
break;
}
label = g_string_new("");
- if (photo->metadata->focallength>0)
- g_string_append_printf(label, _("%dmm "), photo->metadata->focallength);
- if (photo->metadata->shutterspeed > 0.0 && photo->metadata->shutterspeed < 4)
- g_string_append_printf(label, _("%.1fs "), 1/photo->metadata->shutterspeed);
- else if (photo->metadata->shutterspeed >= 4)
- g_string_append_printf(label, _("1/%.0fs "), photo->metadata->shutterspeed);
- if (photo->metadata->aperture!=0.0)
- g_string_append_printf(label, _("F/%.1f "), photo->metadata->aperture);
- if (photo->metadata->iso!=0)
- g_string_append_printf(label, _("ISO%d"), photo->metadata->iso);
+ gshort focallength = rs_exif_focal_length(photo->metadata->exif);
+ if (focallength > 0)
+ g_string_append_printf(label, _("%dmm "), focallength);
+ float shutterspeed = rs_exif_shutter_speed(photo->metadata->exif);
+ if (shutterspeed > 0.0 && shutterspeed < 4)
+ g_string_append_printf(label, _("%.1fs "), 1/shutterspeed);
+ else if (shutterspeed >= 4)
+ g_string_append_printf(label, _("1/%.0fs "), shutterspeed);
+ float aperture = rs_exif_aperture(photo->metadata->exif);
+ if (aperture != 0.0)
+ g_string_append_printf(label, _("F/%.1f "), aperture);
+ gushort iso = rs_exif_iso(photo->metadata->exif);
+ if (iso != 0)
+ g_string_append_printf(label, _("ISO%d"), iso);
gtk_label_set_text(infolabel, label->str);
g_string_free(label, TRUE);
} else
Index: src/rawstudio.c
===================================================================
--- src/rawstudio.c (revision 1849)
+++ src/rawstudio.c (working copy)
@@ -428,10 +428,6 @@
metadata->make = MAKE_UNKNOWN;
metadata->make_ascii = NULL;
metadata->model_ascii = NULL;
- metadata->orientation = 0;
- metadata->aperture = -1.0;
- metadata->iso = 0;
- metadata->shutterspeed = 1.0;
metadata->thumbnail_start = 0;
metadata->thumbnail_length = 0;
metadata->preview_start = 0;
@@ -444,11 +440,11 @@
metadata->saturation = -1.0;
metadata->sharpness = -1.0;
metadata->color_tone = -1.0;
- metadata->focallength = -1;
for(i=0;i<4;i++)
metadata->cam_mul[i] = 1.0f;
matrix4_identity(&metadata->adobe_coeff);
metadata->data = NULL;
+ metadata->exif = NULL;
return(metadata);
}
@@ -459,6 +455,8 @@
g_free(metadata->make_ascii);
if (metadata->model_ascii)
g_free(metadata->model_ascii);
+ if (metadata->exif)
+ rs_exif_free(metadata->exif);
g_free(metadata);
return;
}
@@ -489,6 +487,7 @@
gboolean uncompressed_tiff = FALSE;
RS_COLOR_TRANSFORM *rct;
void *transform = NULL;
+ rs_exif_data exif = photo->metadata->exif;
g_assert(RS_IS_PHOTO(photo));
g_assert(filename != NULL);
@@ -528,7 +527,9 @@
else if (quality < 0)
quality = 0;
- rs_jpeg_save(pixbuf, filename, quality, rs_cms_get_profile_filename(cms, PROFILE_EXPORT));
+ rs_jpeg_save(pixbuf, filename, quality,
+ rs_cms_get_profile_filename(cms, PROFILE_EXPORT),
+ exif);
g_object_unref(pixbuf);
break;
case FILETYPE_PNG:
Index: src/rs-actions.c
===================================================================
--- src/rs-actions.c (revision 1849)
+++ src/rs-actions.c (working copy)
@@ -431,7 +431,8 @@
if (filetype->load_meta)
{
filetype->load_meta(photo->filename, photo->metadata);
- switch (photo->metadata->orientation)
+ gushort orientation = rs_exif_orientation(photo->metadata);
+ switch (orientation)
{
case 90: ORIENTATION_90(photo->orientation);
break;
Index: src/rawstudio.h
===================================================================
--- src/rawstudio.h (revision 1849)
+++ src/rawstudio.h (working copy)
@@ -25,6 +25,7 @@
#include "dcraw_api.h"
#include "rs-arch.h"
#include "rs-cms.h"
+#include "exif.h"
#define BUH printf("%s:%d\n", __FILE__, __LINE__);
@@ -171,10 +172,6 @@
gint make;
gchar *make_ascii;
gchar *model_ascii;
- gushort orientation;
- gfloat aperture;
- gushort iso;
- gfloat shutterspeed;
guint thumbnail_start;
guint thumbnail_length;
guint preview_start;
@@ -188,9 +185,9 @@
gdouble saturation;
gdouble sharpness;
gdouble color_tone;
- gshort focallength;
RS_MATRIX4 adobe_coeff;
gpointer data;
+ rs_exif_data exif;
} RS_METADATA;
typedef struct _photo {
Index: src/rs-jpeg.c
===================================================================
--- src/rs-jpeg.c (revision 1849)
+++ src/rs-jpeg.c (working copy)
@@ -77,7 +77,7 @@
gboolean
rs_jpeg_save(GdkPixbuf *pixbuf, const gchar *filename, const gint quality,
- const gchar *profile_filename)
+ const gchar *profile_filename, rs_exif_data exif)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
@@ -124,5 +124,7 @@
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
+
+ rs_exif_write(filename, exif);
return(TRUE);
}
Index: src/panasonic.c
===================================================================
--- src/panasonic.c (revision 1849)
+++ src/panasonic.c (working copy)
@@ -65,9 +65,6 @@
if (panasonic)
raw_get_uint(rawfile, offset, &panasonic->sensorheight);
break;
- case 0x0017: /* ISO */
- raw_get_ushort(rawfile, offset, &meta->iso);
- break;
case 0x0024: /* WB_RedLevel */
raw_get_uint(rawfile, offset, &uint_temp1);
meta->cam_mul[0] = uint_temp1;
@@ -95,16 +92,6 @@
if (panasonic)
raw_get_uint(rawfile, offset, &panasonic->sensorstart);
break;
- case 0x0112: /* Orientation */
- raw_get_ushort(rawfile, offset, &meta->orientation);
- switch (meta->orientation)
- {
- case 6: meta->orientation = 90;
- break;
- case 8: meta->orientation = 270;
- break;
- }
- break;
case 0x0117: /* StripByteCounts */
if (panasonic)
raw_get_uint(rawfile, offset, &panasonic->sensorlength);
@@ -176,7 +163,8 @@
return NULL;
}
rs_panasonic_load_meta(src, photo->metadata);
- switch (photo->metadata->orientation)
+ gushort orientation = rs_exif_orientation(photo->metadata);
+ switch (orientation)
{
case 90: ORIENTATION_90(photo->orientation);
break;
Index: src/rs-jpeg.h
===================================================================
--- src/rs-jpeg.h (revision 1849)
+++ src/rs-jpeg.h (working copy)
@@ -21,6 +21,7 @@
#define RS_JPEG_H
extern gboolean rs_jpeg_save(GdkPixbuf *pixbuf, const gchar *filename,
- const gint quality, const gchar *profile_filename);
+ const gint quality, const gchar *profile_filename,
+ rs_exif_data exif);
#endif
Index: src/tiff-meta.c
===================================================================
--- src/tiff-meta.c (revision 1849)
+++ src/tiff-meta.c (working copy)
@@ -23,12 +23,8 @@
#include "rawfile.h"
#include "tiff-meta.h"
#include "adobe-coeff.h"
+#include "exif.h"
-/* It is required having some arbitrary maximum exposure time to prevent borked
- * shutter speed values being interpreted from the tiff.
- * 8h seems to be reasonable, even for astronomists with extra battery packs */
-#define EXPO_TIME_MAXVAL (8*60.0*60.0)
-
static void raw_nikon_makernote(RAWFILE *rawfile, guint offset, RS_METADATA *meta);
static void raw_pentax_makernote(RAWFILE *rawfile, guint offset, RS_METADATA *meta);
@@ -121,9 +117,6 @@
}
switch(fieldtag)
{
- case 0x0002: /* ISO */
- raw_get_ushort(rawfile, offset+2, &meta->iso);
- break;
case 0x000c: /* D1 White Balance */
raw_get_uint(rawfile, offset, &uint_temp1);
@@ -319,7 +312,6 @@
guint uint_temp1=0;
guint subfile_type=0;
gboolean is_preview=FALSE;
- gfloat float_temp1=0.0, float_temp2=0.0;
if(!raw_get_ushort(rawfile, offset, &number_of_entries)) return(FALSE);
if (number_of_entries>5000)
@@ -390,13 +382,6 @@
}
}
break;
- case 0x0002: /* CanonFocalLength */
- if (meta->make == MAKE_CANON)
- {
- raw_get_uint(rawfile, offset, &uint_temp1);
- raw_get_short(rawfile, uint_temp1+2, &meta->focallength);
- }
- break;
case 0x0110: /* Model */
raw_get_uint(rawfile, offset, &uint_temp1);
if (!meta->model_ascii)
@@ -434,16 +419,6 @@
if (meta->preview_length==0 || is_preview)
raw_get_uint(rawfile, offset, &meta->preview_length);
break;
- case 0x0112: /* Orientation */
- raw_get_ushort(rawfile, offset, &meta->orientation);
- switch (meta->orientation)
- {
- case 6: meta->orientation = 90;
- break;
- case 8: meta->orientation = 270;
- break;
- }
- break;
case 0x00fe: /* Subfile type */
raw_get_uint (rawfile, offset, &subfile_type);
is_preview = (subfile_type & 1) != 0;
@@ -476,29 +451,6 @@
case 0x0202: /* jpeg length */
raw_get_uint(rawfile, offset, &meta->thumbnail_length);
break;
- case 0x829A: /* Exposure time */
- raw_get_uint(rawfile, offset, &uint_temp1);
- raw_get_float(rawfile, uint_temp1, &float_temp1);
- raw_get_float(rawfile, uint_temp1+4, &float_temp2);
- float_temp1 /= float_temp2;
- if (float_temp1 < EXPO_TIME_MAXVAL)
- meta->shutterspeed = 1/float_temp1;
- break;
- case 0x829D: /* FNumber */
- raw_get_uint(rawfile, offset, &uint_temp1);
- raw_get_float(rawfile, uint_temp1, &float_temp1);
- raw_get_float(rawfile, uint_temp1+4, &float_temp2);
- meta->aperture = float_temp1/float_temp2;
- break;
- case 0x8827: /* ISOSpeedRatings */
- raw_get_ushort(rawfile, offset, &meta->iso);
- break;
- case 0x920A: /* Focal length */
- raw_get_uint(rawfile, offset, &uint_temp1);
- raw_get_float(rawfile, uint_temp1, &float_temp1);
- raw_get_float(rawfile, uint_temp1+4, &float_temp2);
- meta->focallength = (int) (float_temp1 / float_temp2);
- break;
case 0x014a: /* SubIFD */
raw_get_uint(rawfile, offset, &uint_temp1);
raw_get_uint(rawfile, uint_temp1, &uint_temp1);
@@ -519,14 +471,6 @@
raw_get_uint(rawfile, offset, &uint_temp1);
raw_ifd_walker(rawfile, uint_temp1, meta);
break;
- case 0x9201: /* ShutterSpeedValue */
- raw_get_uint(rawfile, offset, &uint_temp1);
- raw_get_float(rawfile, uint_temp1, &float_temp1);
- raw_get_float(rawfile, uint_temp1+4, &float_temp2);
- float_temp1 /= -float_temp2;
- if ((float_temp1 < EXPO_TIME_MAXVAL) && (meta->shutterspeed<0.0))
- meta->shutterspeed = 1.0/pow(2.0, float_temp1);
- break;
case 0x4001: /* white balance for Canon 20D & 350D */
raw_get_uint(rawfile, offset, &uint_temp1);
switch (valuecount)
@@ -571,9 +515,6 @@
raw_init();
meta->make = MAKE_UNKNOWN;
- meta->aperture = 0.0;
- meta->iso = 0;
- meta->shutterspeed = 0.0;
meta->thumbnail_start = 0;
meta->thumbnail_length = 0;
meta->preview_start = 0;
@@ -600,6 +541,8 @@
adobe_coeff_set(&meta->adobe_coeff, meta->make_ascii, meta->model_ascii);
raw_close_file(rawfile);
+
+ meta->exif = rs_exif_load(filename);
}
GdkPixbuf *
@@ -631,6 +574,9 @@
raw_init_file_tiff(rawfile, 0);
meta = rs_metadata_new();
+
+ meta->exif = rs_exif_load(src);
+
offset = get_first_ifd_offset(rawfile);
do {
if (!raw_get_ushort(rawfile, offset, &ifd_num)) break;
@@ -704,7 +650,8 @@
pixbuf2 = gdk_pixbuf_scale_simple(pixbuf, (gint) (128.0*ratio), 128, GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = pixbuf2;
- switch (meta->orientation)
+ gushort orientation = rs_exif_orientation(meta->exif);
+ switch (orientation)
{
/* this is very COUNTER-intuitive - gdk_pixbuf_rotate_simple() is wierd */
case 90:
Index: src/mrw-meta.c
===================================================================
--- src/mrw-meta.c (revision 1849)
+++ src/mrw-meta.c (working copy)
@@ -162,7 +162,8 @@
pixbuf2 = gdk_pixbuf_scale_simple(pixbuf, (gint) (128.0*ratio), 128, GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = pixbuf2;
- switch (meta.orientation)
+ gushort orientation = rs_exif_orientation(meta.exif);
+ switch (orientation)
{
/* this is very COUNTER-intuitive - gdk_pixbuf_rotate_simple() is wierd */
case 90:
Index: src/Makefile.am
===================================================================
--- src/Makefile.am (revision 1849)
+++ src/Makefile.am (working copy)
@@ -48,6 +48,7 @@
panasonic.c panasonic.h \
rs-image.c rs-image.h \
rs-photo.c rs-photo.h \
+ exif.cc exif.h \
dcraw_api.cc dcraw_api.h \
dcraw.cc dcraw.h \
rs-jpeg.c rs-jpeg.h \
Index: src/ciff-meta.c
===================================================================
--- src/ciff-meta.c (revision 1849)
+++ src/ciff-meta.c (working copy)
@@ -43,7 +43,6 @@
guint size=0;
guint absoffset=0;
guint reloffset=0;
- guint uint_temp1=0;
gushort ushort_temp1=0;
gushort wbi=0;
gshort temp;
@@ -57,9 +56,6 @@
switch (type & 0x3fff)
{
- case 0x1029: /* FocalLength */
- raw_get_short(rawfile, absoffset+2, &meta->focallength);
- break;
case 0x102d: /* CanonCameraSettings */
raw_get_short(rawfile, absoffset+26, &temp); /* contrast */
switch(temp)
@@ -116,10 +112,6 @@
meta->thumbnail_start = absoffset;
meta->thumbnail_length = size;
break;
- case 0x1810: /* ImageInfo */
- raw_get_uint(rawfile, absoffset+12, &uint_temp1); /* Orientation */
- meta->orientation = uint_temp1;
- break;
case 0x10a9: /* white balance for D60, 10D, 300D */
if (size > 66)
wbi = "0134567028"[wbi]-'0';
@@ -133,20 +125,6 @@
raw_get_ushort(rawfile, absoffset+6, &ushort_temp1); /* B */
meta->cam_mul[2] = ushort_temp1;
break;
- case 0x102a: /* CanonShotInfo */
- raw_get_ushort(rawfile, absoffset+4, &ushort_temp1); /* iso */
- meta->iso = pow(2, ushort_temp1/32.0 - 4) * 50;
-
- raw_get_ushort(rawfile, absoffset+8, &ushort_temp1); /* aperture */
- meta->aperture = pow(2, ushort_temp1/64.0);
-
- raw_get_ushort(rawfile, absoffset+10, &ushort_temp1); /* shutter */
- meta->shutterspeed = 1.0/pow(2,-((short)ushort_temp1)/32.0);
-
- raw_get_ushort(rawfile, absoffset+14, &wbi);
- if (wbi > 17)
- wbi = 0;
- break;
case 0x080a: /* make / model */
{
gchar makemodel[32];
@@ -240,7 +218,8 @@
pixbuf2 = gdk_pixbuf_scale_simple(pixbuf, (gint) (128.0*ratio), 128, GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = pixbuf2;
- switch (m->orientation)
+ gushort orientation = rs_exif_orientation (m);
+ switch (orientation)
{
/* this is very COUNTER-intuitive - gdk_pixbuf_rotate_simple() is wierd */
case 90:
_______________________________________________
Rawstudio-dev mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-dev