Windows XP Explorer writes Title, Comment, Author, Metadata, Keywords,
authorJan Patera <patera@pictview.com>
Tue, 15 May 2007 18:23:28 +0000 (20:23 +0200)
committerJan Patera <patera@pictview.com>
Tue, 15 May 2007 18:23:28 +0000 (20:23 +0200)
and Subject metadata into proprietary UTF16-encoded tags 0x9c9b-0x9c9f
in IFD0. We now recognize them, exif_entry_get_value returns their value
converted to UTF8. BTW, Explorer corrupts makernote using offsets
relative to IFD0...

libexif/exif-entry.c
libexif/exif-tag.c
libexif/exif-tag.h
libexif/exif-utils.c
libexif/exif-utils.h

index cc05662..97fe743 100644 (file)
@@ -711,16 +711,16 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
                                                    (float) v_rat.denominator);
                break;
        case EXIF_TAG_APERTURE_VALUE:
-  case EXIF_TAG_MAX_APERTURE_VALUE:
+       case EXIF_TAG_MAX_APERTURE_VALUE:
                CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
                CC (e, 1, val, maxlen);
                v_rat = exif_get_rational (e->data, o);
                if (!v_rat.denominator) return val;
-    d = (double) v_rat.numerator / (double) v_rat.denominator;
-    snprintf (val, maxlen, _("%.02f EV"), d);
-    snprintf (b, sizeof (b), _(" (f/%.01f)"), pow (2, d / 2.));
-    if (maxlen > strlen (val) + strlen (b))
-      strncat (val, b, maxlen - strlen (val) - 1);
+               d = (double) v_rat.numerator / (double) v_rat.denominator;
+               snprintf (val, maxlen, _("%.02f EV"), d);
+               snprintf (b, sizeof (b), _(" (f/%.01f)"), pow (2, d / 2.));
+               if (maxlen > strlen (val) + strlen (b))
+                       strncat (val, b, maxlen - strlen (val) - 1);
                break;
        case EXIF_TAG_FOCAL_LENGTH:
                CF (e, EXIF_FORMAT_RATIONAL, val, maxlen);
@@ -785,8 +785,8 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
                CC (e, 1, val, maxlen);
                v_srat = exif_get_srational (e->data, o);
                if (!v_srat.denominator) return val;
-    d = (double) v_srat.numerator / (double) v_srat.denominator;
-    snprintf (val, maxlen, _("%.02f EV"), d);
+               d = (double) v_srat.numerator / (double) v_srat.denominator;
+               snprintf (val, maxlen, _("%.02f EV"), d);
                snprintf (b, sizeof (b), " (APEX: %i)", (int) pow (sqrt(2), d));
                if (maxlen > strlen (val) + strlen (b))
                        strncat (val, b, maxlen - strlen (val) - 1);
@@ -804,13 +804,13 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
                CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen);
                CC (e, 1, val, maxlen);
                v_srat = exif_get_srational (e->data, o);
-    if (!v_srat.denominator) return val;
-    d = (double) v_srat.numerator / (double) v_srat.denominator;
-    snprintf (val, maxlen, _("%.02f EV"), d);
-    snprintf (b, sizeof (b), _(" (%.02f cd/m^2)"),
-        1. / (M_PI * 0.3048 * 0.3048) * pow (2, d));
-    if (maxlen > strlen (val) + strlen (b))
-      strncat (val, b, maxlen - strlen (val) - 1);
+               if (!v_srat.denominator) return val;
+               d = (double) v_srat.numerator / (double) v_srat.denominator;
+               snprintf (val, maxlen, _("%.02f EV"), d);
+               snprintf (b, sizeof (b), _(" (%.02f cd/m^2)"),
+                       1. / (M_PI * 0.3048 * 0.3048) * pow (2, d));
+               if (maxlen > strlen (val) + strlen (b))
+                       strncat (val, b, maxlen - strlen (val) - 1);
                break;
        case EXIF_TAG_FILE_SOURCE:
                CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen);
@@ -843,8 +843,8 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
                CC (e, 1, val, maxlen);
                v_srat = exif_get_srational (e->data, o);
                if (!v_srat.denominator) return val;
-    d = (double) v_srat.numerator / (double) v_srat.denominator;
-    snprintf (val, maxlen, _("%.02f EV"), d);
+               d = (double) v_srat.numerator / (double) v_srat.denominator;
+               snprintf (val, maxlen, _("%.02f EV"), d);
                break;
        case EXIF_TAG_YCBCR_SUB_SAMPLING:
                CF (e, EXIF_FORMAT_SHORT, val, maxlen);
@@ -967,7 +967,15 @@ exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen)
                        snprintf (val, maxlen, "%i", v_short);
                else
                        strncpy (val, _(list[i].strings[j]), maxlen - 1);
