]> git.sesse.net Git - mlt/commitdiff
Read EXIF info inside MLT, based on jpegexiforient
authorj-b-m <jb@kdenlive.org>
Mon, 26 Jul 2010 23:14:31 +0000 (01:14 +0200)
committerj-b-m <jb@kdenlive.org>
Mon, 26 Jul 2010 23:14:31 +0000 (01:14 +0200)
modified:   src/modules/gtk2/producer_pixbuf.c
modified:   src/modules/qimage/qimage_wrapper.cpp
new file:   src/modules/qimage/readexif.h

src/modules/gtk2/producer_pixbuf.c
src/modules/qimage/qimage_wrapper.cpp
src/modules/qimage/readexif.h [new file with mode: 0644]

index a3c106ee3550528c36c34e0c2cda16db420a6a6c..9ed0055af5a53dabb50f07bd02950c0dae61abae 100644 (file)
@@ -23,6 +23,7 @@
 #include <framework/mlt_cache.h>
 #include <framework/mlt_log.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#include "../qimage/readexif.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -217,7 +218,7 @@ static void refresh_image( producer_pixbuf this, mlt_frame frame, int width, int
        this->image = mlt_cache_item_data( this->image_cache, NULL );
 
        // Check if user wants us to reload the image
-       if ( mlt_properties_get_int( producer_props, "force_reload" ) || mlt_properties_get_int( producer_props, "_orientation" ) != mlt_properties_get_int( producer_props, "meta.attr.orientation" ) )
+       if ( mlt_properties_get_int( producer_props, "force_reload" ) )
        {
                pixbuf = NULL;
                this->image = NULL;
@@ -266,7 +267,8 @@ static void refresh_image( producer_pixbuf this, mlt_frame frame, int width, int
                                this->image = NULL;
                }
        }
-
+       int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" );
+       
     // optimization for subsequent iterations on single picture
        if ( width != 0 && ( image_idx != this->image_idx || width != this->width || height != this->height ) )
                this->image = NULL;
