libgimpbase: fix loading exif data from buffer

gimp_metadata_set_from_exif has special code for handling old-style
GIMP exif parasite data, but didn't check for the more common case
of loading exif data from image formats that can't be handled by exiv2.

The exif data in these formats usually start with the TIFF endian
markers instead of "Exif", which caused a failure to read this
metadata for e.g. EXR images, see issue #10903.

We change this function to check for "Exif" at the start of the data,
in which case we assume it to be the old-style exif parasite and in
that case add extra metadata as was previously always done.

In all other cases, we do not add extra metadata.
This commit is contained in:
Jacob Boerema 2024-03-07 13:03:12 -05:00
parent 0c6c3d5347
commit f00ad15b7b
1 changed files with 36 additions and 17 deletions

View File

@ -1332,10 +1332,11 @@ gimp_metadata_set_from_exif (GimpMetadata *metadata,
GError **error) GError **error)
{ {
GByteArray *exif_bytes; GByteArray *exif_bytes = NULL;
GimpMetadata *exif_metadata; GimpMetadata *exif_metadata;
guint8 data_size[2] = { 0, }; const guchar exif_marker[6] = "Exif\0\0";
const guint8 eoi[2] = { 0xff, 0xd9 }; const guchar *data;
gint data_length;
g_return_val_if_fail (GIMP_IS_METADATA (metadata), FALSE); g_return_val_if_fail (GIMP_IS_METADATA (metadata), FALSE);
g_return_val_if_fail (exif_data != NULL || exif_data_length == 0, FALSE); g_return_val_if_fail (exif_data != NULL || exif_data_length == 0, FALSE);
@ -1348,25 +1349,41 @@ gimp_metadata_set_from_exif (GimpMetadata *metadata,
return FALSE; return FALSE;
} }
data_size[0] = ((exif_data_length + 2) & 0xFF00) >> 8; /* Old GIMP exif parasite marker "Exif\0\0" needs special handling. */
data_size[1] = ((exif_data_length + 2) & 0x00FF); if (exif_data_length >= 6 &&
! memcmp (exif_marker, exif_data, sizeof(exif_marker)))
{
guint8 data_size[2] = { 0, };
const guint8 eoi[2] = { 0xff, 0xd9 };
exif_bytes = g_byte_array_new (); data_size[0] = ((exif_data_length + 2) & 0xFF00) >> 8;
exif_bytes = g_byte_array_append (exif_bytes, data_size[1] = ((exif_data_length + 2) & 0x00FF);
minimal_exif, G_N_ELEMENTS (minimal_exif));
exif_bytes = g_byte_array_append (exif_bytes, exif_bytes = g_byte_array_new ();
data_size, 2); exif_bytes = g_byte_array_append (exif_bytes,
exif_bytes = g_byte_array_append (exif_bytes, minimal_exif, G_N_ELEMENTS (minimal_exif));
(guint8 *) exif_data, exif_data_length); exif_bytes = g_byte_array_append (exif_bytes,
exif_bytes = g_byte_array_append (exif_bytes, eoi, 2); data_size, 2);
exif_bytes = g_byte_array_append (exif_bytes,
(guint8 *) exif_data, exif_data_length);
exif_bytes = g_byte_array_append (exif_bytes, eoi, 2);
data = exif_bytes->data;
data_length = exif_bytes->len;
}
else
{
data = exif_data;
data_length = exif_data_length;
}
exif_metadata = gimp_metadata_new (); exif_metadata = gimp_metadata_new ();
if (! gexiv2_metadata_open_buf (GEXIV2_METADATA (exif_metadata), if (! gexiv2_metadata_open_buf (GEXIV2_METADATA (exif_metadata),
exif_bytes->data, exif_bytes->len, error)) data, data_length, error))
{ {
g_object_unref (exif_metadata); g_object_unref (exif_metadata);
g_byte_array_free (exif_bytes, TRUE); if (exif_bytes)
g_byte_array_free (exif_bytes, TRUE);
return FALSE; return FALSE;
} }
@ -1375,13 +1392,15 @@ gimp_metadata_set_from_exif (GimpMetadata *metadata,
g_set_error (error, GIMP_METADATA_ERROR, 0, g_set_error (error, GIMP_METADATA_ERROR, 0,
_("Parsing Exif data failed.")); _("Parsing Exif data failed."));
g_object_unref (exif_metadata); g_object_unref (exif_metadata);
g_byte_array_free (exif_bytes, TRUE); if (exif_bytes)
g_byte_array_free (exif_bytes, TRUE);
return FALSE; return FALSE;
} }
gimp_metadata_add (exif_metadata, metadata); gimp_metadata_add (exif_metadata, metadata);
g_object_unref (exif_metadata); g_object_unref (exif_metadata);
g_byte_array_free (exif_bytes, TRUE); if (exif_bytes)
g_byte_array_free (exif_bytes, TRUE);
return TRUE; return TRUE;
} }