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

Reply via email to