Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginJPEG.cpp view on Meta::CPAN
// - Markus Loibl (markus.loibl@epost.de)
// - Karl-Heinz Bussian (khbussian@moss.de)
// - Hervé Drolon (drolon@infonie.fr)
// - Jascha Wetzel (jascha@mainia.de)
// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
#ifdef _MSC_VER
#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
#endif
extern "C" {
#define XMD_H
#undef FAR
#include <setjmp.h>
#include "../LibJPEG/jinclude.h"
#include "../LibJPEG/jpeglib.h"
#include "../LibJPEG/jerror.h"
}
#include "FreeImage.h"
#include "Utilities.h"
#include "../Metadata/FreeImageTag.h"
// ==========================================================
// Plugin Interface
// ==========================================================
static int s_format_id;
// ----------------------------------------------------------
// Constant declarations
// ----------------------------------------------------------
#define INPUT_BUF_SIZE 4096 // choose an efficiently fread'able size
#define OUTPUT_BUF_SIZE 4096 // choose an efficiently fwrite'able size
#define EXIF_MARKER (JPEG_APP0+1) // EXIF marker / Adobe XMP marker
#define ICC_MARKER (JPEG_APP0+2) // ICC profile marker
#define IPTC_MARKER (JPEG_APP0+13) // IPTC marker / BIM marker
#define ICC_HEADER_SIZE 14 // size of non-profile data in APP2
#define MAX_BYTES_IN_MARKER 65533L // maximum data length of a JPEG marker
#define MAX_DATA_BYTES_IN_MARKER 65519L // maximum data length of a JPEG APP2 marker
#define MAX_JFXX_THUMB_SIZE (MAX_BYTES_IN_MARKER - 5 - 1)
#define JFXX_TYPE_JPEG 0x10 // JFIF extension marker: JPEG-compressed thumbnail image
#define JFXX_TYPE_8bit 0x11 // JFIF extension marker: palette thumbnail image
#define JFXX_TYPE_24bit 0x13 // JFIF extension marker: RGB thumbnail image
// ----------------------------------------------------------
// Typedef declarations
// ----------------------------------------------------------
typedef struct tagErrorManager {
/// "public" fields
struct jpeg_error_mgr pub;
/// for return to caller
jmp_buf setjmp_buffer;
} ErrorManager;
typedef struct tagSourceManager {
/// public fields
struct jpeg_source_mgr pub;
/// source stream
fi_handle infile;
FreeImageIO *m_io;
/// start of buffer
JOCTET * buffer;
/// have we gotten any data yet ?
boolean start_of_file;
} SourceManager;
typedef struct tagDestinationManager {
/// public fields
struct jpeg_destination_mgr pub;
/// destination stream
fi_handle outfile;
FreeImageIO *m_io;
/// start of buffer
JOCTET * buffer;
} DestinationManager;
typedef SourceManager* freeimage_src_ptr;
typedef DestinationManager* freeimage_dst_ptr;
typedef ErrorManager* freeimage_error_ptr;
// ----------------------------------------------------------
// Error handling
// ----------------------------------------------------------
/** Fatal errors (print message and exit) */
static inline void
JPEG_EXIT(j_common_ptr cinfo, int code) {
freeimage_error_ptr error_ptr = (freeimage_error_ptr)cinfo->err;
error_ptr->pub.msg_code = code;
error_ptr->pub.error_exit(cinfo);
}
/** Nonfatal errors (we can keep going, but the data is probably corrupt) */
static inline void
JPEG_WARNING(j_common_ptr cinfo, int code) {
freeimage_error_ptr error_ptr = (freeimage_error_ptr)cinfo->err;
src/Source/FreeImage/PluginJPEG.cpp view on Meta::CPAN
}
}
// ICC profile
BYTE *icc_profile = NULL;
unsigned icc_length = 0;
if( jpeg_read_icc_profile(cinfo, &icc_profile, &icc_length) ) {
// copy ICC profile data
FreeImage_CreateICCProfile(dib, icc_profile, icc_length);
// clean up
free(icc_profile);
}
return TRUE;
}
// ----------------------------------------------------------
// Special markers write functions
// ----------------------------------------------------------
/**
Write JPEG_COM marker (comment)
*/
static BOOL
jpeg_write_comment(j_compress_ptr cinfo, FIBITMAP *dib) {
FITAG *tag = NULL;
// write user comment as a JPEG_COM marker
FreeImage_GetMetadata(FIMD_COMMENTS, dib, "Comment", &tag);
if(tag) {
const char *tag_value = (char*)FreeImage_GetTagValue(tag);
if(NULL != tag_value) {
for(long i = 0; i < (long)strlen(tag_value); i+= MAX_BYTES_IN_MARKER) {
jpeg_write_marker(cinfo, JPEG_COM, (BYTE*)tag_value + i, MIN((long)strlen(tag_value + i), MAX_BYTES_IN_MARKER));
}
return TRUE;
}
}
return FALSE;
}
/**
Write JPEG_APP2 marker (ICC profile)
*/
static BOOL
jpeg_write_icc_profile(j_compress_ptr cinfo, FIBITMAP *dib) {
// marker identifying string "ICC_PROFILE" (null-terminated)
BYTE icc_signature[12] = { 0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00 };
FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
if (iccProfile->size && iccProfile->data) {
// ICC_HEADER_SIZE: ICC signature is 'ICC_PROFILE' + 2 bytes
BYTE *profile = (BYTE*)malloc((iccProfile->size + ICC_HEADER_SIZE) * sizeof(BYTE));
if(profile == NULL) return FALSE;
memcpy(profile, icc_signature, 12);
for(long i = 0; i < (long)iccProfile->size; i += MAX_DATA_BYTES_IN_MARKER) {
unsigned length = MIN((long)(iccProfile->size - i), MAX_DATA_BYTES_IN_MARKER);
// sequence number
profile[12] = (BYTE) ((i / MAX_DATA_BYTES_IN_MARKER) + 1);
// number of markers
profile[13] = (BYTE) (iccProfile->size / MAX_DATA_BYTES_IN_MARKER + 1);
memcpy(profile + ICC_HEADER_SIZE, (BYTE*)iccProfile->data + i, length);
jpeg_write_marker(cinfo, ICC_MARKER, profile, (length + ICC_HEADER_SIZE));
}
free(profile);
return TRUE;
}
return FALSE;
}
/**
Write JPEG_APPD marker (IPTC or Adobe Photoshop profile)
@return Returns TRUE if successful, FALSE otherwise
*/
static BOOL
jpeg_write_iptc_profile(j_compress_ptr cinfo, FIBITMAP *dib) {
//const char *ps_header = "Photoshop 3.0\x08BIM\x04\x04\x0\x0\x0\x0";
const unsigned tag_length = 26;
if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) {
BYTE *profile = NULL;
unsigned profile_size = 0;
// create a binary profile
if(write_iptc_profile(dib, &profile, &profile_size)) {
// write the profile
for(long i = 0; i < (long)profile_size; i += 65517L) {
unsigned length = MIN((long)profile_size - i, 65517L);
unsigned roundup = length & 0x01; // needed for Photoshop
BYTE *iptc_profile = (BYTE*)malloc(length + roundup + tag_length);
if(iptc_profile == NULL) break;
// Photoshop identification string
memcpy(&iptc_profile[0], "Photoshop 3.0\x0", 14);
// 8BIM segment type
memcpy(&iptc_profile[14], "8BIM\x04\x04\x0\x0\x0\x0", 10);
// segment size
iptc_profile[24] = (BYTE)(length >> 8);
iptc_profile[25] = (BYTE)(length & 0xFF);
// segment data
memcpy(&iptc_profile[tag_length], &profile[i], length);
if(roundup)
iptc_profile[length + tag_length] = 0;
jpeg_write_marker(cinfo, IPTC_MARKER, iptc_profile, length + roundup + tag_length);
free(iptc_profile);
}
// release profile
free(profile);
return TRUE;
}
}
return FALSE;
}
( run in 0.985 second using v1.01-cache-2.11-cpan-13bb782fe5a )