eog r4478 - in trunk: . src
- From: friemann svn gnome org
- To: svn-commits-list gnome org
- Subject: eog r4478 - in trunk: . src
- Date: Tue, 18 Mar 2008 21:23:49 +0000 (GMT)
Author: friemann
Date: Tue Mar 18 21:23:49 2008
New Revision: 4478
URL: http://svn.gnome.org/viewvc/eog?rev=4478&view=rev
Log:
2008-03-18 Felix Riemann <friemann svn gnome org>
* src/eog-metadata-reader-jpg.c: (eog_metadata_reader_jpg_dispose),
(eog_metadata_reader_jpg_init),
(eog_metadata_reader_jpg_class_init),
(eog_metadata_reader_jpg_new), (eog_metadata_reader_jpg_finished),
(eog_metadata_identify_app1), (eog_metadata_reader_get_next_block),
(eog_metadata_reader_jpg_consume),
(eog_metadata_reader_jpg_get_exif_chunk),
(eog_metadata_reader_jpg_get_exif_data),
(eog_metadata_reader_jpg_get_xmp_data),
(eog_metadata_reader_jpg_get_icc_chunk),
(eog_metadata_reader_jpg_init_emr_iface):
* src/eog-metadata-reader-jpg.h:
Add missing files to the metadata reader commit.
Added:
trunk/src/eog-metadata-reader-jpg.c
trunk/src/eog-metadata-reader-jpg.h
Modified:
trunk/ChangeLog
Added: trunk/src/eog-metadata-reader-jpg.c
==============================================================================
--- (empty file)
+++ trunk/src/eog-metadata-reader-jpg.c Tue Mar 18 21:23:49 2008
@@ -0,0 +1,528 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "eog-metadata-reader.h"
+#include "eog-metadata-reader-jpg.h"
+#include "eog-debug.h"
+
+typedef enum {
+ EMR_READ = 0,
+ EMR_READ_SIZE_HIGH_BYTE,
+ EMR_READ_SIZE_LOW_BYTE,
+ EMR_READ_MARKER,
+ EMR_SKIP_BYTES,
+ EMR_READ_APP1,
+ EMR_READ_EXIF,
+ EMR_READ_XMP,
+ EMR_READ_ICC,
+ EMR_READ_IPTC,
+ EMR_FINISHED
+} EogMetadataReaderState;
+
+typedef enum {
+ EJA_EXIF = 0,
+ EJA_XMP,
+ EJA_OTHER
+} EogJpegApp1Type;
+
+
+#define EOG_JPEG_MARKER_START 0xFF
+#define EOG_JPEG_MARKER_SOI 0xD8
+#define EOG_JPEG_MARKER_APP1 0xE1
+#define EOG_JPEG_MARKER_APP2 0xE2
+#define EOG_JPEG_MARKER_APP14 0xED
+
+#define IS_FINISHED(priv) (priv->exif_chunk != NULL && \
+ priv->icc_chunk != NULL && \
+ priv->iptc_chunk != NULL && \
+ priv->xmp_chunk != NULL)
+
+struct _EogMetadataReaderJpgPrivate {
+ EogMetadataReaderState state;
+
+ /* data fields */
+ gpointer exif_chunk;
+ guint exif_len;
+
+ gpointer iptc_chunk;
+ guint iptc_len;
+
+ gpointer icc_chunk;
+ guint icc_len;
+
+ gpointer xmp_chunk;
+ guint xmp_len;
+
+ /* management fields */
+ int size;
+ int last_marker;
+ int bytes_read;
+};
+
+#define EOG_METADATA_READER_JPG_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOG_TYPE_METADATA_READER_JPG, EogMetadataReaderJpgPrivate))
+
+static void
+eog_metadata_reader_jpg_init_emr_iface (gpointer g_iface, gpointer iface_data);
+
+
+G_DEFINE_TYPE_WITH_CODE (EogMetadataReaderJpg, eog_metadata_reader_jpg,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (EOG_TYPE_METADATA_READER,
+ eog_metadata_reader_jpg_init_emr_iface))
+
+
+static void
+eog_metadata_reader_jpg_dispose (GObject *object)
+{
+ EogMetadataReaderJpg *emr = EOG_METADATA_READER_JPG (object);
+
+ if (emr->priv->exif_chunk != NULL) {
+ g_free (emr->priv->exif_chunk);
+ emr->priv->exif_chunk = NULL;
+ }
+
+ if (emr->priv->iptc_chunk != NULL) {
+ g_free (emr->priv->iptc_chunk);
+ emr->priv->iptc_chunk = NULL;
+ }
+
+ if (emr->priv->xmp_chunk != NULL) {
+ g_free (emr->priv->xmp_chunk);
+ emr->priv->xmp_chunk = NULL;
+ }
+
+ if (emr->priv->icc_chunk != NULL) {
+ g_free (emr->priv->icc_chunk);
+ emr->priv->icc_chunk = NULL;
+ }
+
+ G_OBJECT_CLASS (eog_metadata_reader_jpg_parent_class)->dispose (object);
+}
+
+static void
+eog_metadata_reader_jpg_init (EogMetadataReaderJpg *obj)
+{
+ EogMetadataReaderJpgPrivate *priv;
+
+ priv = obj->priv = EOG_METADATA_READER_JPG_GET_PRIVATE (obj);
+ priv->exif_chunk = NULL;
+ priv->exif_len = 0;
+ priv->iptc_chunk = NULL;
+ priv->iptc_len = 0;
+ priv->icc_chunk = NULL;
+ priv->icc_len = 0;
+}
+
+static void
+eog_metadata_reader_jpg_class_init (EogMetadataReaderJpgClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass*) klass;
+
+ object_class->dispose = eog_metadata_reader_jpg_dispose;
+
+ g_type_class_add_private (klass, sizeof (EogMetadataReaderJpgPrivate));
+}
+
+EogMetadataReaderJpg*
+eog_metadata_reader_jpg_new (EogMetadataFileType type)
+{
+ EogMetadataReaderJpg *emr;
+
+ /* CAUTION: check for type if we support more metadat-image-formats in the future */
+
+ emr = g_object_new (EOG_TYPE_METADATA_READER_JPG, NULL);
+ return emr;
+}
+
+static gboolean
+eog_metadata_reader_jpg_finished (EogMetadataReaderJpg *emr)
+{
+ g_return_val_if_fail (EOG_IS_METADATA_READER_JPG (emr), TRUE);
+
+ return (emr->priv->state == EMR_FINISHED);
+}
+
+
+static EogJpegApp1Type
+eog_metadata_identify_app1 (gchar *buf, guint len)
+{
+ if (len < 5) {
+ return EJA_OTHER;
+ }
+
+ if (len < 29) {
+ return (strncmp ("Exif", buf, 5) == 0 ? EJA_EXIF : EJA_OTHER);
+ }
+
+ if (strncmp ("Exif", buf, 5) == 0) {
+ return EJA_EXIF;
+ } else if (strncmp ("http://ns.adobe.com/xap/1.0/", buf, 29) == 0) {
+ return EJA_XMP;
+ }
+
+ return EJA_OTHER;
+}
+
+static void
+eog_metadata_reader_get_next_block (EogMetadataReaderJpgPrivate* priv,
+ guchar *chunk,
+ int* i,
+ const guchar *buf,
+ int len,
+ EogMetadataReaderState state)
+{
+ if (*i + priv->size < len) {
+ /* read data in one block */
+ memcpy ((guchar*) (chunk) + priv->bytes_read, &buf[*i], priv->size);
+ priv->state = EMR_READ;
+ *i = *i + priv->size - 1; /* the for-loop consumes the other byte */
+ } else {
+ int chunk_len = len - *i;
+ memcpy ((guchar*) (chunk) + priv->bytes_read, &buf[*i], chunk_len);
+ priv->bytes_read += chunk_len; /* bytes already read */
+ priv->size = (*i + priv->size) - len; /* remaining data to read */
+ *i = len - 1;
+ priv->state = state;
+ }
+}
+
+static void
+eog_metadata_reader_jpg_consume (EogMetadataReaderJpg *emr, const guchar *buf, guint len)
+{
+ EogMetadataReaderJpgPrivate *priv;
+ EogJpegApp1Type app1_type;
+ int i;
+ EogMetadataReaderState next_state;
+ guchar *chunk = NULL;
+
+ g_return_if_fail (EOG_IS_METADATA_READER (emr));
+
+ priv = emr->priv;
+
+ if (priv->state == EMR_FINISHED) return;
+
+ for (i = 0; (i < len) && (priv->state != EMR_FINISHED); i++) {
+
+ switch (priv->state) {
+ case EMR_READ:
+ if (buf[i] == EOG_JPEG_MARKER_START) {
+ priv->state = EMR_READ_MARKER;
+ }
+ else {
+ priv->state = EMR_FINISHED;
+ }
+ break;
+
+ case EMR_READ_MARKER:
+ if ((buf [i] & 0xF0) == 0xE0) { /* we are reading some sort of APPxx marker */
+ /* these are always followed by 2 bytes of size information */
+ priv->last_marker = buf [i];
+ priv->size = 0;
+ priv->state = EMR_READ_SIZE_HIGH_BYTE;
+
+ eog_debug_message (DEBUG_IMAGE_DATA, "APPx Marker Found: %x", priv->last_marker);
+ }
+ else {
+ /* otherwise simply consume the byte */
+ priv->state = EMR_READ;
+ }
+ break;
+
+ case EMR_READ_SIZE_HIGH_BYTE:
+ priv->size = (buf [i] & 0xff) << 8;
+ priv->state = EMR_READ_SIZE_LOW_BYTE;
+ break;
+
+ case EMR_READ_SIZE_LOW_BYTE:
+ priv->size |= (buf [i] & 0xff);
+
+ if (priv->size > 2) /* ignore the two size-bytes */
+ priv->size -= 2;
+
+ if (priv->size == 0) {
+ priv->state = EMR_READ;
+ } else if (priv->last_marker == EOG_JPEG_MARKER_APP1 &&
+ ((priv->exif_chunk == NULL) || (priv->xmp_chunk == NULL)))
+ {
+ priv->state = EMR_READ_APP1;
+ } else if (priv->last_marker == EOG_JPEG_MARKER_APP2 &&
+ priv->icc_chunk == NULL && priv->size > 14)
+ {
+ /* Chunk has 14 bytes identification data */
+ priv->state = EMR_READ_ICC;
+ } else if (priv->last_marker == EOG_JPEG_MARKER_APP14 &&
+ priv->iptc_chunk == NULL)
+ {
+ priv->state = EMR_READ_IPTC;
+ } else {
+ priv->state = EMR_SKIP_BYTES;
+ }
+
+ priv->last_marker = 0;
+ break;
+
+ case EMR_SKIP_BYTES:
+ eog_debug_message (DEBUG_IMAGE_DATA, "Skip bytes: %i", priv->size);
+
+ if (i + priv->size < len) {
+ i = i + priv->size - 1; /* the for-loop consumes the other byte */
+ priv->size = 0;
+ }
+ else {
+ priv->size = (i + priv->size) - len;
+ i = len - 1;
+ }
+ if (priv->size == 0) { /* don't need to skip any more bytes */
+ priv->state = EMR_READ;
+ }
+ break;
+
+ case EMR_READ_APP1:
+ eog_debug_message (DEBUG_IMAGE_DATA, "Read APP1 data, Length: %i", priv->size);
+
+ app1_type = eog_metadata_identify_app1 ((gchar*) &buf[i], priv->size);
+
+ switch (app1_type) {
+ case EJA_EXIF:
+ if (priv->exif_chunk == NULL) {
+ priv->exif_chunk = g_new0 (guchar, priv->size);
+ priv->exif_len = priv->size;
+ priv->bytes_read = 0;
+ chunk = priv->exif_chunk;
+ next_state = EMR_READ_EXIF;
+ }
+ break;
+ case EJA_XMP:
+ if (priv->xmp_chunk == NULL) {
+ priv->xmp_chunk = g_new0 (guchar, priv->size);
+ priv->xmp_len = priv->size;
+ priv->bytes_read = 0;
+ chunk = priv->xmp_chunk;
+ next_state = EMR_READ_XMP;
+ }
+ break;
+ case EJA_OTHER:
+ default:
+ /* skip unknown data */
+ priv->state = EMR_SKIP_BYTES;
+ break;
+ }
+
+ if (chunk) {
+ eog_metadata_reader_get_next_block (priv, chunk,
+ &i, buf,
+ len,
+ next_state);
+ }
+
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_EXIF:
+ eog_debug_message (DEBUG_IMAGE_DATA, "Read continuation of EXIF data, length: %i", priv->size);
+ {
+ eog_metadata_reader_get_next_block (priv, priv->exif_chunk,
+ &i, buf, len, EMR_READ_EXIF);
+ }
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_XMP:
+ eog_debug_message (DEBUG_IMAGE_DATA, "Read continuation of XMP data, length: %i", priv->size);
+ {
+ eog_metadata_reader_get_next_block (priv, priv->xmp_chunk,
+ &i, buf, len, EMR_READ_XMP);
+ }
+ if (IS_FINISHED (priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_ICC:
+ eog_debug_message (DEBUG_IMAGE_DATA,
+ "Read continuation of ICC data, "
+ "length: %i", priv->size);
+
+ if (priv->icc_chunk == NULL) {
+ priv->icc_chunk = g_new0 (guchar, priv->size);
+ priv->icc_len = priv->size;
+ priv->bytes_read = 0;
+ }
+
+ eog_metadata_reader_get_next_block (priv,
+ priv->icc_chunk,
+ &i, buf, len,
+ EMR_READ_ICC);
+
+ /* Test that the chunk actually contains ICC data. */
+ if (priv->state == EMR_READ && priv->icc_chunk) {
+ const char* icc_chunk = priv->icc_chunk;
+ gboolean valid = TRUE;
+
+ /* Chunk should begin with the
+ * ICC_PROFILE\0 identifier */
+ valid &= strncmp (icc_chunk,
+ "ICC_PROFILE\0",12) == 0;
+ /* Make sure this is the first and only
+ * ICC chunk in the file as we don't
+ * support merging chunks yet. */
+ valid &= *(guint16*)(icc_chunk+12) == 0x101;
+
+ if (!valid) {
+ /* This no ICC data. Throw it away. */
+ eog_debug_message (DEBUG_IMAGE_DATA,
+ "Supposed ICC chunk didn't validate. "
+ "Ignoring.");
+ g_free (priv->icc_chunk);
+ priv->icc_chunk = NULL;
+ priv->icc_len = 0;
+ }
+ }
+
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ case EMR_READ_IPTC:
+ eog_debug_message (DEBUG_IMAGE_DATA,
+ "Read continuation of IPTC data, "
+ "length: %i", priv->size);
+
+ if (priv->iptc_chunk == NULL) {
+ priv->iptc_chunk = g_new0 (guchar, priv->size);
+ priv->iptc_len = priv->size;
+ priv->bytes_read = 0;
+ }
+
+ eog_metadata_reader_get_next_block (priv,
+ priv->iptc_chunk,
+ &i, buf, len,
+ EMR_READ_IPTC);
+
+ if (IS_FINISHED(priv))
+ priv->state = EMR_FINISHED;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+ }
+}
+
+/* Returns the raw exif data. NOTE: The caller of this function becomes
+ * the new owner of this piece of memory and is responsible for freeing it!
+ */
+static void
+eog_metadata_reader_jpg_get_exif_chunk (EogMetadataReaderJpg *emr, guchar **data, guint *len)
+{
+ EogMetadataReaderJpgPrivate *priv;
+
+ g_return_if_fail (EOG_IS_METADATA_READER (emr));
+ priv = emr->priv;
+
+ *data = (guchar*) priv->exif_chunk;
+ *len = priv->exif_len;
+
+ priv->exif_chunk = NULL;
+ priv->exif_len = 0;
+}
+
+#ifdef HAVE_EXIF
+static gpointer
+eog_metadata_reader_jpg_get_exif_data (EogMetadataReaderJpg *emr)
+{
+ EogMetadataReaderJpgPrivate *priv;
+ ExifData *data = NULL;
+
+ g_return_val_if_fail (EOG_IS_METADATA_READER (emr), NULL);
+ priv = emr->priv;
+
+ if (priv->exif_chunk != NULL) {
+ data = exif_data_new_from_data (priv->exif_chunk, priv->exif_len);
+ }
+
+ return data;
+}
+#endif
+
+
+#ifdef HAVE_EXEMPI
+
+/* skip the ID + packet */
+#define EOG_XMP_OFFSET (29 + 54)
+
+static gpointer
+eog_metadata_reader_jpg_get_xmp_data (EogMetadataReaderJpg *emr )
+{
+ EogMetadataReaderJpgPrivate *priv;
+ XmpPtr xmp = NULL;
+
+ g_return_val_if_fail (EOG_IS_METADATA_READER (emr), NULL);
+
+ priv = emr->priv;
+
+ if (priv->xmp_chunk != NULL) {
+ xmp = xmp_new (priv->xmp_chunk+EOG_XMP_OFFSET,
+ priv->xmp_len-EOG_XMP_OFFSET);
+ }
+
+ return (gpointer)xmp;
+}
+#endif
+
+/*
+ * FIXME: very broken, assumes the profile fits in a single chunk. Change to
+ * parse the sections and construct a single memory chunk, or maybe even parse
+ * the profile.
+ */
+static void
+eog_metadata_reader_jpg_get_icc_chunk (EogMetadataReaderJpg *emr, guchar **data, guint *len)
+{
+ EogMetadataReaderJpgPrivate *priv;
+
+ g_return_if_fail (EOG_IS_METADATA_READER (emr));
+
+ priv = emr->priv;
+
+ if (priv->icc_chunk) {
+ *data = (guchar*) priv->icc_chunk + 14;
+ *len = priv->icc_len - 14;
+ }
+}
+
+static void
+eog_metadata_reader_jpg_init_emr_iface (gpointer g_iface, gpointer iface_data)
+{
+ EogMetadataReaderInterface *iface;
+
+ iface = (EogMetadataReaderInterface*)g_iface;
+
+ iface->consume =
+ (void (*) (EogMetadataReader *self, const guchar *buf, guint len))
+ eog_metadata_reader_jpg_consume;
+ iface->finished =
+ (gboolean (*) (EogMetadataReader *self))
+ eog_metadata_reader_jpg_finished;
+ iface->get_raw_exif =
+ (void (*) (EogMetadataReader *self, guchar **data, guint *len))
+ eog_metadata_reader_jpg_get_exif_chunk;
+#ifdef HAVE_EXIF
+ iface->get_exif_data =
+ (gpointer (*) (EogMetadataReader *self))
+ eog_metadata_reader_jpg_get_exif_data;
+#endif
+ iface->get_icc_chunk =
+ (void (*) (EogMetadataReader *self, guchar **buf, guint *len))
+ eog_metadata_reader_jpg_get_icc_chunk;
+#ifdef HAVE_EXEMPI
+ iface->get_xmp_ptr =
+ (gpointer (*) (EogMetadataReader *self))
+ eog_metadata_reader_jpg_get_xmp_data;
+#endif
+}
+
Added: trunk/src/eog-metadata-reader-jpg.h
==============================================================================
--- (empty file)
+++ trunk/src/eog-metadata-reader-jpg.h Tue Mar 18 21:23:49 2008
@@ -0,0 +1,33 @@
+#ifndef _EOG_METADATA_READER_JPG_H_
+#define _EOG_METADATA_READER_JPG_H_
+
+G_BEGIN_DECLS
+
+#define EOG_TYPE_METADATA_READER_JPG (eog_metadata_reader_jpg_get_type ())
+#define EOG_METADATA_READER_JPG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EOG_TYPE_METADATA_READER_JPG, EogMetadataReaderJpg))
+#define EOG_METADATA_READER_JPG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EOG_TYPE_METADATA_READER_JPG, EogMetadataReaderJpgClass))
+#define EOG_IS_METADATA_READER_JPG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EOG_TYPE_METADATA_READER_JPG))
+#define EOG_IS_METADATA_READER_JPG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EOG_TYPE_METADATA_READER_JPG))
+#define EOG_METADATA_READER_JPG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EOG_TYPE_METADATA_READER_JPG, EogMetadataReaderJpgClass))
+
+typedef struct _EogMetadataReaderJpg EogMetadataReaderJpg;
+typedef struct _EogMetadataReaderJpgClass EogMetadataReaderJpgClass;
+typedef struct _EogMetadataReaderJpgPrivate EogMetadataReaderJpgPrivate;
+
+struct _EogMetadataReaderJpg {
+ GObject parent;
+
+ EogMetadataReaderJpgPrivate *priv;
+};
+
+struct _EogMetadataReaderJpgClass {
+ GObjectClass parent_klass;
+};
+
+GType eog_metadata_reader_jpg_get_type (void) G_GNUC_CONST;
+
+EogMetadataReaderJpg* eog_metadata_reader_jpg_new (EogMetadataFileType type);
+
+G_END_DECLS
+
+#endif /* _EOG_METADATA_READER_JPG_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]