/[projet1]/public/pc/shared_libraries/freeimage/v3.12.0/Source/FreeImage/PluginJPEG.cpp
Defence Force logotype

Contents of /public/pc/shared_libraries/freeimage/v3.12.0/Source/FreeImage/PluginJPEG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26