@@ -274,51 +276,53 @@ static void refresh_image( producer_pixbuf this, mlt_frame frame, int width, int
                pixbuf = NULL;
        mlt_log_debug( MLT_PRODUCER_SERVICE( producer ), "image %p pixbuf %p idx %d image_idx %d pixbuf_idx %d width %d\n",
                this->image, pixbuf, image_idx, this->image_idx, this->pixbuf_idx, width );
-       if ( !pixbuf && !this->image )
+       if ( ( !pixbuf && !this->image ) || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif )
        {
                this->image = NULL;
                pixbuf = gdk_pixbuf_new_from_file( mlt_properties_get_value( this->filenames, image_idx ), &error );
 
                if ( pixbuf )
                {
-                       int exif_orientation = mlt_properties_get_int( producer_props, "meta.attr.orientation" );
-
-                       if ( exif_orientation > 1 )
-                       {
-                             GdkPixbuf *processed;
-                             GdkPixbufRotation matrix = GDK_PIXBUF_ROTATE_NONE;
-
-                             // Rotate image according to exif data
-                             switch ( exif_orientation ) {
-                               case 2:
-                                   processed = gdk_pixbuf_flip ( pixbuf, TRUE );
-                                   break;
-                               case 4:
-                                   processed = gdk_pixbuf_flip ( pixbuf, FALSE );
-                                   break;
-                               case 8:
-                                   matrix = GDK_PIXBUF_ROTATE_CLOCKWISE;
-                                   processed = pixbuf;
-                                   break;
-                               case 3:
-                                   matrix = GDK_PIXBUF_ROTATE_UPSIDEDOWN;
-                                   processed = pixbuf;
-                                   break;
-                               case 6:
-                                   matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
-                                   processed = pixbuf;
-                                   break;
-                               case 5:
-                                   matrix = GDK_PIXBUF_ROTATE_CLOCKWISE;
-                                   processed = gdk_pixbuf_flip ( pixbuf, TRUE );
-                                   break;
-                               case 7:
-                                   matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
-                                   processed = gdk_pixbuf_flip ( pixbuf, TRUE );
-                                   break;
-
-                             }
-                             pixbuf = gdk_pixbuf_rotate_simple( processed, matrix );
+                       // Read the exif value for this file
+                       if ( disable_exif == 0) {
+                               int exif_orientation = check_exif_orientation(mlt_properties_get_value( this->filenames, image_idx ));
+
+                               if ( exif_orientation > 1 )
+                               {
+                                       GdkPixbuf *processed;
+                                       GdkPixbufRotation matrix = GDK_PIXBUF_ROTATE_NONE;
+
+                                       // Rotate image according to exif data
+                                       switch ( exif_orientation ) {
+                                         case 2:
+                                             processed = gdk_pixbuf_flip ( pixbuf, TRUE );
+                                             break;
+                                         case 3:
+                                             matrix = GDK_PIXBUF_ROTATE_UPSIDEDOWN;
+                                             processed = pixbuf;
+                                             break;
+                                         case 4:
+                                             processed = gdk_pixbuf_flip ( pixbuf, FALSE );
+                                             break;
+                                         case 5:
+                                             matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
+                                             processed = gdk_pixbuf_flip ( pixbuf, TRUE );
+                                             break;
+                                         case 6:
+                                             matrix = GDK_PIXBUF_ROTATE_CLOCKWISE;
+                                             processed = pixbuf;
+                                             break;
+                                         case 7:
+                                             matrix = GDK_PIXBUF_ROTATE_CLOCKWISE;
+                                             processed = gdk_pixbuf_flip ( pixbuf, TRUE );
+                                             break;
+                                         case 8:
+                                             matrix = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
+                                             processed = pixbuf;
+                                             break;
+                                       }
+                                       pixbuf = gdk_pixbuf_rotate_simple( processed, matrix );
+                               }
                        }
                        // Register this pixbuf for destruction and reuse
                        mlt_cache_item_close( pixbuf_cache );
@@ -329,7 +333,7 @@ static void refresh_image( producer_pixbuf this, mlt_frame frame, int width, int
                        mlt_events_block( producer_props, NULL );
                        mlt_properties_set_int( producer_props, "_real_width", gdk_pixbuf_get_width( pixbuf ) );
                        mlt_properties_set_int( producer_props, "_real_height", gdk_pixbuf_get_height( pixbuf ) );
-                       mlt_properties_set_int( producer_props, "_orientation", exif_orientation );
+                       mlt_properties_set_int( producer_props, "_disable_exif", disable_exif );
                        mlt_events_unblock( producer_props, NULL );
 
                        // Store the width/height of the pixbuf temporarily
index ef113af694367514735a9e4aac0f4a9ede8289fc..c16cd57c8e6070e911bdba7ceb9ed309aed141a7 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "qimage_wrapper.h"
+#include "readexif.h"
 
 #ifdef USE_QT3
 #include <qimage.h>
@@ -98,7 +99,7 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
        self->current_image = static_cast<uint8_t*>( mlt_cache_item_data( self->image_cache, NULL ) );
 
        // Check if user wants us to reload the image
-       if ( mlt_properties_get_int( producer_props, "force_reload" ) || mlt_properties_get_int( producer_props, "_orientation" ) != mlt_properties_get_int( producer_props, "meta.attr.orientation" ) )
+       if ( mlt_properties_get_int( producer_props, "force_reload" ) )
        {
                qimage = NULL;
                self->current_image = NULL;
@@ -153,57 +154,63 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
                }
        }
 
-    // optimization for subsequent iterations on single picture
+       int disable_exif = mlt_properties_get_int( producer_props, "disable_exif" );
+
+       // optimization for subsequent iterations on single pictur
        if ( width != 0 && ( image_idx != self->image_idx || width != self->current_width || height != self->current_height ) )
                self->current_image = NULL;
        if ( image_idx != self->qimage_idx )
                qimage = NULL;
-       if ( !qimage && !self->current_image )
+
+       if ( ( !qimage && !self->current_image ) || mlt_properties_get_int( producer_props, "_disable_exif" ) != disable_exif)
        {
                self->current_image = NULL;
                qimage = new QImage( mlt_properties_get_value( self->filenames, image_idx ) );
 
                if ( !qimage->isNull( ) )
                {
-                       // Store the width/height of the qimage
-                       int exif_orientation = mlt_properties_get_int( producer_props, "meta.attr.orientation" );
-
-                       if ( exif_orientation > 1 )
-                       {
-                             // Rotate image according to exif data
-                             QImage processed;
-                             QMatrix matrix;
-
-                             switch ( exif_orientation ) {
-                               case 2:
-                                   matrix.scale( -1, 1 );
-                                   break;
-                               case 3:
-                                   matrix.rotate( 180 );
-                                   break;
-                               case 4:
-                                   matrix.scale( 1, -1 );
-                                   break;
-                               case 5:
-                                   matrix.rotate( 270 );
-                                   matrix.scale( -1, 1 );
-                                   break;
-                               case 6:
-                                   matrix.rotate( 90 );
-                                   break;
-                               case 7:
-                                   matrix.rotate( 90 );
-                                   matrix.scale( -1, 1 );
-                                   break;
-                               case 8:
-                                   matrix.rotate( 270 );
-                                   break;
-                             }
-                             processed = qimage->transformed( matrix );
-                             delete qimage;
-                             qimage = new QImage( processed );
+                       // Read the exif value for this file
+                       if ( disable_exif == 0) {
+                               int exif_orientation = check_exif_orientation(mlt_properties_get_value( self->filenames, image_idx ));
+
+                               if ( exif_orientation > 1 )
+                               {
+                                     // Rotate image according to exif data
+                                     QImage processed;
+                                     QMatrix matrix;
+
+                                     switch ( exif_orientation ) {
+                                         case 2:
+                                             matrix.scale( -1, 1 );
+                                             break;
+                                         case 3:
+                                             matrix.rotate( 180 );
+                                             break;
+                                         case 4:
+                                             matrix.scale( 1, -1 );
+                                             break;
+                                         case 5:
+                                             matrix.rotate( 270 );
+                                             matrix.scale( -1, 1 );
+                                             break;
+                                         case 6:
+                                             matrix.rotate( 90 );
+                                             break;
+                                         case 7:
+                                             matrix.rotate( 90 );
+                                             matrix.scale( -1, 1 );
+                                             break;
+                                         case 8:
+                                             matrix.rotate( 270 );
+                                             break;
+                                     }
+                                     processed = qimage->transformed( matrix );
+                                     delete qimage;
+                                     qimage = new QImage( processed );
+                               }
                        }
-                         
+                       
+                       // Store the width/height of the qimage  
                        self->current_width = qimage->width( );
                        self->current_height = qimage->height( );
 
@@ -216,7 +223,7 @@ void refresh_qimage( producer_qimage self, mlt_frame frame, int width, int heigh
                        mlt_events_block( producer_props, NULL );
                        mlt_properties_set_int( producer_props, "_real_width", self->current_width );
                        mlt_properties_set_int( producer_props, "_real_height", self->current_height );
-                       mlt_properties_set_int( producer_props, "_orientation", exif_orientation );
+                       mlt_properties_set_int( producer_props, "_disable_exif", disable_exif );
                        mlt_events_unblock( producer_props, NULL );
                }
                else
diff --git a/src/modules/qimage/readexif.h b/src/modules/qimage/readexif.h
new file mode 100644 (file)
index 0000000..8e1a504
--- /dev/null
@@ -0,0 +1,196 @@
+/*\r
+ * readexif.h\r
+ * \r
+ * Slightly modified for use in MLT by Jean-Baptiste Mardelle, 2010\r
+ * based on jpegexiforient.c, part of the `jpeg library' by the\r
+ * Independent JPEG Group (IJG)).\r
+ *\r
+ * The Exif orientation value gives the orientation of the camera\r
+ * relative to the scene when the image was captured.  The relation\r
+ * of the '0th row' and '0th column' to visual position is shown as\r
+ * below.\r
+ * \r
+ *\r
+ * Value | 0th Row     | 0th Column\r
+ * ------+-------------+-----------\r
+ *   1   | top         | left side\r
+ *   2   | top         | rigth side\r
+ *   3   | bottom      | rigth side\r
+ *   4   | bottom      | left side\r
+ *   5   | left side   | top\r
+ *   6   | right side  | top\r
+ *   7   | right side  | bottom\r
+ *   8   | left side   | bottom\r
+ *\r
+ * For convenience, here is what the letter F would look like if it were\r
+ * tagged correctly and displayed by a program that ignores the orientation\r
+ * tag:\r
+ *\r
+ *   1        2       3      4         5            6           7          8\r
+ *\r
+ * 888888  888888      88  88      8888888888  88                  88  8888888888\r
+ * 88          88      88  88      88  88      88  88          88  88      88  88\r
+ * 8888      8888    8888  8888    88          8888888888  8888888888          88\r
+ * 88          88      88  88\r
+ * 88          88  888888  888888\r
+ *\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+static FILE * myfile;\r
+static unsigned char exif_data[65536L];\r
+\r
+/* Return next input byte, or EOF if no more */\r
+#define NEXTBYTE()  getc(myfile)\r
+\r
+/* Error exit handler */\r
+#define ERREXIT(msg)  (exit(0))\r
+\r
+/* Read one byte, testing for EOF */\r
+static int\r
+read_1_byte (void)\r
+{\r
+  int c;\r
+\r
+  c = NEXTBYTE();\r
+  if (c == EOF)\r
+    ERREXIT("Premature EOF in JPEG file");\r
+  return c;\r
+}\r
+\r
+/* Read 2 bytes, convert to unsigned int */\r
+/* All 2-byte quantities in JPEG markers are MSB first */\r
+static unsigned int\r
+read_2_bytes (void)\r
+{\r
+  int c1, c2;\r
+\r
+  c1 = NEXTBYTE();\r
+  if (c1 == EOF)\r
+    ERREXIT("Premature EOF in JPEG file");\r
+  c2 = NEXTBYTE();\r
+  if (c2 == EOF)\r
+    ERREXIT("Premature EOF in JPEG file");\r
+  return (((unsigned int) c1) << 8) + ((unsigned int) c2);\r
+}\r
+\r
+int check_exif_orientation(char *fname)\r
+{\r
+  int set_flag;\r
+  unsigned int length, i;\r
+  int is_motorola; /* Flag for byte order */\r
+  unsigned int offset, number_of_tags, tagnum;\r
+\r
+    if ((myfile = fopen(fname, "rb")) == NULL) {\r
+       fprintf(stderr, "can't open %s\n", fname);\r
+       return 0;\r
+    }\r
+\r
+  /* Read File head, check for JPEG SOI + Exif APP1 */\r
+  for (i = 0; i < 4; i++)\r
+    exif_data[i] = (unsigned char) read_1_byte();\r
+  if (exif_data[0] != 0xFF ||\r
+      exif_data[1] != 0xD8 ||\r
+      exif_data[2] != 0xFF ||\r
+      exif_data[3] != 0xE1)\r
+    return 0;\r
+  /* Get the marker parameter length count */\r
+  length = read_2_bytes();\r
+  /* Length includes itself, so must be at least 2 */\r
+  /* Following Exif data length must be at least 6 */\r
+  if (length < 8)\r
+    return 0;\r
+  length -= 8;\r
+  /* Read Exif head, check for "Exif" */\r
+  for (i = 0; i < 6; i++)\r
+    exif_data[i] = (unsigned char) read_1_byte();\r
+  if (exif_data[0] != 0x45 ||\r
+      exif_data[1] != 0x78 ||\r
+      exif_data[2] != 0x69 ||\r
+      exif_data[3] != 0x66 ||\r
+      exif_data[4] != 0 ||\r
+      exif_data[5] != 0)\r
+    return 0;\r
+  /* Read Exif body */\r
+  for (i = 0; i < length; i++)\r
+    exif_data[i] = (unsigned char) read_1_byte();\r
+\r
+  if (length < 12) return 0; /* Length of an IFD entry */\r
+\r
+  /* Discover byte order */\r
+  if (exif_data[0] == 0x49 && exif_data[1] == 0x49)\r
+    is_motorola = 0;\r
+  else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D)\r
+    is_motorola = 1;\r
+  else\r
+    return 0;\r
+\r
+  /* Check Tag Mark */\r
+  if (is_motorola) {\r
+    if (exif_data[2] != 0) return 0;\r
+    if (exif_data[3] != 0x2A) return 0;\r
+  } else {\r
+    if (exif_data[3] != 0) return 0;\r
+    if (exif_data[2] != 0x2A) return 0;\r
+  }\r
+\r
+  /* Get first IFD offset (offset to IFD0) */\r
+  if (is_motorola) {\r
+    if (exif_data[4] != 0) return 0;\r
+    if (exif_data[5] != 0) return 0;\r
+    offset = exif_data[6];\r
+    offset <<= 8;\r
+    offset += exif_data[7];\r
+  } else {\r
+    if (exif_data[7] != 0) return 0;\r
+    if (exif_data[6] != 0) return 0;\r
+    offset = exif_data[5];\r
+    offset <<= 8;\r
+    offset += exif_data[4];\r
+  }\r
+  if (offset > length - 2) return 0; /* check end of data segment */\r
+\r
+  /* Get the number of directory entries contained in this IFD */\r
+  if (is_motorola) {\r
+    number_of_tags = exif_data[offset];\r
+    number_of_tags <<= 8;\r
+    number_of_tags += exif_data[offset+1];\r
+  } else {\r
+    number_of_tags = exif_data[offset+1];\r
+    number_of_tags <<= 8;\r
+    number_of_tags += exif_data[offset];\r
+  }\r
+  if (number_of_tags == 0) return 0;\r
+  offset += 2;\r
+\r
+  /* Search for Orientation Tag in IFD0 */\r
+  for (;;) {\r
+    if (offset > length - 12) return 0; /* check end of data segment */\r
+    /* Get Tag number */\r
+    if (is_motorola) {\r
+      tagnum = exif_data[offset];\r
+      tagnum <<= 8;\r
+      tagnum += exif_data[offset+1];\r
+    } else {\r
+      tagnum = exif_data[offset+1];\r
+      tagnum <<= 8;\r
+      tagnum += exif_data[offset];\r
+    }\r
+    if (tagnum == 0x0112) break; /* found Orientation Tag */\r
+    if (--number_of_tags == 0) return 0;\r
+    offset += 12;\r
+  }\r
+  /* Get the Orientation value */\r
+    if (is_motorola) {\r
+      if (exif_data[offset+8] != 0) return 0;\r
+      set_flag = exif_data[offset+9];\r
+    } else {\r
+      if (exif_data[offset+9] != 0) return 0;\r
+      set_flag = exif_data[offset+8];\r
+    }\r
+    if (set_flag > 8) return 0;\r
+    return set_flag;\r
+}\r
+\r