diff options
Diffstat (limited to 'plugins/FreeImage/Source/Metadata/IPTC.cpp')
| -rw-r--r-- | plugins/FreeImage/Source/Metadata/IPTC.cpp | 325 | 
1 files changed, 325 insertions, 0 deletions
diff --git a/plugins/FreeImage/Source/Metadata/IPTC.cpp b/plugins/FreeImage/Source/Metadata/IPTC.cpp new file mode 100644 index 0000000000..8bfb1b18c7 --- /dev/null +++ b/plugins/FreeImage/Source/Metadata/IPTC.cpp @@ -0,0 +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;
 +}
  | 
