root/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginJPEG.cpp @ 36

Revision 36, 53.0 KB (checked in by vsilva, 8 years ago)

FIX Xades encoding problems

Line 
1// ==========================================================
2// JPEG Loader and writer
3// Based on code developed by The Independent JPEG Group
4//
5// Design and implementation by
6// - Floris van den Berg (flvdberg@wxs.nl)
7// - Jan L. Nauta (jln@magentammt.com)
8// - Markus Loibl (markus.loibl@epost.de)
9// - Karl-Heinz Bussian (khbussian@moss.de)
10// - Hervé Drolon (drolon@infonie.fr)
11// - Jascha Wetzel (jascha@mainia.de)
12// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
13//
14// This file is part of FreeImage 3
15//
16// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
17// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
18// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
19// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
20// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
21// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
22// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
23// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
24// THIS DISCLAIMER.
25//
26// Use at your own risk!
27// ==========================================================
28
29#ifdef _MSC_VER
30#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
31#endif
32
33extern "C" {
34#define XMD_H
35#undef FAR
36#include <setjmp.h>
37
38#include "../LibJPEG/jinclude.h"
39#include "../LibJPEG/jpeglib.h"
40#include "../LibJPEG/jerror.h"
41}
42
43#include "FreeImagePTEiD.h"
44#include "Utilities.h"
45
46#include "../Metadata/FreeImageTag.h"
47
48
49// ==========================================================
50// Plugin Interface
51// ==========================================================
52
53static int s_format_id;
54
55// ----------------------------------------------------------
56//   Constant declarations
57// ----------------------------------------------------------
58
59#define INPUT_BUF_SIZE  4096    // choose an efficiently fread'able size
60#define OUTPUT_BUF_SIZE 4096    // choose an efficiently fwrite'able size
61
62#define EXIF_MARKER             (JPEG_APP0+1)   // EXIF marker / Adobe XMP marker
63#define ICC_MARKER              (JPEG_APP0+2)   // ICC profile marker
64#define IPTC_MARKER             (JPEG_APP0+13)  // IPTC marker / BIM marker
65
66#define ICC_HEADER_SIZE 14                              // size of non-profile data in APP2
67#define MAX_BYTES_IN_MARKER 65533L              // maximum data length of a JPEG marker
68#define MAX_DATA_BYTES_IN_MARKER 65519L // maximum data length of a JPEG APP2 marker
69
70#define MAX_JFXX_THUMB_SIZE (MAX_BYTES_IN_MARKER - 5 - 1)
71
72#define JFXX_TYPE_JPEG  0x10    // JFIF extension marker: JPEG-compressed thumbnail image
73#define JFXX_TYPE_8bit  0x11    // JFIF extension marker: palette thumbnail image
74#define JFXX_TYPE_24bit 0x13    // JFIF extension marker: RGB thumbnail image
75
76// ----------------------------------------------------------
77//   Typedef declarations
78// ----------------------------------------------------------
79
80typedef struct tagErrorManager {
81        /// "public" fields
82        struct jpeg_error_mgr pub;
83        /// for return to caller
84        jmp_buf setjmp_buffer;
85} ErrorManager;
86
87typedef struct tagSourceManager {
88        /// public fields
89        struct jpeg_source_mgr pub;
90        /// source stream
91        fi_handle infile;
92        FreeImageIO *m_io;
93        /// start of buffer
94        JOCTET * buffer;
95        /// have we gotten any data yet ?
96        boolean start_of_file;
97} SourceManager;
98
99typedef struct tagDestinationManager {
100        /// public fields
101        struct jpeg_destination_mgr pub;
102        /// destination stream
103        fi_handle outfile;
104        FreeImageIO *m_io;
105        /// start of buffer
106        JOCTET * buffer;
107} DestinationManager;
108
109typedef SourceManager*          freeimage_src_ptr;
110typedef DestinationManager* freeimage_dst_ptr;
111typedef ErrorManager*           freeimage_error_ptr;
112
113// ----------------------------------------------------------
114//   Error handling
115// ----------------------------------------------------------
116
117/**
118        Receives control for a fatal error.  Information sufficient to
119        generate the error message has been stored in cinfo->err; call
120        output_message to display it.  Control must NOT return to the caller;
121        generally this routine will exit() or longjmp() somewhere.
122*/
123METHODDEF(void)
124jpeg_error_exit (j_common_ptr cinfo) {
125        // always display the message
126        (*cinfo->err->output_message)(cinfo);
127
128        // allow JPEG with unknown markers
129        if((cinfo)->err->msg_code != JERR_UNKNOWN_MARKER) {
130       
131                // let the memory manager delete any temp files before we die
132                jpeg_destroy(cinfo);
133               
134                throw s_format_id;
135        }
136}
137
138/**
139        Actual output of any JPEG message.  Note that this method does not know
140        how to generate a message, only where to send it.
141*/
142METHODDEF(void)
143jpeg_output_message (j_common_ptr cinfo) {
144        char buffer[JMSG_LENGTH_MAX];
145
146        // create the message
147        (*cinfo->err->format_message)(cinfo, buffer);
148        // send it to user's message proc
149        FreeImage_OutputMessageProc(s_format_id, buffer);
150}
151
152// ----------------------------------------------------------
153//   Destination manager
154// ----------------------------------------------------------
155
156/**
157        Initialize destination.  This is called by jpeg_start_compress()
158        before any data is actually written. It must initialize
159        next_output_byte and free_in_buffer. free_in_buffer must be
160        initialized to a positive value.
161*/
162METHODDEF(void)
163init_destination (j_compress_ptr cinfo) {
164        freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest;
165
166        dest->buffer = (JOCTET *)
167          (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
168                                  OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
169
170        dest->pub.next_output_byte = dest->buffer;
171        dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
172}
173
174/**
175        This is called whenever the buffer has filled (free_in_buffer
176        reaches zero). In typical applications, it should write out the
177        *entire* buffer (use the saved start address and buffer length;
178        ignore the current state of next_output_byte and free_in_buffer).
179        Then reset the pointer & count to the start of the buffer, and
180        return TRUE indicating that the buffer has been dumped.
181        free_in_buffer must be set to a positive value when TRUE is
182        returned.  A FALSE return should only be used when I/O suspension is
183        desired.
184*/
185METHODDEF(boolean)
186empty_output_buffer (j_compress_ptr cinfo) {
187        freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest;
188
189        if (dest->m_io->write_proc(dest->buffer, 1, OUTPUT_BUF_SIZE, dest->outfile) != OUTPUT_BUF_SIZE) {
190                // let the memory manager delete any temp files before we die
191                jpeg_destroy((j_common_ptr)cinfo);
192
193                throw(JERR_FILE_WRITE);
194        }
195
196        dest->pub.next_output_byte = dest->buffer;
197        dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
198
199        return TRUE;
200}
201
202/**
203        Terminate destination --- called by jpeg_finish_compress() after all
204        data has been written.  In most applications, this must flush any
205        data remaining in the buffer.  Use either next_output_byte or
206        free_in_buffer to determine how much data is in the buffer.
207*/
208METHODDEF(void)
209term_destination (j_compress_ptr cinfo) {
210        freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest;
211
212        size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
213
214        // write any data remaining in the buffer
215
216        if (datacount > 0) {
217                if (dest->m_io->write_proc(dest->buffer, 1, (unsigned int)datacount, dest->outfile) != datacount) {
218                        // let the memory manager delete any temp files before we die
219                        jpeg_destroy((j_common_ptr)cinfo);
220                       
221                        throw(JERR_FILE_WRITE);
222                }
223        }
224}
225
226// ----------------------------------------------------------
227//   Source manager
228// ----------------------------------------------------------
229
230/**
231        Initialize source.  This is called by jpeg_read_header() before any
232        data is actually read. Unlike init_destination(), it may leave
233        bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
234        will occur immediately).
235*/
236METHODDEF(void)
237init_source (j_decompress_ptr cinfo) {
238        freeimage_src_ptr src = (freeimage_src_ptr) cinfo->src;
239
240        /* We reset the empty-input-file flag for each image,
241         * but we don't clear the input buffer.
242         * This is correct behavior for reading a series of images from one source.
243        */
244
245        src->start_of_file = TRUE;
246}
247
248/**
249        This is called whenever bytes_in_buffer has reached zero and more
250        data is wanted.  In typical applications, it should read fresh data
251        into the buffer (ignoring the current state of next_input_byte and
252        bytes_in_buffer), reset the pointer & count to the start of the
253        buffer, and return TRUE indicating that the buffer has been reloaded.
254        It is not necessary to fill the buffer entirely, only to obtain at
255        least one more byte.  bytes_in_buffer MUST be set to a positive value
256        if TRUE is returned.  A FALSE return should only be used when I/O
257        suspension is desired.
258*/
259METHODDEF(boolean)
260fill_input_buffer (j_decompress_ptr cinfo) {
261        freeimage_src_ptr src = (freeimage_src_ptr) cinfo->src;
262
263        size_t nbytes = src->m_io->read_proc(src->buffer, 1, INPUT_BUF_SIZE, src->infile);
264
265        if (nbytes <= 0) {
266                if (src->start_of_file) {
267                        // treat empty input file as fatal error
268
269                        // let the memory manager delete any temp files before we die
270                        jpeg_destroy((j_common_ptr)cinfo);
271
272                        throw(JERR_INPUT_EMPTY);
273                }
274
275                WARNMS(cinfo, JWRN_JPEG_EOF);
276
277                /* Insert a fake EOI marker */
278
279                src->buffer[0] = (JOCTET) 0xFF;
280                src->buffer[1] = (JOCTET) JPEG_EOI;
281
282                nbytes = 2;
283        }
284
285        src->pub.next_input_byte = src->buffer;
286        src->pub.bytes_in_buffer = nbytes;
287        src->start_of_file = FALSE;
288
289        return TRUE;
290}
291
292/**
293        Skip num_bytes worth of data.  The buffer pointer and count should
294        be advanced over num_bytes input bytes, refilling the buffer as
295        needed. This is used to skip over a potentially large amount of
296        uninteresting data (such as an APPn marker). In some applications
297        it may be possible to optimize away the reading of the skipped data,
298        but it's not clear that being smart is worth much trouble; large
299        skips are uncommon.  bytes_in_buffer may be zero on return.
300        A zero or negative skip count should be treated as a no-op.
301*/
302METHODDEF(void)
303skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
304        freeimage_src_ptr src = (freeimage_src_ptr) cinfo->src;
305
306        /* Just a dumb implementation for now.  Could use fseek() except
307     * it doesn't work on pipes.  Not clear that being smart is worth
308         * any trouble anyway --- large skips are infrequent.
309        */
310
311        if (num_bytes > 0) {
312                while (num_bytes > (long) src->pub.bytes_in_buffer) {
313                  num_bytes -= (long) src->pub.bytes_in_buffer;
314
315                  (void) fill_input_buffer(cinfo);
316
317                  /* note we assume that fill_input_buffer will never return FALSE,
318                   * so suspension need not be handled.
319                   */
320                }
321
322                src->pub.next_input_byte += (size_t) num_bytes;
323                src->pub.bytes_in_buffer -= (size_t) num_bytes;
324        }
325}
326
327/**
328        Terminate source --- called by jpeg_finish_decompress
329        after all data has been read.  Often a no-op.
330
331        NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
332        application must deal with any cleanup that should happen even
333        for error exit.
334*/
335METHODDEF(void)
336term_source (j_decompress_ptr cinfo) {
337  // no work necessary here
338}
339
340// ----------------------------------------------------------
341//   Source manager & Destination manager setup
342// ----------------------------------------------------------
343
344/**
345        Prepare for input from a stdio stream.
346        The caller must have already opened the stream, and is responsible
347        for closing it after finishing decompression.
348*/
349GLOBAL(void)
350jpeg_freeimage_src (j_decompress_ptr cinfo, fi_handle infile, FreeImageIO *io) {
351        freeimage_src_ptr src;
352
353        // allocate memory for the buffer. is released automatically in the end
354
355        if (cinfo->src == NULL) {
356                cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
357                        ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(SourceManager));
358
359                src = (freeimage_src_ptr) cinfo->src;
360
361                src->buffer = (JOCTET *) (*cinfo->mem->alloc_small)
362                        ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * SIZEOF(JOCTET));
363        }
364
365        // initialize the jpeg pointer struct with pointers to functions
366
367        src = (freeimage_src_ptr) cinfo->src;
368        src->pub.init_source = init_source;
369        src->pub.fill_input_buffer = fill_input_buffer;
370        src->pub.skip_input_data = skip_input_data;
371        src->pub.resync_to_restart = jpeg_resync_to_restart; // use default method
372        src->pub.term_source = term_source;
373        src->infile = infile;
374        src->m_io = io;
375        src->pub.bytes_in_buffer = 0;           // forces fill_input_buffer on first read
376        src->pub.next_input_byte = NULL;        // until buffer loaded
377}
378
379/**
380        Prepare for output to a stdio stream.
381        The caller must have already opened the stream, and is responsible
382        for closing it after finishing compression.
383*/
384GLOBAL(void)
385jpeg_freeimage_dst (j_compress_ptr cinfo, fi_handle outfile, FreeImageIO *io) {
386        freeimage_dst_ptr dest;
387
388        if (cinfo->dest == NULL) {
389                cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small)
390                        ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(DestinationManager));
391        }
392
393        dest = (freeimage_dst_ptr) cinfo->dest;
394        dest->pub.init_destination = init_destination;
395        dest->pub.empty_output_buffer = empty_output_buffer;
396        dest->pub.term_destination = term_destination;
397        dest->outfile = outfile;
398        dest->m_io = io;
399}
400
401// ----------------------------------------------------------
402//   Special markers read functions
403// ----------------------------------------------------------
404
405/**
406        Read JPEG_COM marker (comment)
407*/
408static BOOL
409jpeg_read_comment(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
410        size_t length = datalen;
411        BYTE *profile = (BYTE*)dataptr;
412
413        // read the comment
414        char *value = (char*)malloc((length + 1) * sizeof(char));
415        if(value == NULL) return FALSE;
416        memcpy(value, profile, length);
417        value[length] = '\0';
418
419        // create a tag
420        FITAG *tag = FreeImage_CreateTag();
421        if(tag) {
422                unsigned int count = (unsigned int)length + 1;  // includes the null value
423
424                FreeImage_SetTagID(tag, JPEG_COM);
425                FreeImage_SetTagKey(tag, "Comment");
426                FreeImage_SetTagLength(tag, count);
427                FreeImage_SetTagCount(tag, count);
428                FreeImage_SetTagType(tag, FIDT_ASCII);
429                FreeImage_SetTagValue(tag, value);
430               
431                // store the tag
432                FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
433
434                // destroy the tag
435                FreeImage_DeleteTag(tag);
436        }
437
438        free(value);
439
440        return TRUE;
441}
442
443/**
444        Read JPEG_APP2 marker (ICC profile)
445*/
446
447/**
448Handy subroutine to test whether a saved marker is an ICC profile marker.
449*/
450static BOOL
451marker_is_icc(jpeg_saved_marker_ptr marker) {
452    // marker identifying string "ICC_PROFILE" (null-terminated)
453        const BYTE icc_signature[12] = { 0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00 };
454
455        if(marker->marker == ICC_MARKER) {
456                // verify the identifying string
457                if(marker->data_length >= ICC_HEADER_SIZE) {
458                        if(memcmp(icc_signature, marker->data, sizeof(icc_signature)) == 0) {
459                                return TRUE;
460                        }
461                }
462        }
463
464        return FALSE;
465}
466
467/**
468  See if there was an ICC profile in the JPEG file being read;
469  if so, reassemble and return the profile data.
470
471  TRUE is returned if an ICC profile was found, FALSE if not.
472  If TRUE is returned, *icc_data_ptr is set to point to the
473  returned data, and *icc_data_len is set to its length.
474 
475  IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
476  and must be freed by the caller with free() when the caller no longer
477  needs it.  (Alternatively, we could write this routine to use the
478  IJG library's memory allocator, so that the data would be freed implicitly
479  at jpeg_finish_decompress() time.  But it seems likely that many apps
480  will prefer to have the data stick around after decompression finishes.)
481 
482  NOTE: if the file contains invalid ICC APP2 markers, we just silently
483  return FALSE.  You might want to issue an error message instead.
484*/
485static BOOL
486jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned *icc_data_len) {
487        jpeg_saved_marker_ptr marker;
488        int num_markers = 0;
489        int seq_no;
490        JOCTET *icc_data;
491        unsigned total_length;
492
493        const int MAX_SEQ_NO = 255;                     // sufficient since marker numbers are bytes
494        BYTE marker_present[MAX_SEQ_NO+1];      // 1 if marker found
495        unsigned data_length[MAX_SEQ_NO+1];     // size of profile data in marker
496        unsigned data_offset[MAX_SEQ_NO+1];     // offset for data in marker
497       
498        *icc_data_ptr = NULL;           // avoid confusion if FALSE return
499        *icc_data_len = 0;
500       
501        /**
502        this first pass over the saved markers discovers whether there are
503        any ICC markers and verifies the consistency of the marker numbering.
504        */
505       
506        memset(marker_present, 0, (MAX_SEQ_NO + 1));
507       
508        for(marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
509                if (marker_is_icc(marker)) {
510                        if (num_markers == 0) {
511                                // number of markers
512                                num_markers = GETJOCTET(marker->data[13]);
513                        }
514                        else if (num_markers != GETJOCTET(marker->data[13])) {
515                                return FALSE;           // inconsistent num_markers fields
516                        }
517                        // sequence number
518                        seq_no = GETJOCTET(marker->data[12]);
519                        if (seq_no <= 0 || seq_no > num_markers) {
520                                return FALSE;           // bogus sequence number
521                        }
522                        if (marker_present[seq_no]) {
523                                return FALSE;           // duplicate sequence numbers
524                        }
525                        marker_present[seq_no] = 1;
526                        data_length[seq_no] = marker->data_length - ICC_HEADER_SIZE;
527                }
528        }
529       
530        if (num_markers == 0)
531                return FALSE;
532               
533        /**
534        check for missing markers, count total space needed,
535        compute offset of each marker's part of the data.
536        */
537       
538        total_length = 0;
539        for(seq_no = 1; seq_no <= num_markers; seq_no++) {
540                if (marker_present[seq_no] == 0) {
541                        return FALSE;           // missing sequence number
542                }
543                data_offset[seq_no] = total_length;
544                total_length += data_length[seq_no];
545        }
546       
547        if (total_length <= 0)
548                return FALSE;           // found only empty markers ?
549       
550        // allocate space for assembled data
551        icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
552        if (icc_data == NULL)
553                return FALSE;           // out of memory
554       
555        // and fill it in
556        for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
557                if (marker_is_icc(marker)) {
558                        JOCTET FAR *src_ptr;
559                        JOCTET *dst_ptr;
560                        unsigned length;
561                        seq_no = GETJOCTET(marker->data[12]);
562                        dst_ptr = icc_data + data_offset[seq_no];
563                        src_ptr = marker->data + ICC_HEADER_SIZE;
564                        length = data_length[seq_no];
565                        while (length--) {
566                                *dst_ptr++ = *src_ptr++;
567                        }
568                }
569        }
570       
571        *icc_data_ptr = icc_data;
572        *icc_data_len = total_length;
573       
574        return TRUE;
575}
576
577/**
578        Read JPEG_APPD marker (IPTC or Adobe Photoshop profile)
579*/
580static BOOL
581jpeg_read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
582        return read_iptc_profile(dib, dataptr, datalen);
583}
584
585/**
586        Read JPEG_APP1 marker (XMP profile)
587        @param dib Input FIBITMAP
588        @param dataptr Pointer to the APP1 marker
589        @param datalen APP1 marker length
590        @return Returns TRUE if successful, FALSE otherwise
591*/
592static BOOL 
593jpeg_read_xmp_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
594        // marker identifying string for XMP (null terminated)
595        const char *xmp_signature = "http://ns.adobe.com/xap/1.0/";
596        // XMP signature is 29 bytes long
597        const size_t xmp_signature_size = strlen(xmp_signature) + 1;
598
599        size_t length = datalen;
600        BYTE *profile = (BYTE*)dataptr;
601
602        if(length <= xmp_signature_size) {
603                // avoid reading corrupted or empty data
604                return FALSE;
605        }
606
607        // verify the identifying string
608
609        if(memcmp(xmp_signature, profile, strlen(xmp_signature)) == 0) {
610                // XMP profile
611
612                profile += xmp_signature_size;
613                length  -= xmp_signature_size;
614
615                // create a tag
616                FITAG *tag = FreeImage_CreateTag();
617                if(tag) {
618                        FreeImage_SetTagID(tag, JPEG_APP0+1);   // 0xFFE1
619                        FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
620                        FreeImage_SetTagLength(tag, (DWORD)length);
621                        FreeImage_SetTagCount(tag, (DWORD)length);
622                        FreeImage_SetTagType(tag, FIDT_ASCII);
623                        FreeImage_SetTagValue(tag, profile);
624                       
625                        // store the tag
626                        FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
627
628                        // destroy the tag
629                        FreeImage_DeleteTag(tag);
630                }
631
632                return TRUE;
633        }
634
635        return FALSE;
636}
637
638/**
639        Read JPEG_APP1 marker (Exif profile)
640        @param dib Input FIBITMAP
641        @param dataptr Pointer to the APP1 marker
642        @param datalen APP1 marker length
643        @return Returns TRUE if successful, FALSE otherwise
644*/
645static BOOL 
646jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned int length) {
647    // marker identifying string for Exif = "Exif\0\0"
648    BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
649
650        // verify the identifying string
651        if(memcmp(exif_signature, profile, sizeof(exif_signature)) != 0) {
652                // not an Exif profile
653                return FALSE;
654        }
655
656        // create a tag
657        FITAG *tag = FreeImage_CreateTag();
658        if(tag) {
659                FreeImage_SetTagID(tag, EXIF_MARKER);   // (JPEG_APP0 + 1) => EXIF marker / Adobe XMP marker
660                FreeImage_SetTagKey(tag, g_TagLib_ExifRawFieldName);
661                FreeImage_SetTagLength(tag, (DWORD)length);
662                FreeImage_SetTagCount(tag, (DWORD)length);
663                FreeImage_SetTagType(tag, FIDT_BYTE);
664                FreeImage_SetTagValue(tag, profile);
665
666                // store the tag
667                FreeImage_SetMetadata(FIMD_EXIF_RAW, dib, FreeImage_GetTagKey(tag), tag);
668
669                // destroy the tag
670                FreeImage_DeleteTag(tag);
671
672                return TRUE;
673        }
674
675        return FALSE;
676}
677
678/**
679        Read JFIF "JFXX" extension APP0 marker
680        @param dib Input FIBITMAP
681        @param dataptr Pointer to the APP0 marker
682        @param datalen APP0 marker length
683        @return Returns TRUE if successful, FALSE otherwise
684*/
685static BOOL
686jpeg_read_jfxx(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) {
687        if(datalen < 6) {
688                return FALSE;
689        }
690       
691        const int id_length = 5;
692        const BYTE *data = dataptr + id_length;
693        unsigned remaining = datalen - id_length;
694               
695        const BYTE type = *data;
696        ++data, --remaining;
697
698        switch(type) {
699                case JFXX_TYPE_JPEG:
700                {
701                        // load the thumbnail
702                        FIMEMORY* hmem = FreeImage_OpenMemory(const_cast<BYTE*>(data), remaining);
703                        FIBITMAP* thumbnail = FreeImage_LoadFromMemory(FIF_JPEG, hmem);
704                        FreeImage_CloseMemory(hmem);
705                        // store the thumbnail
706                        FreeImage_SetThumbnail(dib, thumbnail);
707                        // then delete it
708                        FreeImage_Unload(thumbnail);
709                        break;
710                }
711                case JFXX_TYPE_8bit:
712                        // colormapped uncompressed thumbnail (no supported)
713                        break;
714                case JFXX_TYPE_24bit:
715                        // truecolor uncompressed thumbnail (no supported)
716                        break;
717                default:
718                        break;
719        }
720
721        return TRUE;
722}
723
724
725/**
726        Read JPEG special markers
727*/
728static BOOL
729read_markers(j_decompress_ptr cinfo, FIBITMAP *dib) {
730        jpeg_saved_marker_ptr marker;
731
732        for(marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
733                switch(marker->marker) {
734                        case JPEG_APP0:
735                                // JFIF is handled by libjpeg already, handle JFXX
736                                if(memcmp(marker->data, "JFIF" , 5) == 0) {
737                                        continue;
738                                }
739                                if(memcmp(marker->data, "JFXX" , 5) == 0) {
740                                        if(!cinfo->saw_JFIF_marker || cinfo->JFIF_minor_version < 2) {
741                                                FreeImage_OutputMessageProc(s_format_id, "Warning: non-standard JFXX segment");
742                                        }                                       
743                                        jpeg_read_jfxx(dib, marker->data, marker->data_length);
744                                }
745                                // other values such as 'Picasa' : ignore safely unknown APP0 marker
746                                break;
747                        case JPEG_COM:
748                                // JPEG comment
749                                jpeg_read_comment(dib, marker->data, marker->data_length);
750                                break;
751                        case EXIF_MARKER:
752                                // Exif or Adobe XMP profile
753                                jpeg_read_exif_profile(dib, marker->data, marker->data_length);
754                                jpeg_read_xmp_profile(dib, marker->data, marker->data_length);
755                                jpeg_read_exif_profile_raw(dib, marker->data, marker->data_length);
756                                break;
757                        case IPTC_MARKER:
758                                // IPTC/NAA or Adobe Photoshop profile
759                                jpeg_read_iptc_profile(dib, marker->data, marker->data_length);
760                                break;
761                }
762        }
763
764        // ICC profile
765        BYTE *icc_profile = NULL;
766        unsigned icc_length = 0;
767
768        if( jpeg_read_icc_profile(cinfo, &icc_profile, &icc_length) ) {
769                // copy ICC profile data
770                FreeImage_CreateICCProfile(dib, icc_profile, icc_length);
771                // clean up
772                free(icc_profile);
773        }
774
775        return TRUE;
776}
777
778// ----------------------------------------------------------
779//   Special markers write functions
780// ----------------------------------------------------------
781
782/**
783        Write JPEG_COM marker (comment)
784*/
785static BOOL
786jpeg_write_comment(j_compress_ptr cinfo, FIBITMAP *dib) {
787        FITAG *tag = NULL;
788
789        // write user comment as a JPEG_COM marker
790        FreeImage_GetMetadata(FIMD_COMMENTS, dib, "Comment", &tag);
791        if(tag) {
792                const char *tag_value = (char*)FreeImage_GetTagValue(tag);
793
794                if(NULL != tag_value) {
795                        for(long i = 0; i < (long)strlen(tag_value); i+= MAX_BYTES_IN_MARKER) {
796                                jpeg_write_marker(cinfo, JPEG_COM, (BYTE*)tag_value + i, MIN((long)strlen(tag_value + i), MAX_BYTES_IN_MARKER));
797                        }
798                        return TRUE;
799                }
800        }
801        return FALSE;
802}
803
804/**
805        Write JPEG_APP2 marker (ICC profile)
806*/
807static BOOL
808jpeg_write_icc_profile(j_compress_ptr cinfo, FIBITMAP *dib) {
809    // marker identifying string "ICC_PROFILE" (null-terminated)
810        BYTE icc_signature[12] = { 0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00 };
811
812        FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
813
814        if (iccProfile->size && iccProfile->data) {
815                // ICC_HEADER_SIZE: ICC signature is 'ICC_PROFILE' + 2 bytes
816
817                BYTE *profile = (BYTE*)malloc((iccProfile->size + ICC_HEADER_SIZE) * sizeof(BYTE));
818                if(profile == NULL) return FALSE;
819                memcpy(profile, icc_signature, 12);
820
821                for(long i = 0; i < (long)iccProfile->size; i += MAX_DATA_BYTES_IN_MARKER) {
822                        unsigned length = MIN((long)(iccProfile->size - i), MAX_DATA_BYTES_IN_MARKER);
823                        // sequence number
824                        profile[12] = (BYTE) ((i / MAX_DATA_BYTES_IN_MARKER) + 1);
825                        // number of markers
826                        profile[13] = (BYTE) (iccProfile->size / MAX_DATA_BYTES_IN_MARKER + 1);
827
828                        memcpy(profile + ICC_HEADER_SIZE, (BYTE*)iccProfile->data + i, length);
829                        jpeg_write_marker(cinfo, ICC_MARKER, profile, (length + ICC_HEADER_SIZE));
830        }
831
832                free(profile);
833
834                return TRUE;           
835        }
836       
837        return FALSE;
838}
839
840/**
841        Write JPEG_APPD marker (IPTC or Adobe Photoshop profile)
842        @return Returns TRUE if successful, FALSE otherwise
843*/
844static BOOL 
845jpeg_write_iptc_profile(j_compress_ptr cinfo, FIBITMAP *dib) {
846        //const char *ps_header = "Photoshop 3.0\x08BIM\x04\x04\x0\x0\x0\x0";
847        const unsigned tag_length = 26;
848
849        if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) {
850                BYTE *profile = NULL;
851                unsigned profile_size = 0;
852
853                // create a binary profile
854                if(write_iptc_profile(dib, &profile, &profile_size)) {
855
856                        // write the profile
857                        for(long i = 0; i < (long)profile_size; i += 65517L) {
858                                unsigned length = MIN((long)profile_size - i, 65517L);
859                                unsigned roundup = length & 0x01;       // needed for Photoshop
860                                BYTE *iptc_profile = (BYTE*)malloc(length + roundup + tag_length);
861                                if(iptc_profile == NULL) break;
862                                // Photoshop identification string
863                                memcpy(&iptc_profile[0], "Photoshop 3.0\x0", 14);
864                                // 8BIM segment type
865                                memcpy(&iptc_profile[14], "8BIM\x04\x04\x0\x0\x0\x0", 10);
866                                // segment size
867                                iptc_profile[24] = (BYTE)(length >> 8);
868                                iptc_profile[25] = (BYTE)(length & 0xFF);
869                                // segment data
870                                memcpy(&iptc_profile[tag_length], &profile[i], length);
871                                if(roundup)
872                                        iptc_profile[length + tag_length] = 0;
873                                jpeg_write_marker(cinfo, IPTC_MARKER, iptc_profile, length + roundup + tag_length);
874                                free(iptc_profile);
875                        }
876
877                        // release profile
878                        free(profile);
879
880                        return TRUE;
881                }
882        }
883
884        return FALSE;
885}
886
887/**
888        Write JPEG_APP1 marker (XMP profile)
889        @return Returns TRUE if successful, FALSE otherwise
890*/
891static BOOL 
892jpeg_write_xmp_profile(j_compress_ptr cinfo, FIBITMAP *dib) {
893        // marker identifying string for XMP (null terminated)
894        const char *xmp_signature = "http://ns.adobe.com/xap/1.0/";
895
896        FITAG *tag_xmp = NULL;
897        FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp);
898
899        if(tag_xmp) {
900                const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag_xmp);
901
902                if(NULL != tag_value) {
903                        // XMP signature is 29 bytes long
904                        unsigned int xmp_header_size = (unsigned int)strlen(xmp_signature) + 1;
905
906                        DWORD tag_length = FreeImage_GetTagLength(tag_xmp);
907
908                        BYTE *profile = (BYTE*)malloc((tag_length + xmp_header_size) * sizeof(BYTE));
909                        if(profile == NULL) return FALSE;
910                        memcpy(profile, xmp_signature, xmp_header_size);
911
912                        for(DWORD i = 0; i < tag_length; i += 65504L) {
913                                unsigned length = MIN((long)(tag_length - i), 65504L);
914                               
915                                memcpy(profile + xmp_header_size, tag_value + i, length);
916                                jpeg_write_marker(cinfo, EXIF_MARKER, profile, (length + xmp_header_size));
917                        }
918
919                        free(profile);
920
921                        return TRUE;   
922                }
923        }
924
925        return FALSE;
926}
927
928/**
929        Write JPEG_APP1 marker (Exif profile)
930        @return Returns TRUE if successful, FALSE otherwise
931*/
932static BOOL
933jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) {
934    // marker identifying string for Exif = "Exif\0\0"
935    BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
936
937        FITAG *tag_exif = NULL;
938        FreeImage_GetMetadata(FIMD_EXIF_RAW, dib, g_TagLib_ExifRawFieldName, &tag_exif);
939
940        if(tag_exif) {
941                const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag_exif);
942               
943                // verify the identifying string
944                if(memcmp(exif_signature, tag_value, sizeof(exif_signature)) != 0) {
945                        // not an Exif profile
946                        return FALSE;
947                }
948
949                if(NULL != tag_value) {
950                        DWORD tag_length = FreeImage_GetTagLength(tag_exif);
951
952                        BYTE *profile = (BYTE*)malloc(tag_length * sizeof(BYTE));
953                        if(profile == NULL) return FALSE;
954
955                        for(DWORD i = 0; i < tag_length; i += 65504L) {
956                                unsigned length = MIN((long)(tag_length - i), 65504L);
957                               
958                                memcpy(profile, tag_value + i, length);
959                                jpeg_write_marker(cinfo, EXIF_MARKER, profile, length);
960                        }
961
962                        free(profile);
963
964                        return TRUE;   
965                }
966        }
967
968        return FALSE;
969}
970
971/**
972        Write thumbnail (JFXX segment, JPEG compressed)
973*/
974static BOOL
975jpeg_write_jfxx(j_compress_ptr cinfo, FIBITMAP *dib) {
976        // get the thumbnail to be stored
977        FIBITMAP* thumbnail = FreeImage_GetThumbnail(dib);
978        if(!thumbnail) {
979                return TRUE;
980        }
981        // check for a compatible output format
982        if((FreeImage_GetImageType(thumbnail) != FIT_BITMAP) || (FreeImage_GetBPP(thumbnail) != 8) && (FreeImage_GetBPP(thumbnail) != 24)) {
983                FreeImage_OutputMessageProc(s_format_id, FI_MSG_WARNING_INVALID_THUMBNAIL);
984                return FALSE;
985        }
986       
987        // stores the thumbnail as a baseline JPEG into a memory block
988        // return the memory block only if its size is within JFXX marker size limit!
989        FIMEMORY *stream = FreeImage_OpenMemory();
990       
991        if(FreeImage_SaveToMemory(FIF_JPEG, thumbnail, stream, JPEG_BASELINE)) {
992                // check that the memory block size is within JFXX marker size limit
993                FreeImage_SeekMemory(stream, 0, SEEK_END);
994                const long eof = FreeImage_TellMemory(stream);
995                if(eof > MAX_JFXX_THUMB_SIZE) {
996                        FreeImage_OutputMessageProc(s_format_id, "Warning: attached thumbnail is %d bytes larger than maximum supported size - Thumbnail saving aborted", eof - MAX_JFXX_THUMB_SIZE);
997                        FreeImage_CloseMemory(stream);
998                        return FALSE;
999                }
1000        } else {
1001                FreeImage_CloseMemory(stream);
1002                return FALSE;
1003        }
1004
1005        BYTE* thData = NULL;
1006        DWORD thSize = 0;
1007       
1008        FreeImage_AcquireMemory(stream, &thData, &thSize);     
1009       
1010        BYTE id_length = 5; //< "JFXX"
1011        BYTE type = JFXX_TYPE_JPEG;
1012       
1013        DWORD totalsize = id_length + sizeof(type) + thSize;
1014        jpeg_write_m_header(cinfo, JPEG_APP0, totalsize);
1015       
1016        jpeg_write_m_byte(cinfo, 'J');
1017        jpeg_write_m_byte(cinfo, 'F');
1018        jpeg_write_m_byte(cinfo, 'X');
1019        jpeg_write_m_byte(cinfo, 'X');
1020        jpeg_write_m_byte(cinfo, '\0');
1021       
1022        jpeg_write_m_byte(cinfo, type);
1023       
1024        // write thumbnail to destination.
1025        // We "cram it straight into the data destination module", because write_m_byte is slow
1026       
1027        freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest;
1028       
1029        BYTE* & out = dest->pub.next_output_byte;
1030        size_t & bufRemain = dest->pub.free_in_buffer;
1031       
1032        const BYTE *thData_end = thData + thSize;
1033
1034        while(thData < thData_end) {
1035                *(out)++ = *(thData)++;
1036                if (--bufRemain == 0) { 
1037                        // buffer full - flush
1038                        if (!dest->pub.empty_output_buffer(cinfo)) {
1039                                break;
1040                        }
1041                }
1042        }
1043       
1044        FreeImage_CloseMemory(stream);
1045
1046        return TRUE;
1047}
1048
1049/**
1050        Write JPEG special markers
1051*/
1052static BOOL
1053write_markers(j_compress_ptr cinfo, FIBITMAP *dib) {
1054        // write thumbnail as a JFXX marker
1055        jpeg_write_jfxx(cinfo, dib);
1056
1057        // write user comment as a JPEG_COM marker
1058        jpeg_write_comment(cinfo, dib);
1059
1060        // write ICC profile
1061        jpeg_write_icc_profile(cinfo, dib);
1062
1063        // write IPTC profile
1064        jpeg_write_iptc_profile(cinfo, dib);
1065
1066        // write Adobe XMP profile
1067        jpeg_write_xmp_profile(cinfo, dib);
1068
1069        // write Exif raw data
1070        jpeg_write_exif_profile_raw(cinfo, dib);
1071
1072        return TRUE;
1073}
1074
1075// ------------------------------------------------------------
1076//   Keep original size info when using scale option on loading
1077// ------------------------------------------------------------
1078static void 
1079store_size_info(FIBITMAP *dib, JDIMENSION width, JDIMENSION height) {
1080        char buffer[256];
1081        // create a tag
1082        FITAG *tag = FreeImage_CreateTag();
1083        if(tag) {
1084                size_t length = 0;
1085                // set the original width
1086                sprintf(buffer, "%d", (int)width);
1087                length = strlen(buffer) + 1;    // include the NULL/0 value
1088                FreeImage_SetTagKey(tag, "OriginalJPEGWidth");
1089                FreeImage_SetTagLength(tag, (DWORD)length);
1090                FreeImage_SetTagCount(tag, (DWORD)length);
1091                FreeImage_SetTagType(tag, FIDT_ASCII);
1092                FreeImage_SetTagValue(tag, buffer);
1093                FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
1094                // set the original height
1095                sprintf(buffer, "%d", (int)height);
1096                length = strlen(buffer) + 1;    // include the NULL/0 value
1097                FreeImage_SetTagKey(tag, "OriginalJPEGHeight");
1098                FreeImage_SetTagLength(tag, (DWORD)length);
1099                FreeImage_SetTagCount(tag, (DWORD)length);
1100                FreeImage_SetTagType(tag, FIDT_ASCII);
1101                FreeImage_SetTagValue(tag, buffer);
1102                FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
1103                // destroy the tag
1104                FreeImage_DeleteTag(tag);
1105        }
1106}
1107
1108// ------------------------------------------------------------
1109//   Rotate a dib according to Exif info
1110// ------------------------------------------------------------
1111
1112static void 
1113rotate_exif(FIBITMAP **dib) {
1114        // check for Exif rotation
1115        if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, *dib)) {
1116                FIBITMAP *rotated = NULL;
1117                // process Exif rotation
1118                FITAG *tag = NULL;
1119                FreeImage_GetMetadata(FIMD_EXIF_MAIN, *dib, "Orientation", &tag);
1120                if(tag != NULL) {
1121                        if(FreeImage_GetTagID(tag) == TAG_ORIENTATION) {
1122                                unsigned short orientation = *((unsigned short *)FreeImage_GetTagValue(tag));
1123                                switch (orientation) {
1124                                        case 1:         // "top, left side" => 0°
1125                                                break;
1126                                        case 2:         // "top, right side" => flip left-right
1127                                                FreeImage_FlipHorizontal(*dib);
1128                                                break;
1129                                        case 3:         // "bottom, right side"; => -180°
1130                                                rotated = FreeImage_Rotate(*dib, 180);
1131                                                FreeImage_Unload(*dib);
1132                                                *dib = rotated;
1133                                                break;
1134                                        case 4:         // "bottom, left side" => flip up-down
1135                                                FreeImage_FlipVertical(*dib);
1136                                                break;
1137                                        case 5:         // "left side, top" => +90° + flip up-down
1138                                                rotated = FreeImage_Rotate(*dib, 90);
1139                                                FreeImage_Unload(*dib);
1140                                                *dib = rotated;
1141                                                FreeImage_FlipVertical(*dib);
1142                                                break;
1143                                        case 6:         // "right side, top" => -90°
1144                                                rotated = FreeImage_Rotate(*dib, -90);
1145                                                FreeImage_Unload(*dib);
1146                                                *dib = rotated;
1147                                                break;
1148                                        case 7:         // "right side, bottom" => -90° + flip up-down
1149                                                rotated = FreeImage_Rotate(*dib, -90);
1150                                                FreeImage_Unload(*dib);
1151                                                *dib = rotated;
1152                                                FreeImage_FlipVertical(*dib);
1153                                                break;
1154                                        case 8:         // "left side, bottom" => +90°
1155                                                rotated = FreeImage_Rotate(*dib, 90);
1156                                                FreeImage_Unload(*dib);
1157                                                *dib = rotated;
1158                                                break;
1159                                        default:
1160                                                break;
1161                                }
1162                        }
1163                }
1164        }
1165}
1166
1167
1168// ==========================================================
1169// Plugin Implementation
1170// ==========================================================
1171
1172static const char * DLL_CALLCONV
1173Format() {
1174        return "JPEG";
1175}
1176
1177static const char * DLL_CALLCONV
1178Description() {
1179        return "JPEG - JFIF Compliant";
1180}
1181
1182static const char * DLL_CALLCONV
1183Extension() {
1184        return "jpg,jif,jpeg,jpe";
1185}
1186
1187static const char * DLL_CALLCONV
1188RegExpr() {
1189        return "^\377\330\377";
1190}
1191
1192static const char * DLL_CALLCONV
1193MimeType() {
1194        return "image/jpeg";
1195}
1196
1197static BOOL DLL_CALLCONV
1198Validate(FreeImageIO *io, fi_handle handle) {
1199        BYTE jpeg_signature[] = { 0xFF, 0xD8 };
1200        BYTE signature[2] = { 0, 0 };
1201
1202        io->read_proc(signature, 1, sizeof(jpeg_signature), handle);
1203
1204        return (memcmp(jpeg_signature, signature, sizeof(jpeg_signature)) == 0);
1205}
1206
1207static BOOL DLL_CALLCONV
1208SupportsExportDepth(int depth) {
1209        return (
1210                        (depth == 8) ||
1211                        (depth == 24)
1212                );
1213}
1214
1215static BOOL DLL_CALLCONV
1216SupportsExportType(FREE_IMAGE_TYPE type) {
1217        return (type == FIT_BITMAP) ? TRUE : FALSE;
1218}
1219
1220static BOOL DLL_CALLCONV
1221SupportsICCProfiles() {
1222        return TRUE;
1223}
1224
1225static BOOL DLL_CALLCONV
1226SupportsNoPixels() {
1227        return TRUE;
1228}
1229
1230// ----------------------------------------------------------
1231
1232static FIBITMAP * DLL_CALLCONV
1233Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
1234        if (handle) {
1235                FIBITMAP *dib = NULL;
1236
1237                BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
1238
1239                try {
1240                        // set up the jpeglib structures
1241
1242                        struct jpeg_decompress_struct cinfo;
1243                        struct jpeg_error_mgr jerr;
1244
1245                        // step 1: allocate and initialize JPEG decompression object
1246
1247                        cinfo.err = jpeg_std_error(&jerr);
1248
1249                        jerr.error_exit     = jpeg_error_exit;
1250                        jerr.output_message = jpeg_output_message;
1251
1252                        jpeg_create_decompress(&cinfo);
1253
1254                        // step 2a: specify data source (eg, a handle)
1255
1256                        jpeg_freeimage_src(&cinfo, handle, io);
1257
1258                        // step 2b: save special markers for later reading
1259                       
1260                        jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
1261                        for(int m = 0; m < 16; m++) {
1262                                jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF);
1263                        }
1264
1265                        // step 3: read handle parameters with jpeg_read_header()
1266
1267                        jpeg_read_header(&cinfo, TRUE);
1268
1269                        // step 4: set parameters for decompression
1270
1271                        unsigned int scale_denom = 1;           // fraction by which to scale image
1272                        int     requested_size = flags >> 16;   // requested user size in pixels
1273                        if(requested_size > 0) {
1274                                // the JPEG codec can perform x2, x4 or x8 scaling on loading
1275                                // try to find the more appropriate scaling according to user's need
1276                                double scale = MAX((double)cinfo.image_width, (double)cinfo.image_height) / (double)requested_size;
1277                                if(scale >= 8) {
1278                                        scale_denom = 8;
1279                                } else if(scale >= 4) {
1280                                        scale_denom = 4;
1281                                } else if(scale >= 2) {
1282                                        scale_denom = 2;
1283                                }
1284                        }
1285                        cinfo.scale_num = 1;
1286                        cinfo.scale_denom = scale_denom;
1287
1288                        if ((flags & JPEG_ACCURATE) != JPEG_ACCURATE) {
1289                                cinfo.dct_method          = JDCT_IFAST;
1290                                cinfo.do_fancy_upsampling = FALSE;
1291                        }
1292
1293                        // step 5a: start decompressor and calculate output width and height
1294
1295                        jpeg_start_decompress(&cinfo);
1296
1297                        // step 5b: allocate dib and init header
1298
1299                        if((cinfo.num_components == 4) && (cinfo.out_color_space == JCS_CMYK)) {
1300                                // CMYK image
1301                                if((flags & JPEG_CMYK) == JPEG_CMYK) {
1302                                        // load as CMYK
1303                                        dib = FreeImage_AllocateHeader(header_only, cinfo.output_width, cinfo.output_height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1304                                        if(!dib) return NULL;
1305                                        FreeImage_GetICCProfile(dib)->flags |= FIICC_COLOR_IS_CMYK;
1306                                } else {
1307                                        // load as CMYK and convert to RGB
1308                                        dib = FreeImage_AllocateHeader(header_only, cinfo.output_width, cinfo.output_height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1309                                        if(!dib) return NULL;
1310                                }
1311                        } else {
1312                                // RGB or greyscale image
1313                                dib = FreeImage_AllocateHeader(header_only, cinfo.output_width, cinfo.output_height, 8 * cinfo.num_components, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1314                                if(!dib) return NULL;
1315
1316                                if (cinfo.num_components == 1) {
1317                                        // build a greyscale palette
1318                                        RGBQUAD *colors = FreeImage_GetPalette(dib);
1319
1320                                        for (int i = 0; i < 256; i++) {
1321                                                colors[i].rgbRed   = (BYTE)i;
1322                                                colors[i].rgbGreen = (BYTE)i;
1323                                                colors[i].rgbBlue  = (BYTE)i;
1324                                        }
1325                                }
1326                        }
1327                        if(scale_denom != 1) {
1328                                // store original size info if a scaling was requested
1329                                store_size_info(dib, cinfo.image_width, cinfo.image_height);
1330                        }
1331
1332                        // step 5c: handle metrices
1333
1334                        if (cinfo.density_unit == 1) {
1335                                // dots/inch
1336                                FreeImage_SetDotsPerMeterX(dib, (unsigned) (((float)cinfo.X_density) / 0.0254000 + 0.5));
1337                                FreeImage_SetDotsPerMeterY(dib, (unsigned) (((float)cinfo.Y_density) / 0.0254000 + 0.5));
1338                        } else if (cinfo.density_unit == 2) {
1339                                // dots/cm
1340                                FreeImage_SetDotsPerMeterX(dib, (unsigned) (cinfo.X_density * 100));
1341                                FreeImage_SetDotsPerMeterY(dib, (unsigned) (cinfo.Y_density * 100));
1342                        }
1343                       
1344                        // step 6: read special markers
1345                       
1346                        read_markers(&cinfo, dib);
1347
1348                        // --- header only mode => clean-up and return
1349
1350                        if (header_only) {
1351                                // release JPEG decompression object
1352                                jpeg_destroy_decompress(&cinfo);
1353                                // return header data
1354                                return dib;
1355                        }
1356
1357                        // step 7a: while (scan lines remain to be read) jpeg_read_scanlines(...);
1358
1359                        if((cinfo.out_color_space == JCS_CMYK) && ((flags & JPEG_CMYK) != JPEG_CMYK)) {
1360                                // convert from CMYK to RGB
1361
1362                                JSAMPARRAY buffer;              // output row buffer
1363                                unsigned row_stride;    // physical row width in output buffer
1364
1365                                // JSAMPLEs per row in output buffer
1366                                row_stride = cinfo.output_width * cinfo.output_components;
1367                                // make a one-row-high sample array that will go away when done with image
1368                                buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
1369
1370                                while (cinfo.output_scanline < cinfo.output_height) {
1371                                        JSAMPROW src = buffer[0];
1372                                        JSAMPROW dst = FreeImage_GetScanLine(dib, cinfo.output_height - cinfo.output_scanline - 1);
1373
1374                                        jpeg_read_scanlines(&cinfo, buffer, 1);
1375
1376                                        for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
1377                                                WORD K = (WORD)src[3];
1378                                                dst[FI_RGBA_RED]   = (BYTE)((K * src[0]) / 255);
1379                                                dst[FI_RGBA_GREEN] = (BYTE)((K * src[1]) / 255);
1380                                                dst[FI_RGBA_BLUE]  = (BYTE)((K * src[2]) / 255);
1381                                                src += 4;
1382                                                dst += 3;
1383                                        }
1384                                }
1385                        } else {
1386                                // normal case (RGB or greyscale image)
1387
1388                                while (cinfo.output_scanline < cinfo.output_height) {
1389                                        JSAMPROW dst = FreeImage_GetScanLine(dib, cinfo.output_height - cinfo.output_scanline - 1);
1390
1391                                        jpeg_read_scanlines(&cinfo, &dst, 1);
1392                                }
1393
1394                                // step 7b: swap red and blue components (see LibJPEG/jmorecfg.h: #define RGB_RED, ...)
1395                                // The default behavior of the JPEG library is kept "as is" because LibTIFF uses
1396                                // LibJPEG "as is".
1397
1398#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
1399                                if(cinfo.num_components == 3) {
1400                                        for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
1401                                                BYTE *target = FreeImage_GetScanLine(dib, y);
1402                                                for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
1403                                                        INPLACESWAP(target[0], target[2]);
1404                                                        target += 3;
1405                                                }
1406                                        }
1407                                }
1408#endif
1409                        }
1410
1411                        // step 8: finish decompression
1412
1413                        jpeg_finish_decompress(&cinfo);
1414
1415                        // step 9: release JPEG decompression object
1416
1417                        jpeg_destroy_decompress(&cinfo);
1418
1419                        // check for automatic Exif rotation
1420                        if(!header_only && ((flags & JPEG_EXIFROTATE) == JPEG_EXIFROTATE)) {
1421                                rotate_exif(&dib);
1422                        }
1423
1424                        // everything went well. return the loaded dib
1425
1426                        return (FIBITMAP *)dib;
1427                } catch (...) {
1428                        if(NULL != dib) {
1429                                FreeImage_Unload(dib);
1430                        }
1431                }
1432        }
1433
1434        return NULL;
1435}
1436
1437// ----------------------------------------------------------
1438
1439static BOOL DLL_CALLCONV
1440Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
1441        if ((dib) && (handle)) {
1442                try {
1443                        // Check dib format
1444
1445                        const char *sError = "only 24-bit highcolor or 8-bit greyscale/palette bitmaps can be saved as JPEG";
1446
1447                        FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
1448                        WORD bpp = (WORD)FreeImage_GetBPP(dib);
1449
1450                        if ((bpp != 24) && (bpp != 8)) {
1451                                throw sError;
1452                        }
1453
1454                        if(bpp == 8) {
1455                                // allow grey, reverse grey and palette
1456                                if ((color_type != FIC_MINISBLACK) && (color_type != FIC_MINISWHITE) && (color_type != FIC_PALETTE)) {
1457                                        throw sError;
1458                                }
1459                        }
1460
1461
1462                        struct jpeg_compress_struct cinfo;
1463                        struct jpeg_error_mgr jerr;
1464
1465                        // Step 1: allocate and initialize JPEG compression object
1466
1467                        cinfo.err = jpeg_std_error(&jerr);
1468
1469                        jerr.error_exit     = jpeg_error_exit;
1470                        jerr.output_message = jpeg_output_message;
1471
1472                        // Now we can initialize the JPEG compression object
1473
1474                        jpeg_create_compress(&cinfo);
1475
1476                        // Step 2: specify data destination (eg, a file)
1477
1478                        jpeg_freeimage_dst(&cinfo, handle, io);
1479
1480                        // Step 3: set parameters for compression
1481
1482                        cinfo.image_width = FreeImage_GetWidth(dib);
1483                        cinfo.image_height = FreeImage_GetHeight(dib);
1484
1485                        switch(color_type) {
1486                                case FIC_MINISBLACK :
1487                                case FIC_MINISWHITE :
1488                                        cinfo.in_color_space = JCS_GRAYSCALE;
1489                                        cinfo.input_components = 1;
1490                                        break;
1491
1492                                default :
1493                                        cinfo.in_color_space = JCS_RGB;
1494                                        cinfo.input_components = 3;
1495                                        break;
1496                        }
1497
1498                        jpeg_set_defaults(&cinfo);
1499
1500                    // progressive-JPEG support
1501                        if((flags & JPEG_PROGRESSIVE) == JPEG_PROGRESSIVE) {
1502                                jpeg_simple_progression(&cinfo);
1503                        }
1504                       
1505                        // compute optimal Huffman coding tables for the image
1506                        if((flags & JPEG_OPTIMIZE) == JPEG_OPTIMIZE) {
1507                                cinfo.optimize_coding = TRUE;
1508                        }
1509
1510                        // Set JFIF density parameters from the DIB data
1511
1512                        cinfo.X_density = (UINT16) (0.5 + 0.0254 * FreeImage_GetDotsPerMeterX(dib));
1513                        cinfo.Y_density = (UINT16) (0.5 + 0.0254 * FreeImage_GetDotsPerMeterY(dib));
1514                        cinfo.density_unit = 1; // dots / inch
1515
1516                        // thumbnail support (JFIF 1.02 extension markers)
1517                        if(FreeImage_GetThumbnail(dib) != NULL) {
1518                                cinfo.write_JFIF_header = 1; //<### force it, though when color is CMYK it will be incorrect
1519                                cinfo.JFIF_minor_version = 2;
1520                        }
1521
1522                        // baseline JPEG support
1523                        if ((flags & JPEG_BASELINE) ==  JPEG_BASELINE) {
1524                                cinfo.write_JFIF_header = 0;    // No marker for non-JFIF colorspaces
1525                                cinfo.write_Adobe_marker = 0;   // write no Adobe marker by default                             
1526                        }
1527
1528                        // set subsampling options if required
1529
1530                        if(cinfo.in_color_space == JCS_RGB) {
1531                                if((flags & JPEG_SUBSAMPLING_411) == JPEG_SUBSAMPLING_411) { 
1532                                        // 4:1:1 (4x1 1x1 1x1) - CrH 25% - CbH 25% - CrV 100% - CbV 100%
1533                                        // the horizontal color resolution is quartered
1534                                        cinfo.comp_info[0].h_samp_factor = 4;   // Y
1535                                        cinfo.comp_info[0].v_samp_factor = 1; 
1536                                        cinfo.comp_info[1].h_samp_factor = 1;   // Cb
1537                                        cinfo.comp_info[1].v_samp_factor = 1; 
1538                                        cinfo.comp_info[2].h_samp_factor = 1;   // Cr
1539                                        cinfo.comp_info[2].v_samp_factor = 1; 
1540                                } else if((flags & JPEG_SUBSAMPLING_420) == JPEG_SUBSAMPLING_420) {
1541                                        // 4:2:0 (2x2 1x1 1x1) - CrH 50% - CbH 50% - CrV 50% - CbV 50%
1542                                        // the chrominance resolution in both the horizontal and vertical directions is cut in half
1543                                        cinfo.comp_info[0].h_samp_factor = 2;   // Y
1544                                        cinfo.comp_info[0].v_samp_factor = 2; 
1545                                        cinfo.comp_info[1].h_samp_factor = 1;   // Cb
1546                                        cinfo.comp_info[1].v_samp_factor = 1; 
1547                                        cinfo.comp_info[2].h_samp_factor = 1;   // Cr
1548                                        cinfo.comp_info[2].v_samp_factor = 1; 
1549                                } else if((flags & JPEG_SUBSAMPLING_422) == JPEG_SUBSAMPLING_422){ //2x1 (low)
1550                                        // 4:2:2 (2x1 1x1 1x1) - CrH 50% - CbH 50% - CrV 100% - CbV 100%
1551                                        // half of the horizontal resolution in the chrominance is dropped (Cb & Cr),
1552                                        // while the full resolution is retained in the vertical direction, with respect to the luminance
1553                                        cinfo.comp_info[0].h_samp_factor = 2;   // Y
1554                                        cinfo.comp_info[0].v_samp_factor = 1; 
1555                                        cinfo.comp_info[1].h_samp_factor = 1;   // Cb
1556                                        cinfo.comp_info[1].v_samp_factor = 1; 
1557                                        cinfo.comp_info[2].h_samp_factor = 1;   // Cr
1558                                        cinfo.comp_info[2].v_samp_factor = 1; 
1559                                } 
1560                                else if((flags & JPEG_SUBSAMPLING_444) == JPEG_SUBSAMPLING_444){ //1x1 (no subsampling)
1561                                        // 4:4:4 (1x1 1x1 1x1) - CrH 100% - CbH 100% - CrV 100% - CbV 100%
1562                                        // the resolution of chrominance information (Cb & Cr) is preserved
1563                                        // at the same rate as the luminance (Y) information
1564                                        cinfo.comp_info[0].h_samp_factor = 1;   // Y
1565                                        cinfo.comp_info[0].v_samp_factor = 1; 
1566                                        cinfo.comp_info[1].h_samp_factor = 1;   // Cb
1567                                        cinfo.comp_info[1].v_samp_factor = 1; 
1568                                        cinfo.comp_info[2].h_samp_factor = 1;   // Cr
1569                                        cinfo.comp_info[2].v_samp_factor = 1; 
1570                                } 
1571                        }
1572
1573                        // Step 4: set quality
1574                        // the first 7 bits are reserved for low level quality settings
1575                        // the other bits are high level (i.e. enum-ish)
1576
1577                        int quality;
1578
1579                        if ((flags & JPEG_QUALITYBAD) == JPEG_QUALITYBAD) {
1580                                quality = 10;
1581                        } else if ((flags & JPEG_QUALITYAVERAGE) == JPEG_QUALITYAVERAGE) {
1582                                quality = 25;
1583                        } else if ((flags & JPEG_QUALITYNORMAL) == JPEG_QUALITYNORMAL) {
1584                                quality = 50;
1585                        } else if ((flags & JPEG_QUALITYGOOD) == JPEG_QUALITYGOOD) {
1586                                quality = 75;
1587                        } else  if ((flags & JPEG_QUALITYSUPERB) == JPEG_QUALITYSUPERB) {
1588                                quality = 100;
1589                        } else {
1590                                if ((flags & 0x7F) == 0) {
1591                                        quality = 75;
1592                                } else {
1593                                        quality = flags & 0x7F;
1594                                }
1595                        }
1596
1597                        jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */
1598
1599                        // Step 5: Start compressor
1600
1601                        jpeg_start_compress(&cinfo, TRUE);
1602
1603                        // Step 6: Write special markers
1604                       
1605                        if ((flags & JPEG_BASELINE) !=  JPEG_BASELINE) {
1606                                write_markers(&cinfo, dib);
1607                        }
1608
1609                        // Step 7: while (scan lines remain to be written)
1610
1611                        if(color_type == FIC_RGB) {
1612                                // 24-bit RGB image : need to swap red and blue channels
1613                                unsigned pitch = FreeImage_GetPitch(dib);
1614                                BYTE *target = (BYTE*)malloc(pitch * sizeof(BYTE));
1615                                if (target == NULL) {
1616                                        throw FI_MSG_ERROR_MEMORY;
1617                                }
1618
1619                                while (cinfo.next_scanline < cinfo.image_height) {
1620                                        // get a copy of the scanline
1621                                        memcpy(target, FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1), pitch);
1622#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
1623                                        // swap R and B channels
1624                                        BYTE *target_p = target;
1625                                        for(unsigned x = 0; x < cinfo.image_width; x++) {
1626                                                INPLACESWAP(target_p[0], target_p[2]);
1627                                                target_p += 3;
1628                                        }
1629#endif
1630                                        // write the scanline
1631                                        jpeg_write_scanlines(&cinfo, &target, 1);
1632                                }
1633                                free(target);
1634                        }
1635                        else if(color_type == FIC_MINISBLACK) {
1636                                // 8-bit standard greyscale images
1637                                while (cinfo.next_scanline < cinfo.image_height) {
1638                                        JSAMPROW b = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1);
1639
1640                                        jpeg_write_scanlines(&cinfo, &b, 1);
1641                                }
1642                        }
1643                        else if(color_type == FIC_PALETTE) {
1644                                // 8-bit palettized images are converted to 24-bit images
1645                                RGBQUAD *palette = FreeImage_GetPalette(dib);
1646                                BYTE *target = (BYTE*)malloc(cinfo.image_width * 3);
1647                                if (target == NULL) {
1648                                        throw FI_MSG_ERROR_MEMORY;
1649                                }
1650
1651                                while (cinfo.next_scanline < cinfo.image_height) {
1652                                        BYTE *source = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1);
1653                                        FreeImage_ConvertLine8To24(target, source, cinfo.image_width, palette);
1654
1655#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
1656                                        // swap R and B channels
1657                                        BYTE *target_p = target;
1658                                        for(unsigned x = 0; x < cinfo.image_width; x++) {
1659                                                INPLACESWAP(target_p[0], target_p[2]);
1660                                                target_p += 3;
1661                                        }
1662#endif
1663
1664
1665                                        jpeg_write_scanlines(&cinfo, &target, 1);
1666                                }
1667
1668                                free(target);
1669                        }
1670                        else if(color_type == FIC_MINISWHITE) {
1671                                // reverse 8-bit greyscale image, so reverse grey value on the fly
1672                                unsigned i;
1673                                BYTE reverse[256];
1674                                BYTE *target = (BYTE *)malloc(cinfo.image_width);
1675                                if (target == NULL) {
1676                                        throw FI_MSG_ERROR_MEMORY;
1677                                }
1678
1679                                for(i = 0; i < 256; i++) {
1680                                        reverse[i] = (BYTE)(255 - i);
1681                                }
1682
1683                                while(cinfo.next_scanline < cinfo.image_height) {
1684                                        BYTE *source = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1);
1685                                        for(i = 0; i < cinfo.image_width; i++) {
1686                                                target[i] = reverse[ source[i] ];
1687                                        }
1688                                        jpeg_write_scanlines(&cinfo, &target, 1);
1689                                }
1690
1691                                free(target);
1692                        }
1693
1694                        // Step 8: Finish compression
1695
1696                        jpeg_finish_compress(&cinfo);
1697
1698                        // Step 9: release JPEG compression object
1699
1700                        jpeg_destroy_compress(&cinfo);
1701
1702                        return TRUE;
1703
1704                } catch (const char *text) {
1705                        FreeImage_OutputMessageProc(s_format_id, text);
1706                        return FALSE;
1707                } catch (FREE_IMAGE_FORMAT) {
1708                        return FALSE;
1709                }
1710        }
1711
1712        return FALSE;
1713}
1714
1715// ==========================================================
1716//   Init
1717// ==========================================================
1718
1719void DLL_CALLCONV
1720InitJPEG(Plugin *plugin, int format_id) {
1721        s_format_id = format_id;
1722
1723        plugin->format_proc = Format;
1724        plugin->description_proc = Description;
1725        plugin->extension_proc = Extension;
1726        plugin->regexpr_proc = RegExpr;
1727        plugin->open_proc = NULL;
1728        plugin->close_proc = NULL;
1729        plugin->pagecount_proc = NULL;
1730        plugin->pagecapability_proc = NULL;
1731        plugin->load_proc = Load;
1732        plugin->save_proc = Save;
1733        plugin->validate_proc = Validate;
1734        plugin->mime_proc = MimeType;
1735        plugin->supports_export_bpp_proc = SupportsExportDepth;
1736        plugin->supports_export_type_proc = SupportsExportType;
1737        plugin->supports_icc_profiles_proc = SupportsICCProfiles;
1738        plugin->supports_no_pixels_proc = SupportsNoPixels;
1739}
Note: See TracBrowser for help on using the browser.