Hi,
I'd like to submit a patch to bring exif support in, at least for saving
jpegs. This new code would use the exiv2 library, and much of the code
is borrowed from UFRaw. I'm not a C developer by any means, and this is
my first time submitting a patch to anything, but please tell me what
you think. I welcome any advice and guidance you can give.
Thanks,
Daniel Falk
Index: src/rawstudio.c
===================================================================
--- src/rawstudio.c (revision 1866)
+++ src/rawstudio.c (working copy)
@@ -530,7 +530,7 @@
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), photo);
g_object_unref(pixbuf);
break;
case FILETYPE_PNG:
Index: src/rs-exiv.cc
===================================================================
--- src/rs-exiv.cc (revision 0)
+++ src/rs-exiv.cc (revision 0)
@@ -0,0 +1,104 @@
+extern "C" {
+#include "rs-exiv.hh"
+}
+
+#include <exiv2/image.hpp>
+#include <exiv2/exif.hpp>
+#include <sstream>
+#include <cassert>
+
+#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
+
+void delete_irrelevant_keys(Exiv2::ExifData &exifData);
+
+
+/*
+ **Code borrowed and heavily and adapted from UFRaw**
+
+ read_exif()
+ ------------
+ Returns true if the exif information was retrieved successfully, false
+ otherwise.
+ * filename specifies the path to the raw file containing the exif data
+ * out_exif_buffer is an output parameter and returns a pointer to the exif
+ buffer
+ * out_exif_buffer_len is also an output parameter that specifies the length
of
+ that buffer.
+ */
+extern "C" gboolean read_exif(
+ const gchar *filename
+ , guchar
**out_exif_buffer
+ , guint
*out_exif_buffer_len)
+{
+ Exiv2::Image::AutoPtr image;
+ image = Exiv2::ImageFactory::open(filename);
+
+ assert(image.get() != 0);
+ image->readMetadata();
+
+ Exiv2::ExifData &exifData = image->exifData();
+
+ if (exifData.empty())
+ {
+ std::string error(filename);
+ error += ": No Exif data found in the file";
+ throw Exiv2::Error(1, error);
+ return FALSE;
+ }
+
+ /* Reset orientation tag since rawstudio already rotates the image
(right?) */
+ Exiv2::ExifData::iterator pos;
+
+ pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation"));
+
+ if ( pos != exifData.end() )
+ pos->setValue("1"); /* 1 = Normal orientation */
+
+ //delete keys that aren't pertinent to the output jpeg file
+ delete_irrelevant_keys(exifData);
+
+
+ Exiv2::DataBuf buf(exifData.copy());
+
+ const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
+
+ // If buffer too big for JPEG, try deleting some stuff.
+
+ if ( buf.size_ + sizeof(ExifHeader) > MAX_BYTES_IN_MARKER )
+ {
+ if ( (pos =
exifData.findKey(Exiv2::ExifKey("Exif.Photo.MakerNote"))) != exifData.end() )
+ {
+ exifData.erase(pos);
+ buf = exifData.copy();
+ }
+ }
+
+ if ( buf.size_ + sizeof(ExifHeader) > MAX_BYTES_IN_MARKER )
+ {
+ exifData.eraseThumbnail();
+ buf = exifData.copy();
+ }
+
+ *out_exif_buffer_len = buf.size_ + sizeof(ExifHeader);
+ *out_exif_buffer = g_new(unsigned char, *out_exif_buffer_len);
+ memcpy(*out_exif_buffer, ExifHeader, sizeof(ExifHeader));
+ memcpy(*out_exif_buffer + sizeof(ExifHeader), buf.pData_, buf.size_);
+
+ return TRUE;
+}
+
+void delete_irrelevant_keys(Exiv2::ExifData &exifData)
+{
+ Exiv2::ExifData::iterator pos;
+
+ // Delete original TIFF data, which is irrelevant
+ if ( (pos=exifData.findKey(Exiv2::ExifKey("Exif.Image.StripOffsets")))
+ != exifData.end() )
+ exifData.erase(pos);
+ if ( (pos=exifData.findKey(Exiv2::ExifKey("Exif.Image.RowsPerStrip")))
+ != exifData.end() )
+ exifData.erase(pos);
+ if ( (pos=exifData.findKey(Exiv2::ExifKey("Exif.Image.StripByteCounts")))
+ != exifData.end() )
+ exifData.erase(pos);
+}
Index: src/rs-jpeg.c
===================================================================
--- src/rs-jpeg.c (revision 1866)
+++ src/rs-jpeg.c (working copy)
@@ -27,10 +27,13 @@
#include "rawstudio.h"
#include "rs-image.h"
#include "rs-jpeg.h"
+#include "rs-exiv.hh"
+
/* This function is an almost verbatim copy from little cms. Thanks Marti, you
rock! */
#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define EXIF_MARKER (JPEG_APP0 + 1) /* JPEG marker code for EXIF */
#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
@@ -77,7 +80,7 @@
gboolean
rs_jpeg_save(GdkPixbuf *pixbuf, const gchar *filename, const gint quality,
- const gchar *profile_filename)
+ const gchar *profile_filename, RS_PHOTO *photo)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
@@ -115,14 +118,32 @@
g_free(buffer);
}
}
+
+
+ //write exif data
+ guchar *exif_buffer = NULL;
+ guint exif_buffer_len = 0;
+
+ if(read_exif(photo->filename, &exif_buffer, (guint *)&exif_buffer_len))
+ {
+ if (exif_buffer_len <= MAX_BYTES_IN_MARKER)
+ {
+ jpeg_write_marker(&cinfo, EXIF_MARKER, exif_buffer,
exif_buffer_len);
+ g_free(exif_buffer);
+ }
+ }
+
+
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = GET_PIXBUF_PIXEL(pixbuf, 0,
cinfo.next_scanline);
if (jpeg_write_scanlines(&cinfo, row_pointer, 1) != 1)
break;
}
+
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
return(TRUE);
}
+
Index: src/rs-jpeg.h
===================================================================
--- src/rs-jpeg.h (revision 1866)
+++ src/rs-jpeg.h (working copy)
@@ -21,6 +21,6 @@
#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_PHOTO *photo);
#endif
Index: src/rs-exiv.hh
===================================================================
--- src/rs-exiv.hh (revision 0)
+++ src/rs-exiv.hh (revision 0)
@@ -0,0 +1,3 @@
+#include <glib.h>
+
+gboolean read_exif(const gchar *filename, guchar **exif_buffer, guint
*exif_buffer_len);
_______________________________________________
Rawstudio-dev mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-dev