diff options
Diffstat (limited to 'plugins/FreeImage/Source/Metadata/IPTC.cpp')
-rw-r--r-- | plugins/FreeImage/Source/Metadata/IPTC.cpp | 650 |
1 files changed, 325 insertions, 325 deletions
diff --git a/plugins/FreeImage/Source/Metadata/IPTC.cpp b/plugins/FreeImage/Source/Metadata/IPTC.cpp index 8bfb1b18c7..1aba46c094 100644 --- a/plugins/FreeImage/Source/Metadata/IPTC.cpp +++ b/plugins/FreeImage/Source/Metadata/IPTC.cpp @@ -1,325 +1,325 @@ -// ==========================================================
-// Metadata functions implementation
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// This file is part of FreeImage 3
-//
-// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
-// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
-// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
-// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
-// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
-// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
-// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
-// THIS DISCLAIMER.
-//
-// Use at your own risk!
-// ==========================================================
-
-#ifdef _MSC_VER
-#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
-#endif
-
-#include "FreeImage.h"
-#include "Utilities.h"
-#include "FreeImageTag.h"
-
-// ----------------------------------------------------------
-// IPTC JPEG / TIFF markers routines
-// ----------------------------------------------------------
-
-static const char* IPTC_DELIMITER = ";"; // keywords/supplemental category delimiter
-/**
- Read and decode IPTC binary data
-*/
-BOOL
-read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
- char defaultKey[16];
- size_t length = datalen;
- BYTE *profile = (BYTE*)dataptr;
-
- std::string Keywords;
- std::string SupplementalCategory;
-
- WORD tag_id;
-
- if(!dataptr || (datalen == 0)) {
- return FALSE;
- }
-
- // create a tag
-
- FITAG *tag = FreeImage_CreateTag();
-
- TagLib& tag_lib = TagLib::instance();
-
- // find start of the BIM portion of the binary data
- size_t offset = 0;
- while(offset < length - 1) {
- if((profile[offset] == 0x1C) && (profile[offset+1] == 0x02))
- break;
- offset++;
- }
-
- // for each tag
- while (offset < length) {
-
- // identifies start of a tag
- if (profile[offset] != 0x1c) {
- break;
- }
- // we need at least five bytes left to read a tag
- if ((offset + 5) >= length) {
- break;
- }
-
- offset++;
-
- int directoryType = profile[offset++];
- int tagType = profile[offset++];;
- int tagByteCount = ((profile[offset] & 0xFF) << 8) | (profile[offset + 1] & 0xFF);
- offset += 2;
-
- if ((offset + tagByteCount) > length) {
- // data for tag extends beyond end of iptc segment
- break;
- }
-
- // process the tag
-
- tag_id = (WORD)(tagType | (directoryType << 8));
-
- FreeImage_SetTagID(tag, tag_id);
- FreeImage_SetTagLength(tag, tagByteCount);
-
- // allocate a buffer to store the tag value
- BYTE *iptc_value = (BYTE*)malloc((tagByteCount + 1) * sizeof(BYTE));
- memset(iptc_value, 0, (tagByteCount + 1) * sizeof(BYTE));
-
- // get the tag value
-
- switch (tag_id) {
- case TAG_RECORD_VERSION:
- {
- // short
- FreeImage_SetTagType(tag, FIDT_SSHORT);
- FreeImage_SetTagCount(tag, 1);
- short *pvalue = (short*)&iptc_value[0];
- *pvalue = (short)((profile[offset] << 8) | profile[offset + 1]);
- FreeImage_SetTagValue(tag, pvalue);
- break;
- }
-
- case TAG_RELEASE_DATE:
- case TAG_DATE_CREATED:
- // Date object
- case TAG_RELEASE_TIME:
- case TAG_TIME_CREATED:
- // time
- default:
- {
- // string
- FreeImage_SetTagType(tag, FIDT_ASCII);
- FreeImage_SetTagCount(tag, tagByteCount);
- for(int i = 0; i < tagByteCount; i++) {
- iptc_value[i] = profile[offset + i];
- }
- iptc_value[tagByteCount] = '\0';
- FreeImage_SetTagValue(tag, (char*)&iptc_value[0]);
- break;
- }
- }
-
- if(tag_id == TAG_SUPPLEMENTAL_CATEGORIES) {
- // concatenate the categories
- if(SupplementalCategory.length() == 0) {
- SupplementalCategory.append((char*)iptc_value);
- } else {
- SupplementalCategory.append(IPTC_DELIMITER);
- SupplementalCategory.append((char*)iptc_value);
- }
- }
- else if(tag_id == TAG_KEYWORDS) {
- // concatenate the keywords
- if(Keywords.length() == 0) {
- Keywords.append((char*)iptc_value);
- } else {
- Keywords.append(IPTC_DELIMITER);
- Keywords.append((char*)iptc_value);
- }
- }
- else {
- // get the tag key and description
- const char *key = tag_lib.getTagFieldName(TagLib::IPTC, tag_id, defaultKey);
- FreeImage_SetTagKey(tag, key);
- const char *description = tag_lib.getTagDescription(TagLib::IPTC, tag_id);
- FreeImage_SetTagDescription(tag, description);
-
- // store the tag
- if(key) {
- FreeImage_SetMetadata(FIMD_IPTC, dib, key, tag);
- }
- }
-
- free(iptc_value);
-
- // next tag
- offset += tagByteCount;
-
- }
-
- // store the 'keywords' tag
- if(Keywords.length()) {
- FreeImage_SetTagType(tag, FIDT_ASCII);
- FreeImage_SetTagID(tag, TAG_KEYWORDS);
- FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::IPTC, TAG_KEYWORDS, defaultKey));
- FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::IPTC, TAG_KEYWORDS));
- FreeImage_SetTagLength(tag, (DWORD)Keywords.length());
- FreeImage_SetTagCount(tag, (DWORD)Keywords.length());
- FreeImage_SetTagValue(tag, (char*)Keywords.c_str());
- FreeImage_SetMetadata(FIMD_IPTC, dib, FreeImage_GetTagKey(tag), tag);
- }
-
- // store the 'supplemental category' tag
- if(SupplementalCategory.length()) {
- FreeImage_SetTagType(tag, FIDT_ASCII);
- FreeImage_SetTagID(tag, TAG_SUPPLEMENTAL_CATEGORIES);
- FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::IPTC, TAG_SUPPLEMENTAL_CATEGORIES, defaultKey));
- FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::IPTC, TAG_SUPPLEMENTAL_CATEGORIES));
- FreeImage_SetTagLength(tag, (DWORD)SupplementalCategory.length());
- FreeImage_SetTagCount(tag, (DWORD)SupplementalCategory.length());
- FreeImage_SetTagValue(tag, (char*)SupplementalCategory.c_str());
- FreeImage_SetMetadata(FIMD_IPTC, dib, FreeImage_GetTagKey(tag), tag);
- }
-
- // delete the tag
-
- FreeImage_DeleteTag(tag);
-
- return TRUE;
-}
-
-// --------------------------------------------------------------------------
-
-static BYTE*
-append_iptc_tag(BYTE *profile, unsigned *profile_size, WORD id, DWORD length, const void *value) {
- BYTE *buffer = NULL;
-
- // calculate the new buffer size
- size_t buffer_size = (5 + *profile_size + length) * sizeof(BYTE);
- buffer = (BYTE*)malloc(buffer_size);
- if(!buffer)
- return NULL;
-
- // add the header
- buffer[0] = 0x1C;
- buffer[1] = 0x02;
- // add the tag type
- buffer[2] = (BYTE)(id & 0x00FF);
- // add the tag length
- buffer[3] = (BYTE)(length >> 8);
- buffer[4] = (BYTE)(length & 0xFF);
- // add the tag value
- memcpy(buffer + 5, (BYTE*)value, length);
- // append the previous profile
- if(NULL == profile) {
- *profile_size = (5 + length);
- }
- else {
- memcpy(buffer + 5 + length, profile, *profile_size);
- *profile_size += (5 + length);
- free(profile);
- }
-
- return buffer;
-}
-
-/**
-Encode IPTC metadata into a binary buffer.
-The buffer is allocated by the function and must be freed by the caller.
-*/
-BOOL
-write_iptc_profile(FIBITMAP *dib, BYTE **profile, unsigned *profile_size) {
- FITAG *tag = NULL;
- FIMETADATA *mdhandle = NULL;
-
- BYTE *buffer = NULL;
- unsigned buffer_size = 0;
-
- // parse all IPTC tags and rebuild a IPTC profile
- mdhandle = FreeImage_FindFirstMetadata(FIMD_IPTC, dib, &tag);
-
- if(mdhandle) {
- do {
- WORD tag_id = FreeImage_GetTagID(tag);
-
- // append the tag to the profile
-
- switch(tag_id) {
- case TAG_RECORD_VERSION:
- // ignore (already handled)
- break;
-
- case TAG_SUPPLEMENTAL_CATEGORIES:
- case TAG_KEYWORDS:
- if(FreeImage_GetTagType(tag) == FIDT_ASCII) {
- std::string value = (const char*)FreeImage_GetTagValue(tag);
-
- // split the tag value
- std::vector<std::string> output;
- std::string delimiter = IPTC_DELIMITER;
-
- size_t offset = 0;
- size_t delimiterIndex = 0;
-
- delimiterIndex = value.find(delimiter, offset);
- while (delimiterIndex != std::string::npos) {
- output.push_back(value.substr(offset, delimiterIndex - offset));
- offset += delimiterIndex - offset + delimiter.length();
- delimiterIndex = value.find(delimiter, offset);
- }
- output.push_back(value.substr(offset));
-
- // add as many tags as there are comma separated strings
- for(int i = 0; i < (int)output.size(); i++) {
- std::string& tag_value = output[i];
- buffer = append_iptc_tag(buffer, &buffer_size, tag_id, (DWORD)tag_value.length(), tag_value.c_str());
- }
-
- }
- break;
-
- case TAG_URGENCY:
- if(FreeImage_GetTagType(tag) == FIDT_ASCII) {
- DWORD length = 1; // keep the first octet only
- buffer = append_iptc_tag(buffer, &buffer_size, tag_id, length, FreeImage_GetTagValue(tag));
- }
- break;
-
- default:
- if(FreeImage_GetTagType(tag) == FIDT_ASCII) {
- DWORD length = FreeImage_GetTagLength(tag);
- buffer = append_iptc_tag(buffer, &buffer_size, tag_id, length, FreeImage_GetTagValue(tag));
- }
- break;
- }
-
- } while(FreeImage_FindNextMetadata(mdhandle, &tag));
-
- FreeImage_FindCloseMetadata(mdhandle);
-
- // add the DirectoryVersion tag
- const short version = 0x0200;
- buffer = append_iptc_tag(buffer, &buffer_size, TAG_RECORD_VERSION, sizeof(version), &version);
-
- *profile = buffer;
- *profile_size = buffer_size;
-
- return TRUE;
- }
-
- return FALSE;
-}
+// ========================================================== +// Metadata functions implementation +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifdef _MSC_VER +#pragma warning (disable : 4786) // identifier was truncated to 'number' characters +#endif + +#include "FreeImage.h" +#include "Utilities.h" +#include "FreeImageTag.h" + +// ---------------------------------------------------------- +// IPTC JPEG / TIFF markers routines +// ---------------------------------------------------------- + +static const char* IPTC_DELIMITER = ";"; // keywords/supplemental category delimiter +/** + Read and decode IPTC binary data +*/ +BOOL +read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) { + char defaultKey[16]; + size_t length = datalen; + BYTE *profile = (BYTE*)dataptr; + + std::string Keywords; + std::string SupplementalCategory; + + WORD tag_id; + + if(!dataptr || (datalen == 0)) { + return FALSE; + } + + // create a tag + + FITAG *tag = FreeImage_CreateTag(); + + TagLib& tag_lib = TagLib::instance(); + + // find start of the BIM portion of the binary data + size_t offset = 0; + while(offset < length - 1) { + if((profile[offset] == 0x1C) && (profile[offset+1] == 0x02)) + break; + offset++; + } + + // for each tag + while (offset < length) { + + // identifies start of a tag + if (profile[offset] != 0x1c) { + break; + } + // we need at least five bytes left to read a tag + if ((offset + 5) >= length) { + break; + } + + offset++; + + int directoryType = profile[offset++]; + int tagType = profile[offset++];; + int tagByteCount = ((profile[offset] & 0xFF) << 8) | (profile[offset + 1] & 0xFF); + offset += 2; + + if ((offset + tagByteCount) > length) { + // data for tag extends beyond end of iptc segment + break; + } + + // process the tag + + tag_id = (WORD)(tagType | (directoryType << 8)); + + FreeImage_SetTagID(tag, tag_id); + FreeImage_SetTagLength(tag, tagByteCount); + + // allocate a buffer to store the tag value + BYTE *iptc_value = (BYTE*)malloc((tagByteCount + 1) * sizeof(BYTE)); + memset(iptc_value, 0, (tagByteCount + 1) * sizeof(BYTE)); + + // get the tag value + + switch (tag_id) { + case TAG_RECORD_VERSION: + { + // short + FreeImage_SetTagType(tag, FIDT_SSHORT); + FreeImage_SetTagCount(tag, 1); + short *pvalue = (short*)&iptc_value[0]; + *pvalue = (short)((profile[offset] << 8) | profile[offset + 1]); + FreeImage_SetTagValue(tag, pvalue); + break; + } + + case TAG_RELEASE_DATE: + case TAG_DATE_CREATED: + // Date object + case TAG_RELEASE_TIME: + case TAG_TIME_CREATED: + // time + default: + { + // string + FreeImage_SetTagType(tag, FIDT_ASCII); + FreeImage_SetTagCount(tag, tagByteCount); + for(int i = 0; i < tagByteCount; i++) { + iptc_value[i] = profile[offset + i]; + } + iptc_value[tagByteCount] = '\0'; + FreeImage_SetTagValue(tag, (char*)&iptc_value[0]); + break; + } + } + + if(tag_id == TAG_SUPPLEMENTAL_CATEGORIES) { + // concatenate the categories + if(SupplementalCategory.length() == 0) { + SupplementalCategory.append((char*)iptc_value); + } else { + SupplementalCategory.append(IPTC_DELIMITER); + SupplementalCategory.append((char*)iptc_value); + } + } + else if(tag_id == TAG_KEYWORDS) { + // concatenate the keywords + if(Keywords.length() == 0) { + Keywords.append((char*)iptc_value); + } else { + Keywords.append(IPTC_DELIMITER); + Keywords.append((char*)iptc_value); + } + } + else { + // get the tag key and description + const char *key = tag_lib.getTagFieldName(TagLib::IPTC, tag_id, defaultKey); + FreeImage_SetTagKey(tag, key); + const char *description = tag_lib.getTagDescription(TagLib::IPTC, tag_id); + FreeImage_SetTagDescription(tag, description); + + // store the tag + if(key) { + FreeImage_SetMetadata(FIMD_IPTC, dib, key, tag); + } + } + + free(iptc_value); + + // next tag + offset += tagByteCount; + + } + + // store the 'keywords' tag + if(Keywords.length()) { + FreeImage_SetTagType(tag, FIDT_ASCII); + FreeImage_SetTagID(tag, TAG_KEYWORDS); + FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::IPTC, TAG_KEYWORDS, defaultKey)); + FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::IPTC, TAG_KEYWORDS)); + FreeImage_SetTagLength(tag, (DWORD)Keywords.length()); + FreeImage_SetTagCount(tag, (DWORD)Keywords.length()); + FreeImage_SetTagValue(tag, (char*)Keywords.c_str()); + FreeImage_SetMetadata(FIMD_IPTC, dib, FreeImage_GetTagKey(tag), tag); + } + + // store the 'supplemental category' tag + if(SupplementalCategory.length()) { + FreeImage_SetTagType(tag, FIDT_ASCII); + FreeImage_SetTagID(tag, TAG_SUPPLEMENTAL_CATEGORIES); + FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::IPTC, TAG_SUPPLEMENTAL_CATEGORIES, defaultKey)); + FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::IPTC, TAG_SUPPLEMENTAL_CATEGORIES)); + FreeImage_SetTagLength(tag, (DWORD)SupplementalCategory.length()); + FreeImage_SetTagCount(tag, (DWORD)SupplementalCategory.length()); + FreeImage_SetTagValue(tag, (char*)SupplementalCategory.c_str()); + FreeImage_SetMetadata(FIMD_IPTC, dib, FreeImage_GetTagKey(tag), tag); + } + + // delete the tag + + FreeImage_DeleteTag(tag); + + return TRUE; +} + +// -------------------------------------------------------------------------- + +static BYTE* +append_iptc_tag(BYTE *profile, unsigned *profile_size, WORD id, DWORD length, const void *value) { + BYTE *buffer = NULL; + + // calculate the new buffer size + size_t buffer_size = (5 + *profile_size + length) * sizeof(BYTE); + buffer = (BYTE*)malloc(buffer_size); + if(!buffer) + return NULL; + + // add the header + buffer[0] = 0x1C; + buffer[1] = 0x02; + // add the tag type + buffer[2] = (BYTE)(id & 0x00FF); + // add the tag length + buffer[3] = (BYTE)(length >> 8); + buffer[4] = (BYTE)(length & 0xFF); + // add the tag value + memcpy(buffer + 5, (BYTE*)value, length); + // append the previous profile + if(NULL == profile) { + *profile_size = (5 + length); + } + else { + memcpy(buffer + 5 + length, profile, *profile_size); + *profile_size += (5 + length); + free(profile); + } + + return buffer; +} + +/** +Encode IPTC metadata into a binary buffer. +The buffer is allocated by the function and must be freed by the caller. +*/ +BOOL +write_iptc_profile(FIBITMAP *dib, BYTE **profile, unsigned *profile_size) { + FITAG *tag = NULL; + FIMETADATA *mdhandle = NULL; + + BYTE *buffer = NULL; + unsigned buffer_size = 0; + + // parse all IPTC tags and rebuild a IPTC profile + mdhandle = FreeImage_FindFirstMetadata(FIMD_IPTC, dib, &tag); + + if(mdhandle) { + do { + WORD tag_id = FreeImage_GetTagID(tag); + + // append the tag to the profile + + switch(tag_id) { + case TAG_RECORD_VERSION: + // ignore (already handled) + break; + + case TAG_SUPPLEMENTAL_CATEGORIES: + case TAG_KEYWORDS: + if(FreeImage_GetTagType(tag) == FIDT_ASCII) { + std::string value = (const char*)FreeImage_GetTagValue(tag); + + // split the tag value + std::vector<std::string> output; + std::string delimiter = IPTC_DELIMITER; + + size_t offset = 0; + size_t delimiterIndex = 0; + + delimiterIndex = value.find(delimiter, offset); + while (delimiterIndex != std::string::npos) { + output.push_back(value.substr(offset, delimiterIndex - offset)); + offset += delimiterIndex - offset + delimiter.length(); + delimiterIndex = value.find(delimiter, offset); + } + output.push_back(value.substr(offset)); + + // add as many tags as there are comma separated strings + for(int i = 0; i < (int)output.size(); i++) { + std::string& tag_value = output[i]; + buffer = append_iptc_tag(buffer, &buffer_size, tag_id, (DWORD)tag_value.length(), tag_value.c_str()); + } + + } + break; + + case TAG_URGENCY: + if(FreeImage_GetTagType(tag) == FIDT_ASCII) { + DWORD length = 1; // keep the first octet only + buffer = append_iptc_tag(buffer, &buffer_size, tag_id, length, FreeImage_GetTagValue(tag)); + } + break; + + default: + if(FreeImage_GetTagType(tag) == FIDT_ASCII) { + DWORD length = FreeImage_GetTagLength(tag); + buffer = append_iptc_tag(buffer, &buffer_size, tag_id, length, FreeImage_GetTagValue(tag)); + } + break; + } + + } while(FreeImage_FindNextMetadata(mdhandle, &tag)); + + FreeImage_FindCloseMetadata(mdhandle); + + // add the DirectoryVersion tag + const short version = 0x0200; + buffer = append_iptc_tag(buffer, &buffer_size, TAG_RECORD_VERSION, sizeof(version), &version); + + *profile = buffer; + *profile_size = buffer_size; + + return TRUE; + } + + return FALSE; +} |