// Returns true on success and false for memory errors and corrupt profiles. // The caller must use MetadataFree() on 'metadata' in all cases. static int ExtractMetadataFromJPEG(j_decompress_ptr dinfo, Metadata* const metadata) { static const struct { int marker; const char* signature; size_t signature_length; size_t storage_offset; } kJPEGMetadataMap[] = { // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ... { JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif) }, // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG // TODO(jzern) Add support for 'ExtendedXMP' { JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp) }, { 0, NULL, 0, 0 }, }; jpeg_saved_marker_ptr marker; // Treat ICC profiles separately as they may be segmented and out of order. if (!StoreICCP(dinfo, &metadata->iccp)) return 0; for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) { int i; for (i = 0; kJPEGMetadataMap[i].marker != 0; ++i) { if (marker->marker == kJPEGMetadataMap[i].marker && marker->data_length > kJPEGMetadataMap[i].signature_length && !memcmp(marker->data, kJPEGMetadataMap[i].signature, kJPEGMetadataMap[i].signature_length)) { MetadataPayload* const payload = (MetadataPayload*)((uint8_t*)metadata + kJPEGMetadataMap[i].storage_offset); if (payload->bytes == NULL) { const char* marker_data = (const char*)marker->data + kJPEGMetadataMap[i].signature_length; const size_t marker_data_length = marker->data_length - kJPEGMetadataMap[i].signature_length; if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0; } else { fprintf(stderr, "Ignoring additional '%s' marker\n", kJPEGMetadataMap[i].signature); } } } } return 1; }
// 'end' now points to the profile payload. payload->bytes = HexStringToBytes(end, expected_length); if (payload->bytes == NULL) return 0; payload->size = expected_length; return 1; } static const struct { const char* name; int (*process)(const char* profile, size_t profile_len, MetadataPayload* const payload); size_t storage_offset; } kPNGMetadataMap[] = { // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData // See also: ExifTool on CPAN. { "Raw profile type exif", ProcessRawProfile, METADATA_OFFSET(exif) }, { "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) }, // Exiftool puts exif data in APP1 chunk, too. { "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) }, // XMP Specification Part 3, Section 3 #PNG { "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) }, { NULL, NULL, 0 }, }; // Looks for metadata at both the beginning and end of the PNG file, giving // preference to the head. // Returns true on success. The caller must use MetadataFree() on 'metadata' in // all cases. static int ExtractMetadataFromPNG(png_structp png, png_infop const head_info, png_infop const end_info,
#include "webp/config.h" #endif #include <stdio.h> #ifdef WEBP_HAVE_TIFF #include <tiffio.h> #include "webp/encode.h" #include "./metadata.h" static const struct { ttag_t tag; size_t storage_offset; } kTIFFMetadataMap[] = { { TIFFTAG_ICCPROFILE, METADATA_OFFSET(iccp) }, { TIFFTAG_XMLPACKET, METADATA_OFFSET(xmp) }, { 0, 0 }, }; // Returns true on success. The caller must use MetadataFree() on 'metadata' in // all cases. static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) { int i; toff_t exif_ifd_offset; for (i = 0; kTIFFMetadataMap[i].tag != 0; ++i) { MetadataPayload* const payload = (MetadataPayload*)((uint8_t*)metadata + kTIFFMetadataMap[i].storage_offset); void* tag_data;