Esempio n. 1
0
// ------------------------------------------------------------
//   Keep original size info when using scale option on loading
// ------------------------------------------------------------
static void 
store_size_info(FIBITMAP *dib, JDIMENSION width, JDIMENSION height) {
	char buffer[256];
	// create a tag
	FITAG *tag = FreeImage_CreateTag();
	if(tag) {
		size_t length = 0;
		// set the original width
		sprintf(buffer, "%d", (int)width);
		length = strlen(buffer) + 1;	// include the NULL/0 value
		FreeImage_SetTagKey(tag, "OriginalJPEGWidth");
		FreeImage_SetTagLength(tag, (DWORD)length);
		FreeImage_SetTagCount(tag, (DWORD)length);
		FreeImage_SetTagType(tag, FIDT_ASCII);
		FreeImage_SetTagValue(tag, buffer);
		FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
		// set the original height
		sprintf(buffer, "%d", (int)height);
		length = strlen(buffer) + 1;	// include the NULL/0 value
		FreeImage_SetTagKey(tag, "OriginalJPEGHeight");
		FreeImage_SetTagLength(tag, (DWORD)length);
		FreeImage_SetTagCount(tag, (DWORD)length);
		FreeImage_SetTagType(tag, FIDT_ASCII);
		FreeImage_SetTagValue(tag, buffer);
		FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
		// destroy the tag
		FreeImage_DeleteTag(tag);
	}
}
Esempio n. 2
0
/**
Read JPEG_APP1 marker (Exif profile)
@param dib Input FIBITMAP
@param dataptr Pointer to the APP1 marker
@param datalen APP1 marker length
@return Returns TRUE if successful, FALSE otherwise
*/
BOOL  
jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned length) {
    // marker identifying string for Exif = "Exif\0\0"
    BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };

	// verify the identifying string
	if(memcmp(exif_signature, profile, sizeof(exif_signature)) != 0) {
		// not an Exif profile
		return FALSE;
	}

	// create a tag
	FITAG *tag = FreeImage_CreateTag();
	if(tag) {
		FreeImage_SetTagKey(tag, g_TagLib_ExifRawFieldName);
		FreeImage_SetTagLength(tag, (DWORD)length);
		FreeImage_SetTagCount(tag, (DWORD)length);
		FreeImage_SetTagType(tag, FIDT_BYTE);
		FreeImage_SetTagValue(tag, profile);

		// store the tag
		FreeImage_SetMetadata(FIMD_EXIF_RAW, dib, FreeImage_GetTagKey(tag), tag);

		// destroy the tag
		FreeImage_DeleteTag(tag);

		return TRUE;
	}

	return FALSE;
}
void FreeImageGifData::add24bitBGRDataPage(int width, int height, BYTE* pData)
{
    FIBITMAP* newBitmap = FreeImage_Allocate(width, height, 24, 0x0000FF, 0x00FF00, 0xFF0000);
    BYTE* bitmapData = FreeImage_GetBits(newBitmap);
    memcpy(bitmapData, pData, width * height * 3);
    
    //Set metadata
    FIBITMAP* convBitmap = FreeImage_ColorQuantizeEx(newBitmap, FIQ_WUQUANT, 256);

    FITAG* delayTag = FreeImage_CreateTag();
    
    FreeImage_SetMetadata(FIMD_ANIMATION, convBitmap, NULL, NULL);

    LONG delayVal = 20;
    if (delayTag) {
        FreeImage_SetTagKey(delayTag, "FrameTime");
        FreeImage_SetTagType(delayTag, FIDT_LONG);
        FreeImage_SetTagCount(delayTag, 1);
        FreeImage_SetTagLength(delayTag, 4);
        FreeImage_SetTagValue(delayTag, &delayVal);
        FreeImage_SetMetadata(FIMD_ANIMATION, convBitmap, FreeImage_GetTagKey(delayTag), delayTag);
        FreeImage_DeleteTag(delayTag);
    }

    FreeImage_AppendPage(m_gifHandle, convBitmap);
    
    int pCount = FreeImage_GetPageCount(m_gifHandle);
    FreeImage_Unload(newBitmap);
    FreeImage_Unload(convBitmap);
}
Esempio n. 4
0
/**
   Build and set a FITAG whose type is FIDT_ASCII.
   The tag must be destroyed by the caller using FreeImage_DeleteTag.
   @param model Metadata model to be filled
   @param dib Image to be filled
   @param key Tag key
   @param value Tag value
   @return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL
mng_SetKeyValue(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, const char *value) {
    if(!dib || !key || !value) {
        return FALSE;
    }
    // create a tag
    FITAG *tag = FreeImage_CreateTag();
    if(tag) {
        BOOL bSuccess = TRUE;
        // fill the tag
        DWORD tag_length = (DWORD)(strlen(value) + 1);
        bSuccess &= FreeImage_SetTagKey(tag, key);
        bSuccess &= FreeImage_SetTagLength(tag, tag_length);
        bSuccess &= FreeImage_SetTagCount(tag, tag_length);
        bSuccess &= FreeImage_SetTagType(tag, FIDT_ASCII);
        bSuccess &= FreeImage_SetTagValue(tag, value);
        if(bSuccess) {
            // set the tag
            FreeImage_SetMetadata(model, dib, FreeImage_GetTagKey(tag), tag);
        }
        FreeImage_DeleteTag(tag);
        return bSuccess;
    }

    return FALSE;
}
Esempio n. 5
0
/**
	Read JPEG_COM marker (comment)
*/
static BOOL 
jpeg_read_comment(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
	size_t length = datalen;
	BYTE *profile = (BYTE*)dataptr;

	// read the comment
	char *value = (char*)malloc((length + 1) * sizeof(char));
	if(value == NULL) return FALSE;
	memcpy(value, profile, length);
	value[length] = '\0';

	// create a tag
	FITAG *tag = FreeImage_CreateTag();
	if(tag) {
		unsigned int count = (unsigned int)length + 1;	// includes the null value

		FreeImage_SetTagID(tag, JPEG_COM);
		FreeImage_SetTagKey(tag, "Comment");
		FreeImage_SetTagLength(tag, count);
		FreeImage_SetTagCount(tag, count);
		FreeImage_SetTagType(tag, FIDT_ASCII);
		FreeImage_SetTagValue(tag, value);
		
		// store the tag
		FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);

		// destroy the tag
		FreeImage_DeleteTag(tag);
	}

	free(value);

	return TRUE;
}
Esempio n. 6
0
void ofxGifEncoder::doSave() {
	// create a multipage bitmap
	FIMULTIBITMAP *multi = FreeImage_OpenMultiBitmap(FIF_GIF, ofToDataPath(fileName).c_str(), TRUE, FALSE); 
	FIBITMAP * bmp = NULL;
	
	for(int i = 0; i < frames.size(); i++ ) { 
		// we need to swap the channels if we're on little endian (see ofImage::swapRgb);
#ifdef TARGET_LITTLE_ENDIAN
        swapRgb(frames[i]);
#endif
		// get the pixel data
		bmp	= FreeImage_ConvertFromRawBits(
            frames[i]->pixels, 
            frames[i]->width,
            frames[i]->height, 
            frames[i]->width*(frames[i]->bitsPerPixel/8), 
            frames[i]->bitsPerPixel, 
            0, 0, 0, true // in of006 this (topdown) had to be false.
        );	 
        
#ifdef TARGET_LITTLE_ENDIAN
        swapRgb(frames[i]);
#endif
        
        DWORD frameDuration = (DWORD) (frames[i]->duration * 1000.f);

        bmp = FreeImage_ColorQuantizeEx(bmp, FIQ_NNQUANT, nColors);
		
		// dithering :)
        if(ditherMode > OFX_GIF_DITHER_NONE) bmp = FreeImage_Dither(bmp, (FREE_IMAGE_DITHER)ditherMode);
        
		// clear any animation metadata used by this dib as we’ll adding our own ones 
		FreeImage_SetMetadata(FIMD_ANIMATION, bmp, NULL, NULL); 
		// add animation tags to dib[i] 
		FITAG *tag = FreeImage_CreateTag(); 
		
		if(tag) { 
			FreeImage_SetTagKey(tag, "FrameTime"); 
			FreeImage_SetTagType(tag, FIDT_LONG); 
			FreeImage_SetTagCount(tag, 1); 
			FreeImage_SetTagLength(tag, 4); 
			FreeImage_SetTagValue(tag, &frameDuration); 
			FreeImage_SetMetadata(FIMD_ANIMATION, bmp, FreeImage_GetTagKey(tag), tag); 
			FreeImage_DeleteTag(tag); 
		} 
		FreeImage_AppendPage(multi, bmp); 
	} 
	
	FreeImage_Unload(bmp);
	FreeImage_CloseMultiBitmap(multi); 
}
Esempio n. 7
0
static BOOL 
ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
	// XMP keyword
	const char *g_png_xmp_keyword = "XML:com.adobe.xmp";

	FITAG *tag = NULL;
	png_textp text_ptr = NULL;
	int num_text = 0;

	// iTXt/tEXt/zTXt chuncks
	if(png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) {
		for(int i = 0; i < num_text; i++) {
			// create a tag
			tag = FreeImage_CreateTag();
			if(!tag) return FALSE;

			DWORD tag_length = (DWORD) MAX(text_ptr[i].text_length, text_ptr[i].itxt_length);

			FreeImage_SetTagLength(tag, tag_length);
			FreeImage_SetTagCount(tag, tag_length);
			FreeImage_SetTagType(tag, FIDT_ASCII);
			FreeImage_SetTagValue(tag, text_ptr[i].text);

			if(strcmp(text_ptr[i].key, g_png_xmp_keyword) == 0) {
				// store the tag as XMP
				FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
				FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
			} else {
				// store the tag as a comment
				FreeImage_SetTagKey(tag, text_ptr[i].key);
				FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
			}
			
			// destroy the tag
			FreeImage_DeleteTag(tag);
		}
	}

	return TRUE;
}
Esempio n. 8
0
/**
	Read JPEG_APP1 marker (XMP profile)
	@param dib Input FIBITMAP
	@param dataptr Pointer to the APP1 marker
	@param datalen APP1 marker length
	@return Returns TRUE if successful, FALSE otherwise
*/
static BOOL  
jpeg_read_xmp_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
	// marker identifying string for XMP (null terminated)
	char *xmp_signature = "http://ns.adobe.com/xap/1.0/";

	size_t length = datalen;
	BYTE *profile = (BYTE*)dataptr;

	// verify the identifying string

	if(memcmp(xmp_signature, profile, strlen(xmp_signature)) == 0) {
		// XMP profile

		size_t offset = strlen(xmp_signature) + 1;
		profile += offset;
		length  -= offset;

		// create a tag
		FITAG *tag = FreeImage_CreateTag();
		if(tag) {
			FreeImage_SetTagID(tag, JPEG_APP0+1);	// 0xFFE1
			FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
			FreeImage_SetTagLength(tag, (DWORD)length);
			FreeImage_SetTagCount(tag, (DWORD)length);
			FreeImage_SetTagType(tag, FIDT_ASCII);
			FreeImage_SetTagValue(tag, profile);
			
			// store the tag
			FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);

			// destroy the tag
			FreeImage_DeleteTag(tag);
		}

		return TRUE;
	}

	return FALSE;
}
Esempio n. 9
0
static BOOL 
FreeImage_SetMetadataEx(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, WORD id, FREE_IMAGE_MDTYPE type, DWORD count, DWORD length, const void *value)
{
	BOOL bResult = FALSE;
	FITAG *tag = FreeImage_CreateTag();
	if(tag) {
		FreeImage_SetTagKey(tag, key);
		FreeImage_SetTagID(tag, id);
		FreeImage_SetTagType(tag, type);
		FreeImage_SetTagCount(tag, count);
		FreeImage_SetTagLength(tag, length);
		FreeImage_SetTagValue(tag, value);
		if(model == FIMD_ANIMATION) {
			TagLib& s = TagLib::instance();
			// get the tag description
			const char *description = s.getTagDescription(TagLib::ANIMATION, id);
			FreeImage_SetTagDescription(tag, description);
		}
		// store the tag
		bResult = FreeImage_SetMetadata(model, dib, key, tag);
		FreeImage_DeleteTag(tag);
	}
	return bResult;
}
Esempio n. 10
0
static BOOL 
ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
	// XMP keyword
	const char *g_png_xmp_keyword = "XML:com.adobe.xmp";

	FITAG *tag = NULL;
	png_textp text_ptr = NULL;
	png_timep mod_time = NULL;
	int num_text = 0;

	// iTXt/tEXt/zTXt chuncks
	if(png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) {
		for(int i = 0; i < num_text; i++) {
			// create a tag
			tag = FreeImage_CreateTag();
			if(!tag) return FALSE;

			DWORD tag_length = (DWORD) MAX(text_ptr[i].text_length, text_ptr[i].itxt_length);

			FreeImage_SetTagLength(tag, tag_length);
			FreeImage_SetTagCount(tag, tag_length);
			FreeImage_SetTagType(tag, FIDT_ASCII);
			FreeImage_SetTagValue(tag, text_ptr[i].text);

			if(strcmp(text_ptr[i].key, g_png_xmp_keyword) == 0) {
				// store the tag as XMP
				FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
				FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
			} else {
				// store the tag as a comment
				FreeImage_SetTagKey(tag, text_ptr[i].key);
				FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
			}
			
			// destroy the tag
			FreeImage_DeleteTag(tag);
		}
	}

	// timestamp chunk
	if(png_get_tIME(png_ptr, info_ptr, &mod_time)) {
		char timestamp[32];
		// create a tag
		tag = FreeImage_CreateTag();
		if(!tag) return FALSE;

		// convert as 'yyyy:MM:dd hh:mm:ss'
		sprintf(timestamp, "%4d:%02d:%02d %2d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second);

		DWORD tag_length = (DWORD)strlen(timestamp) + 1;
		FreeImage_SetTagLength(tag, tag_length);
		FreeImage_SetTagCount(tag, tag_length);
		FreeImage_SetTagType(tag, FIDT_ASCII);
		FreeImage_SetTagID(tag, TAG_DATETIME);
		FreeImage_SetTagValue(tag, timestamp);

		// store the tag as Exif-TIFF
		FreeImage_SetTagKey(tag, "DateTime");
		FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, FreeImage_GetTagKey(tag), tag);

		// destroy the tag
		FreeImage_DeleteTag(tag);
	}

	return TRUE;
}
Esempio n. 11
0
void
tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
	char defaultKey[16];

	size_t tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);

	TagLib& tag_lib = TagLib::instance();

	for(unsigned i = 0; i < tag_size; i++) {

		const TIFFFieldInfo *fieldInfo = &xtiffFieldInfo[i];

		if(fieldInfo->field_type == TIFF_ASCII) {
			char *params = NULL;

			if(TIFFGetField(tif, fieldInfo->field_tag, &params)) {
				// create a tag
				FITAG *tag = FreeImage_CreateTag();
				if(!tag)
					return;

				WORD tag_id = (WORD)fieldInfo->field_tag;

				FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)fieldInfo->field_type);
				FreeImage_SetTagID(tag, tag_id);
				FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::GEOTIFF, tag_id, defaultKey));
				FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::GEOTIFF, tag_id));
				FreeImage_SetTagLength(tag, (DWORD)strlen(params) + 1);
				FreeImage_SetTagCount(tag, FreeImage_GetTagLength(tag));
				FreeImage_SetTagValue(tag, params);
				FreeImage_SetMetadata(FIMD_GEOTIFF, dib, FreeImage_GetTagKey(tag), tag);

				// delete the tag
				FreeImage_DeleteTag(tag);
			}
		} else {
			short tag_count = 0;
			void* data = NULL;

			if(TIFFGetField(tif, fieldInfo->field_tag, &tag_count, &data)) {
				// create a tag
				FITAG *tag = FreeImage_CreateTag();
				if(!tag)
					return;

				WORD tag_id = (WORD)fieldInfo->field_tag;
				FREE_IMAGE_MDTYPE tag_type = (FREE_IMAGE_MDTYPE)fieldInfo->field_type;

				FreeImage_SetTagType(tag, tag_type);
				FreeImage_SetTagID(tag, tag_id);
				FreeImage_SetTagKey(tag, tag_lib.getTagFieldName(TagLib::GEOTIFF, tag_id, defaultKey));
				FreeImage_SetTagDescription(tag, tag_lib.getTagDescription(TagLib::GEOTIFF, tag_id));
				FreeImage_SetTagLength(tag, FreeImage_TagDataWidth(tag_type) * tag_count);
				FreeImage_SetTagCount(tag, tag_count);
				FreeImage_SetTagValue(tag, data);
				FreeImage_SetMetadata(FIMD_GEOTIFF, dib, FreeImage_GetTagKey(tag), tag);

				// delete the tag
				FreeImage_DeleteTag(tag);
			}
		}
	} // for(tag_size)
}
Esempio n. 12
0
/**
Process a Canon maker note tag. 
A single Canon tag may contain many other tags within.
*/
static BOOL 
processCanonMakerNoteTag(FIBITMAP *dib, FITAG *tag) {
	char defaultKey[16];
	DWORD startIndex = 0;
	TagLib& s = TagLib::instance();

	WORD tag_id = FreeImage_GetTagID(tag);

	int subTagTypeBase = 0;

	switch(tag_id) {
		case TAG_CANON_CAMERA_STATE_0x01:
			subTagTypeBase = 0xC100;
			startIndex = 1;
			break;
		case TAG_CANON_CAMERA_STATE_0x02:
			subTagTypeBase = 0xC200;
			startIndex = 0;
			break;
		case TAG_CANON_CAMERA_STATE_0x04:
			subTagTypeBase = 0xC400;
			startIndex = 1;
			break;
		case TAG_CANON_CAMERA_STATE_0x12:
			subTagTypeBase = 0xC120;
			startIndex = 0;
			break;
		case TAG_CANON_CAMERA_STATE_0xA0:
			subTagTypeBase = 0xCA00;
			startIndex = 1;
			break;
		case TAG_CANON_CAMERA_STATE_0xE0:
			subTagTypeBase = 0xCE00;
			startIndex = 1;
			break;

		default:
		{
			// process as a normal tag

			// get the tag key and description
			const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
			FreeImage_SetTagKey(tag, key);
			const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
			FreeImage_SetTagDescription(tag, description);

			// store the tag
			if(key) {
				FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, tag);
			}

			return TRUE;
		}
		break;

	}

	WORD *pvalue = (WORD*)FreeImage_GetTagValue(tag);

	// create a tag
	FITAG *canonTag = FreeImage_CreateTag();
	if(!canonTag) return FALSE;

	// we intentionally skip the first array member (if needed)
    for (DWORD i = startIndex; i < FreeImage_GetTagCount(tag); i++) {

		tag_id = (WORD)(subTagTypeBase + i);

		FreeImage_SetTagID(canonTag, tag_id);
		FreeImage_SetTagType(canonTag, FIDT_SHORT);
		FreeImage_SetTagCount(canonTag, 1);
		FreeImage_SetTagLength(canonTag, 2);
		FreeImage_SetTagValue(canonTag, &pvalue[i]);

		// get the tag key and description
		const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
		FreeImage_SetTagKey(canonTag, key);
		const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
		FreeImage_SetTagDescription(canonTag, description);

		// store the tag
		if(key) {
			FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, canonTag);
		}
	}

	// delete the tag
	FreeImage_DeleteTag(canonTag);

	return TRUE;
}
Esempio n. 13
0
/**
	Process Exif directory

	@param dib Input FIBITMAP
	@param tiffp Pointer to the TIFF header
	@param offset 0th IFD offset
	@param length Length of the datafile
	@param msb_order Endianess order of the datafile
	@return 
*/
static BOOL 
jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order) {
	WORD de, nde;

	std::stack<WORD>			destack;	// directory entries stack
	std::stack<BYTE*>			ifdstack;	// IFD stack
	std::stack<TagLib::MDMODEL>	modelstack; // metadata model stack

	// Keep a list of already visited IFD to avoid stack overflows 
	// when recursive/cyclic directory structures exist. 
	// This kind of recursive Exif file was encountered with Kodak images coming from 
	// KODAK PROFESSIONAL DCS Photo Desk JPEG Export v3.2 W
	std::map<DWORD, int> visitedIFD;

    #define DIR_ENTRY_ADDR(_start, _entry) (_start + 2 + (12 * _entry))

	// set the metadata model to Exif

	TagLib::MDMODEL md_model = TagLib::EXIF_MAIN;

	// set the pointer to the first IFD and follow it were it leads.

	BYTE *ifdp = (BYTE*)tiffp + offset;

	de = 0;

	do {
		// if there is anything on the stack then pop it off
		if(!destack.empty()) {
			ifdp		= ifdstack.top();	ifdstack.pop();
			de			= destack.top();	destack.pop();
			md_model	= modelstack.top();	modelstack.pop();
		}

		// remember that we've visited this directory so that we don't visit it again later
		DWORD visited = (DWORD)( (((size_t)ifdp & 0xFFFF) << 16) | (size_t)de );
		if(visitedIFD.find(visited) != visitedIFD.end()) {
			continue;
		} else {
			visitedIFD[visited] = 1;	// processed
		}

		// determine how many entries there are in the current IFD
		nde = ReadUint16(msb_order, ifdp);

		for(; de < nde; de++) {
			char *pde = NULL;	// pointer to the directory entry
			char *pval = NULL;	// pointer to the tag value
			
			// create a tag
			FITAG *tag = FreeImage_CreateTag();
			if(!tag) return FALSE;

			// point to the directory entry
			pde = (char*) DIR_ENTRY_ADDR(ifdp, de);

			// get the tag ID
			FreeImage_SetTagID(tag, ReadUint16(msb_order, pde));
			// get the tag format
			WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2);
            if((tag_type - 1) >= EXIF_NUM_FORMATS) {
                // a problem occured : delete the tag (not free'd after)
			    FreeImage_DeleteTag(tag);
				// break out of the for loop
				break;
            }
			FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type);

			// get number of components
			FreeImage_SetTagCount(tag, ReadUint32(msb_order, pde + 4));
			// get the size of the tag value in bytes
			FreeImage_SetTagLength(tag, FreeImage_GetTagCount(tag) * FreeImage_TagDataWidth((WORD)FreeImage_GetTagType(tag)));

			if(FreeImage_GetTagLength(tag) <= 4) {
				// 4 bytes or less and value is in the dir entry itself
				pval = pde + 8;
			} else {
				// if its bigger than 4 bytes, the directory entry contains an offset
				// first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data
				DWORD offset_value = ReadUint32(msb_order, pde + 8);
				if(offset_value > length) {
					// a problem occured : delete the tag (not free'd after)
					FreeImage_DeleteTag(tag);
					// jump to next entry
					continue;
				}
				// now check if offset + tag length exceeds buffer
				if(offset_value > length - FreeImage_GetTagLength(tag)) {
					// a problem occured : delete the tag (not free'd after)
					FreeImage_DeleteTag(tag);
					// jump to next entry
					continue;
				}
				pval = (char*)(tiffp + offset_value);
			}

			// check for a IFD offset
			BOOL isIFDOffset = FALSE;
			switch(FreeImage_GetTagID(tag)) {
				case TAG_EXIF_OFFSET:
				case TAG_GPS_OFFSET:
				case TAG_INTEROP_OFFSET:
				case TAG_MAKER_NOTE:
					isIFDOffset = TRUE;
					break;
			}
			if(isIFDOffset)	{
				DWORD sub_offset = 0;
				TagLib::MDMODEL next_mdmodel = md_model;
				BYTE *next_ifd = ifdp;
				
				// get offset and metadata model
				if (FreeImage_GetTagID(tag) == TAG_MAKER_NOTE) {
					processMakerNote(dib, pval, msb_order, &sub_offset, &next_mdmodel);
					next_ifd = (BYTE*)pval + sub_offset;
				} else {
					processIFDOffset(tag, pval, msb_order, &sub_offset, &next_mdmodel);
					next_ifd = (BYTE*)tiffp + sub_offset;
				}

				if((sub_offset < (DWORD) length) && (next_mdmodel != TagLib::UNKNOWN)) {
					// push our current directory state onto the stack
					ifdstack.push(ifdp);
					// bump to the next entry
					de++;
					destack.push(de);

					// push our current metadata model
					modelstack.push(md_model);

					// push new state onto of stack to cause a jump
					ifdstack.push(next_ifd);
					destack.push(0);

					// select a new metadata model
					modelstack.push(next_mdmodel);
					
					// delete the tag as it won't be stored nor deleted in the for() loop
					FreeImage_DeleteTag(tag);
					
					break; // break out of the for loop
				}
				else {
					// unsupported camera model, canon maker tag or or something unknown
					// process as a standard tag
					processExifTag(dib, tag, pval, msb_order, md_model);
				}			

			} else {
				// process as a standard tag
				processExifTag(dib, tag, pval, msb_order, md_model);
			}
			
			// delete the tag
			FreeImage_DeleteTag(tag);

        } // for(nde)

		// additional thumbnail data is skipped

    } while (!destack.empty()); 


	return TRUE;
}
Esempio n. 14
0
/**
Read a single Exif tag

@param tif TIFF handle
@param tag_id TIFF Tag ID
@param dib Image being read
@param md_model Metadata model where to store the tag
@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL 
tiff_read_exif_tag(TIFF *tif, uint32 tag_id, FIBITMAP *dib, TagLib::MDMODEL md_model) {
	uint32 value_count = 0;
	int mem_alloc = 0;
	void *raw_data = NULL;

	if(tag_id == TIFFTAG_EXIFIFD) {
		// Exif IFD offset - skip this tag
		// md_model should be EXIF_MAIN, the Exif IFD is processed later using the EXIF_EXIF metadata model
		return TRUE;
	}
	if((tag_id == TIFFTAG_GPSIFD) && (md_model == TagLib::EXIF_MAIN)) {
		// Exif GPS IFD offset - skip this tag
		// should be processed in another way ...
		return TRUE;
	}
	
	TagLib& tagLib = TagLib::instance();

	// get the tag key - use NULL to avoid reading GeoTIFF tags
	const char *key = tagLib.getTagFieldName(md_model, (WORD)tag_id, NULL);
	if(key == NULL) {
		return TRUE;
	}

	const TIFFField *fip = TIFFFieldWithTag(tif, tag_id);
	if(fip == NULL) {
		return TRUE;
	}

	if(TIFFFieldPassCount(fip)) { 
		// a count value is required for 'TIFFGetField'

		if (TIFFFieldReadCount(fip) != TIFF_VARIABLE2) {
			// a count is required, it will be of type uint16
			uint16 value_count16 = 0;
			if(TIFFGetField(tif, tag_id, &value_count16, &raw_data) != 1) {
				// stop, ignore error
				return TRUE;
			}
			value_count = value_count16;
		} else {
			// a count is required, it will be of type uint32
			uint32 value_count32 = 0;
			if(TIFFGetField(tif, tag_id, &value_count32, &raw_data) != 1) {
				// stop, ignore error
				return TRUE;
			}
			value_count = value_count32;
		}

	} else {
		// determine count

		if (TIFFFieldReadCount(fip) == TIFF_VARIABLE || TIFFFieldReadCount(fip) == TIFF_VARIABLE2) {
			value_count = 1;
		} else if (TIFFFieldReadCount(fip) == TIFF_SPP) {
			uint16 spp;
			TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
			value_count = spp;
		} else {
			value_count = TIFFFieldReadCount(fip);
		}

		// access fields as pointers to data
		// (### determining this is NOT robust... and hardly can be. It is implemented looking the _TIFFVGetField code)

		if(TIFFFieldTag(fip) == TIFFTAG_TRANSFERFUNCTION) {
			// reading this tag cause a bug probably located somewhere inside libtiff
			return TRUE;
		}

		if ((TIFFFieldDataType(fip) == TIFF_ASCII
		     || TIFFFieldReadCount(fip) == TIFF_VARIABLE
		     || TIFFFieldReadCount(fip) == TIFF_VARIABLE2
		     || TIFFFieldReadCount(fip) == TIFF_SPP
			 || value_count > 1)
			 
			 && TIFFFieldTag(fip) != TIFFTAG_PAGENUMBER
			 && TIFFFieldTag(fip) != TIFFTAG_HALFTONEHINTS
			 && TIFFFieldTag(fip) != TIFFTAG_YCBCRSUBSAMPLING
			 && TIFFFieldTag(fip) != TIFFTAG_DOTRANGE

			 && TIFFFieldTag(fip) != TIFFTAG_BITSPERSAMPLE	//<- these two are tricky - 
			 && TIFFFieldTag(fip) != TIFFTAG_COMPRESSION	//<- they are defined as TIFF_VARIABLE but in reality return a single value
			 ) {
				 if(TIFFGetField(tif, tag_id, &raw_data) != 1) {
					 // stop, ignore error
					 return TRUE;
				 }
		} else {
			int value_size = 0;

			// access fields as values

			// Note: 
			// For TIFF_RATIONAL values, TIFFDataWidth() returns 8, but LibTIFF use internaly 4-byte float to represent rationals.
			{
				TIFFDataType tag_type = TIFFFieldDataType(fip);
				switch(tag_type) {
					case TIFF_RATIONAL:
					case TIFF_SRATIONAL:
						value_size = 4;
						break;
					default:
						value_size = TIFFDataWidth(tag_type);
						break;
				}
			}

			raw_data = _TIFFmalloc(value_size * value_count);
			mem_alloc = 1;
			int ok = FALSE;
			
			// ### if value_count > 1, tag is PAGENUMBER or HALFTONEHINTS or YCBCRSUBSAMPLING or DOTRANGE, 
			// all off which are value_count == 2 (see tif_dirinfo.c)
			switch(value_count)
			{
				case 1:
					ok = TIFFGetField(tif, tag_id, raw_data);
					break;
				case 2:
					ok = TIFFGetField(tif, tag_id, raw_data, (BYTE*)(raw_data) + value_size*1);
					break;
/* # we might need more in the future:
				case 3:
					ok = TIFFGetField(tif, tag_id, raw_data, (BYTE*)(raw_data) + value_size*1, (BYTE*)(raw_data) + value_size*2);
					break;
*/
				default:
					FreeImage_OutputMessageProc(FIF_TIFF, "Unimplemented variable number of parameters for Tiff Tag %s", TIFFFieldName(fip));
					break;
			}
			if(ok != 1) {
				_TIFFfree(raw_data);
				return TRUE;
			}
		}
	}

	// build FreeImage tag from Tiff Tag data we collected

	FITAG *fitag = FreeImage_CreateTag();
	if(!fitag) {
		if(mem_alloc) {
			_TIFFfree(raw_data);
		}
		return FALSE;
	}

	FreeImage_SetTagID(fitag, (WORD)tag_id);
	FreeImage_SetTagKey(fitag, key);

	switch(TIFFFieldDataType(fip)) {
		case TIFF_BYTE:
			FreeImage_SetTagType(fitag, FIDT_BYTE);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_UNDEFINED:
			FreeImage_SetTagType(fitag, FIDT_UNDEFINED);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SBYTE:
			FreeImage_SetTagType(fitag, FIDT_SBYTE);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SHORT:
			FreeImage_SetTagType(fitag, FIDT_SHORT);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SSHORT:
			FreeImage_SetTagType(fitag, FIDT_SSHORT);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_LONG:
			FreeImage_SetTagType(fitag, FIDT_LONG);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_IFD:
			FreeImage_SetTagType(fitag, FIDT_IFD);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SLONG:
			FreeImage_SetTagType(fitag, FIDT_SLONG);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_RATIONAL: {
			// LibTIFF converts rational to floats : reconvert floats to rationals
			DWORD *rvalue = (DWORD*)malloc(2 * value_count * sizeof(DWORD));
			for(uint32 i = 0; i < value_count; i++) {
				float *fv = (float*)raw_data;
				FIRational rational(fv[i]);
				rvalue[2*i] = rational.getNumerator();
				rvalue[2*i+1] = rational.getDenominator();
			}
			FreeImage_SetTagType(fitag, FIDT_RATIONAL);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, rvalue);
			free(rvalue);
		}
		break;

		case TIFF_SRATIONAL: {
			// LibTIFF converts rational to floats : reconvert floats to rationals
			LONG *rvalue = (LONG*)malloc(2 * value_count * sizeof(LONG));
			for(uint32 i = 0; i < value_count; i++) {
				float *fv = (float*)raw_data;
				FIRational rational(fv[i]);
				rvalue[2*i] = rational.getNumerator();
				rvalue[2*i+1] = rational.getDenominator();
			}
			FreeImage_SetTagType(fitag, FIDT_RATIONAL);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, rvalue);
			free(rvalue);
		}
		break;

		case TIFF_FLOAT:
			FreeImage_SetTagType(fitag, FIDT_FLOAT);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_DOUBLE:
			FreeImage_SetTagType(fitag, FIDT_DOUBLE);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_LONG8:	// BigTIFF 64-bit unsigned integer 
			FreeImage_SetTagType(fitag, FIDT_LONG8);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_IFD8:		// BigTIFF 64-bit unsigned integer (offset) 
			FreeImage_SetTagType(fitag, FIDT_IFD8);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SLONG8:		// BigTIFF 64-bit signed integer 
			FreeImage_SetTagType(fitag, FIDT_SLONG8);
			FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_ASCII:
		default: {
			size_t length = 0;
			if(!mem_alloc && (TIFFFieldDataType(fip) == TIFF_ASCII) && (TIFFFieldReadCount(fip) == TIFF_VARIABLE)) {
				// when metadata tag is of type ASCII and it's value is of variable size (TIFF_VARIABLE),
				// tiff_read_exif_tag function gives length of 1 so all strings are truncated ...
				// ... try to avoid this by using an explicit calculation for 'length'
				length = strlen((char*)raw_data) + 1;
			}
			else {
				// remember that raw_data = _TIFFmalloc(value_size * value_count);
				const int value_size = TIFFDataWidth( TIFFFieldDataType(fip) );
				length = value_size * value_count;
			}
			FreeImage_SetTagType(fitag, FIDT_ASCII);
			FreeImage_SetTagLength(fitag, (DWORD)length);
			FreeImage_SetTagCount(fitag, (DWORD)length);
			FreeImage_SetTagValue(fitag, raw_data);
		}
		break;
	}

	const char *description = tagLib.getTagDescription(md_model, (WORD)tag_id);
	if(description) {
		FreeImage_SetTagDescription(fitag, description);
	}
	// store the tag
	FreeImage_SetMetadata(tagLib.getFreeImageModel(md_model), dib, FreeImage_GetTagKey(fitag), fitag);

	// destroy the tag
	FreeImage_DeleteTag(fitag);

	if(mem_alloc) {
		_TIFFfree(raw_data);
	}
	return TRUE;
}
Esempio n. 15
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	WebPMux *mux = NULL;
	WebPMuxFrameInfo webp_frame = { 0 };	// raw image
	WebPData color_profile;	// ICC raw data
	WebPData xmp_metadata;	// XMP raw data
	WebPData exif_metadata;	// EXIF raw data
	FIBITMAP *dib = NULL;
	WebPMuxError error_status;

	if(!handle) {
		return NULL;
	}

	try {
		// get the MUX object
		mux = (WebPMux*)data;
		if(!mux) {
			throw (1);
		}
		
		// gets the feature flags from the mux object
		uint32_t webp_flags = 0;
		error_status = WebPMuxGetFeatures(mux, &webp_flags);
		if(error_status != WEBP_MUX_OK) {
			throw (1);
		}

		// get image data
		error_status = WebPMuxGetFrame(mux, 1, &webp_frame);

		if(error_status == WEBP_MUX_OK) {
			// decode the data (can be limited to the header if flags uses FIF_LOAD_NOPIXELS)
			dib = DecodeImage(&webp_frame.bitstream, flags);
			if(!dib) {
				throw (1);
			}
			
			// get ICC profile
			if(webp_flags & ICCP_FLAG) {
				error_status = WebPMuxGetChunk(mux, "ICCP", &color_profile);
				if(error_status == WEBP_MUX_OK) {
					FreeImage_CreateICCProfile(dib, (void*)color_profile.bytes, (long)color_profile.size);
				}
			}

			// get XMP metadata
			if(webp_flags & XMP_FLAG) {
				error_status = WebPMuxGetChunk(mux, "XMP ", &xmp_metadata);
				if(error_status == WEBP_MUX_OK) {
					// create a tag
					FITAG *tag = FreeImage_CreateTag();
					if(tag) {
						FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
						FreeImage_SetTagLength(tag, (DWORD)xmp_metadata.size);
						FreeImage_SetTagCount(tag, (DWORD)xmp_metadata.size);
						FreeImage_SetTagType(tag, FIDT_ASCII);
						FreeImage_SetTagValue(tag, xmp_metadata.bytes);
						
						// store the tag
						FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);

						// destroy the tag
						FreeImage_DeleteTag(tag);
					}
				}
			}

			// get Exif metadata
			if(webp_flags & EXIF_FLAG) {
				error_status = WebPMuxGetChunk(mux, "EXIF", &exif_metadata);
				if(error_status == WEBP_MUX_OK) {
					// read the Exif raw data as a blob
					jpeg_read_exif_profile_raw(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
					// read and decode the Exif data
					jpeg_read_exif_profile(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
				}
			}
		}

		WebPDataClear(&webp_frame.bitstream);

		return dib;

	} catch(int) {
		WebPDataClear(&webp_frame.bitstream);
		return NULL;
	}
}
Esempio n. 16
0
/**
	Process Exif directory

	@param dib Input FIBITMAP
	@param tiffp Pointer to the TIFF header
	@param offset 0th IFD offset
	@param length Length of the datafile
	@param msb_order Endianess order of the datafile
	@return
*/
static BOOL
jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order) {
    WORD de, nde;

    std::stack<WORD>			destack;	// directory entries stack
    std::stack<const BYTE*>		ifdstack;	// IFD stack
    std::stack<TagLib::MDMODEL>	modelstack; // metadata model stack

    // Keep a list of already visited IFD to avoid stack overflows
    // when recursive/cyclic directory structures exist.
    // This kind of recursive Exif file was encountered with Kodak images coming from
    // KODAK PROFESSIONAL DCS Photo Desk JPEG Export v3.2 W
    std::map<DWORD, int> visitedIFD;

    /*
    "An Image File Directory (IFD) consists of a 2-byte count of the number of directory
    entries (i.e. the number of fields), followed by a sequence of 12-byte field
    entries, followed by a 4-byte offset of the next IFD (or 0 if none)."
    The "next IFD" (1st IFD) is the thumbnail.
    */
#define DIR_ENTRY_ADDR(_start, _entry) (_start + 2 + (12 * _entry))

    // set the metadata model to Exif

    TagLib::MDMODEL md_model = TagLib::EXIF_MAIN;

    // set the pointer to the first IFD (0th IFD) and follow it were it leads.

    const BYTE *ifd0th = (BYTE*)tiffp + offset;

    const BYTE *ifdp = ifd0th;

    de = 0;

    do {
        // if there is anything on the stack then pop it off
        if(!destack.empty()) {
            ifdp		= ifdstack.top();
            ifdstack.pop();
            de			= destack.top();
            destack.pop();
            md_model	= modelstack.top();
            modelstack.pop();
        }

        // remember that we've visited this directory and entry so that we don't visit it again later
        DWORD visited = (DWORD)( (((size_t)ifdp & 0xFFFF) << 16) | (size_t)de );
        if(visitedIFD.find(visited) != visitedIFD.end()) {
            continue;
        } else {
            visitedIFD[visited] = 1;	// processed
        }

        // determine how many entries there are in the current IFD
        nde = ReadUint16(msb_order, ifdp);

        for(; de < nde; de++) {
            char *pde = NULL;	// pointer to the directory entry
            char *pval = NULL;	// pointer to the tag value

            // create a tag
            FITAG *tag = FreeImage_CreateTag();
            if(!tag) return FALSE;

            // point to the directory entry
            pde = (char*) DIR_ENTRY_ADDR(ifdp, de);

            // get the tag ID
            FreeImage_SetTagID(tag, ReadUint16(msb_order, pde));
            // get the tag type
            WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2);
            if((tag_type - 1) >= EXIF_NUM_FORMATS) {
                // a problem occured : delete the tag (not free'd after)
                FreeImage_DeleteTag(tag);
                // break out of the for loop
                break;
            }
            FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type);

            // get number of components
            FreeImage_SetTagCount(tag, ReadUint32(msb_order, pde + 4));
            // check that tag length (size of the tag value in bytes) will fit in a DWORD
            unsigned tag_data_width = FreeImage_TagDataWidth(FreeImage_GetTagType(tag));
            if (tag_data_width != 0 && FreeImage_GetTagCount(tag) > ~(DWORD)0 / tag_data_width) {
                FreeImage_DeleteTag(tag);
                // jump to next entry
                continue;
            }
            FreeImage_SetTagLength(tag, FreeImage_GetTagCount(tag) * tag_data_width);

            if(FreeImage_GetTagLength(tag) <= 4) {
                // 4 bytes or less and value is in the dir entry itself
                pval = pde + 8;
            } else {
                // if its bigger than 4 bytes, the directory entry contains an offset
                // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data
                DWORD offset_value = ReadUint32(msb_order, pde + 8);
                if(offset_value > length) {
                    // a problem occured : delete the tag (not free'd after)
                    FreeImage_DeleteTag(tag);
                    // jump to next entry
                    continue;
                }
                // now check that length does not exceed the buffer size
                if(FreeImage_GetTagLength(tag) > length - offset_value) {
                    // a problem occured : delete the tag (not free'd after)
                    FreeImage_DeleteTag(tag);
                    // jump to next entry
                    continue;
                }
                pval = (char*)(tiffp + offset_value);
            }

            // check for a IFD offset
            BOOL isIFDOffset = FALSE;
            switch(FreeImage_GetTagID(tag)) {
            case TAG_EXIF_OFFSET:
            case TAG_GPS_OFFSET:
            case TAG_INTEROP_OFFSET:
            case TAG_MAKER_NOTE:
                isIFDOffset = TRUE;
                break;
            }
            if(isIFDOffset)	{
                DWORD sub_offset = 0;
                TagLib::MDMODEL next_mdmodel = md_model;
                const BYTE *next_ifd = ifdp;

                // get offset and metadata model
                if (FreeImage_GetTagID(tag) == TAG_MAKER_NOTE) {
                    processMakerNote(dib, pval, msb_order, &sub_offset, &next_mdmodel);
                    next_ifd = (BYTE*)pval + sub_offset;
                } else {
                    processIFDOffset(tag, pval, msb_order, &sub_offset, &next_mdmodel);
                    next_ifd = (BYTE*)tiffp + sub_offset;
                }

                if((sub_offset < (DWORD) length) && (next_mdmodel != TagLib::UNKNOWN)) {
                    // push our current directory state onto the stack
                    ifdstack.push(ifdp);
                    // bump to the next entry
                    de++;
                    destack.push(de);

                    // push our current metadata model
                    modelstack.push(md_model);

                    // push new state onto of stack to cause a jump
                    ifdstack.push(next_ifd);
                    destack.push(0);

                    // select a new metadata model
                    modelstack.push(next_mdmodel);

                    // delete the tag as it won't be stored nor deleted in the for() loop
                    FreeImage_DeleteTag(tag);

                    break; // break out of the for loop
                }
                else {
                    // unsupported camera model, canon maker tag or something unknown
                    // process as a standard tag
                    processExifTag(dib, tag, pval, msb_order, md_model);
                }

            } else {
                // process as a standard tag
                processExifTag(dib, tag, pval, msb_order, md_model);
            }

            // delete the tag
            FreeImage_DeleteTag(tag);

        } // for(nde)

        // additional thumbnail data is skipped

    } while (!destack.empty());

    //
    // --- handle thumbnail data ---
    //

    const WORD entriesCount0th = ReadUint16(msb_order, ifd0th);

    DWORD next_offset = ReadUint32(msb_order, DIR_ENTRY_ADDR(ifd0th, entriesCount0th));
    if((next_offset == 0) || (next_offset >= length)) {
        return TRUE; //< no thumbnail
    }

    const BYTE* const ifd1st = (BYTE*)tiffp + next_offset;
    const WORD entriesCount1st = ReadUint16(msb_order, ifd1st);

    unsigned thCompression = 0;
    unsigned thOffset = 0;
    unsigned thSize = 0;

    for(int e = 0; e < entriesCount1st; e++) {

        // point to the directory entry
        const BYTE* base = DIR_ENTRY_ADDR(ifd1st, e);

        // check for buffer overflow
        const size_t remaining = (size_t)base + 12 - (size_t)tiffp;
        if(remaining >= length) {
            // bad IFD1 directory, ignore it
            return FALSE;
        }

        // get the tag ID
        WORD tag = ReadUint16(msb_order, base);
        // get the tag type
        WORD type = ReadUint16(msb_order, base + sizeof(WORD));
        // get number of components
        DWORD count = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD));
        // get the tag value
        DWORD offset = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD) + sizeof(DWORD));

        switch(tag) {
        case TAG_COMPRESSION:
            // Tiff Compression Tag (should be COMPRESSION_OJPEG (6), but is not always respected)
            thCompression = offset;
            break;
        case TAG_JPEG_INTERCHANGE_FORMAT:
            // Tiff JPEGInterchangeFormat Tag
            thOffset = offset;
            break;
        case TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
            // Tiff JPEGInterchangeFormatLength Tag
            thSize = offset;
            break;
        // ### X and Y Resolution ignored, orientation ignored
        case TAG_X_RESOLUTION:		// XResolution
        case TAG_Y_RESOLUTION:		// YResolution
        case TAG_RESOLUTION_UNIT:	// ResolutionUnit
        case TAG_ORIENTATION:		// Orientation
            break;
        default:
            break;
        }
    }

    if(/*thCompression != 6 ||*/ thOffset == 0 || thSize == 0) {
        return TRUE;
    }

    if(thOffset + thSize > length) {
        return TRUE;
    }

    // load the thumbnail

    const BYTE *thLocation = tiffp + thOffset;

    FIMEMORY* hmem = FreeImage_OpenMemory(const_cast<BYTE*>(thLocation), thSize);
    FIBITMAP* thumbnail = FreeImage_LoadFromMemory(FIF_JPEG, hmem);
    FreeImage_CloseMemory(hmem);

    // store the thumbnail
    FreeImage_SetThumbnail(dib, thumbnail);
    // then delete it
    FreeImage_Unload(thumbnail);

    return TRUE;
}
Esempio n. 17
0
//--------------------------------------------------------------
void ofxGifEncoder::save (vector <ofxGifFrame *> frames, string fileName, int nColors) {
    
    if (nColors < 2 || nColors > 256) {
        ofLog(OF_LOG_WARNING, "nColors must be between 2 and 256. your gif won't be saved");
        return;
    }
    
	// create a multipage bitmap
	FIMULTIBITMAP *multi = FreeImage_OpenMultiBitmap(FIF_GIF, ofToDataPath(fileName).c_str(), TRUE, FALSE); 
	
	FIBITMAP * bmp = NULL;
	
	for(int i = 0; i < frames.size(); i++ ) { 
		// we need to swap the channels if we're on little endian (see ofImage::swapRgb);
#ifdef TARGET_LITTLE_ENDIAN
        swapRgb(frames[i]);
#endif
		
		// get the pixel data
		bmp	= FreeImage_ConvertFromRawBits(
            frames[i]->pixels, 
            frames[i]->width,
            frames[i]->height, 
            frames[i]->width*(frames[i]->bitsPerPixel/8), 
            frames[i]->bitsPerPixel, 
            0,
            0,
            0, 
            true // in of006 this (topdown) had to be false.
        );	 
		
		
#ifdef TARGET_LITTLE_ENDIAN
        swapRgb(frames[i]);
#endif
    		
        DWORD frameDuration = (DWORD) frames[i]->duration * 1000.f;
		
        // bmp =  FreeImage_ColorQuantize(bmp, FIQ_NNQUANT);
		
		// if we want to set a reduced color palette (2 to 256);
        bmp = FreeImage_ColorQuantizeEx(bmp, FIQ_NNQUANT, nColors);
		
		// dithering :)
		// you can set a different dither pattern for each frame
        // bmp = FreeImage_Dither(bmp, (FREE_IMAGE_DITHER)((i+1)%6));
        //bmp = FreeImage_Dither(bmp, FID_BAYER8x8);
        
		// clear any animation metadata used by this dib as we’ll adding our own ones 
		FreeImage_SetMetadata(FIMD_ANIMATION, bmp, NULL, NULL); 
		// add animation tags to dib[i] 
		FITAG *tag = FreeImage_CreateTag(); 
		
		if(tag) { 
			FreeImage_SetTagKey(tag, "FrameTime"); 
			FreeImage_SetTagType(tag, FIDT_LONG); 
			FreeImage_SetTagCount(tag, 1); 
			FreeImage_SetTagLength(tag, 4); 
			FreeImage_SetTagValue(tag, &frameDuration); 
			FreeImage_SetMetadata(FIMD_ANIMATION, bmp, FreeImage_GetTagKey(tag), tag); 
			FreeImage_DeleteTag(tag); 
		} 
		FreeImage_AppendPage(multi, bmp); 
	} 
	
	FreeImage_Unload(bmp);
	FreeImage_CloseMultiBitmap(multi); 
}
Esempio n. 18
0
/**
Read a single exif tag
*/
static BOOL 
tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& tagLib, TIFFDirectory *td, uint32 tag) {
	const TIFFField *fip;
	uint32 value_count;
	int mem_alloc = 0;
	void *raw_data = NULL;

	if(tag == TIFFTAG_EXIFIFD) {
		return TRUE;
	}

	// get the tag key - use NULL to avoid reading GeoTIFF tags
	const char *key = tagLib.getTagFieldName(md_model, (WORD)tag, NULL);
	if(key == NULL) {
		return TRUE;
	}

	fip = TIFFFieldWithTag(tif, tag);
	if(fip == NULL) {
		return TRUE;
	}

	if(fip->field_passcount) { //<- "passcount" means "returns count"
		if (fip->field_readcount != TIFF_VARIABLE2) { //<- TIFF_VARIABLE2 means "uses LONG count"

			// assume TIFF_VARIABLE (uses SHORT count)
			uint16 value_count16;
			if(TIFFGetField(tif, tag, &value_count16, &raw_data) != 1) {
				return TRUE;
			}
			value_count = value_count16;
		} else {
			if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) {
				return TRUE;
			}
		}
	} else {

		// determine count

		if (fip->field_readcount == TIFF_VARIABLE || fip->field_readcount == TIFF_VARIABLE2) {
			value_count = 1;
		} else if (fip->field_readcount == TIFF_SPP) {
			value_count = td->td_samplesperpixel;
		} else {
			value_count = fip->field_readcount;
		}

		// access fields as pointers to data
		// (### determining this is NOT robust... and hardly can be. It is implemented looking the _TIFFVGetField code)

		if(fip->field_tag == TIFFTAG_TRANSFERFUNCTION) {
			// reading this tag cause a bug probably located somewhere inside libtiff
			return TRUE;
		}

		if ((fip->field_type == TIFF_ASCII
		     || fip->field_readcount == TIFF_VARIABLE
		     || fip->field_readcount == TIFF_VARIABLE2
		     || fip->field_readcount == TIFF_SPP
			 || value_count > 1)
			 
			 && fip->field_tag != TIFFTAG_PAGENUMBER
			 && fip->field_tag != TIFFTAG_HALFTONEHINTS
			 && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
			 && fip->field_tag != TIFFTAG_DOTRANGE

			 && fip->field_tag != TIFFTAG_BITSPERSAMPLE	//<- these two are tricky - 
			 && fip->field_tag != TIFFTAG_COMPRESSION	//<- they are defined as TIFF_VARIABLE but in reality return a single value
			 ) {
				 if(TIFFGetField(tif, tag, &raw_data) != 1) {
					 return TRUE;
				 }
		} else {

			// access fields as values

			const int value_size = _TIFFDataSize(fip->field_type);
			raw_data = _TIFFmalloc(value_size * value_count);
			mem_alloc = 1;
			int ok = FALSE;
			
			// ### if value_count > 1, tag is PAGENUMBER or HALFTONEHINTS or YCBCRSUBSAMPLING or DOTRANGE, 
			// all off which are value_count == 2 (see tif_dirinfo.c)
			switch(value_count)
			{
				case 1:
					ok = TIFFGetField(tif, tag, raw_data);
					break;
				case 2:
					ok = TIFFGetField(tif, tag, raw_data, (BYTE*)(raw_data) + value_size*1);
					break;
/* # we might need more in the future:
				case 3:
					ok = TIFFGetField(tif, tag, raw_data, (BYTE*)(raw_data) + value_size*1, (BYTE*)(raw_data) + value_size*2);
					break;
*/
				default:
					FreeImage_OutputMessageProc(FIF_TIFF, "Unimplemented variable number of parameters for Tiff Tag %s", fip->field_name);
					break;
			}
			if(ok != 1) {
				_TIFFfree(raw_data);
				return TRUE;
			}
		}
	}

	// build FreeImage tag from Tiff Tag data we collected

	FITAG *fitag = FreeImage_CreateTag();
	if(!fitag) {
		if(mem_alloc) {
			_TIFFfree(raw_data);
		}
		return FALSE;
	}

	FreeImage_SetTagID(fitag, (WORD)tag);
	FreeImage_SetTagKey(fitag, key);

	switch(fip->field_type) {
		case TIFF_BYTE:
			FreeImage_SetTagType(fitag, FIDT_BYTE);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_UNDEFINED:
			FreeImage_SetTagType(fitag, FIDT_UNDEFINED);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SBYTE:
			FreeImage_SetTagType(fitag, FIDT_SBYTE);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SHORT:
			FreeImage_SetTagType(fitag, FIDT_SHORT);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SSHORT:
			FreeImage_SetTagType(fitag, FIDT_SSHORT);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_LONG:
			FreeImage_SetTagType(fitag, FIDT_LONG);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_IFD:
			FreeImage_SetTagType(fitag, FIDT_IFD);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SLONG:
			FreeImage_SetTagType(fitag, FIDT_SLONG);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_RATIONAL: {
			// LibTIFF converts rational to floats : reconvert floats to rationals
			DWORD *rvalue = (DWORD*)malloc(2 * value_count * sizeof(DWORD));
			for(uint32 i = 0; i < value_count; i++) {
				float *fv = (float*)raw_data;
				FIRational rational(fv[i]);
				rvalue[2*i] = rational.getNumerator();
				rvalue[2*i+1] = rational.getDenominator();
			}
			FreeImage_SetTagType(fitag, FIDT_RATIONAL);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, rvalue);
			free(rvalue);
		}
		break;

		case TIFF_SRATIONAL: {
			// LibTIFF converts rational to floats : reconvert floats to rationals
			LONG *rvalue = (LONG*)malloc(2 * value_count * sizeof(LONG));
			for(uint32 i = 0; i < value_count; i++) {
				float *fv = (float*)raw_data;
				FIRational rational(fv[i]);
				rvalue[2*i] = rational.getNumerator();
				rvalue[2*i+1] = rational.getDenominator();
			}
			FreeImage_SetTagType(fitag, FIDT_RATIONAL);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, rvalue);
			free(rvalue);
		}
		break;

		case TIFF_FLOAT:
			FreeImage_SetTagType(fitag, FIDT_FLOAT);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_DOUBLE:
			FreeImage_SetTagType(fitag, FIDT_DOUBLE);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_LONG8:	// BigTIFF 64-bit unsigned integer 
			FreeImage_SetTagType(fitag, FIDT_LONG8);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_IFD8:		// BigTIFF 64-bit unsigned integer (offset) 
			FreeImage_SetTagType(fitag, FIDT_IFD8);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		case TIFF_SLONG8:		// BigTIFF 64-bit signed integer 
			FreeImage_SetTagType(fitag, FIDT_SLONG8);
			FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
			FreeImage_SetTagCount(fitag, value_count);
			FreeImage_SetTagValue(fitag, raw_data);
			break;

		default: {
			size_t length = strlen((char*)raw_data) + 1;
			FreeImage_SetTagType(fitag, FIDT_ASCII);
			FreeImage_SetTagLength(fitag, (DWORD)length);
			FreeImage_SetTagCount(fitag, (DWORD)length);
			FreeImage_SetTagValue(fitag, raw_data);
		}
		break;
	}

	const char *description = tagLib.getTagDescription(md_model, (WORD)tag);
	if(description) {
		FreeImage_SetTagDescription(fitag, description);
	}
	// store the tag
	FreeImage_SetMetadata(tagLib.getFreeImageModel(md_model), dib, FreeImage_GetTagKey(fitag), fitag);

	// destroy the tag
	FreeImage_DeleteTag(fitag);

	if(mem_alloc) {
		_TIFFfree(raw_data);
	}
	return TRUE;
}
Esempio n. 19
0
/**
Process a Canon maker note tag. 
A single Canon tag may contain many other tags within.
*/
static void 
processCanonMakerNoteTag(FIBITMAP *dib, FITAG *tag) {
	char defaultKey[16];
	DWORD startIndex = 0;
	TagLib& s = TagLib::instance();

	WORD tag_id = FreeImage_GetTagID(tag);

	if((tag_id == TAG_CANON_CAMERA_STATE_1) || (tag_id == TAG_CANON_CAMERA_STATE_2) || (tag_id == TAG_CANON_CAMERA_STATE_4)) {
		// this single tag has multiple values within

		int subTagTypeBase = 0;

		switch(tag_id) {
			case TAG_CANON_CAMERA_STATE_1:
				subTagTypeBase = 0xC100;
				startIndex = 1;
				break;
			case TAG_CANON_CAMERA_STATE_2:
				subTagTypeBase = 0xC200;
				startIndex = 0;
				break;
			case TAG_CANON_CAMERA_STATE_4:
				subTagTypeBase = 0xC400;
				startIndex = 2;
				break;
		}

		WORD *pvalue = (WORD*)FreeImage_GetTagValue(tag);

        // we intentionally skip the first array member
        for (DWORD i = startIndex; i < FreeImage_GetTagCount(tag); i++) {
			// create a tag
			FITAG *canonTag = FreeImage_CreateTag();
			if(!canonTag) return;

			tag_id = (WORD)(subTagTypeBase + i);

			FreeImage_SetTagID(canonTag, tag_id);
			FreeImage_SetTagType(canonTag, FIDT_SHORT);
			FreeImage_SetTagCount(canonTag, 1);
			FreeImage_SetTagLength(canonTag, 2);
			FreeImage_SetTagValue(canonTag, &pvalue[i]);

			// get the tag key and description
			const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
			FreeImage_SetTagKey(canonTag, key);
			const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
			FreeImage_SetTagDescription(canonTag, description);

			// store the tag
			if(key) {
				FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, canonTag);
			}

			// delete the tag
			FreeImage_DeleteTag(canonTag);
        }
	}
	else {
		// process as a normal tag

		// get the tag key and description
		const char *key = s.getTagFieldName(TagLib::EXIF_MAKERNOTE_CANON, tag_id, defaultKey);
		FreeImage_SetTagKey(tag, key);
		const char *description = s.getTagDescription(TagLib::EXIF_MAKERNOTE_CANON, tag_id);
		FreeImage_SetTagDescription(tag, description);

		// store the tag
		if(key) {
			FreeImage_SetMetadata(FIMD_EXIF_MAKERNOTE, dib, key, tag);
		}
	}
}
Esempio n. 20
0
BOOL tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
    int  i;
    short count;

	TagLib& tagLib = TagLib::instance();

	TIFFDirectory *td = &tif->tif_dir;
    
	count = (short) TIFFGetTagListCount(tif);
    for(i = 0; i < count; i++) {
        ttag_t tag = TIFFGetTagListEntry(tif, i);
        const TIFFFieldInfo *fip;
        uint32 value_count;
        int mem_alloc = 0;
        void *raw_data;

		if(tag == TIFFTAG_EXIFIFD) continue;

		// get the tag key - use NULL to avoid reading GeoTIFF tags
		const char *key = tagLib.getTagFieldName(md_model, (WORD)tag, NULL);
		if(key == NULL) continue;
        
		fip = TIFFFieldWithTag(tif, tag);
        if(fip == NULL) continue;
		
		if(fip->field_passcount) {
			if (fip->field_readcount != TIFF_VARIABLE2) {
				// assume TIFF_VARIABLE
				uint16 value_count16;
				if(TIFFGetField(tif, tag, &value_count16, &raw_data) != 1) continue;
				value_count = value_count16;
			} else {
				if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) continue;
			}
		} else {
			if (fip->field_readcount == TIFF_VARIABLE || fip->field_readcount == TIFF_VARIABLE2) {
				value_count = 1;
			} else if (fip->field_readcount == TIFF_SPP) {
				value_count = td->td_samplesperpixel;
			} else {
				value_count = fip->field_readcount;
			}
			if (fip->field_type == TIFF_ASCII 
				|| fip->field_readcount == TIFF_VARIABLE
				|| fip->field_readcount == TIFF_VARIABLE2
				|| fip->field_readcount == TIFF_SPP
				|| value_count > 1) {
				if(TIFFGetField(tif, tag, &raw_data) != 1) continue;
			} else {
				raw_data = _TIFFmalloc(_TIFFDataSize(fip->field_type) * value_count);
				mem_alloc = 1;
				if(TIFFGetField(tif, tag, raw_data) != 1) {
					_TIFFfree(raw_data);
					continue;
				}
			}
		}
		
		// create a tag
		FITAG *fitag = FreeImage_CreateTag();
		if(!fitag) {
			if(mem_alloc)
				_TIFFfree(raw_data);
			return FALSE;
		}

		FreeImage_SetTagID(fitag, (WORD)tag);
		FreeImage_SetTagKey(fitag, key);

		switch(fip->field_type) {
			case TIFF_BYTE:
				FreeImage_SetTagType(fitag, FIDT_BYTE);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_UNDEFINED:
				FreeImage_SetTagType(fitag, FIDT_UNDEFINED);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_SBYTE:
				FreeImage_SetTagType(fitag, FIDT_SBYTE);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_SHORT:
				FreeImage_SetTagType(fitag, FIDT_SHORT);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_SSHORT:
				FreeImage_SetTagType(fitag, FIDT_SSHORT);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_LONG:
				FreeImage_SetTagType(fitag, FIDT_LONG);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_IFD:
				FreeImage_SetTagType(fitag, FIDT_IFD);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_SLONG:
				FreeImage_SetTagType(fitag, FIDT_SLONG);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_RATIONAL:
			{
				// LibTIFF converts rational to floats : reconvert floats to rationals
				DWORD *rvalue = (DWORD*)malloc(2 * value_count * sizeof(DWORD));
				for(uint32 i = 0; i < value_count; i++) {
					float *fv = (float*)raw_data;
					FIRational rational(fv[i]);
					rvalue[2*i] = rational.getNumerator();
					rvalue[2*i+1] = rational.getDenominator();
				}
				FreeImage_SetTagType(fitag, FIDT_RATIONAL);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, rvalue);
				free(rvalue);
			}
			break;

			case TIFF_SRATIONAL:
			{
				// LibTIFF converts rational to floats : reconvert floats to rationals
				LONG *rvalue = (LONG*)malloc(2 * value_count * sizeof(LONG));
				for(uint32 i = 0; i < value_count; i++) {
					float *fv = (float*)raw_data;
					FIRational rational(fv[i]);
					rvalue[2*i] = rational.getNumerator();
					rvalue[2*i+1] = rational.getDenominator();
				}
				FreeImage_SetTagType(fitag, FIDT_RATIONAL);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, rvalue);
				free(rvalue);
			}
			break;

			case TIFF_FLOAT:
				FreeImage_SetTagType(fitag, FIDT_FLOAT);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			case TIFF_DOUBLE:
				FreeImage_SetTagType(fitag, FIDT_DOUBLE);
				FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
				FreeImage_SetTagCount(fitag, value_count);
				FreeImage_SetTagValue(fitag, raw_data);
				break;

			default:
			{
				size_t length = strlen((char*)raw_data) + 1;
				FreeImage_SetTagType(fitag, FIDT_ASCII);
				FreeImage_SetTagLength(fitag, (DWORD)length);
				FreeImage_SetTagCount(fitag, (DWORD)length);
				FreeImage_SetTagValue(fitag, raw_data);
			}
			break;
		}

		const char *description = tagLib.getTagDescription(md_model, (WORD)tag);
		if(description) {
			FreeImage_SetTagDescription(fitag, description);
		}
		// store the tag
		FreeImage_SetMetadata(tagLib.getFreeImageModel(md_model), dib, FreeImage_GetTagKey(fitag), fitag);

		// destroy the tag
		FreeImage_DeleteTag(fitag);
	
		if(mem_alloc)
			_TIFFfree(raw_data);
    }

	return TRUE;

}
Esempio n. 21
0
/**
Read ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
@see ReadProfile, ReadDescriptiveMetadata
*/
static ERR
ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) {
	ERR error_code = 0;		// error code as returned by the interface
	size_t currentPos = 0;	// current stream position
	
	WMPStream *pStream = pID->pStream;
	WmpDEMisc *wmiDEMisc = &pID->WMP.wmiDEMisc;
	BYTE *pbProfile = NULL;

	try {
		// save current position
		error_code = pStream->GetPos(pStream, &currentPos);
		JXR_CHECK(error_code);

		// ICC profile
		if(0 != wmiDEMisc->uColorProfileByteCount) {
			unsigned cbByteCount = wmiDEMisc->uColorProfileByteCount;
			unsigned uOffset = wmiDEMisc->uColorProfileOffset;
			error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
			JXR_CHECK(error_code);
			FreeImage_CreateICCProfile(dib, pbProfile, cbByteCount);
		}

		// XMP metadata
		if(0 != wmiDEMisc->uXMPMetadataByteCount) {
			unsigned cbByteCount = wmiDEMisc->uXMPMetadataByteCount;
			unsigned uOffset = wmiDEMisc->uXMPMetadataOffset;
			error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
			JXR_CHECK(error_code);
			// store the tag as XMP
			FITAG *tag = FreeImage_CreateTag();
			if(tag) {
				FreeImage_SetTagLength(tag, cbByteCount);
				FreeImage_SetTagCount(tag, cbByteCount);
				FreeImage_SetTagType(tag, FIDT_ASCII);
				FreeImage_SetTagValue(tag, pbProfile);
				FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
				FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
				FreeImage_DeleteTag(tag);
			}
		}

		// IPTC metadata
		if(0 != wmiDEMisc->uIPTCNAAMetadataByteCount) {
			unsigned cbByteCount = wmiDEMisc->uIPTCNAAMetadataByteCount;
			unsigned uOffset = wmiDEMisc->uIPTCNAAMetadataOffset;
			error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
			JXR_CHECK(error_code);
			// decode the IPTC profile
			read_iptc_profile(dib, pbProfile, cbByteCount);
		}

		// Exif metadata
		if(0 != wmiDEMisc->uEXIFMetadataByteCount) {
			unsigned cbByteCount = wmiDEMisc->uEXIFMetadataByteCount;
			unsigned uOffset = wmiDEMisc->uEXIFMetadataOffset;
			error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
			JXR_CHECK(error_code);
			// decode the Exif profile
			jpegxr_read_exif_profile(dib, pbProfile, cbByteCount, uOffset);
		}

		// Exif-GPS metadata
		if(0 != wmiDEMisc->uGPSInfoMetadataByteCount) {
			unsigned cbByteCount = wmiDEMisc->uGPSInfoMetadataByteCount;
			unsigned uOffset = wmiDEMisc->uGPSInfoMetadataOffset;
			error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
			JXR_CHECK(error_code);
			// decode the Exif-GPS profile
			jpegxr_read_exif_gps_profile(dib, pbProfile, cbByteCount, uOffset);
		}

		// free profile buffer
		free(pbProfile);
		// restore initial position
		error_code = pID->pStream->SetPos(pID->pStream, currentPos);
		JXR_CHECK(error_code);

		// as a LAST STEP, read descriptive metadata
		// these metadata overwrite possible identical Exif-TIFF metadata 
		// that could have been read inside the Exif IFD
		
		return ReadDescriptiveMetadata(pID, dib);

	} catch(...) {
		// free profile buffer
		free(pbProfile);
		if(currentPos) {
			// restore initial position
			pStream->SetPos(pStream, currentPos);
		}
		return error_code;
	}
}
Esempio n. 22
0
void ofxGifEncoder::processFrame(ofxGifFrame * frame, FIMULTIBITMAP *multi){
    FIBITMAP * bmp = NULL;
    // we need to swap the channels if we're on little endian (see ofImage::swapRgb);

    
    if (frame->bitsPerPixel ==32){
        ofLog() << "image is transaprent!";
        frame = convertTo24BitsWithGreenScreen(frame);
    }
    
#ifdef TARGET_LITTLE_ENDIAN
    swapRgb(frame);
#endif
    
    
    // from here on, we can only deal with 24 bits
    
    // get the pixel data
    bmp	= FreeImage_ConvertFromRawBits(
                                       frame->pixels,
                                       frame->width,
                                       frame->height,
                                       frame->width*(frame->bitsPerPixel/8),
                                       frame->bitsPerPixel,
                                       0, 0, 0, true // in of006 this (topdown) had to be false.
                                       );
    
    FIBITMAP * bmpConverted;
    
#ifdef TARGET_LITTLE_ENDIAN
    swapRgb(frame);
#endif
    
    FIBITMAP * quantizedBmp = NULL;
    FIBITMAP * ditheredBmp  = NULL;
    FIBITMAP * processedBmp = NULL;
    
    
    quantizedBmp = FreeImage_ColorQuantizeEx(bmp, FIQ_WUQUANT, nColors);
    processedBmp = quantizedBmp;
    
    if (nChannels == 4){
        calculatePalette(processedBmp);
        FreeImage_SetTransparentIndex(processedBmp,getClosestToGreenScreenPaletteColorIndex());
    }


    
    // dithering :)
    if(ditherMode > OFX_GIF_DITHER_NONE) {
        ditheredBmp = FreeImage_Dither(processedBmp, (FREE_IMAGE_DITHER)ditherMode);
        processedBmp = ditheredBmp;
    }
    
    DWORD frameDuration = (DWORD) (frame->duration * 1000.f);
    
    // clear any animation metadata used by this dib as we’ll adding our own ones
    FreeImage_SetMetadata(FIMD_ANIMATION, processedBmp, NULL, NULL);
    // add animation tags to dib[frameNum]
    FITAG *tag = FreeImage_CreateTag();
    if(tag) {
        FreeImage_SetTagKey(tag, "FrameTime");
        FreeImage_SetTagType(tag, FIDT_LONG);
        FreeImage_SetTagCount(tag, 1);
        FreeImage_SetTagLength(tag, 4);
        FreeImage_SetTagValue(tag, &frameDuration);
        FreeImage_SetMetadata(FIMD_ANIMATION, processedBmp, FreeImage_GetTagKey(tag), tag);
        FreeImage_DeleteTag(tag);
    }
    
    FreeImage_AppendPage(multi, processedBmp);
    
    // clear freeimage stuff
    if(bmp          != NULL) FreeImage_Unload(bmp);
    if(quantizedBmp != NULL) FreeImage_Unload(quantizedBmp);
    if(ditheredBmp  != NULL) FreeImage_Unload(ditheredBmp);
    
    // no need to unload processedBmp, as it points to either of the above

}
Esempio n. 23
0
/**
	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;

	// 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;
}
Esempio n. 24
0
/**
Convert a DPKPROPVARIANT to a FITAG, then store the tag as FIMD_EXIF_MAIN
@see ReadDescriptiveMetadata
*/
static BOOL
ReadPropVariant(WORD tag_id, const DPKPROPVARIANT & varSrc, FIBITMAP *dib) {
	DWORD dwSize;

	if(varSrc.vt == DPKVT_EMPTY) {
		return FALSE;
	}

	// get the tag key
	TagLib& s = TagLib::instance();
	const char *key = s.getTagFieldName(TagLib::EXIF_MAIN, tag_id, NULL);
	if(!key) {
		return FALSE;
	}

	// create a tag
	FITAG *tag = FreeImage_CreateTag();
	if(tag) {
		// set tag ID
		FreeImage_SetTagID(tag, tag_id);
		// set tag type, count, length and value
		switch (varSrc.vt) {
			case DPKVT_LPSTR:
				FreeImage_SetTagType(tag, FIDT_ASCII);
				dwSize = (DWORD)strlen(varSrc.VT.pszVal) + 1;
				FreeImage_SetTagCount(tag, dwSize);
				FreeImage_SetTagLength(tag, dwSize);
				FreeImage_SetTagValue(tag, varSrc.VT.pszVal);
				break;
			
			case DPKVT_LPWSTR:
				FreeImage_SetTagType(tag, FIDT_UNDEFINED);
				dwSize = (DWORD)(sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1)); // +1 for NULL term
				FreeImage_SetTagCount(tag, dwSize);
				FreeImage_SetTagLength(tag, dwSize);
				FreeImage_SetTagValue(tag, varSrc.VT.pwszVal);
				break;
	            
			case DPKVT_UI2:
				FreeImage_SetTagType(tag, FIDT_SHORT);
				FreeImage_SetTagCount(tag, 1);
				FreeImage_SetTagLength(tag, 2);
				FreeImage_SetTagValue(tag, &varSrc.VT.uiVal);
				break;

			case DPKVT_UI4:
				FreeImage_SetTagType(tag, FIDT_LONG);
				FreeImage_SetTagCount(tag, 1);
				FreeImage_SetTagLength(tag, 4);
				FreeImage_SetTagValue(tag, &varSrc.VT.ulVal);
				break;

			default:
				assert(FALSE); // This case is not handled
				break;
		}
		// get the tag desctiption
		const char *description = s.getTagDescription(TagLib::EXIF_MAIN, tag_id);
		FreeImage_SetTagDescription(tag, description);

		// store the tag
		FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, key, tag);

		FreeImage_DeleteTag(tag);
	}
	return TRUE;
}