Beispiel #1
0
void
tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
	char defaultKey[16];

	if(FreeImage_GetMetadataCount(FIMD_GEOTIFF, dib) == 0) {
		return;
	}

	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];

		FITAG *tag = NULL;
		const char *key = tag_lib.getTagFieldName(TagLib::GEOTIFF, (WORD)fieldInfo->field_tag, defaultKey);

		if(FreeImage_GetMetadata(FIMD_GEOTIFF, dib, key, &tag)) {
			if(FreeImage_GetTagType(tag) == FIDT_ASCII) {
				TIFFSetField(tif, fieldInfo->field_tag, FreeImage_GetTagValue(tag));
			} else {
				TIFFSetField(tif, fieldInfo->field_tag, FreeImage_GetTagCount(tag), FreeImage_GetTagValue(tag));
			}
		}
	}
}
Beispiel #2
0
/**
Write all known exif tags

@param tif TIFF handle
@param md_model Metadata model from where to load the tags
@param dib Image being written
@return Returns TRUE if successful, returns FALSE otherwise
*/
BOOL 
tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
	char defaultKey[16];
	
	// only EXIF_MAIN so far
	if(md_model != TagLib::EXIF_MAIN) {
		return FALSE;
	}
	
	if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib) == 0) {
		return FALSE;
	}
	
	TagLib& tag_lib = TagLib::instance();
	
	for (int fi = 0, nfi = (int)tif->tif_nfields; nfi > 0; nfi--, fi++) {
		const TIFFField *fld = tif->tif_fields[fi];
		
		const uint32 tag_id = TIFFFieldTag(fld);

		if(skip_write_field(tif, tag_id)) {
			// skip tags that are already handled by the LibTIFF writing process
			continue;
		}

		FITAG *tag = NULL;
		// get the tag key
		const char *key = tag_lib.getTagFieldName(TagLib::EXIF_MAIN, (WORD)tag_id, defaultKey);

		if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, key, &tag)) {
			FREE_IMAGE_MDTYPE tag_type = FreeImage_GetTagType(tag);
			TIFFDataType tif_tag_type = TIFFFieldDataType(fld);
			
			// check for identical formats

			// (enum value are the sames between FREE_IMAGE_MDTYPE and TIFFDataType types)
			if((int)tif_tag_type != (int)tag_type) {
				// skip tag or _TIFFmemcpy will fail
				continue;
			}
			// type of storage may differ (e.g. rationnal array vs float array type)
			if((unsigned)_TIFFDataSize(tif_tag_type) != FreeImage_TagDataWidth(tag_type)) {
				// skip tag or _TIFFmemcpy will fail
				continue;
			}

			if(tag_type == FIDT_ASCII) {
				TIFFSetField(tif, tag_id, FreeImage_GetTagValue(tag));
			} else {
				TIFFSetField(tif, tag_id, FreeImage_GetTagCount(tag), FreeImage_GetTagValue(tag));
			}
		}
	}

	return TRUE;
}
Beispiel #3
0
static void 
rotate_exif(FIBITMAP **dib) {
	// check for Exif rotation
	if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, *dib)) {
		FIBITMAP *rotated = NULL;
		// process Exif rotation
		FITAG *tag = NULL;
		FreeImage_GetMetadata(FIMD_EXIF_MAIN, *dib, "Orientation", &tag);
		if(tag != NULL) {
			if(FreeImage_GetTagID(tag) == TAG_ORIENTATION) {
				unsigned short orientation = *((unsigned short *)FreeImage_GetTagValue(tag));
				switch (orientation) {
					case 1:		// "top, left side" => 0°
						break;
					case 2:		// "top, right side" => flip left-right
						FreeImage_FlipHorizontal(*dib);
						break;
					case 3:		// "bottom, right side"; => -180°
						rotated = FreeImage_Rotate(*dib, 180);
						FreeImage_Unload(*dib);
						*dib = rotated;
						break;
					case 4:		// "bottom, left side" => flip up-down
						FreeImage_FlipVertical(*dib);
						break;
					case 5:		// "left side, top" => +90° + flip up-down
						rotated = FreeImage_Rotate(*dib, 90);
						FreeImage_Unload(*dib);
						*dib = rotated;
						FreeImage_FlipVertical(*dib);
						break;
					case 6:		// "right side, top" => -90°
						rotated = FreeImage_Rotate(*dib, -90);
						FreeImage_Unload(*dib);
						*dib = rotated;
						break;
					case 7:		// "right side, bottom" => -90° + flip up-down
						rotated = FreeImage_Rotate(*dib, -90);
						FreeImage_Unload(*dib);
						*dib = rotated;
						FreeImage_FlipVertical(*dib);
						break;
					case 8:		// "left side, bottom" => +90°
						rotated = FreeImage_Rotate(*dib, 90);
						FreeImage_Unload(*dib);
						*dib = rotated;
						break;
					default:
						break;
				}
			}
		}
	}
}
Beispiel #4
0
unsigned fipImage::getMetadataCount(FREE_IMAGE_MDMODEL model) const {
	return FreeImage_GetMetadataCount(model, _dib);
}
Beispiel #5
0
/**
Write a metadata model as a TIF IFD to a FIMEMORY handle.
The entries in the TIF IFD are sorted in ascending order by tag id.	
The last entry is written as 0 (4 bytes) which means no more IFD to follow. 
Supported metadata models are
<ul>
<li>FIMD_EXIF_MAIN
<li>FIMD_EXIF_EXIF
<li>FIMD_EXIF_GPS
<li>FIMD_EXIF_INTEROP
</ul>
The end of the buffer is filled with 4 bytes equal to 0 (end of IFD offset)

@param dib Input FIBITMAP
@param md_model Metadata model to write
@param hmem Memory handle
@return Returns TRUE if successful, FALSE otherwise
@see tiff_get_ifd_profile
*/
static BOOL
tiff_write_ifd(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, FIMEMORY *hmem) {
	FITAG *tag = NULL;
	FIMETADATA *mdhandle = NULL;
	std::vector<FITAG*> vTagList;
	TagLib::MDMODEL internal_md_model;

	DWORD ifd_offset = 0;	// WORD-aligned IFD value offset

	const BYTE empty_byte = 0;

	// start of the file
	const long start_of_file = FreeImage_TellMemory(hmem);

	// get the metadata count
	unsigned metadata_count = FreeImage_GetMetadataCount(md_model, dib);
	if(metadata_count == 0) {
		return FALSE;
	}

	TagLib& s = TagLib::instance();

	// check for supported metadata models
	switch(md_model) {
		case FIMD_EXIF_MAIN:
			internal_md_model = TagLib::EXIF_MAIN;
			break;
		case FIMD_EXIF_EXIF:
			internal_md_model = TagLib::EXIF_EXIF;
			break;
		case FIMD_EXIF_GPS:
			internal_md_model = TagLib::EXIF_GPS;
			break;
		case FIMD_EXIF_INTEROP:
			internal_md_model = TagLib::EXIF_INTEROP;
			break;
		default:
			return FALSE;
	}

	try {
		// 1) according to the TIFF specifications, 
		// the entries in a TIF IFD must be sorted in ascending order by tag id

		// store the tags into a vector
		vTagList.reserve(metadata_count);
		mdhandle = FreeImage_FindFirstMetadata(md_model, dib, &tag);
		if(mdhandle) {
			// parse the tags and store them inside vTagList
			do {
				// rewrite the tag id using FreeImage internal database
				// (in case the tag id is wrong or missing)
				const char *key = FreeImage_GetTagKey(tag);
				int tag_id = s.getTagID(internal_md_model, key);
				if(tag_id != -1) {
					// this is a known tag, set the tag ID
					FreeImage_SetTagID(tag, (WORD)tag_id);
					// record the tag
					vTagList.push_back(tag);
				}
				// else ignore this tag
			} while(FreeImage_FindNextMetadata(mdhandle, &tag));

			FreeImage_FindCloseMetadata(mdhandle);

			// sort the vector by tag id
			std::sort(vTagList.begin(), vTagList.end(), PredicateTagIDCompare());

			// update the metadata_count
			metadata_count = (unsigned)vTagList.size();

		} else {
			throw(1);
		}

		// 2) prepare the place for each IFD entries.

		/*
		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). Do not forget to write the 4 bytes of 0 after the last IFD.
		*/

		{		
			// prepare place for 2 bytes for number of entries + 12 bytes for each entry
			unsigned ifd_size = 2 + 12 * metadata_count;
			FreeImage_WriteMemory(&empty_byte, 1, ifd_size, hmem);
			// record the offset used to write values > 4-bytes
			ifd_offset = FreeImage_TellMemory(hmem);
			// rewind
			FreeImage_SeekMemory(hmem, start_of_file, SEEK_SET);
		}

		// 3) write each IFD entry in tag id ascending order

		// number of directory entries
		WORD nde = (WORD)metadata_count;
		FreeImage_WriteMemory(&nde, 1, 2, hmem);

		// for each entry ...
		for(unsigned i = 0; i < metadata_count; i++) {
			FITAG *tag = vTagList[i];
			// tag id
			WORD tag_id = FreeImage_GetTagID(tag);
			FreeImage_WriteMemory(&tag_id, 1, 2, hmem);
			// tag type (compliant with TIFF specification)
			WORD tag_type = (WORD)FreeImage_GetTagType(tag);
			FreeImage_WriteMemory(&tag_type, 1, 2, hmem);
			// tag count
			DWORD tag_count = FreeImage_GetTagCount(tag);
			FreeImage_WriteMemory(&tag_count, 1, 4, hmem);
			// tag value or offset (results are in BYTE's units)
			unsigned tag_length = FreeImage_GetTagLength(tag);
			if(tag_length <= 4) {
				// 4 bytes or less, write the value (left justified)
				const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag);
				FreeImage_WriteMemory(tag_value, 1, tag_length, hmem);
				for(unsigned k = tag_length; k < 4; k++) {
					FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
				}
			} else {
				// write an offset
				FreeImage_WriteMemory(&ifd_offset, 1, 4, hmem);
				// write the value
				long current_position = FreeImage_TellMemory(hmem);
				FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
				FreeImage_WriteMemory(FreeImage_GetTagValue(tag), 1, tag_length, hmem);
				if(tag_length & 1) {
					// align to the next WORD boundary
					FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
				}
				// next offset to use
				ifd_offset = FreeImage_TellMemory(hmem);
				// rewind
				FreeImage_SeekMemory(hmem, current_position, SEEK_SET);
			}
		}

		// end-of-IFD or next IFD (0 == none)
		FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
		FreeImage_WriteMemory(&empty_byte, 1, 4, hmem);

		return TRUE;
	}
	catch(int) {
		return FALSE;
	}
}
Beispiel #6
0
/**
Write ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
*/
static ERR
WriteMetadata(PKImageEncode *pIE, FIBITMAP *dib) {
	ERR error_code = 0;		// error code as returned by the interface
	BYTE *profile = NULL;
	unsigned profile_size = 0;
	
	try {
		// write ICC profile
		{
			FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
			if(iccProfile->data) {
				error_code = pIE->SetColorContext(pIE, (U8*)iccProfile->data, iccProfile->size);
				JXR_CHECK(error_code);
			}
		}
		
		// write descriptive metadata
		if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib)) {
			error_code = WriteDescriptiveMetadata(pIE, dib);
			JXR_CHECK(error_code);
		}

		// write IPTC metadata
		if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) {
			// create a binary profile
			if(write_iptc_profile(dib, &profile, &profile_size)) {
				// write the profile
				error_code = PKImageEncode_SetIPTCNAAMetadata_WMP(pIE, profile, profile_size);
				JXR_CHECK(error_code);
				// release profile
				free(profile);
				profile = NULL;
			}
		}

		// write XMP metadata
		{
			FITAG *tag_xmp = NULL;
			if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp)) {
				error_code = PKImageEncode_SetXMPMetadata_WMP(pIE, (BYTE*)FreeImage_GetTagValue(tag_xmp), FreeImage_GetTagLength(tag_xmp));
				JXR_CHECK(error_code);
			}
		}

		// write Exif metadata
		{
			if(tiff_get_ifd_profile(dib, FIMD_EXIF_EXIF, &profile, &profile_size)) {
				error_code = PKImageEncode_SetEXIFMetadata_WMP(pIE, profile, profile_size);
				JXR_CHECK(error_code);
				// release profile
				free(profile);
				profile = NULL;
			}
		}

		// write Exif GPS metadata
		{
			if(tiff_get_ifd_profile(dib, FIMD_EXIF_GPS, &profile, &profile_size)) {
				error_code = PKImageEncode_SetGPSInfoMetadata_WMP(pIE, profile, profile_size);
				JXR_CHECK(error_code);
				// release profile
				free(profile);
				profile = NULL;
			}
		}

		return WMP_errSuccess;

	} catch(...) {
		free(profile);
		return error_code;
	}
}