-               break;  
+               break;
+       case EXIF_TAG_XP_TITLE:
+       case EXIF_TAG_XP_COMMENT:
+       case EXIF_TAG_XP_AUTHOR:
+       case EXIF_TAG_XP_KEYWORDS:
+       case EXIF_TAG_XP_SUBJECT:
+               /* Warning! The texts are converted from UTF16 to UTF8 */
+               exif_convert_utf16_to_utf8(val, (unsigned short*)e->data, MIN(maxlen, e->size));
+               break;
        case EXIF_TAG_INTEROPERABILITY_VERSION:
                if (e->format == EXIF_FORMAT_UNDEFINED) {
                        strncpy (val, (char *) e->data, MIN (maxlen, e->size));
index d283fbb..6115c59 100644 (file)
@@ -486,6 +486,16 @@ static struct {
         N_("A tag used to record fractions of seconds for the "
            "<DateTimeDigitized> tag."),
         { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } },
+       {EXIF_TAG_XP_TITLE, "XPTitle", N_("XP Title"), "",
+        { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } },
+       {EXIF_TAG_XP_COMMENT, "XPComment", N_("XP Comment"), "",
+        { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } },
+       {EXIF_TAG_XP_AUTHOR, "XPAuthor", N_("XP Author"), "",
+        { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } },
+       {EXIF_TAG_XP_KEYWORDS, "XPKeywords", N_("XP Keywords"), "",
+        { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } },
+       {EXIF_TAG_XP_SUBJECT, "XPSubject", N_("XP Subject"), "",
+        { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } },
        {EXIF_TAG_FLASH_PIX_VERSION, "FlashPixVersion", "FlashPixVersion",
         N_("The FlashPix format version supported by a FPXR file."),
         { ESL_NNNN, ESL_NNNN, ESL_MMMM, ESL_NNNN, ESL_NNNN } },
index 9f0903b..a99a085 100644 (file)
@@ -107,6 +107,11 @@ typedef enum {
        EXIF_TAG_SUB_SEC_TIME                   = 0x9290,
        EXIF_TAG_SUB_SEC_TIME_ORIGINAL          = 0x9291,
        EXIF_TAG_SUB_SEC_TIME_DIGITIZED         = 0x9292,
+       EXIF_TAG_XP_TITLE                       = 0x9c9b,
+       EXIF_TAG_XP_COMMENT                     = 0x9c9c,
+       EXIF_TAG_XP_AUTHOR                      = 0x9c9d,
+       EXIF_TAG_XP_KEYWORDS                    = 0x9c9e,
+       EXIF_TAG_XP_SUBJECT                     = 0x9c9f,
        EXIF_TAG_FLASH_PIX_VERSION              = 0xa000,
        EXIF_TAG_COLOR_SPACE                    = 0xa001,
        EXIF_TAG_PIXEL_X_DIMENSION              = 0xa002,
index 9386012..bdcbef7 100644 (file)
@@ -212,3 +212,40 @@ exif_set_srational (unsigned char *buf, ExifByteOrder order,
        exif_set_slong (buf, order, value.numerator);
        exif_set_slong (buf + 4, order, value.denominator);
 }
+
+void
+exif_convert_utf16_to_utf8 (char *out, const unsigned short *in, int maxlen)
+{
+       /* This function converts rather UCS2 than UTF16 to UTF8 */
+       if (maxlen <= 0) {
+               return;
+       }
+       while (*in) {
+               if (*in < 0x80) {
+                       if (maxlen > 1) {
+                               *out++ = (char)*in++;
+                               maxlen--;
+                       } else {
+                               break;
+                       }
+               } else if (*in < 0x800) {
+                       if (maxlen > 2) {
+                               *out++ = ((*in >> 6) & 0x1F) | 0xC0;
+                               *out++ = (*in++ & 0x3F) | 0x80;
+                               maxlen -= 2;
+                       } else {
+                               break;
+                       }
+               } else {
+                       if (maxlen > 2) {
+                               *out++ = ((*in >> 12) & 0x0F) | 0xE0;
+                               *out++ = ((*in >> 6) & 0x3F) | 0x80;
+                               *out++ = (*in++ & 0x3F) | 0x80;
+                               maxlen -= 3;
+                       } else {
+                               break;
+                       }
+               }
+       }
+       *out = 0;
+}
\ No newline at end of file
index d621e32..06fb278 100644 (file)
@@ -65,6 +65,8 @@ void exif_set_rational  (unsigned char *b, ExifByteOrder order,
 void exif_set_srational (unsigned char *b, ExifByteOrder order,
                         ExifSRational value);
 
+void exif_convert_utf16_to_utf8 (char *out, const unsigned short *in, int maxlen);
+
 /* Please do not use this function outside of the library. */
 void exif_array_set_byte_order (ExifFormat, unsigned char *, unsigned int,
                ExifByteOrder o_orig, ExifByteOrder o_new);