Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/Metadata/Exif.cpp view on Meta::CPAN
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 > dwLength) {
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;
}
// --------------------------------------------------------------------------
/**
Read and decode JPEG_APP1 marker (Exif profile)
@param dib Input FIBITMAP
@param data Pointer to the APP1 marker
@param length APP1 marker length
@return Returns TRUE if successful, FALSE otherwise
*/
BOOL
jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *data, unsigned length) {
// marker identifying string for Exif = "Exif\0\0"
BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Classic TIFF signature - little-endian order
BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Classic TIFF signature - big-endian order
// profile size is up to 32-bit
DWORD dwProfileLength = (DWORD)length;
BYTE *pbProfile = (BYTE*)data;
// verify the identifying string
if(memcmp(exif_signature, pbProfile, sizeof(exif_signature)) == 0) {
// This is an Exif profile
// should contain a TIFF header with up to 2 IFDs (IFD stands for 'Image File Directory')
// 0th IFD : the image attributes, 1st IFD : may be used for thumbnail
pbProfile += sizeof(exif_signature);
dwProfileLength -= sizeof(exif_signature);
// read the TIFF header (8 bytes)
// check the endianess order
BOOL bBigEndian = TRUE;
if(memcmp(pbProfile, lsb_first, sizeof(lsb_first)) == 0) {
// Exif section is in little-endian order
bBigEndian = FALSE;
} else {
if(memcmp(pbProfile, msb_first, sizeof(msb_first)) == 0) {
// Exif section is in big-endian order
bBigEndian = TRUE;
} else {
// Invalid Exif alignment marker
return FALSE;
}
}
// this is the offset to the first IFD (Image File Directory)
DWORD dwFirstOffset = ReadUint32(bBigEndian, pbProfile + 4);
if (dwFirstOffset > dwProfileLength) {
// bad Exif data
return FALSE;
}
/*
Note: as FreeImage 3.14.0, this test is no longer needed for images with similar suspicious offset
=> tested with Pentax Optio 230, FujiFilm SP-2500 and Canon EOS 300D
if (dwFirstOffset < 8 || dwFirstOffset > 16) {
// This is usually set to 8
// but PENTAX Optio 230 has it set differently, and uses it as offset.
FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value");
return FALSE;
}
*/
// process Exif directories, starting with Exif-TIFF IFD
return jpeg_read_exif_dir(dib, pbProfile, dwFirstOffset, dwProfileLength, 0, bBigEndian, TagLib::EXIF_MAIN);
}
return FALSE;
}
// ==========================================================
// Exif JPEG helper routines
// ==========================================================
/**
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;
}
// ==========================================================
// Exif JPEG-XR helper routines
// ==========================================================
/**
Read and decode JPEG-XR Exif IFD
@param dib Input FIBITMAP
@param profile Pointer to the Exif marker
@param length Exif marker length
@param file_offset Reference offset in the original file of each tag value whose length is > 4
@return Returns TRUE if successful, FALSE otherwise
*/
BOOL
jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset) {
// assume Little Endian order
BOOL bBigEndian = FALSE;
// process Exif specific IFD
return jpeg_read_exif_dir(dib, profile, 0, length, file_offset, bBigEndian, TagLib::EXIF_EXIF);
}
/**
Read and decode JPEG-XR Exif-GPS IFD
@param dib Input FIBITMAP
@param profile Pointer to the Exif-GPS profile
@param length Exif-GPS profile length
@param file_offset Reference offset in the original file of each tag value whose length is > 4
@return Returns TRUE if successful, FALSE otherwise
*/
BOOL
jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset) {
// assume Little Endian order
BOOL bBigEndian = FALSE;
( run in 1.186 second using v1.01-cache-2.11-cpan-119454b85a5 )