Coverage Report

Created: 2025-10-12 06:53

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