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 )