Coverage Report

Created: 2026-01-20 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/jpeg.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2025 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                        JJJJJ  PPPP   EEEEE   GGGG                           %
15
%                          J    P   P  E      G                               %
16
%                          J    PPPP   EEE    G  GG                           %
17
%                        J J    P      E      G   G                           %
18
%                        JJJ    P      EEEEE   GGG                            %
19
%                                                                             %
20
%                                                                             %
21
%                       Read/Write JPEG Image Format.                         %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
27
%                                                                             %
28
%                                                                             %
29
%                                                                             %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31
%
32
% This software is based in part on the work of the Independent JPEG Group.
33
% See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
34
% licensing restrictions.  Blob support contributed by Glenn Randers-Pehrson.
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "magick/studio.h"
43
#include "magick/analyze.h"
44
#include "magick/attribute.h"
45
#include "magick/blob.h"
46
#include "magick/colormap.h"
47
#include "magick/enum_strings.h"
48
#include "magick/log.h"
49
#include "magick/magick.h"
50
#include "magick/monitor.h"
51
#include "magick/pixel_cache.h"
52
#include "magick/profile.h"
53
#include "magick/resource.h"
54
#include "magick/utility.h"
55
#include "magick/static.h"
56

57
/*
58
  Forward declarations.
59
*/
60
static unsigned int
61
  WriteJPEGImage(const ImageInfo *,Image *);
62

63
/*
64
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65
%                                                                             %
66
%                                                                             %
67
%                                                                             %
68
%   I s J P E G                                                               %
69
%                                                                             %
70
%                                                                             %
71
%                                                                             %
72
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73
%
74
%  Method IsJPEG returns True if the image format type, identified by the
75
%  magick string, is JPEG.
76
%
77
%  The format of the IsJPEG  method is:
78
%
79
%      unsigned int IsJPEG(const unsigned char *magick,const size_t length)
80
%
81
%  A description of each parameter follows:
82
%
83
%    o status:  Method IsJPEG returns True if the image format type is JPEG.
84
%
85
%    o magick: This string is generally the first few bytes of an image file
86
%      or blob.
87
%
88
%    o length: Specifies the length of the magick string.
89
%
90
%
91
*/
92
static unsigned int IsJPEG(const unsigned char *magick,const size_t length)
93
0
{
94
0
  if (length < 3)
95
0
    return(False);
96
0
  if (memcmp(magick,"\377\330\377",3) == 0)
97
0
    return(True);
98
0
  return(False);
99
0
}
100

101
#if defined(HasJPEG)
102
#define JPEG_INTERNAL_OPTIONS
103
/*
104
  Avoid conflicting typedef for INT32
105
*/
106
#if defined(__MINGW32__)
107
# define XMD_H 1
108
#endif
109
/*
110
  The JPEG headers have the annoying problem that they define
111
  HAVE_STDLIB_H and we do too.  The define isn't actually used
112
  so just undef it.
113
*/
114
#undef HAVE_STDLIB_H
115
#include <setjmp.h>
116
#include "jpeglib.h"
117
#include "jerror.h"
118

119
/*
120
  Define declarations.
121
*/
122
218k
#define ICC_MARKER  (JPEG_APP0+2)
123
218k
#define IPTC_MARKER  (JPEG_APP0+13)
124
66
#define XML_MARKER  (JPEG_APP0+1)
125
2.08M
#define MaxBufferExtent  8192
126
#define JPEG_MARKER_MAX_SIZE 65533
127
682k
#define MaxWarningCount 3
128
129
/*
130
  Set to 1 to use libjpeg callback for progress indication.  This is
131
  not enabled by default since it outputs multiple progress
132
  indications, which may be confusing for the user.  However, the
133
  libjpeg method provides more detailed progress.
134
*/
135
#define USE_LIBJPEG_PROGRESS 0 /* Use libjpeg callback for progress */
136
137
static const char xmp_std_header[]="http://ns.adobe.com/xap/1.0/";
138
139

140
/*
141
  Struct to lessen the impact of multiple sample types
142
143
  This assumes a normal architecture where pointer size is consistent.
144
*/
145
typedef struct
146
{
147
  union
148
  {
149
    void *v;
150
    JSAMPLE *j;
151
#if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES
152
    J12SAMPLE *j12;
153
#endif /* if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES */
154
#if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES
155
    J16SAMPLE *j16;
156
#endif /* if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES */
157
  } t;
158
} magick_jpeg_pixels_t;
159
160
typedef struct _DestinationManager
161
{
162
  struct jpeg_destination_mgr
163
    manager;
164
165
  Image
166
    *image;
167
168
  JOCTET
169
    *buffer;
170
171
} DestinationManager;
172
173
typedef struct _MagickClientData
174
{
175
  Image
176
    *image;
177
178
  MagickBool
179
    ping;
180
181
  MagickBool
182
    completed;
183
184
  jmp_buf
185
    error_recovery;
186
187
  unsigned int
188
    max_warning_count;
189
190
  magick_uint16_t
191
    warning_counts[JMSG_LASTMSGCODE];
192
193
  int
194
    max_scan_number;
195
196
  ProfileInfo
197
    profiles[16];
198
199
  unsigned char
200
    buffer[65537+200];
201
202
  magick_jpeg_pixels_t
203
    *jpeg_pixels;
204
205
} MagickClientData;
206
207
typedef struct _SourceManager
208
{
209
  struct jpeg_source_mgr
210
    manager;
211
212
  Image
213
    *image;
214
215
  JOCTET
216
    *buffer;
217
218
  boolean
219
    start_of_blob;
220
} SourceManager;
221
222
static MagickClientData *AllocateMagickClientData(void)
223
707k
{
224
707k
  MagickClientData
225
707k
    *client_data;
226
227
707k
  client_data = MagickAllocateClearedMemory(MagickClientData *, sizeof(MagickClientData));
228
229
707k
  return client_data;
230
707k
}
231
232
static MagickClientData *FreeMagickClientData(MagickClientData *client_data)
233
707k
{
234
707k
  unsigned int
235
707k
    i;
236
237
  /* Free profiles data */
238
707k
  if (client_data != (MagickClientData *) NULL)
239
707k
    {
240
12.0M
      for (i=0 ; i < ArraySize(client_data->profiles); i++)
241
11.3M
        {
242
11.3M
          MagickFreeMemory(client_data->profiles[i].name);
243
11.3M
          MagickFreeResourceLimitedMemory(unsigned char *,client_data->profiles[i].info);
244
11.3M
        }
245
707k
      if (client_data->jpeg_pixels != (magick_jpeg_pixels_t *) NULL)
246
682k
        MagickFreeResourceLimitedMemory(void *,client_data->jpeg_pixels->t.v);
247
248
707k
      MagickFreeMemory(client_data);
249
707k
    }
250
707k
  return client_data;
251
707k
}
252
253
/* Append named profile to profiles in client data. */
254
static MagickPassFail
255
AppendProfile(MagickClientData *client_data,
256
              const char *name,
257
              const unsigned char *profile_chunk,
258
              const size_t chunk_length)
259
513k
{
260
513k
  unsigned int
261
513k
    i;
262
263
  /*
264
    If entry with matching name is found, then add/append data to
265
    profile 'info' and update profile length
266
  */
267
1.63M
  for (i=0 ; i < ArraySize(client_data->profiles); i++)
268
1.63M
    {
269
1.63M
      ProfileInfo *profile=&client_data->profiles[i];
270
1.63M
      if (!profile->name)
271
71.1k
        break;
272
1.56M
      if (strcmp(profile->name,name) == 0)
273
442k
        {
274
442k
          const size_t new_length = profile->length+chunk_length;
275
442k
          unsigned char *info = MagickReallocateResourceLimitedMemory(unsigned char *,
276
442k
                                                                      profile->info,new_length);
277
442k
          if (info != (unsigned char *) NULL)
278
442k
            {
279
442k
              profile->info = info;
280
442k
              (void) memcpy(profile->info+profile->length,profile_chunk,chunk_length);
281
442k
              profile->length=new_length;
282
442k
              return MagickPass;
283
442k
            }
284
442k
        }
285
1.56M
    }
286
287
288
  /*
289
    If no matching entry, then find unallocated entry, add data to
290
     profile 'info' and update profile length
291
  */
292
105k
  for (i=0 ; i < ArraySize(client_data->profiles); i++)
293
105k
    {
294
105k
      ProfileInfo *profile=&client_data->profiles[i];
295
105k
      if (profile->name)
296
34.8k
        continue;
297
71.1k
      profile->name=AcquireString(name);
298
71.1k
      profile->info=MagickAllocateResourceLimitedMemory(unsigned char*,chunk_length);
299
71.1k
      if (!profile->name || !profile->info)
300
0
        {
301
0
          MagickFreeMemory(profile->name);
302
0
          MagickFreeResourceLimitedMemory(unsigned char *,profile->info);
303
0
          break;
304
0
        }
305
71.1k
      (void) memcpy(profile->info,profile_chunk,chunk_length);
306
71.1k
      profile->length=chunk_length;
307
71.1k
      return MagickPass;
308
71.1k
    }
309
0
  return MagickFail;
310
71.1k
}
311
312
/*
313
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314
%                                                                             %
315
%                                                                             %
316
%                                                                             %
317
%   R e a d J P E G I m a g e                                                 %
318
%                                                                             %
319
%                                                                             %
320
%                                                                             %
321
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322
%
323
%  Method ReadJPEGImage reads a JPEG image file and returns it.  It allocates
324
%  the memory necessary for the new Image structure and returns a pointer to
325
%  the new image.
326
%
327
%  The format of the ReadJPEGImage method is:
328
%
329
%      Image *ReadJPEGImage(const ImageInfo *image_info,
330
%        ExceptionInfo *exception)
331
%
332
%  A description of each parameter follows:
333
%
334
%    o image:  Method ReadJPEGImage returns a pointer to the image after
335
%      reading.  A null image is returned if there is a memory shortage or
336
%      if the image cannot be read.
337
%
338
%    o image_info: Specifies a pointer to a ImageInfo structure.
339
%
340
%    o exception: return any errors or warnings in this structure.
341
%
342
%
343
*/
344
345
346
/*
347
  Format a libjpeg warning or trace event while decoding.  Warnings
348
  are converted to GraphicsMagick warning exceptions while traces are
349
  optionally logged.
350
351
  JPEG message codes range from 0 to JMSG_LASTMSGCODE
352
*/
353
static void JPEGDecodeMessageHandler(j_common_ptr jpeg_info,int msg_level)
354
14.0M
{
355
14.0M
  char
356
14.0M
    message[JMSG_LENGTH_MAX];
357
358
14.0M
  struct jpeg_error_mgr
359
14.0M
    *err;
360
361
14.0M
  MagickClientData
362
14.0M
    *client_data;
363
364
14.0M
  Image
365
14.0M
    *image;
366
367
14.0M
  message[0]='\0';
368
14.0M
  err=jpeg_info->err;
369
14.0M
  client_data=(MagickClientData *) jpeg_info->client_data;
370
14.0M
  image=client_data->image;
371
  /* msg_level is -1 for warnings, 0 and up for trace messages. */
372
14.0M
  if (msg_level < 0)
373
2.58M
    {
374
2.58M
      unsigned int strikes = 0;
375
      /* A warning */
376
2.58M
      (err->format_message)(jpeg_info,message);
377
378
2.58M
      if ((err->msg_code >= 0) &&
379
2.58M
          ((size_t) err->msg_code < ArraySize(client_data->warning_counts)))
380
2.58M
        {
381
2.58M
          client_data->warning_counts[err->msg_code]++;
382
2.58M
          strikes=client_data->warning_counts[err->msg_code];
383
2.58M
        }
384
385
2.58M
      if (image->logging)
386
2.58M
        {
387
2.58M
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
388
2.58M
                                "[%s] JPEG Warning[%u]: \"%s\""
389
2.58M
                                " (code=%d "
390
2.58M
                                "parms=0x%02x,0x%02x,"
391
2.58M
                                "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)",
392
2.58M
                                image->filename,
393
2.58M
                                strikes,
394
2.58M
                                message,err->msg_code,
395
2.58M
                                err->msg_parm.i[0], err->msg_parm.i[1],
396
2.58M
                                err->msg_parm.i[2], err->msg_parm.i[3],
397
2.58M
                                err->msg_parm.i[4], err->msg_parm.i[5],
398
2.58M
                                err->msg_parm.i[6], err->msg_parm.i[7]);
399
2.58M
        }
400
2.58M
      if (strikes > client_data->max_warning_count)
401
118k
        {
402
118k
          ThrowException2(&image->exception,CorruptImageError,(char *) message,
403
118k
                          image->filename);
404
118k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
405
118k
                                "Longjmp error recovery");
406
118k
          longjmp(client_data->error_recovery,1);
407
0
          SignalHandlerExit(EXIT_FAILURE);
408
118k
        }
409
410
2.46M
      if ((err->num_warnings == 0) ||
411
1.80M
          (err->trace_level >= 3))
412
659k
        ThrowException2(&image->exception,CorruptImageWarning,message,
413
2.46M
                        image->filename);
414
      /* JWRN_JPEG_EOF - "Premature end of JPEG file" */
415
2.46M
      err->num_warnings++;
416
2.46M
      return /* False */;
417
2.58M
    }
418
11.4M
  else
419
11.4M
    {
420
      /* A trace message */
421
11.4M
      if ((image->logging) && (msg_level >= err->trace_level))
422
11.4M
        {
423
11.4M
          (err->format_message)(jpeg_info,message);
424
11.4M
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
425
11.4M
                                "[%s] JPEG Trace: \"%s\"",image->filename,
426
11.4M
                                message);
427
11.4M
        }
428
11.4M
    }
429
11.4M
  return /* True */;
430
14.0M
}
431
432
static void JPEGDecodeProgressMonitor(j_common_ptr cinfo)
433
15.5M
{
434
15.5M
  MagickClientData *client_data = (MagickClientData *) cinfo->client_data;
435
15.5M
  Image *image = client_data->image;
436
15.5M
  const int max_scan_number = client_data->max_scan_number;
437
438
#if USE_LIBJPEG_PROGRESS
439
  {
440
    struct jpeg_progress_mgr *p = cinfo->progress;
441
442
#if 0
443
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
444
                          "Progress: pass_counter=%ld, pass_limit=%ld,"
445
                          " completed_passes=%d, total_passes=%d, filename=%s",
446
                          p->pass_counter, p->pass_limit,
447
                          p->completed_passes, p->total_passes, image->filename);
448
#endif
449
450
    if (QuantumTick(p->pass_counter,p->pass_limit))
451
      if (!MagickMonitorFormatted(p->pass_counter,p->pass_limit,&image->exception,
452
                                  "[%s] Loading image: %lux%lu (pass %d of %d)...  ",
453
                                  image->filename,
454
                                  image->columns,image->rows,
455
                                  p->completed_passes+1, p->total_passes))
456
        {
457
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
458
                                "Quitting (longjmp) due to progress monitor");
459
          longjmp(client_data->error_recovery,1);
460
          SignalHandlerExit(EXIT_FAILURE);
461
        }
462
  }
463
#endif /* USE_LIBJPEG_PROGRESS */
464
465
15.5M
  if (cinfo->is_decompressor)
466
15.5M
    {
467
15.5M
      int scan_no = ((j_decompress_ptr) cinfo)->input_scan_number;
468
469
15.5M
      if (scan_no > max_scan_number)
470
7
        {
471
7
          char message[MaxTextExtent];
472
7
          FormatString(message,"Scan number %d exceeds maximum scans (%d)",
473
7
                       scan_no, max_scan_number);
474
7
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s", message);
475
7
          ThrowException2(&image->exception,CorruptImageError,(char *) message,
476
7
                          image->filename);
477
7
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
478
7
                                "Longjmp error recovery");
479
7
          longjmp(client_data->error_recovery,1);
480
0
          SignalHandlerExit(EXIT_FAILURE);
481
7
        }
482
15.5M
    }
483
15.5M
}
484
485
static boolean FillInputBuffer(j_decompress_ptr cinfo)
486
1.38M
{
487
1.38M
  SourceManager
488
1.38M
    *source;
489
490
1.38M
  source=(SourceManager *) cinfo->src;
491
1.38M
  source->manager.bytes_in_buffer=
492
1.38M
    ReadBlob(source->image,MaxBufferExtent,(char *) source->buffer);
493
1.38M
  if (source->manager.bytes_in_buffer == 0)
494
654k
    {
495
654k
      if (source->start_of_blob)
496
0
        ERREXIT(cinfo,JERR_INPUT_EMPTY);
497
654k
      WARNMS(cinfo,JWRN_JPEG_EOF);
498
654k
      source->buffer[0]=(JOCTET) 0xff;
499
654k
      source->buffer[1]=(JOCTET) JPEG_EOI;
500
654k
      source->manager.bytes_in_buffer=2;
501
654k
    }
502
1.38M
  source->manager.next_input_byte=source->buffer;
503
1.38M
  source->start_of_blob=FALSE;
504
1.38M
  return(TRUE);
505
1.38M
}
506
507
static int GetCharacter(j_decompress_ptr jpeg_info)
508
103M
{
509
103M
  if (jpeg_info->src->bytes_in_buffer == 0)
510
162k
    if ((!((*jpeg_info->src->fill_input_buffer)(jpeg_info))) ||
511
126k
        (jpeg_info->src->bytes_in_buffer == 0))
512
0
      return EOF;
513
103M
  jpeg_info->src->bytes_in_buffer--;
514
103M
  return(GETJOCTET(*jpeg_info->src->next_input_byte++));
515
103M
}
516
517
static void InitializeSource(j_decompress_ptr cinfo)
518
681k
{
519
681k
  SourceManager
520
681k
    *source;
521
522
681k
  source=(SourceManager *) cinfo->src;
523
681k
  source->start_of_blob=TRUE;
524
681k
}
525
526
/*
527
  Format and report a libjpeg error event.  Errors are reported via a
528
  GraphicsMagick error exception. The function terminates with
529
  longjmp() so it never returns to the caller.
530
*/
531
static void JPEGErrorHandler(j_common_ptr jpeg_info) MAGICK_FUNC_NORETURN;
532
533
static void JPEGErrorHandler(j_common_ptr jpeg_info)
534
371k
{
535
371k
  char
536
371k
    message[JMSG_LENGTH_MAX];
537
538
371k
  struct jpeg_error_mgr
539
371k
    *err;
540
541
371k
  MagickClientData
542
371k
    *client_data;
543
544
371k
  Image
545
371k
    *image;
546
547
371k
  message[0]='\0';
548
371k
  err=jpeg_info->err;
549
371k
  client_data=(MagickClientData *) jpeg_info->client_data;
550
371k
  image=client_data->image;
551
371k
  (err->format_message)(jpeg_info,message);
552
371k
  if (image->logging)
553
371k
    {
554
371k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
555
371k
                            "[%s] JPEG Error: \"%s\" (code=%d, "
556
371k
                            "parms=0x%02x,0x%02x,"
557
371k
                            "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)",
558
371k
                            image->filename,message,err->msg_code,
559
371k
                            err->msg_parm.i[0], err->msg_parm.i[1],
560
371k
                            err->msg_parm.i[2], err->msg_parm.i[3],
561
371k
                            err->msg_parm.i[4], err->msg_parm.i[5],
562
371k
                            err->msg_parm.i[6], err->msg_parm.i[7]);
563
371k
    }
564
371k
  if (client_data->completed)
565
20.8k
    ThrowException2(&image->exception,CoderWarning,(char *) message,
566
371k
                    image->filename);
567
351k
  else
568
351k
    ThrowException2(&image->exception,CoderError,(char *) message,
569
371k
                    image->filename);
570
371k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Longjmp error recovery");
571
371k
  longjmp(client_data->error_recovery,1);
572
0
  SignalHandlerExit(EXIT_FAILURE);
573
371k
}
574
575
#define GetProfileLength(jpeg_info, length)                             \
576
915k
  do {                                                                  \
577
915k
    int                                                                 \
578
915k
      _c;                                                               \
579
915k
                                                                        \
580
915k
    if (((_c = GetCharacter(jpeg_info)) != EOF) && (_c >= 0))           \
581
915k
      {                                                                 \
582
915k
        length=(size_t) _c*256;                                         \
583
915k
        if (((_c = GetCharacter(jpeg_info)) != EOF) && (_c >= 0))       \
584
915k
          length+=(size_t)_c;                                           \
585
915k
        else                                                            \
586
915k
          length=0;                                                     \
587
915k
      }                                                                 \
588
915k
    else                                                                \
589
915k
      {                                                                 \
590
0
        length=0;                                                       \
591
0
      }                                                                 \
592
915k
  } while(0)
593
594
static boolean ReadComment(j_decompress_ptr jpeg_info)
595
223k
{
596
223k
  char
597
223k
    *comment;
598
599
223k
  MagickClientData
600
223k
    *client_data;
601
602
223k
  Image
603
223k
    *image;
604
605
223k
  register char
606
223k
    *p;
607
608
223k
  size_t
609
223k
    i,
610
223k
    length;
611
612
223k
  int
613
223k
    c;
614
615
  /*
616
    Determine length of comment.
617
  */
618
223k
  client_data=(MagickClientData *) jpeg_info->client_data;
619
223k
  image=client_data->image;
620
223k
  GetProfileLength(jpeg_info, length);
621
223k
  if (length <= 2)
622
8.20k
    return(True);
623
215k
  length-=2;
624
215k
  comment=(char *) client_data->buffer;
625
  /*
626
    Read comment.
627
  */
628
215k
  p=comment;
629
17.6M
  for (i=0; i < length; i++)
630
17.4M
    {
631
17.4M
      if ((c=GetCharacter(jpeg_info)) == EOF)
632
0
        break;
633
17.4M
      *p=c;
634
17.4M
      p++;
635
17.4M
    }
636
215k
  *p='\0';
637
215k
  (void) SetImageAttribute(image,"comment",comment);
638
215k
  return(True);
639
223k
}
640
641
static boolean ReadGenericProfile(j_decompress_ptr jpeg_info)
642
565k
{
643
565k
  MagickClientData
644
565k
    *client_data;
645
646
565k
  size_t
647
565k
    header_length=0,
648
565k
    length;
649
650
565k
  register size_t
651
565k
    i;
652
653
565k
  char
654
565k
    profile_name[MaxTextExtent];
655
656
565k
  unsigned char
657
565k
    *profile;
658
659
565k
  int
660
565k
    c,
661
565k
    marker;
662
663
  /*
664
    Determine length of generic profile.
665
  */
666
565k
  GetProfileLength(jpeg_info, length);
667
565k
  if (length <= 2)
668
52.6k
    return(True);
669
512k
  length-=2;
670
671
  /*
672
    jpeg_info->unread_marker ('int') is either zero or the code of a
673
    JPEG marker that has been read from the data source, but has not
674
    yet been processed.  The underlying type for a marker appears to
675
    be UINT8 (JPEG_COM, or JPEG_APP0+n).
676
677
    Unexpected markers are prevented due to registering for specific
678
    markers we are interested in via jpeg_set_marker_processor().
679
680
    #define JPEG_APP0 0xE0
681
    #define JPEG_COM 0xFE
682
683
    #define ICC_MARKER  (JPEG_APP0+2)
684
    #define IPTC_MARKER  (JPEG_APP0+13)
685
    #define XML_MARKER  (JPEG_APP0+1)
686
   */
687
512k
  marker=jpeg_info->unread_marker-JPEG_APP0;
688
689
  /*
690
    Compute generic profile name.
691
  */
692
512k
  FormatString(profile_name,"APP%d",marker);
693
694
  /*
695
    Obtain Image.
696
  */
697
512k
  client_data=(MagickClientData *) jpeg_info->client_data;
698
699
  /*
700
    Copy profile from JPEG to allocated memory.
701
  */
702
512k
  profile=client_data->buffer;
703
704
56.1M
  for (i=0 ; i < length ; i++)
705
55.6M
    {
706
55.6M
      if ((c=GetCharacter(jpeg_info)) != EOF)
707
55.6M
        profile[i]=c;
708
9.32k
      else
709
9.32k
        break;
710
55.6M
    }
711
512k
  if (i != length)
712
0
    return True;
713
714
  /*
715
    Detect EXIF and XMP profiles.
716
  */
717
512k
  if ((marker == 1) && (length > 4) &&
718
70.0k
      (strncmp((char *) profile,"Exif",4) == 0))
719
39.0k
    {
720
39.0k
      FormatString(profile_name,"EXIF");
721
39.0k
    }
722
473k
  else if (((marker == 1) && (length > strlen(xmp_std_header)+1)) &&
723
14.9k
           (memcmp(profile, xmp_std_header, strlen(xmp_std_header)+1) == 0))
724
1.82k
    {
725
      /*
726
        XMP is required to fit in one 64KB chunk.  Strip off its JPEG
727
         namespace header.
728
      */
729
1.82k
      header_length=strlen(xmp_std_header)+1;
730
1.82k
      FormatString((char *) profile_name,"XMP");
731
1.82k
    }
732
733
  /*
734
    Store profile in Image.
735
  */
736
512k
  (void) AppendProfile(client_data,profile_name,profile+header_length,
737
512k
                            length-header_length);
738
739
512k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
740
512k
                        "Profile: %s, header %" MAGICK_SIZE_T_F "u bytes, "
741
512k
                        "data %" MAGICK_SIZE_T_F "u bytes",
742
512k
                        profile_name, (MAGICK_SIZE_T) header_length,
743
512k
                        (MAGICK_SIZE_T) length-header_length);
744
745
512k
  return (True);
746
512k
}
747
748
static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
749
88.5k
{
750
88.5k
  char
751
88.5k
    magick[12];
752
753
88.5k
  MagickClientData
754
88.5k
    *client_data;
755
756
88.5k
  unsigned char
757
88.5k
    *profile;
758
759
88.5k
  long
760
88.5k
    length;
761
762
88.5k
  register long
763
88.5k
    i;
764
765
88.5k
  int
766
88.5k
    c;
767
768
  /*
769
    Determine length of color profile.
770
  */
771
88.5k
  GetProfileLength(jpeg_info, length);
772
88.5k
  length-=2;
773
88.5k
  if (length <= 14)
774
65.2k
    {
775
87.3k
      while (--length >= 0)
776
22.0k
        (void) GetCharacter(jpeg_info);
777
65.2k
      return(True);
778
65.2k
    }
779
291k
  for (i=0; i < 12; i++)
780
268k
    magick[i]=GetCharacter(jpeg_info);
781
23.3k
  if (LocaleCompare(magick,"ICC_PROFILE") != 0)
782
19.2k
    {
783
      /*
784
        Not a ICC profile, return.
785
      */
786
6.19M
      for (i=0; i < length-12; i++)
787
6.17M
        (void) GetCharacter(jpeg_info);
788
19.2k
      return(True);
789
19.2k
    }
790
4.07k
  (void) GetCharacter(jpeg_info);  /* id */
791
4.07k
  (void) GetCharacter(jpeg_info);  /* markers */
792
4.07k
  length-=14;
793
4.07k
  client_data=(MagickClientData *) jpeg_info->client_data;
794
795
  /*
796
    Read color profile.
797
  */
798
4.07k
  profile=client_data->buffer;
799
800
4.07k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
801
4.07k
                        "ICC profile chunk: %ld bytes",
802
4.07k
    length);
803
804
3.76M
  for (i=0 ; i < length; i++)
805
3.76M
    {
806
3.76M
      if ((c=GetCharacter(jpeg_info)) != EOF)
807
3.76M
        profile[i]=c;
808
212
      else
809
212
        break;
810
3.76M
    }
811
4.07k
  if (i == length)
812
2.04k
    (void) AppendProfile(client_data,"ICM",profile,length);
813
814
4.07k
  return(True);
815
23.3k
}
816
817
static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
818
38.2k
{
819
38.2k
  MagickClientData
820
38.2k
    *client_data;
821
822
38.2k
  Image
823
38.2k
    *image;
824
825
38.2k
  long
826
38.2k
    length,
827
38.2k
    tag_length;
828
829
38.2k
  unsigned char
830
38.2k
    *profile;
831
832
38.2k
  register long
833
38.2k
    i;
834
835
#ifdef GET_ONLY_IPTC_DATA
836
  unsigned char
837
    tag[MaxTextExtent];
838
#endif
839
840
38.2k
  int
841
38.2k
    c;
842
843
  /*
844
    Determine length of binary data stored here.
845
  */
846
38.2k
  GetProfileLength(jpeg_info, length);
847
38.2k
  length-=2;
848
38.2k
  if (length <= 0)
849
3.02k
    return(True);
850
35.2k
  tag_length=0;
851
#ifdef GET_ONLY_IPTC_DATA
852
  *tag='\0';
853
#endif
854
35.2k
  client_data=(MagickClientData *) jpeg_info->client_data;
855
35.2k
  image=client_data->image;
856
#ifdef GET_ONLY_IPTC_DATA
857
  /*
858
    Find the beginning of the IPTC portion of the binary data.
859
  */
860
  for (*tag='\0'; length > 0; )
861
    {
862
      *tag=GetCharacter(jpeg_info);
863
      *(tag+1)=GetCharacter(jpeg_info);
864
      length-=2;
865
      if ((*tag == 0x1c) && (*(tag+1) == 0x02))
866
        break;
867
    }
868
  tag_length=2;
869
#else
870
  /*
871
    Validate that this was written as a Photoshop resource format slug.
872
  */
873
35.2k
  {
874
35.2k
    char
875
35.2k
      magick[MaxTextExtent];
876
877
352k
    for (i=0; i < 10 && i < length; i++)
878
316k
      magick[i]=GetCharacter(jpeg_info);
879
35.2k
    magick[i]='\0';
880
35.2k
    length-=i;
881
35.2k
    if (LocaleCompare(magick,"Photoshop ") != 0)
882
22.9k
      {
883
        /*
884
          Not a ICC profile, return.
885
        */
886
6.54M
        for (i=0; i < length; i++)
887
6.52M
          (void) GetCharacter(jpeg_info);
888
22.9k
        return(True);
889
22.9k
      }
890
35.2k
  }
891
  /*
892
    Remove the version number.
893
  */
894
49.6k
  for (i=0; i < 4 && i < length; i++)
895
37.4k
    (void) GetCharacter(jpeg_info);
896
12.2k
  length-=i;
897
12.2k
  tag_length=0;
898
12.2k
#endif
899
12.2k
  if (length <= 0)
900
989
    return(True);
901
902
11.2k
  if ((size_t) length+tag_length > sizeof(client_data->buffer))
903
0
    ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
904
11.2k
      (char *) NULL);
905
11.2k
  profile=client_data->buffer;
906
  /*
907
    Read the payload of this binary data.
908
  */
909
11.2k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
910
11.2k
                        "Profile: IPTC, %ld bytes",
911
11.2k
    length);
912
913
11.3M
  for (i=0; i < length; i++)
914
11.3M
    {
915
11.3M
      if ((c=GetCharacter(jpeg_info)) != EOF)
916
11.3M
        profile[i]=c;
917
395
      else
918
395
        break;
919
11.3M
    }
920
11.2k
  if (i == length)
921
8.63k
    (void) AppendProfile(client_data,"IPTC",profile,length);
922
923
11.2k
  return(True);
924
11.2k
}
925
926
static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
927
268k
{
928
268k
  SourceManager
929
268k
    *source;
930
931
268k
  if (number_bytes <= 0)
932
0
    return;
933
268k
  source=(SourceManager *) cinfo->src;
934
319k
  while (number_bytes > (long) source->manager.bytes_in_buffer)
935
50.8k
  {
936
50.8k
    number_bytes-=(long) source->manager.bytes_in_buffer;
937
50.8k
    (void) FillInputBuffer(cinfo);
938
50.8k
  }
939
268k
  source->manager.next_input_byte+=(size_t) number_bytes;
940
268k
  source->manager.bytes_in_buffer-=(size_t) number_bytes;
941
268k
}
942
943
static void TerminateSource(j_decompress_ptr cinfo)
944
136k
{
945
136k
  (void) cinfo;
946
136k
}
947
948
static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
949
681k
{
950
681k
  SourceManager
951
681k
    *source;
952
953
681k
  cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
954
681k
    ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
955
681k
  source=(SourceManager *) cinfo->src;
956
681k
  source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
957
681k
    ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
958
681k
  source=(SourceManager *) cinfo->src;
959
681k
  source->manager.init_source=InitializeSource;
960
681k
  source->manager.fill_input_buffer=FillInputBuffer;
961
681k
  source->manager.skip_input_data=SkipInputData;
962
681k
  source->manager.resync_to_restart=jpeg_resync_to_restart;
963
681k
  source->manager.term_source=TerminateSource;
964
681k
  source->manager.bytes_in_buffer=0;
965
681k
  source->manager.next_input_byte=NULL;
966
681k
  source->image=image;
967
681k
}
968
969
/*
970
  Estimate the IJG quality factor used when saving the file.
971
*/
972
static int
973
EstimateJPEGQuality(const struct jpeg_decompress_struct *jpeg_info,
974
                    Image *image)
975
171k
{
976
171k
  int
977
171k
    save_quality;
978
979
171k
  register long
980
171k
    i;
981
982
171k
  save_quality=0;
983
#if !defined(LIBJPEG_TURBO_VERSION_NUMBER) && defined(D_LOSSLESS_SUPPORTED)
984
  if (image->compression==LosslessJPEGCompression)
985
    {
986
      save_quality=100;
987
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
988
                            "Quality: 100 (lossless)");
989
    }
990
  else
991
#endif
992
993
171k
    {
994
171k
      int
995
171k
        hashval,
996
171k
        sum;
997
998
      /*
999
        Log the JPEG quality that was used for compression.
1000
      */
1001
171k
      sum=0;
1002
855k
      for (i=0; i < NUM_QUANT_TBLS; i++)
1003
684k
        {
1004
684k
          int
1005
684k
            j;
1006
1007
684k
          if (jpeg_info->quant_tbl_ptrs[i] != NULL)
1008
11.4M
            for (j=0; j < DCTSIZE2; j++)
1009
11.2M
              {
1010
11.2M
                UINT16 *c;
1011
11.2M
                c=jpeg_info->quant_tbl_ptrs[i]->quantval;
1012
11.2M
                sum+=c[j];
1013
11.2M
              }
1014
684k
        }
1015
171k
      if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
1016
83.4k
          (jpeg_info->quant_tbl_ptrs[1] != NULL))
1017
21.2k
        {
1018
21.2k
          int
1019
21.2k
            hash[] =
1020
21.2k
            {
1021
21.2k
              1020, 1015,  932,  848,  780,  735,  702,  679,  660,  645,
1022
21.2k
              632,  623,  613,  607,  600,  594,  589,  585,  581,  571,
1023
21.2k
              555,  542,  529,  514,  494,  474,  457,  439,  424,  410,
1024
21.2k
              397,  386,  373,  364,  351,  341,  334,  324,  317,  309,
1025
21.2k
              299,  294,  287,  279,  274,  267,  262,  257,  251,  247,
1026
21.2k
              243,  237,  232,  227,  222,  217,  213,  207,  202,  198,
1027
21.2k
              192,  188,  183,  177,  173,  168,  163,  157,  153,  148,
1028
21.2k
              143,  139,  132,  128,  125,  119,  115,  108,  104,   99,
1029
21.2k
              94,   90,   84,   79,   74,   70,   64,   59,   55,   49,
1030
21.2k
              45,   40,   34,   30,   25,   20,   15,   11,    6,    4,
1031
21.2k
              0
1032
21.2k
            };
1033
1034
21.2k
          int
1035
21.2k
            sums[] =
1036
21.2k
            {
1037
21.2k
              32640,32635,32266,31495,30665,29804,29146,28599,28104,27670,
1038
21.2k
              27225,26725,26210,25716,25240,24789,24373,23946,23572,22846,
1039
21.2k
              21801,20842,19949,19121,18386,17651,16998,16349,15800,15247,
1040
21.2k
              14783,14321,13859,13535,13081,12702,12423,12056,11779,11513,
1041
21.2k
              11135,10955,10676,10392,10208, 9928, 9747, 9564, 9369, 9193,
1042
21.2k
              9017, 8822, 8639, 8458, 8270, 8084, 7896, 7710, 7527, 7347,
1043
21.2k
              7156, 6977, 6788, 6607, 6422, 6236, 6054, 5867, 5684, 5495,
1044
21.2k
              5305, 5128, 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698,
1045
21.2k
              3509, 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
1046
21.2k
              1666, 1483, 1297, 1109,  927,  735,  554,  375,  201,  128,
1047
21.2k
              0
1048
21.2k
            };
1049
1050
21.2k
          hashval=(jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
1051
21.2k
                   jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
1052
21.2k
                   jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
1053
21.2k
                   jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
1054
858k
          for (i=0; i < 100; i++)
1055
858k
            {
1056
858k
              if ((hashval >= hash[i]) || (sum >= sums[i]))
1057
21.1k
                {
1058
21.1k
                  save_quality=i+1;
1059
21.1k
                  if (image->logging)
1060
21.1k
                    {
1061
21.1k
                      if ((hashval > hash[i]) || (sum > sums[i]))
1062
18.5k
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1063
18.5k
                                              "Quality: %d (approximate)",
1064
18.5k
                                              save_quality);
1065
2.54k
                      else
1066
2.54k
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1067
2.54k
                                              "Quality: %d",save_quality);
1068
21.1k
                    }
1069
21.1k
                  break;
1070
21.1k
                }
1071
858k
            }
1072
21.2k
        }
1073
149k
      else
1074
149k
        if (jpeg_info->quant_tbl_ptrs[0] != NULL)
1075
62.1k
          {
1076
62.1k
            int
1077
62.1k
              bwhash[] =
1078
62.1k
              {
1079
62.1k
                510,  505,  422,  380,  355,  338,  326,  318,  311,  305,
1080
62.1k
                300,  297,  293,  291,  288,  286,  284,  283,  281,  280,
1081
62.1k
                279,  278,  277,  273,  262,  251,  243,  233,  225,  218,
1082
62.1k
                211,  205,  198,  193,  186,  181,  177,  172,  168,  164,
1083
62.1k
                158,  156,  152,  148,  145,  142,  139,  136,  133,  131,
1084
62.1k
                129,  126,  123,  120,  118,  115,  113,  110,  107,  105,
1085
62.1k
                102,  100,   97,   94,   92,   89,   87,   83,   81,   79,
1086
62.1k
                76,   74,   70,   68,   66,   63,   61,   57,   55,   52,
1087
62.1k
                50,   48,   44,   42,   39,   37,   34,   31,   29,   26,
1088
62.1k
                24,   21,   18,   16,   13,   11,    8,    6,    3,    2,
1089
62.1k
                0
1090
62.1k
              };
1091
1092
62.1k
            int
1093
62.1k
              bwsum[] =
1094
62.1k
              {
1095
62.1k
                16320,16315,15946,15277,14655,14073,13623,13230,12859,12560,
1096
62.1k
                12240,11861,11456,11081,10714,10360,10027, 9679, 9368, 9056,
1097
62.1k
                8680, 8331, 7995, 7668, 7376, 7084, 6823, 6562, 6345, 6125,
1098
62.1k
                5939, 5756, 5571, 5421, 5240, 5086, 4976, 4829, 4719, 4616,
1099
62.1k
                4463, 4393, 4280, 4166, 4092, 3980, 3909, 3835, 3755, 3688,
1100
62.1k
                3621, 3541, 3467, 3396, 3323, 3247, 3170, 3096, 3021, 2952,
1101
62.1k
                2874, 2804, 2727, 2657, 2583, 2509, 2437, 2362, 2290, 2211,
1102
62.1k
                2136, 2068, 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477,
1103
62.1k
                1398, 1326, 1251, 1179, 1109, 1031,  961,  884,  814,  736,
1104
62.1k
                667,  592,  518,  441,  369,  292,  221,  151,   86,   64,
1105
62.1k
                0
1106
62.1k
              };
1107
1108
62.1k
            hashval=(jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
1109
62.1k
                     jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
1110
1.89M
            for (i=0; i < 100; i++)
1111
1.89M
              {
1112
1.89M
                if ((hashval >= bwhash[i]) || (sum >= bwsum[i]))
1113
61.9k
                  {
1114
61.9k
                    save_quality=i+1;
1115
61.9k
                    if (image->logging)
1116
61.9k
                      {
1117
61.9k
                        if ((hashval > bwhash[i]) || (sum > bwsum[i]))
1118
59.2k
                          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1119
59.2k
                                                "Quality: %ld (approximate)",
1120
59.2k
                                                i+1);
1121
2.76k
                        else
1122
2.76k
                          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1123
2.76k
                                                "Quality: %ld",i+1);
1124
61.9k
                      }
1125
61.9k
                    break;
1126
61.9k
                  }
1127
1.89M
              }
1128
62.1k
          }
1129
171k
    }
1130
1131
171k
  return save_quality;
1132
171k
}
1133
1134
static const char *JPEGColorSpaceToString(const J_COLOR_SPACE colorspace)
1135
171k
{
1136
171k
  const char
1137
171k
    *s;
1138
1139
171k
  switch (colorspace)
1140
171k
    {
1141
0
    default:
1142
3.16k
    case JCS_UNKNOWN:
1143
3.16k
      s = "UNKNOWN";
1144
3.16k
      break;
1145
48.3k
    case JCS_GRAYSCALE:
1146
48.3k
      s = "GRAYSCALE";
1147
48.3k
      break;
1148
91.4k
    case JCS_RGB:
1149
91.4k
      s = "RGB";
1150
91.4k
      break;
1151
0
    case JCS_YCbCr:
1152
0
      s = "YCbCr";
1153
0
      break;
1154
28.2k
    case JCS_CMYK:
1155
28.2k
      s = "CMYK";
1156
28.2k
      break;
1157
0
    case JCS_YCCK:
1158
0
      s = "YCCK";
1159
0
      break;
1160
171k
    }
1161
171k
  return s;
1162
171k
}
1163
1164
/*
1165
  Format JPEG color space to a string buffer of length MaxTextExtent.
1166
*/
1167
static void
1168
FormatJPEGColorSpace(const J_COLOR_SPACE colorspace,
1169
                     char *colorspace_name)
1170
171k
{
1171
171k
  (void) strlcpy(colorspace_name,JPEGColorSpaceToString(colorspace),MaxTextExtent);
1172
171k
}
1173
1174
/*
1175
  Format JPEG sampling factors to a string.
1176
*/
1177
static MagickPassFail
1178
FormatJPEGSamplingFactors(const struct jpeg_decompress_struct *jpeg_info,
1179
                          char *sampling_factors)
1180
171k
{
1181
171k
  unsigned int
1182
171k
    quantums = 0;
1183
1184
171k
  MagickPassFail
1185
171k
    status = MagickFail;
1186
1187
171k
  switch (jpeg_info->out_color_space)
1188
171k
    {
1189
0
    default:
1190
3.16k
    case JCS_UNKNOWN:
1191
      /* error/unspecified */
1192
3.16k
      break;
1193
48.3k
    case JCS_GRAYSCALE:
1194
      /* monochrome */
1195
48.3k
      quantums = 1;
1196
48.3k
      break;
1197
91.4k
    case JCS_RGB:
1198
      /* red/green/blue as specified by the RGB_RED, RGB_GREEN,
1199
         RGB_BLUE, and RGB_PIXELSIZE macros */
1200
91.4k
      quantums = 3;
1201
91.4k
      break;
1202
0
    case JCS_YCbCr:
1203
      /* Y/Cb/Cr (also known as YUV) */
1204
0
      quantums = 3;
1205
0
      break;
1206
28.2k
    case JCS_CMYK:
1207
      /* C/M/Y/K */
1208
28.2k
      quantums = 4;
1209
28.2k
      break;
1210
0
    case JCS_YCCK:
1211
      /* Y/Cb/Cr/K */
1212
0
      quantums = 4;
1213
0
      break;
1214
#if 0
1215
#if defined(JCS_EXTENSIONS) && JCS_EXTENSIONS
1216
    case JCS_EXT_RGB:
1217
      /* red/green/blue */
1218
      quantums = 3;
1219
      break;
1220
    case JCS_EXT_RGBX:
1221
      /* red/green/blue/x */
1222
      quantums = 4;
1223
      break;
1224
    case JCS_EXT_BGR:
1225
      /* blue/green/red */
1226
      quantums = 3;
1227
      break;
1228
    case JCS_EXT_BGRX:
1229
      /* blue/green/red/x */
1230
      quantums = 4;
1231
      break;
1232
    case JCS_EXT_XBGR:
1233
      /* x/blue/green/red */
1234
      quantums = 4;
1235
      break;
1236
    case JCS_EXT_XRGB:
1237
      /* x/red/green/blue */
1238
      quantums = 4;
1239
      break;
1240
1241
#if defined(JCS_ALPHA_EXTENSIONS) && JCS_ALPHA_EXTENSIONS
1242
    case JCS_EXT_RGBA:
1243
      /* red/green/blue/alpha */
1244
      quantums = 4;
1245
      break;
1246
    case JCS_EXT_BGRA:
1247
      /* blue/green/red/alpha */
1248
      quantums = 4;
1249
      break;
1250
    case JCS_EXT_ABGR:
1251
      /* alpha/blue/green/red */
1252
      quantums = 4;
1253
      break;
1254
    case JCS_EXT_ARGB:
1255
      /* alpha/red/green/blue */
1256
      quantums = 4;
1257
      break;
1258
    case JCS_RGB565:
1259
      /* 5-bit red/6-bit green/5-bit blue [decompression only] */
1260
      quantums = 3;
1261
      break;
1262
#endif /* defined(JCS_ALPHA_EXTENSIONS) && JCS_ALPHA_EXTENSIONS */
1263
#endif /* if defined(JCS_EXTENSIONS) && JCS_EXTENSIONS */
1264
#endif
1265
171k
    }
1266
1267
171k
  switch (quantums)
1268
171k
    {
1269
3.16k
    case 0:
1270
3.16k
      break;
1271
48.3k
    case 1:
1272
48.3k
      (void) FormatString(sampling_factors,"%dx%d",
1273
48.3k
                          jpeg_info->comp_info[0].h_samp_factor,
1274
48.3k
                          jpeg_info->comp_info[0].v_samp_factor);
1275
48.3k
      status = MagickPass;
1276
48.3k
      break;
1277
91.4k
    case 3:
1278
91.4k
      (void) FormatString(sampling_factors,"%dx%d,%dx%d,%dx%d",
1279
91.4k
                          jpeg_info->comp_info[0].h_samp_factor,
1280
91.4k
                          jpeg_info->comp_info[0].v_samp_factor,
1281
91.4k
                          jpeg_info->comp_info[1].h_samp_factor,
1282
91.4k
                          jpeg_info->comp_info[1].v_samp_factor,
1283
91.4k
                          jpeg_info->comp_info[2].h_samp_factor,
1284
91.4k
                          jpeg_info->comp_info[2].v_samp_factor);
1285
91.4k
      status = MagickPass;
1286
91.4k
      break;
1287
28.2k
    case 4:
1288
28.2k
      (void) FormatString(sampling_factors,"%dx%d,%dx%d,%dx%d,%dx%d",
1289
28.2k
                          jpeg_info->comp_info[0].h_samp_factor,
1290
28.2k
                          jpeg_info->comp_info[0].v_samp_factor,
1291
28.2k
                          jpeg_info->comp_info[1].h_samp_factor,
1292
28.2k
                          jpeg_info->comp_info[1].v_samp_factor,
1293
28.2k
                          jpeg_info->comp_info[2].h_samp_factor,
1294
28.2k
                          jpeg_info->comp_info[2].v_samp_factor,
1295
28.2k
                          jpeg_info->comp_info[3].h_samp_factor,
1296
28.2k
                          jpeg_info->comp_info[3].v_samp_factor);
1297
28.2k
      status = MagickPass;
1298
28.2k
      break;
1299
171k
    }
1300
171k
  return status;
1301
171k
}
1302
1303
static MagickBool
1304
IsITUFax(const Image* image)
1305
332k
{
1306
332k
  size_t
1307
332k
    profile_length;
1308
1309
332k
  const unsigned char
1310
332k
    *profile;
1311
1312
332k
  MagickBool
1313
332k
    status;
1314
1315
332k
  status=MagickFalse;
1316
332k
  if ((profile=GetImageProfile(image,"APP1",&profile_length)) &&
1317
0
      (profile_length >= 5))
1318
0
    {
1319
0
      if (profile[0] == 0x47 &&
1320
0
          profile[1] == 0x33 &&
1321
0
          profile[2] == 0x46 &&
1322
0
          profile[3] == 0x41 &&
1323
0
          profile[4] == 0x58)
1324
0
      status=MagickTrue;
1325
0
    }
1326
1327
332k
    return status;
1328
332k
}
1329
1330
#define ThrowJPEGReaderException(code_,reason_,image_)  \
1331
76.2k
  {                                                     \
1332
76.2k
    client_data=FreeMagickClientData(client_data);      \
1333
76.2k
    ThrowReaderException(code_,reason_,image_);         \
1334
0
  }
1335
1336
static Image *ReadJPEGImage(const ImageInfo *image_info,
1337
                            ExceptionInfo *exception)
1338
706k
{
1339
706k
  Image
1340
706k
    *image;
1341
1342
706k
  MagickClientData
1343
706k
    *client_data = (MagickClientData *) NULL;
1344
1345
706k
  IndexPacket
1346
706k
    index;
1347
1348
706k
  long
1349
706k
    y;
1350
1351
706k
  magick_jpeg_pixels_t
1352
706k
    jpeg_pixels; /* Contents freed by FreeMagickClientData() */
1353
1354
706k
  const char
1355
706k
    *value;
1356
1357
706k
  register unsigned long
1358
706k
    i;
1359
1360
706k
  struct jpeg_error_mgr
1361
706k
    jpeg_error;
1362
1363
706k
  struct jpeg_progress_mgr
1364
706k
    jpeg_progress;
1365
1366
706k
  struct jpeg_decompress_struct
1367
706k
    jpeg_info;
1368
1369
706k
  MagickPassFail
1370
706k
    status;
1371
1372
706k
  unsigned long
1373
706k
    number_pixels;
1374
1375
  /*
1376
    Open image file.
1377
  */
1378
706k
  assert(image_info != (const ImageInfo *) NULL);
1379
706k
  assert(image_info->signature == MagickSignature);
1380
706k
  assert(exception != (ExceptionInfo *) NULL);
1381
706k
  assert(exception->signature == MagickSignature);
1382
706k
  image=AllocateImage(image_info);
1383
706k
  if (image == (Image *) NULL)
1384
706k
    ThrowJPEGReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1385
706k
  client_data=AllocateMagickClientData();
1386
706k
  if (client_data == (MagickClientData *) NULL)
1387
706k
    ThrowJPEGReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1388
706k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1389
706k
  if (status == MagickFail)
1390
706k
    ThrowJPEGReaderException(FileOpenError,UnableToOpenFile,image);
1391
706k
  if (BlobIsSeekable(image) && GetBlobSize(image) < 107)
1392
681k
    ThrowJPEGReaderException(CorruptImageError,InsufficientImageDataInFile,image);
1393
  /*
1394
    Initialize structures.
1395
  */
1396
681k
  (void) memset(&jpeg_pixels,0,sizeof(jpeg_pixels));
1397
681k
  (void) memset(&jpeg_progress,0,sizeof(jpeg_progress));
1398
681k
  (void) memset(&jpeg_info,0,sizeof(jpeg_info));
1399
681k
  (void) memset(&jpeg_error,0,sizeof(jpeg_error));
1400
681k
  jpeg_info.err=jpeg_std_error(&jpeg_error);
1401
681k
  jpeg_info.err->emit_message=/*(void (*)(j_common_ptr,int))*/ JPEGDecodeMessageHandler;
1402
681k
  jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1403
681k
  client_data->image=image;
1404
681k
  client_data->ping=image_info->ping;
1405
681k
  client_data->max_scan_number=100;
1406
681k
  client_data->max_warning_count=MaxWarningCount;
1407
681k
  client_data->jpeg_pixels=&jpeg_pixels;
1408
1409
  /*
1410
    Allow the user to set how many warnings of any given type are
1411
    allowed before promotion of the warning to a hard error.
1412
  */
1413
681k
  if ((value=AccessDefinition(image_info,"jpeg","max-warnings")))
1414
0
    client_data->max_warning_count=strtol(value,(char **) NULL, 10);
1415
1416
  /*
1417
    Set initial longjmp based error handler.
1418
  */
1419
681k
  if (setjmp(client_data->error_recovery) != 0)
1420
463k
    {
1421
463k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1422
463k
                            "Setjmp return from longjmp!");
1423
463k
      jpeg_destroy_decompress(&jpeg_info);
1424
463k
      GetImageException(image,exception);
1425
463k
      client_data=FreeMagickClientData(client_data);
1426
463k
      CloseBlob(image);
1427
463k
      if (exception->severity < ErrorException)
1428
0
        return(image);
1429
463k
      DestroyImage(image);
1430
463k
      return((Image *) NULL);
1431
463k
    }
1432
218k
  jpeg_info.client_data=(void *) client_data;
1433
1434
218k
  jpeg_create_decompress(&jpeg_info);
1435
  /*
1436
    Specify a memory limit for libjpeg which is 1/5th the absolute
1437
    limit.  Don't actually consume the resource since we don't know
1438
    how much libjpeg will actually consume.
1439
  */
1440
218k
  jpeg_info.mem->max_memory_to_use=(long) (GetMagickResourceLimit(MemoryResource) -
1441
218k
                                           GetMagickResource(MemoryResource))/5U;
1442
218k
  if (image->logging)
1443
681k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1444
681k
                          "Memory capped to %ld bytes", jpeg_info.mem->max_memory_to_use);
1445
  /*
1446
    Register our progress monitor
1447
  */
1448
218k
  jpeg_progress.progress_monitor=(void (*)(j_common_ptr)) JPEGDecodeProgressMonitor;
1449
218k
  jpeg_info.progress=&jpeg_progress;
1450
1451
218k
  JPEGSourceManager(&jpeg_info,image);
1452
218k
  jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1453
218k
  jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1454
218k
  jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1455
10.4M
  for (i=1; i < 16; i++)
1456
10.2M
    if ((i != 2) && (i != 13) && (i != 14))
1457
8.17M
      jpeg_set_marker_processor(&jpeg_info,JPEG_APP0+i,ReadGenericProfile);
1458
218k
  if (image->logging)
1459
681k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1460
681k
                          "Reading JPEG header...");
1461
218k
  i=jpeg_read_header(&jpeg_info,True);
1462
218k
  if (image->logging)
1463
332k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1464
332k
                          "Done with reading JPEG header");
1465
218k
  if (IsITUFax(image))
1466
0
    {
1467
0
      if (image->logging)
1468
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1469
0
                              "Image colorspace set to LAB");
1470
0
      image->colorspace=LABColorspace;
1471
0
      jpeg_info.out_color_space = JCS_YCbCr;
1472
0
    }
1473
218k
  else if (jpeg_info.out_color_space == JCS_CMYK)
1474
67.1k
    {
1475
67.1k
      if (image->logging)
1476
67.1k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1477
67.1k
                              "Image colorspace set to CMYK");
1478
67.1k
      image->colorspace=CMYKColorspace;
1479
67.1k
    }
1480
218k
  if (jpeg_info.saw_JFIF_marker)
1481
51.8k
    {
1482
51.8k
      if ((jpeg_info.X_density != 1U) && (jpeg_info.Y_density != 1U))
1483
50.7k
        {
1484
          /*
1485
            Set image resolution.
1486
          */
1487
50.7k
          image->x_resolution=jpeg_info.X_density;
1488
50.7k
          image->y_resolution=jpeg_info.Y_density;
1489
50.7k
          if (jpeg_info.density_unit == 1)
1490
7.22k
            image->units=PixelsPerInchResolution;
1491
50.7k
          if (jpeg_info.density_unit == 2)
1492
735
            image->units=PixelsPerCentimeterResolution;
1493
50.7k
          if (image->logging)
1494
50.7k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1495
50.7k
                                  "Image resolution set to %gx%g %s",
1496
50.7k
                                  image->x_resolution,
1497
50.7k
                                  image->y_resolution,
1498
50.7k
                                  ResolutionTypeToString(image->units));
1499
50.7k
        }
1500
51.8k
    }
1501
1502
  /*
1503
    If the desired image size is pre-set (e.g. by using -size), then
1504
    let the JPEG library subsample for us.
1505
  */
1506
218k
  number_pixels=image->columns*image->rows;
1507
218k
  if (number_pixels != 0)
1508
0
    {
1509
0
      double
1510
0
        scale_factor;
1511
1512
1513
0
      if (image->logging)
1514
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1515
0
                              "Requested Geometry: %lux%lu",
1516
0
                              image->columns,image->rows);
1517
0
      jpeg_calc_output_dimensions(&jpeg_info);
1518
0
      image->magick_columns=jpeg_info.output_width;
1519
0
      image->magick_rows=jpeg_info.output_height;
1520
0
      if (image->logging)
1521
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1522
0
                              "magick_geometry=%lux%lu",
1523
0
                              image->magick_columns, image->magick_rows);
1524
0
      scale_factor=(double) jpeg_info.output_width/image->columns;
1525
0
      if (scale_factor > ((double) jpeg_info.output_height/image->rows))
1526
0
        scale_factor=(double) jpeg_info.output_height/image->rows;
1527
0
      jpeg_info.scale_denom *=(unsigned int) scale_factor;
1528
0
      jpeg_calc_output_dimensions(&jpeg_info);
1529
0
      if (image->logging)
1530
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1531
0
                              "Original Geometry: %lux%lu,"
1532
0
                              " Scale_factor: %ld (scale_num=%d,"
1533
0
                              " scale_denom=%d)",
1534
0
                              image->magick_columns, image->magick_rows,
1535
0
                              (long) scale_factor,
1536
0
                              jpeg_info.scale_num,jpeg_info.scale_denom);
1537
0
    }
1538
#if 0
1539
  /*
1540
    The subrange parameter is set by the filename array syntax similar
1541
    to the way an image is requested from a list (e.g. myfile.jpg[2]).
1542
    Argument values other than zero are used to scale the image down
1543
    by that factor.  IJG JPEG 62 (6b) supports values of 1,2,4, or 8
1544
    while IJG JPEG 70 supports all values in the range 1-16.  This
1545
    feature is useful in case you want to view all of the images with
1546
    a consistent ratio.  Unfortunately, it uses the same syntax as
1547
    list member access.
1548
  */
1549
  else if (image_info->subrange != 0)
1550
    {
1551
      jpeg_info.scale_denom *=(int) image_info->subrange;
1552
      jpeg_calc_output_dimensions(&jpeg_info);
1553
      if (image->logging)
1554
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1555
                              "Requested Scaling Denominator: %d "
1556
                              "(scale_num=%d, scale_denom=%d)",
1557
                              (int) image_info->subrange,
1558
                              jpeg_info.scale_num,jpeg_info.scale_denom);
1559
1560
    }
1561
#endif
1562
218k
#if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1563
#if !defined(LIBJPEG_TURBO_VERSION_NUMBER) && defined(D_LOSSLESS_SUPPORTED)
1564
  /* This code is based on a patch to IJG JPEG 6b, or somesuch.  Standard
1565
     library does not have a 'process' member. */
1566
  image->interlace=
1567
    jpeg_info.process == JPROC_PROGRESSIVE ? LineInterlace : NoInterlace;
1568
  image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1569
    LosslessJPEGCompression : JPEGCompression;
1570
  if (jpeg_info.data_precision > 8)
1571
    MagickError2(OptionError,
1572
                 "12-bit JPEG not supported. Reducing pixel data to 8 bits",
1573
                 (char *) NULL);
1574
#else
1575
218k
  image->interlace=jpeg_info.progressive_mode ? LineInterlace : NoInterlace;
1576
218k
  image->compression=JPEGCompression;
1577
218k
#endif
1578
#else
1579
  image->compression=JPEGCompression;
1580
  image->interlace=LineInterlace;
1581
#endif
1582
1583
  /*
1584
    Allow the user to enable/disable block smoothing.
1585
  */
1586
218k
  if ((value=AccessDefinition(image_info,"jpeg","block-smoothing")))
1587
0
    {
1588
0
      if (LocaleCompare(value,"FALSE") == 0)
1589
0
        jpeg_info.do_block_smoothing=False;
1590
0
      else
1591
0
        jpeg_info.do_block_smoothing=True;
1592
0
    }
1593
1594
  /*
1595
    Allow the user to select the DCT decoding algorithm.
1596
  */
1597
218k
  if ((value=AccessDefinition(image_info,"jpeg","dct-method")))
1598
0
    {
1599
0
      if (LocaleCompare(value,"ISLOW") == 0)
1600
0
        jpeg_info.dct_method=JDCT_ISLOW;
1601
0
      else if (LocaleCompare(value,"IFAST") == 0)
1602
0
        jpeg_info.dct_method=JDCT_IFAST;
1603
0
      else if (LocaleCompare(value,"FLOAT") == 0)
1604
0
        jpeg_info.dct_method=JDCT_FLOAT;
1605
0
      else if (LocaleCompare(value,"DEFAULT") == 0)
1606
0
        jpeg_info.dct_method=JDCT_DEFAULT;
1607
0
      else if (LocaleCompare(value,"FASTEST") == 0)
1608
0
        jpeg_info.dct_method=JDCT_FASTEST;
1609
0
    }
1610
1611
  /*
1612
    Allow the user to enable/disable fancy upsampling.
1613
  */
1614
218k
  if ((value=AccessDefinition(image_info,"jpeg","fancy-upsampling")))
1615
0
    {
1616
0
      if (LocaleCompare(value,"FALSE") == 0)
1617
0
        jpeg_info.do_fancy_upsampling=False;
1618
0
      else
1619
0
        jpeg_info.do_fancy_upsampling=True;
1620
0
    }
1621
1622
  /*
1623
    Allow the user to adjust the maximum JPEG scan number
1624
  */
1625
218k
  if ((value=AccessDefinition(image_info,"jpeg","max-scan-number")))
1626
244k
    {
1627
244k
      client_data->max_scan_number=strtol(value,(char **) NULL, 10);
1628
244k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1629
244k
                            "JPEG max-scan-number set to %d",
1630
244k
                            client_data->max_scan_number);
1631
244k
    }
1632
1633
218k
  jpeg_calc_output_dimensions(&jpeg_info);
1634
218k
  image->columns=jpeg_info.output_width;
1635
218k
  image->rows=jpeg_info.output_height;
1636
218k
  image->depth=Min(jpeg_info.data_precision,Min(16,QuantumDepth));
1637
1638
218k
  if (image->logging)
1639
332k
    {
1640
332k
      if (image->interlace == LineInterlace)
1641
147k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1642
147k
                              "Interlace: progressive");
1643
185k
      else
1644
185k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1645
185k
                              "Interlace: nonprogressive");
1646
332k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1647
332k
                            (int) jpeg_info.data_precision);
1648
332k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Components: %d",
1649
332k
                            (int) jpeg_info.output_components);
1650
332k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1651
332k
                            (int) jpeg_info.output_width,
1652
332k
                            (int) jpeg_info.output_height);
1653
332k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"DCT Method: %d",
1654
332k
                            jpeg_info.dct_method);
1655
332k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Fancy Upsampling: %s",
1656
332k
                            (jpeg_info.do_fancy_upsampling ? "true" : "false"));
1657
332k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Block Smoothing: %s",
1658
332k
                            (jpeg_info.do_block_smoothing ? "true" : "false"));
1659
332k
    }
1660
1661
218k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
1662
47.1k
    {
1663
47.1k
      jpeg_destroy_decompress(&jpeg_info);
1664
47.1k
      ThrowJPEGReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1665
0
    }
1666
1667
171k
  if (image->logging)
1668
285k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1669
285k
                          "Starting JPEG decompression...");
1670
171k
  (void) jpeg_start_decompress(&jpeg_info);
1671
171k
  image->columns=jpeg_info.output_width;
1672
171k
  image->rows=jpeg_info.output_height;
1673
171k
  {
1674
171k
    char
1675
171k
      attribute[MaxTextExtent];
1676
1677
    /*
1678
      Estimate and retain JPEG properties as attributes.
1679
    */
1680
171k
    FormatString(attribute,"%d",EstimateJPEGQuality(&jpeg_info,image));
1681
171k
    (void) SetImageAttribute(image,"JPEG-Quality",attribute);
1682
1683
171k
    FormatString(attribute,"%ld",(long)jpeg_info.out_color_space);
1684
171k
    (void) SetImageAttribute(image,"JPEG-Colorspace",attribute);
1685
1686
171k
    FormatJPEGColorSpace(jpeg_info.out_color_space,attribute);
1687
171k
    (void) SetImageAttribute(image,"JPEG-Colorspace-Name",attribute);
1688
171k
    if (image->logging)
1689
171k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1690
171k
                            "Colorspace: %s (%d)", attribute,
1691
171k
                            jpeg_info.out_color_space);
1692
1693
171k
    if (FormatJPEGSamplingFactors(&jpeg_info,attribute) != MagickFail)
1694
168k
      {
1695
168k
        (void) SetImageAttribute(image,"JPEG-Sampling-factors",attribute);
1696
168k
        if (image->logging)
1697
168k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1698
168k
                                "Sampling Factors: %s", attribute);
1699
168k
      }
1700
171k
  }
1701
1702
171k
  image->depth=Min(jpeg_info.data_precision,Min(16,QuantumDepth));
1703
171k
  if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1704
48.3k
    {
1705
      /*
1706
        Build colormap if we can
1707
      */
1708
48.3k
      unsigned long max_index = MaxValueGivenBits(image->depth);
1709
48.3k
      if (max_index <= MaxMap)
1710
48.3k
        if (!AllocateImageColormap(image,max_index+1LU))
1711
0
          {
1712
0
            jpeg_destroy_decompress(&jpeg_info);
1713
0
            ThrowJPEGReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1714
0
          }
1715
48.3k
      if (image_info->ping)
1716
0
        {
1717
0
          image->is_grayscale=MagickTrue;
1718
0
        }
1719
48.3k
    }
1720
122k
  else
1721
122k
    {
1722
122k
      if (image_info->ping)
1723
0
        {
1724
0
          image->is_grayscale=MagickFalse;
1725
0
          image->is_monochrome=MagickFalse;
1726
0
        }
1727
122k
    }
1728
1729
  /*
1730
    Store profiles in image.
1731
  */
1732
2.91M
  for (i=0 ; i < ArraySize(client_data->profiles); i++)
1733
2.73M
    {
1734
2.73M
      ProfileInfo *profile=&client_data->profiles[i];
1735
2.73M
      if (!profile->name)
1736
2.72M
        continue;
1737
18.9k
      if (!profile->length)
1738
0
        continue;
1739
18.9k
      if (!profile->info)
1740
0
        continue;
1741
18.9k
      (void) SetImageProfile(image,profile->name,profile->info,profile->length);
1742
18.9k
    }
1743
1744
171k
  if (image_info->ping)
1745
0
    {
1746
0
      jpeg_destroy_decompress(&jpeg_info);
1747
0
      client_data=FreeMagickClientData(client_data);
1748
0
      CloseBlob(image);
1749
0
      return(image);
1750
0
    }
1751
171k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
1752
0
    {
1753
0
      jpeg_destroy_decompress(&jpeg_info);
1754
0
      ThrowJPEGReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1755
0
    }
1756
1757
  /*
1758
    Verify that we support the number of output components.
1759
  */
1760
171k
  if ((jpeg_info.output_components != 1) &&
1761
122k
      (jpeg_info.output_components != 3) &&
1762
31.4k
      (jpeg_info.output_components != 4))
1763
3.16k
    {
1764
3.16k
      jpeg_destroy_decompress(&jpeg_info);
1765
3.16k
      ThrowJPEGReaderException(CoderError,ImageTypeNotSupported,image);
1766
0
    }
1767
  /*
1768
    Verify that file size is reasonable (if we can)
1769
  */
1770
168k
  if (BlobIsSeekable(image))
1771
168k
    {
1772
168k
      magick_off_t
1773
168k
        blob_size;
1774
1775
168k
      double
1776
168k
        ratio = 0;
1777
1778
168k
      blob_size = GetBlobSize(image);
1779
1780
168k
      if (blob_size != 0)
1781
168k
        {
1782
          /* magick columns/rows are only set if size was specified! */
1783
168k
          if (image->magick_columns && image->magick_rows)
1784
0
            ratio = ((double) image->magick_columns*image->magick_rows*
1785
0
                     jpeg_info.output_components/blob_size);
1786
168k
          else
1787
168k
            ratio = ((double) image->columns*image->rows*
1788
168k
                     jpeg_info.output_components/blob_size);
1789
168k
        }
1790
1791
      /* All-black JPEG can produce tremendous compression ratios.
1792
         Allow for it. */
1793
168k
      if ((blob_size == 0) || (ratio > 2500.0))
1794
1.10k
        {
1795
1.10k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1796
1.10k
                                "Unreasonable dimensions: "
1797
1.10k
                                "geometry=%lux%lu,"
1798
1.10k
                                " magick_geometry=%lux%lu,"
1799
1.10k
                                " components=%d, "
1800
1.10k
                                "blob size=%" MAGICK_OFF_F "d bytes, "
1801
1.10k
                                "compression ratio %g",
1802
1.10k
                                image->columns, image->rows,
1803
1.10k
                                image->magick_columns, image->magick_rows,
1804
1.10k
                                jpeg_info.output_components, blob_size, ratio);
1805
1806
1.10k
          jpeg_destroy_decompress(&jpeg_info);
1807
1.10k
          ThrowJPEGReaderException(CorruptImageError,InsufficientImageDataInFile,image);
1808
0
        }
1809
168k
    }
1810
1811
166k
  switch (jpeg_info.data_precision)
1812
166k
    {
1813
0
#if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES
1814
5.25k
    case 16:
1815
5.25k
      jpeg_pixels.t.j16 =
1816
5.25k
        MagickAllocateResourceLimitedClearedArray(J16SAMPLE *,
1817
5.25k
                                                  jpeg_info.output_components,
1818
5.25k
                                                  MagickArraySize(image->columns,
1819
5.25k
                                                                  sizeof(J16SAMPLE)));
1820
5.25k
      break;
1821
0
#endif /* if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES */
1822
0
#if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES
1823
37.1k
    case 12:
1824
37.1k
      jpeg_pixels.t.j12 =
1825
37.1k
        MagickAllocateResourceLimitedClearedArray(J12SAMPLE *,
1826
37.1k
                                                  jpeg_info.output_components,
1827
37.1k
                                                  MagickArraySize(image->columns,
1828
37.1k
                                                                  sizeof(J12SAMPLE)));
1829
37.1k
      break;
1830
0
#endif /* if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES */
1831
124k
    default:
1832
124k
      {
1833
124k
        jpeg_pixels.t.j =
1834
124k
          MagickAllocateResourceLimitedClearedArray(JSAMPLE *,
1835
124k
                                                    jpeg_info.output_components,
1836
124k
                                                    MagickArraySize(image->columns,
1837
124k
                                                                    sizeof(JSAMPLE)));
1838
124k
      }
1839
166k
    }
1840
1841
166k
  if (jpeg_pixels.t.v == (void *) NULL)
1842
0
    {
1843
0
      jpeg_destroy_decompress(&jpeg_info);
1844
0
      ThrowJPEGReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1845
0
    }
1846
1847
  /*
1848
    Extended longjmp-based error handler (with jpeg_pixels)
1849
  */
1850
166k
  if (setjmp(client_data->error_recovery) != 0)
1851
5.63k
    {
1852
5.63k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1853
5.63k
                            "Setjmp return from longjmp!");
1854
      /* Error handling code executed if longjmp was invoked */
1855
5.63k
      MagickFreeResourceLimitedMemory(void *,jpeg_pixels.t.v);
1856
5.63k
      jpeg_destroy_decompress(&jpeg_info);
1857
5.63k
      if (image->exception.severity > exception->severity)
1858
1.47k
        CopyException(exception,&image->exception);
1859
5.63k
      client_data=FreeMagickClientData(client_data);
1860
5.63k
      CloseBlob(image);
1861
5.63k
      number_pixels=image->columns*image->rows;
1862
5.63k
      if (number_pixels != 0)
1863
5.63k
        return(image);
1864
0
      DestroyImage(image);
1865
0
      return((Image *) NULL);
1866
5.63k
    }
1867
1868
1869
  /*
1870
    Convert JPEG pixels to pixel packets.
1871
  */
1872
12.1M
  for (y=0; y < (long) image->rows; y++)
1873
12.0M
    {
1874
12.0M
      register IndexPacket
1875
12.0M
        *indexes;
1876
1877
12.0M
      register long
1878
12.0M
        x;
1879
1880
12.0M
      register PixelPacket
1881
12.0M
        *q;
1882
1883
      /*
1884
        Read scanlines (one scanline per cycle). Stop at first serious error.
1885
      */
1886
12.0M
#if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES
1887
12.0M
      if (jpeg_info.data_precision == 16)
1888
666k
        {
1889
666k
          {
1890
666k
            J16SAMPROW
1891
666k
              scanline[1];
1892
1893
666k
            scanline[0]=(J16SAMPROW) jpeg_pixels.t.j16;
1894
666k
            if ((jpeg16_read_scanlines(&jpeg_info, scanline,1) != 1) ||
1895
664k
                (image->exception.severity >= ErrorException))
1896
1
              {
1897
1
                status=MagickFail;
1898
1
                break;
1899
1
              }
1900
666k
          }
1901
666k
        } else
1902
11.3M
#endif /* if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES */
1903
11.3M
#if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES
1904
11.3M
        if (jpeg_info.data_precision == 12)
1905
1.20M
          {
1906
1.20M
            J12SAMPROW
1907
1.20M
              scanline[1];
1908
1909
1.20M
            scanline[0]=(J12SAMPROW) jpeg_pixels.t.j12;
1910
1.20M
            if ((jpeg12_read_scanlines(&jpeg_info, scanline,1) != 1) ||
1911
1.20M
                (image->exception.severity >= ErrorException))
1912
3.14k
              {
1913
3.14k
                status=MagickFail;
1914
3.14k
                break;
1915
3.14k
              }
1916
1.20M
          } else
1917
10.1M
#endif /* if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES */
1918
10.1M
          {
1919
10.1M
            JSAMPROW
1920
10.1M
              scanline[1];
1921
1922
10.1M
            scanline[0]=(JSAMPROW) jpeg_pixels.t.j;
1923
10.1M
            if ((jpeg_read_scanlines(&jpeg_info, scanline,1) != 1) ||
1924
10.1M
                (image->exception.severity >= ErrorException))
1925
221
              {
1926
221
                status=MagickFail;
1927
221
                break;
1928
221
              }
1929
10.1M
          }
1930
1931
12.0M
      q=SetImagePixels(image,0,y,image->columns,1);
1932
12.0M
      if (q == (PixelPacket *) NULL)
1933
21
        {
1934
21
          status=MagickFail;
1935
21
          break;
1936
21
        }
1937
12.0M
      indexes=AccessMutableIndexes(image);
1938
1939
12.0M
      if (jpeg_info.output_components == 1)
1940
5.35M
        {
1941
5.35M
          if (image->storage_class == PseudoClass)
1942
5.35M
            {
1943
5.35M
              switch(jpeg_info.data_precision)
1944
5.35M
                {
1945
0
#if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES
1946
64.8k
                case 16:
1947
64.8k
                  {
1948
3.04M
                    for (x=0; x < (long) image->columns; x++)
1949
2.97M
                    {
1950
2.97M
                      index=(IndexPacket) ScaleQuantumToIndex((ScaleShortToQuantum(jpeg_pixels.t.j16[x])));
1951
2.97M
                      VerifyColormapIndex(image,index);
1952
2.97M
                      indexes[x]=index;
1953
2.97M
                      *q++=image->colormap[index];
1954
2.97M
                    }
1955
64.8k
                    break;
1956
0
                  }
1957
0
#endif /* if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES */
1958
0
#if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES
1959
105k
                case 12:
1960
105k
                  {
1961
105k
                    const unsigned int
1962
105k
                      scale_short = 65535U/MAXJ12SAMPLE;
1963
1964
5.19M
                    for (x=0; x < (long) image->columns; x++)
1965
5.09M
                    {
1966
5.09M
                      index=(IndexPacket) ScaleQuantumToIndex((ScaleShortToQuantum(scale_short*((unsigned short)jpeg_pixels.t.j12[x]))));
1967
5.09M
                      VerifyColormapIndex(image,index);
1968
5.09M
                      indexes[x]=index;
1969
5.09M
                      *q++=image->colormap[index];
1970
5.09M
                    }
1971
105k
                    break;
1972
0
                  }
1973
0
#endif /* if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES */
1974
5.18M
                default:
1975
5.18M
                  {
1976
1.85G
                    for (x=0; x < (long) image->columns; x++)
1977
1.84G
                      {
1978
1.84G
                        index=(IndexPacket) (GETJSAMPLE(jpeg_pixels.t.j[x]));
1979
1.84G
                        VerifyColormapIndex(image,index);
1980
1.84G
                        indexes[x]=index;
1981
1.84G
                        *q++=image->colormap[index];
1982
1.84G
                      }
1983
5.18M
                  }
1984
5.35M
                }
1985
5.35M
            }
1986
0
          else
1987
0
            {
1988
0
              switch(jpeg_info.data_precision)
1989
0
                {
1990
0
#if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES
1991
0
                case 16:
1992
0
                  {
1993
                    /* J16SAMPLE is a 'unsigned short' with maximum value MAXJ16SAMPLE (65535) */
1994
0
                    for (x=0; x < (long) image->columns; x++)
1995
0
                    {
1996
0
                      q->red=q->green=q->blue=ScaleShortToQuantum(jpeg_pixels.t.j16[x]);
1997
0
                      q->opacity=OpaqueOpacity;
1998
0
                      q++;
1999
0
                    }
2000
0
                    break;
2001
0
                  }
2002
0
#endif /* if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES */
2003
0
#if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES
2004
0
                case 12:
2005
0
                  {
2006
                    /* J12SAMPLE is a 'short' with maximum value MAXJ12SAMPLE (4095) */
2007
0
                    const unsigned int
2008
0
                      scale_short = 65535U/MAXJ12SAMPLE;
2009
2010
0
                    for (x=0; x < (long) image->columns; x++)
2011
0
                    {
2012
0
                      q->red=q->green=q->blue=ScaleShortToQuantum(scale_short*((unsigned short)jpeg_pixels.t.j12[x]));
2013
0
                      q->opacity=OpaqueOpacity;
2014
0
                      q++;
2015
0
                    }
2016
0
                    break;
2017
0
                  }
2018
0
#endif /* if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES */
2019
0
                default:
2020
0
                  {
2021
0
                    for (x=0; x < (long) image->columns; x++)
2022
0
                      {
2023
0
                        q->red=q->green=q->blue=ScaleCharToQuantum(GETJSAMPLE(jpeg_pixels.t.j[x]));
2024
0
                        q->opacity=OpaqueOpacity;
2025
0
                        q++;
2026
0
                      }
2027
0
                  }
2028
0
                }
2029
0
            }
2030
5.35M
        }
2031
6.67M
      else if ((jpeg_info.output_components == 3) ||
2032
3.53M
               (jpeg_info.output_components == 4))
2033
6.67M
        {
2034
6.67M
          switch(jpeg_info.data_precision)
2035
6.67M
            {
2036
0
#if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES
2037
599k
            case 16:
2038
599k
              {
2039
                /* J16SAMPLE is a 'unsigned short' with maximum value MAXJ16SAMPLE (65535) */
2040
599k
                i = 0;
2041
32.8M
                for (x=0; x < (long) image->columns; x++)
2042
32.2M
                  {
2043
32.2M
                    q->red=ScaleShortToQuantum(jpeg_pixels.t.j16[i++]);
2044
32.2M
                    q->green=ScaleShortToQuantum(jpeg_pixels.t.j16[i++]);
2045
32.2M
                    q->blue=ScaleShortToQuantum(jpeg_pixels.t.j16[i++]);
2046
32.2M
                    if (jpeg_info.output_components > 3)
2047
30.2M
                      q->opacity=ScaleShortToQuantum(jpeg_pixels.t.j16[i++]);
2048
2.01M
                    else
2049
2.01M
                      q->opacity=OpaqueOpacity;
2050
32.2M
                    q++;
2051
32.2M
                  }
2052
599k
                break;
2053
0
              }
2054
0
#endif /* if defined(HAVE_JPEG16_READ_SCANLINES) && HAVE_JPEG16_READ_SCANLINES */
2055
0
#if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES
2056
1.09M
            case 12:
2057
1.09M
              {
2058
                /* J12SAMPLE is a 'short' with maximum value MAXJ12SAMPLE (4095) */
2059
1.09M
                const unsigned int
2060
1.09M
                  scale_short = 65535U/MAXJ12SAMPLE;
2061
2062
1.09M
                i = 0;
2063
280M
                for (x=0; x < (long) image->columns; x++)
2064
279M
                  {
2065
279M
                    q->red=ScaleShortToQuantum(scale_short*((unsigned short)jpeg_pixels.t.j12[i++]));
2066
279M
                    q->green=ScaleShortToQuantum(scale_short*((unsigned short)jpeg_pixels.t.j12[i++]));
2067
279M
                    q->blue=ScaleShortToQuantum(scale_short*((unsigned short)jpeg_pixels.t.j12[i++]));
2068
279M
                    if (jpeg_info.output_components > 3)
2069
79.6M
                      q->opacity=ScaleShortToQuantum(scale_short*((unsigned short)jpeg_pixels.t.j12[i++]));
2070
200M
                    else
2071
200M
                      q->opacity=OpaqueOpacity;
2072
279M
                    q++;
2073
279M
                  }
2074
1.09M
                break;
2075
0
              }
2076
0
#endif /* if defined(HAVE_JPEG12_READ_SCANLINES) && HAVE_JPEG12_READ_SCANLINES */
2077
4.97M
            default:
2078
4.97M
              {
2079
4.97M
                i = 0;
2080
776M
                for (x=0; x < (long) image->columns; x++)
2081
771M
                  {
2082
771M
                    q->red=ScaleCharToQuantum(GETJSAMPLE(jpeg_pixels.t.j[i++]));
2083
771M
                    q->green=ScaleCharToQuantum(GETJSAMPLE(jpeg_pixels.t.j[i++]));
2084
771M
                    q->blue=ScaleCharToQuantum(GETJSAMPLE(jpeg_pixels.t.j[i++]));
2085
771M
                    if (jpeg_info.output_components > 3)
2086
384M
                      q->opacity=ScaleCharToQuantum(GETJSAMPLE(jpeg_pixels.t.j[i++]));
2087
387M
                    else
2088
387M
                      q->opacity=OpaqueOpacity;
2089
771M
                    q++;
2090
771M
                  }
2091
4.97M
              }
2092
6.67M
            }
2093
6.67M
          if (image->colorspace == CMYKColorspace)
2094
3.53M
            {
2095
              /*
2096
                CMYK pixels are inverted.
2097
              */
2098
3.53M
              q=AccessMutablePixels(image);
2099
498M
              for (x=0; x < (long) image->columns; x++)
2100
494M
                {
2101
494M
                  q->red=MaxRGB-q->red;
2102
494M
                  q->green=MaxRGB-q->green;
2103
494M
                  q->blue=MaxRGB-q->blue;
2104
494M
                  q->opacity=MaxRGB-q->opacity;
2105
494M
                  q++;
2106
494M
                }
2107
3.53M
            }
2108
6.67M
        }
2109
12.0M
      if (!SyncImagePixels(image))
2110
0
        {
2111
0
          status=MagickFail;
2112
0
          break;
2113
0
        }
2114
12.0M
#if !USE_LIBJPEG_PROGRESS
2115
12.0M
      if (QuantumTick(y,image->rows))
2116
3.44M
        if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
2117
3.44M
                                    image->filename,
2118
3.44M
                                    image->columns,image->rows))
2119
0
          {
2120
0
            status=MagickFail;
2121
0
            jpeg_abort_decompress(&jpeg_info);
2122
0
            break;
2123
0
          }
2124
12.0M
#endif /* !USE_LIBJPEG_PROGRESS */
2125
12.0M
    }
2126
  /*
2127
    Free jpeg resources.
2128
  */
2129
161k
  if (status == MagickPass)
2130
157k
    {
2131
      /*
2132
        jpeg_finish_decompress() may throw an exception while it is
2133
        finishing the remainder of the JPEG file.  At this point we
2134
        have already decoded the image so we handle exceptions from
2135
        jpeg_finish_decompress() specially, mapping reported
2136
        exceptions as warnings rather than errors.  We try using
2137
        jpeg_finish_decompress() and if it results in a longjmp(),
2138
        then we skip over it again.
2139
      */
2140
157k
      client_data->completed=MagickTrue;
2141
157k
      if (setjmp(client_data->error_recovery) != 0)
2142
21.6k
        {
2143
21.6k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2144
21.6k
                                "Setjmp return from longjmp!");
2145
21.6k
        }
2146
136k
      else
2147
136k
        {
2148
136k
          (void) jpeg_finish_decompress(&jpeg_info);
2149
136k
        }
2150
157k
    }
2151
161k
  jpeg_destroy_decompress(&jpeg_info);
2152
161k
  MagickFreeResourceLimitedMemory(void *,jpeg_pixels.t.v);
2153
161k
  client_data=FreeMagickClientData(client_data);
2154
161k
  CloseBlob(image);
2155
2156
  /*
2157
    Retrieve image orientation from EXIF (if present) and store in
2158
    image.
2159
2160
    EXIF orientation enumerations match TIFF enumerations, which happen
2161
    to match the enumeration values used by GraphicsMagick.
2162
  */
2163
161k
  if (status == MagickPass)
2164
157k
    {
2165
157k
      const ImageAttribute
2166
157k
        *attribute;
2167
2168
157k
      attribute = GetImageAttribute(image,"EXIF:Orientation");
2169
157k
      if ((attribute != (const ImageAttribute *) NULL) &&
2170
1.67k
          (attribute->value != (char *) NULL))
2171
1.67k
        {
2172
1.67k
          int
2173
1.67k
            orientation;
2174
2175
1.67k
          orientation=MagickAtoI(attribute->value);
2176
1.67k
          if ((orientation > UndefinedOrientation) &&
2177
213
              (orientation <= LeftBottomOrientation))
2178
71
            image->orientation=(OrientationType) orientation;
2179
1.67k
        }
2180
157k
    }
2181
161k
  if (image->logging)
2182
161k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"return");
2183
161k
  GetImageException(image,exception);
2184
161k
  StopTimer(&image->timer);
2185
161k
  return(image);
2186
161k
}
2187
#endif
2188

2189
/*
2190
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2191
%                                                                             %
2192
%                                                                             %
2193
%                                                                             %
2194
%   R e g i s t e r J P E G I m a g e                                         %
2195
%                                                                             %
2196
%                                                                             %
2197
%                                                                             %
2198
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2199
%
2200
%  Method RegisterJPEGImage adds attributes for the JPEG image format to
2201
%  the list of supported formats.  The attributes include the image format
2202
%  tag, a method to read and/or write the format, whether the format
2203
%  supports the saving of more than one frame to the same file or blob,
2204
%  whether the format supports native in-memory I/O, and a brief
2205
%  description of the format.
2206
%
2207
%  The format of the RegisterJPEGImage method is:
2208
%
2209
%      RegisterJPEGImage(void)
2210
%
2211
*/
2212
ModuleExport void RegisterJPEGImage(void)
2213
15
{
2214
15
  static const char
2215
15
    description[]="Joint Photographic Experts Group JFIF format";
2216
2217
15
#if defined(HasJPEG) && defined(JPEG_LIB_VERSION)
2218
15
  static const char
2219
15
    version[] = "IJG JPEG " DefineValueToString(JPEG_LIB_VERSION);
2220
15
#define HAVE_JPEG_VERSION
2221
15
#endif
2222
2223
15
  MagickInfo
2224
15
    *entry;
2225
2226
15
  MagickBool
2227
15
    thread_support;
2228
2229
15
#if defined(SETJMP_IS_THREAD_SAFE) && (SETJMP_IS_THREAD_SAFE)
2230
15
  thread_support=MagickTrue;  /* libjpeg is thread safe */
2231
#else
2232
  thread_support=MagickFalse; /* libjpeg is not thread safe */
2233
#endif
2234
2235
15
  entry=SetMagickInfo("JPEG");
2236
15
  entry->thread_support=thread_support;
2237
15
#if defined(HasJPEG)
2238
15
  entry->decoder=(DecoderHandler) ReadJPEGImage;
2239
15
  entry->encoder=(EncoderHandler) WriteJPEGImage;
2240
15
#endif
2241
15
  entry->magick=(MagickHandler) IsJPEG;
2242
15
  entry->adjoin=False;
2243
15
  entry->description=description;
2244
15
#if defined(HAVE_JPEG_VERSION)
2245
15
    entry->version=version;
2246
15
#endif
2247
15
  entry->module="JPEG";
2248
15
  entry->coder_class=PrimaryCoderClass;
2249
15
  (void) RegisterMagickInfo(entry);
2250
2251
15
  entry=SetMagickInfo("JPG");
2252
15
  entry->thread_support=thread_support;
2253
15
#if defined(HasJPEG)
2254
15
  entry->decoder=(DecoderHandler) ReadJPEGImage;
2255
15
  entry->encoder=(EncoderHandler) WriteJPEGImage;
2256
15
#endif
2257
15
  entry->adjoin=False;
2258
15
  entry->description=description;
2259
15
#if defined(HAVE_JPEG_VERSION)
2260
15
    entry->version=version;
2261
15
#endif
2262
15
  entry->module="JPEG";
2263
15
  entry->coder_class=PrimaryCoderClass;
2264
15
  (void) RegisterMagickInfo(entry);
2265
15
}
2266

2267
/*
2268
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2269
%                                                                             %
2270
%                                                                             %
2271
%                                                                             %
2272
%   U n r e g i s t e r J P E G I m a g e                                     %
2273
%                                                                             %
2274
%                                                                             %
2275
%                                                                             %
2276
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277
%
2278
%  Method UnregisterJPEGImage removes format registrations made by the
2279
%  JPEG module from the list of supported formats.
2280
%
2281
%  The format of the UnregisterJPEGImage method is:
2282
%
2283
%      UnregisterJPEGImage(void)
2284
%
2285
*/
2286
ModuleExport void UnregisterJPEGImage(void)
2287
0
{
2288
0
  (void) UnregisterMagickInfo("JPEG");
2289
0
  (void) UnregisterMagickInfo("JPG");
2290
0
}
2291

2292
#if defined(HasJPEG)
2293
/*
2294
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2295
%                                                                             %
2296
%                                                                             %
2297
%                                                                             %
2298
%  W r i t e J P E G I m a g e                                                %
2299
%                                                                             %
2300
%                                                                             %
2301
%                                                                             %
2302
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2303
%
2304
%  Method WriteJPEGImage writes a JPEG image file and returns it.  It
2305
%  allocates the memory necessary for the new Image structure and returns a
2306
%  pointer to the new image.
2307
%
2308
%  The format of the WriteJPEGImage method is:
2309
%
2310
%      unsigned int WriteJPEGImage(const ImageInfo *image_info,Image *image)
2311
%
2312
%  A description of each parameter follows:
2313
%
2314
%    o status:  Method WriteJPEGImage return True if the image is written.
2315
%      False is returned is there is of a memory shortage or if the image
2316
%      file cannot be opened for writing.
2317
%
2318
%    o image_info: Specifies a pointer to a ImageInfo structure.
2319
%
2320
%    o jpeg_image:  A pointer to an Image structure.
2321
%
2322
%
2323
*/
2324
2325
static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
2326
7.45k
{
2327
7.45k
  DestinationManager
2328
7.45k
    *destination;
2329
2330
7.45k
  destination=(DestinationManager *) cinfo->dest;
2331
7.45k
  destination->manager.free_in_buffer=WriteBlob(destination->image,
2332
7.45k
    MaxBufferExtent,(char *) destination->buffer);
2333
7.45k
  if (destination->manager.free_in_buffer != MaxBufferExtent)
2334
6
    ERREXIT(cinfo,JERR_FILE_WRITE);
2335
7.45k
  destination->manager.next_output_byte=destination->buffer;
2336
7.45k
  return(TRUE);
2337
7.45k
}
2338
2339
static void InitializeDestination(j_compress_ptr cinfo)
2340
726
{
2341
726
  DestinationManager
2342
726
    *destination;
2343
2344
726
  destination=(DestinationManager *) cinfo->dest;
2345
726
  destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
2346
726
    ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
2347
726
  destination->manager.next_output_byte=destination->buffer;
2348
726
  destination->manager.free_in_buffer=MaxBufferExtent;
2349
726
}
2350
2351
static void TerminateDestination(j_compress_ptr cinfo)
2352
720
{
2353
720
  DestinationManager
2354
720
    *destination;
2355
2356
720
  destination=(DestinationManager *) cinfo->dest;
2357
720
  if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
2358
719
    {
2359
719
      size_t
2360
719
        number_bytes;
2361
2362
719
      number_bytes=WriteBlob(destination->image,MaxBufferExtent-
2363
719
        destination->manager.free_in_buffer,(char *) destination->buffer);
2364
719
      if (number_bytes != (MaxBufferExtent-destination->manager.free_in_buffer))
2365
3
        ERREXIT(cinfo,JERR_FILE_WRITE);
2366
719
    }
2367
720
}
2368
2369
/*
2370
  Output generic APPN profile
2371
*/
2372
static void WriteAPPNProfile(j_compress_ptr jpeg_info,
2373
                              const unsigned char *profile,
2374
                              const size_t profile_length,
2375
                              const char * profile_name)
2376
642
{
2377
642
  size_t
2378
642
    j;
2379
2380
642
  int
2381
642
    marker_id;
2382
2383
642
  marker_id=JPEG_APP0+(int) MagickAtoL(profile_name+3);
2384
1.29k
  for (j=0; j < profile_length; j+=65533L)
2385
652
    jpeg_write_marker(jpeg_info,marker_id,
2386
652
                      profile+j,(int)
2387
652
                      Min(profile_length-j,65533L));
2388
642
}
2389
2390
/*
2391
  Output EXIF profile
2392
*/
2393
static void WriteEXIFProfile(j_compress_ptr jpeg_info,
2394
                              const unsigned char *profile,
2395
                              const size_t profile_length)
2396
65
{
2397
65
  size_t
2398
65
    j;
2399
2400
148
  for (j=0; j < profile_length; j+=65533L)
2401
83
    jpeg_write_marker(jpeg_info,JPEG_APP0+1,
2402
83
                      profile+j,(int)
2403
83
                      Min(profile_length-j,65533L));
2404
65
}
2405
2406
/*
2407
  Output ICC color profile as a APP marker.
2408
*/
2409
static void WriteICCProfile(j_compress_ptr jpeg_info,
2410
                            const unsigned char *color_profile,
2411
                            const size_t profile_length)
2412
18
{
2413
18
  register long
2414
18
    i,
2415
18
    j;
2416
2417
61
  for (i=0; i < (long) profile_length; i+=65519)
2418
43
  {
2419
43
    unsigned char
2420
43
      *profile;
2421
2422
43
    size_t
2423
43
      alloc_length,
2424
43
      length=0;
2425
2426
2427
43
    length=Min(profile_length-i,65519);
2428
43
    alloc_length=length+14;
2429
43
    profile=MagickAllocateResourceLimitedMemory(unsigned char *,alloc_length);
2430
43
    if (profile == (unsigned char *) NULL)
2431
0
      break;
2432
43
    (void) strlcpy((char *) profile,"ICC_PROFILE",alloc_length);
2433
43
    profile[12]=(unsigned char) ((i/65519)+1);
2434
43
    profile[13]=(unsigned char) ((profile_length/65519)+1);
2435
1.84M
    for (j=0; j < (long) length; j++)
2436
1.84M
      profile[j+14]=color_profile[i+j];
2437
43
    jpeg_write_marker(jpeg_info,ICC_MARKER,profile,(unsigned int) alloc_length);
2438
43
    MagickFreeResourceLimitedMemory(unsigned char *,profile);
2439
43
  }
2440
18
}
2441
2442
/*
2443
  Output binary Photoshop resource data using an APP marker.
2444
*/
2445
static void WriteIPTCProfile(j_compress_ptr jpeg_info,
2446
                            const unsigned char *iptc_profile,
2447
                            const size_t profile_length)
2448
17
{
2449
17
  register long
2450
17
    i;
2451
2452
17
  unsigned long
2453
17
    roundup,
2454
17
    tag_length;
2455
2456
#ifdef GET_ONLY_IPTC_DATA
2457
  tag_length=26;
2458
#else
2459
17
  tag_length=14;
2460
17
#endif
2461
62
  for (i=0; i < (long) profile_length; i+=65500)
2462
45
  {
2463
45
    size_t
2464
45
      length;
2465
2466
45
    unsigned char
2467
45
      *profile;
2468
2469
45
    length=Min(profile_length-i,65500);
2470
45
    roundup=(length & 0x01); /* round up for Photoshop */
2471
45
    profile=MagickAllocateResourceLimitedMemory(unsigned char *,length+roundup+tag_length);
2472
45
    if (profile == (unsigned char *) NULL)
2473
0
      break;
2474
#ifdef GET_ONLY_IPTC_DATA
2475
    (void) memcpy(profile,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2476
    profile[13]=0x00;
2477
    profile[24]=length >> 8;
2478
    profile[25]=length & 0xff;
2479
#else
2480
45
    (void) memcpy(profile,"Photoshop 3.0 ",14);
2481
45
    profile[13]=0x00;
2482
45
#endif
2483
45
    (void) memcpy(&(profile[tag_length]),&(iptc_profile[i]),length);
2484
45
    if (roundup)
2485
6
      profile[length+tag_length]=0;
2486
45
    jpeg_write_marker(jpeg_info,IPTC_MARKER,profile,(unsigned int)
2487
45
      (length+roundup+tag_length));
2488
45
    MagickFreeResourceLimitedMemory(unsigned char *,profile);
2489
45
  }
2490
17
}
2491
2492
/*
2493
  Output Adobe XMP XML profile.
2494
*/
2495
static void WriteXMPProfile(j_compress_ptr jpeg_info,
2496
                            const unsigned char *profile,
2497
                            const size_t profile_length)
2498
35
{
2499
35
  size_t
2500
35
    count,
2501
35
    index,
2502
35
        header_length,
2503
35
        total_length;
2504
2505
35
  unsigned int
2506
35
        marker_length,
2507
35
        remaining;
2508
2509
35
  header_length=strlen(xmp_std_header)+1; /* Include terminating null */
2510
35
  total_length=header_length+profile_length;
2511
  /* XMP profile must be no larger than range of 'unsigned int' */
2512
35
  remaining=(unsigned int) Min(UINT_MAX,total_length);
2513
2514
35
  marker_length=Min(remaining,JPEG_MARKER_MAX_SIZE);
2515
35
  jpeg_write_m_header(jpeg_info,XML_MARKER,marker_length);
2516
35
  count=marker_length;
2517
35
  {
2518
1.05k
    for (index=0 ; index < header_length; index++)
2519
1.01k
      {
2520
1.01k
        jpeg_write_m_byte(jpeg_info,xmp_std_header[index]);
2521
1.01k
        --remaining;
2522
1.01k
        --count;
2523
1.01k
      }
2524
35
  }
2525
2526
2.33M
  for (index=0; remaining > 0; --remaining)
2527
2.33M
    {
2528
2.33M
      if (count == 0)
2529
31
        {
2530
31
          marker_length=Min(remaining,JPEG_MARKER_MAX_SIZE);
2531
31
          jpeg_write_m_header(jpeg_info,XML_MARKER,marker_length);
2532
31
          count=marker_length;
2533
31
        }
2534
2.33M
      jpeg_write_m_byte(jpeg_info,profile[index]);
2535
2.33M
      index++;
2536
2.33M
      count--;
2537
2.33M
    }
2538
35
}
2539
2540
/*
2541
  Output profiles to JPEG stream.
2542
*/
2543
static void WriteProfiles(j_compress_ptr jpeg_info,Image *image)
2544
726
{
2545
726
  const char
2546
726
    *profile_name;
2547
2548
726
  const unsigned char *
2549
726
    profile;
2550
2551
726
  ImageProfileIterator
2552
726
    profile_iterator;
2553
2554
726
  size_t
2555
726
    profile_length=0;
2556
2557
726
  profile_iterator=AllocateImageProfileIterator(image);
2558
1.50k
  while(NextImageProfile(profile_iterator,&profile_name,&profile,
2559
1.50k
                         &profile_length) != MagickFail)
2560
777
    {
2561
777
      if (LocaleNCompare(profile_name,"APP",3) == 0)
2562
642
        {
2563
642
          WriteAPPNProfile(jpeg_info, profile, profile_length, profile_name);
2564
642
        }
2565
135
      else if (LocaleCompare(profile_name,"EXIF") == 0)
2566
65
        {
2567
65
          WriteEXIFProfile(jpeg_info, profile, profile_length);
2568
65
        }
2569
70
      else if ((LocaleCompare(profile_name,"ICM") == 0) ||
2570
52
               (LocaleCompare(profile_name,"ICC") == 0))
2571
18
        {
2572
18
          WriteICCProfile(jpeg_info, profile, profile_length);
2573
18
        }
2574
52
      else if ((LocaleCompare(profile_name,"IPTC") == 0) ||
2575
35
               (LocaleCompare(profile_name,"8BIM") == 0))
2576
17
        {
2577
17
          WriteIPTCProfile(jpeg_info, profile, profile_length);
2578
17
        }
2579
35
      else if (LocaleCompare(profile_name,"XMP") == 0)
2580
35
        {
2581
35
          WriteXMPProfile(jpeg_info, profile, profile_length);
2582
35
        }
2583
0
      else
2584
0
        {
2585
          /*
2586
            Skip unknown profile type
2587
          */
2588
0
          if (image->logging)
2589
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2590
0
                                  "Skipped Profile: %s, %"
2591
0
                                  MAGICK_SIZE_T_F "u bytes",
2592
0
                                  profile_name,
2593
0
                                  (MAGICK_SIZE_T) profile_length);
2594
0
          continue;
2595
0
        }
2596
2597
777
      if (image->logging)
2598
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2599
0
                              "Wrote Profile: %s, %"
2600
0
                              MAGICK_SIZE_T_F "u bytes",profile_name,
2601
0
                              (MAGICK_SIZE_T) profile_length);
2602
777
    }
2603
726
  DeallocateImageProfileIterator(profile_iterator);
2604
726
}
2605
2606
static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2607
726
{
2608
726
  DestinationManager
2609
726
    *destination;
2610
2611
726
  cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2612
726
    ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2613
726
  destination=(DestinationManager *) cinfo->dest;
2614
726
  destination->manager.init_destination=InitializeDestination;
2615
726
  destination->manager.empty_output_buffer=EmptyOutputBuffer;
2616
726
  destination->manager.term_destination=TerminateDestination;
2617
726
  destination->image=image;
2618
726
}
2619
2620
/*
2621
  Format a libjpeg warning or trace event while encoding.  Warnings
2622
  are converted to GraphicsMagick warning exceptions while traces are
2623
  optionally logged.
2624
2625
  JPEG message codes range from 0 to JMSG_LASTMSGCODE
2626
*/
2627
static void JPEGEncodeMessageHandler(j_common_ptr jpeg_info,int msg_level)
2628
0
{
2629
0
  char
2630
0
    message[JMSG_LENGTH_MAX];
2631
2632
0
  struct jpeg_error_mgr
2633
0
    *err;
2634
2635
0
  MagickClientData
2636
0
    *client_data;
2637
2638
0
  Image
2639
0
    *image;
2640
2641
0
  message[0]='\0';
2642
0
  err=jpeg_info->err;
2643
0
  client_data=(MagickClientData *) jpeg_info->client_data;
2644
0
  image=client_data->image;
2645
  /* msg_level is -1 for warnings, 0 and up for trace messages. */
2646
0
  if (msg_level < 0)
2647
0
    {
2648
0
      unsigned int strikes = 0;
2649
      /* A warning */
2650
0
      (err->format_message)(jpeg_info,message);
2651
2652
0
      if ((err->msg_code >= 0) &&
2653
0
          ((size_t) err->msg_code < ArraySize(client_data->warning_counts)))
2654
0
        {
2655
0
          client_data->warning_counts[err->msg_code]++;
2656
0
          strikes=client_data->warning_counts[err->msg_code];
2657
0
        }
2658
2659
0
      if (image->logging)
2660
0
        {
2661
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2662
0
                                "[%s] JPEG Warning[%u]: \"%s\""
2663
0
                                " (code=%d "
2664
0
                                "parms=0x%02x,0x%02x,"
2665
0
                                "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)",
2666
0
                                image->filename,
2667
0
                                strikes,
2668
0
                                message,err->msg_code,
2669
0
                                err->msg_parm.i[0], err->msg_parm.i[1],
2670
0
                                err->msg_parm.i[2], err->msg_parm.i[3],
2671
0
                                err->msg_parm.i[4], err->msg_parm.i[5],
2672
0
                                err->msg_parm.i[6], err->msg_parm.i[7]);
2673
0
        }
2674
      /*
2675
      if (strikes > client_data->max_warning_count)
2676
        {
2677
          ThrowException2(&image->exception,CorruptImageError,(char *) message,
2678
                          image->filename);
2679
          longjmp(client_data->error_recovery,1);
2680
        }
2681
2682
      if ((err->num_warnings == 0) ||
2683
          (err->trace_level >= 3))
2684
        ThrowException2(&image->exception,CorruptImageWarning,message,
2685
                        image->filename);
2686
      */
2687
      /* JWRN_JPEG_EOF - "Premature end of JPEG file" */
2688
0
      err->num_warnings++;
2689
0
      return /* False */;
2690
0
    }
2691
0
  else
2692
0
    {
2693
      /* A trace message */
2694
0
      if ((image->logging) && (msg_level >= err->trace_level))
2695
0
        {
2696
0
          (err->format_message)(jpeg_info,message);
2697
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2698
0
                                "[%s] JPEG Trace: \"%s\"",image->filename,
2699
0
                                message);
2700
0
        }
2701
0
    }
2702
0
  return /* True */;
2703
0
}
2704
2705
2706
static void JPEGEncodeProgressMonitor(j_common_ptr cinfo)
2707
257k
{
2708
#if USE_LIBJPEG_PROGRESS
2709
  struct jpeg_progress_mgr *p = cinfo->progress;
2710
  MagickClientData *client_data = (MagickClientData *) cinfo->client_data;
2711
  Image *image = client_data->image;
2712
2713
#if 0
2714
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2715
                        "Progress: pass_counter=%ld, pass_limit=%ld,"
2716
                        " completed_passes=%d, total_passes=%d, filename=%s",
2717
                        p->pass_counter, p->pass_limit,
2718
                        p->completed_passes, p->total_passes, image->filename);
2719
#endif
2720
2721
  if (QuantumTick(p->pass_counter,p->pass_limit))
2722
    if (!MagickMonitorFormatted(p->pass_counter,p->pass_limit,&image->exception,
2723
                                "[%s] Saving image: %lux%lu (pass %d of %d)...  ",
2724
                                image->filename,
2725
                                image->columns,image->rows,
2726
                                p->completed_passes+1, p->total_passes))
2727
      {
2728
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2729
                              "Quitting due to progress monitor");
2730
        longjmp(client_data->error_recovery,1);
2731
      }
2732
#else
2733
257k
  (void) cinfo;
2734
257k
#endif /* USE_LIBJPEG_PROGRESS */
2735
257k
}
2736
2737
2738
#define ThrowJPEGWriterException(code_,reason_,image_)  \
2739
0
  {                                                     \
2740
0
    client_data=FreeMagickClientData(client_data);      \
2741
0
    ThrowWriterException(code_,reason_,image_);         \
2742
0
  }
2743
2744
static MagickPassFail WriteJPEGImage(const ImageInfo *image_info,Image *imagep)
2745
726
{
2746
726
  Image
2747
726
    * volatile image = imagep;  /* volatile to avoid "clobber" */
2748
2749
726
  MagickClientData
2750
726
    *client_data = (MagickClientData *) NULL;
2751
2752
726
  const ImageAttribute
2753
726
    *attribute;
2754
2755
726
  magick_jpeg_pixels_t
2756
726
    jpeg_pixels; /* Contents freed by FreeMagickClientData() */
2757
2758
726
  char
2759
726
    *sampling_factors,
2760
726
    *preserve_settings;
2761
2762
726
  const char
2763
726
    *value;
2764
2765
726
  long
2766
726
    y;
2767
2768
726
  register const PixelPacket
2769
726
    *p;
2770
2771
726
  register long
2772
726
    x;
2773
2774
726
  register unsigned long
2775
726
    i;
2776
2777
726
  struct jpeg_error_mgr
2778
726
    jpeg_error;
2779
2780
726
  struct jpeg_progress_mgr
2781
726
    jpeg_progress;
2782
2783
726
  struct jpeg_compress_struct
2784
726
    jpeg_info;
2785
2786
726
  MagickPassFail
2787
726
    status;
2788
2789
726
  unsigned long
2790
726
    input_colorspace;
2791
2792
726
  unsigned long
2793
726
    quality;
2794
2795
726
  magick_int64_t
2796
726
    huffman_memory;
2797
2798
726
  ImageCharacteristics
2799
726
    characteristics;
2800
2801
  /*
2802
    Open image file.
2803
  */
2804
726
  assert(image_info != (const ImageInfo *) NULL);
2805
726
  assert(image_info->signature == MagickSignature);
2806
726
  assert(imagep != (Image *) NULL);
2807
726
  assert(imagep->signature == MagickSignature);
2808
726
  client_data=AllocateMagickClientData();
2809
726
  if (client_data == (MagickClientData *) NULL)
2810
726
    ThrowJPEGWriterException(ResourceLimitError,MemoryAllocationFailed,image);
2811
726
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2812
726
  if (status == False)
2813
726
    ThrowJPEGWriterException(FileOpenError,UnableToOpenFile,image);
2814
2815
726
  (void) memset(&jpeg_pixels,0,sizeof(jpeg_pixels));
2816
726
  (void) memset(&jpeg_progress,0,sizeof(jpeg_progress));
2817
726
  (void) memset(&jpeg_info,0,sizeof(jpeg_info));
2818
726
  (void) memset(&jpeg_error,0,sizeof(jpeg_error));
2819
2820
  /*
2821
    Set initial longjmp based error handler.
2822
  */
2823
726
  jpeg_info.client_data=(void *) image;
2824
726
  jpeg_info.err=jpeg_std_error(&jpeg_error);
2825
726
  jpeg_info.err->emit_message=/*(void (*)(j_common_ptr,int))*/ JPEGEncodeMessageHandler;
2826
726
  jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2827
726
  client_data->image=image;
2828
726
  client_data->max_warning_count=MaxWarningCount;
2829
  /*
2830
    Allow the user to set how many warnings of any given type are
2831
    allowed before promotion of the warning to a hard error.
2832
  */
2833
726
  if ((value=AccessDefinition(image_info,"jpeg","max-warnings")))
2834
0
    client_data->max_warning_count=strtol(value,(char **) NULL, 10);
2835
726
  client_data->jpeg_pixels = &jpeg_pixels;
2836
726
  jpeg_info.client_data=(void *) client_data;
2837
726
  if (setjmp(client_data->error_recovery) != 0)
2838
9
    {
2839
9
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2840
9
                            "Setjmp return from longjmp!");
2841
9
      jpeg_destroy_compress(&jpeg_info);
2842
9
      client_data=FreeMagickClientData(client_data);
2843
9
      CloseBlob(image);
2844
9
      return MagickFail ;
2845
9
    }
2846
2847
717
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2848
717
                        "  Write JPEG Image: image->orientation = %d",
2849
717
                        image->orientation);
2850
2851
  /*
2852
    Transform image to user-requested colorspace.
2853
  */
2854
717
  if (UndefinedColorspace != image_info->colorspace)
2855
0
    {
2856
0
      if (image->logging)
2857
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2858
0
                              "  Transforming colorspace from %s to %s",
2859
0
                              ColorspaceTypeToString(image->colorspace),
2860
0
                              ColorspaceTypeToString(image_info->colorspace));
2861
0
      (void) TransformColorspace(image,image_info->colorspace);
2862
0
    }
2863
2864
  /*
2865
    This writer expects an RGB-compatible colorspace. If the current
2866
    colorspace is not RGB-compatible, then convert it to RGB.
2867
2868
    Convert RGB-compatible colorspaces (e.g. CineonLog) to RGB by
2869
    default.  User can still override it by explicitly specifying the
2870
    desired colorspace.
2871
  */
2872
717
  if (((UndefinedColorspace == image_info->colorspace) &&
2873
726
       (!IsRGBCompatibleColorspace(image->colorspace))) ||
2874
696
      ((IsRGBCompatibleColorspace(image->colorspace) &&
2875
696
        !IsRGBColorspace(image->colorspace))))
2876
30
    {
2877
30
      if (image->logging)
2878
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2879
0
                              "  Transforming colorspace from %s to RGB",
2880
0
                              ColorspaceTypeToString(image->colorspace));
2881
30
      (void) TransformColorspace(image,RGBColorspace);
2882
30
    }
2883
2884
  /*
2885
    Analyze image to be written.
2886
  */
2887
717
  if (!GetImageCharacteristics(image,&characteristics,
2888
717
                               (OptimizeType == image_info->type),
2889
717
                               &image->exception))
2890
0
    {
2891
0
      client_data=FreeMagickClientData(client_data);
2892
0
      CloseBlob(image);
2893
0
      return MagickFail;
2894
0
    }
2895
2896
717
  jpeg_create_compress(&jpeg_info);
2897
717
  JPEGDestinationManager(&jpeg_info,image);
2898
717
  jpeg_info.image_width=(unsigned int) image->columns;
2899
717
  jpeg_info.image_height=(unsigned int) image->rows;
2900
717
  jpeg_info.input_components=3;
2901
717
  jpeg_info.in_color_space=JCS_RGB;
2902
2903
  /*
2904
    Register our progress monitor
2905
  */
2906
717
  jpeg_progress.progress_monitor=(void (*)(j_common_ptr)) JPEGEncodeProgressMonitor;
2907
717
  jpeg_info.progress=&jpeg_progress;
2908
2909
  /*
2910
    Set JPEG colorspace as per user request.
2911
  */
2912
717
  {
2913
717
    MagickBool
2914
717
      colorspace_set=MagickFalse;
2915
2916
717
    if (IsCMYKColorspace(image_info->colorspace))
2917
0
      {
2918
0
        jpeg_info.input_components=4;
2919
0
        jpeg_info.in_color_space=JCS_CMYK;
2920
0
        colorspace_set=MagickTrue;
2921
0
      }
2922
717
    else if (IsYCbCrColorspace(image_info->colorspace))
2923
0
      {
2924
0
        jpeg_info.input_components=3;
2925
0
        jpeg_info.in_color_space=JCS_YCbCr;
2926
0
        colorspace_set=MagickTrue;
2927
0
      }
2928
717
    else if (IsGrayColorspace(image_info->colorspace))
2929
0
      {
2930
0
        jpeg_info.input_components=1;
2931
0
        jpeg_info.in_color_space=JCS_GRAYSCALE;
2932
0
        colorspace_set=MagickTrue;
2933
0
      }
2934
2935
717
    if (!colorspace_set)
2936
726
      {
2937
726
        if (IsCMYKColorspace(image->colorspace))
2938
0
          {
2939
0
            jpeg_info.input_components=4;
2940
0
            jpeg_info.in_color_space=JCS_CMYK;
2941
0
          }
2942
726
        else if (IsYCbCrColorspace(image->colorspace))
2943
0
          {
2944
0
            jpeg_info.input_components=3;
2945
0
            jpeg_info.in_color_space=JCS_YCbCr;
2946
0
          }
2947
726
        else if ((IsGrayColorspace(image->colorspace) ||
2948
726
                  (characteristics.grayscale)))
2949
608
          {
2950
608
            jpeg_info.input_components=1;
2951
608
            jpeg_info.in_color_space=JCS_GRAYSCALE;
2952
608
          }
2953
118
        else
2954
118
          {
2955
118
            jpeg_info.input_components=3;
2956
118
            jpeg_info.in_color_space=JCS_RGB;
2957
118
          }
2958
726
      }
2959
717
  }
2960
2961
717
  input_colorspace=UndefinedColorspace;
2962
717
  quality=image_info->quality;
2963
  /* Check for -define jpeg:preserve-settings */
2964
  /* ImageMagick:
2965
     GetImageOption();
2966
  */
2967
  /* GraphicsMagick */
2968
717
  preserve_settings=(char *) AccessDefinition(image_info,"jpeg",
2969
717
                                              "preserve-settings");
2970
2971
717
  sampling_factors=image_info->sampling_factor;
2972
2973
717
  if (preserve_settings)
2974
0
    {
2975
0
      if (image->logging)
2976
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2977
0
                              "  JPEG:preserve-settings flag is defined.");
2978
2979
      /* Retrieve input file quality */
2980
0
      attribute=GetImageAttribute(image,"JPEG-Quality");
2981
0
      if ((attribute != (const ImageAttribute *) NULL) &&
2982
0
          (attribute->value != (char *) NULL))
2983
0
        {
2984
0
          (void) sscanf(attribute->value,"%lu",&quality);
2985
0
          if (image->logging)
2986
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2987
0
                                  "  Input quality=%lu",quality);
2988
0
        }
2989
2990
      /* Retrieve input file colorspace */
2991
0
      attribute=GetImageAttribute(image,"JPEG-Colorspace");
2992
0
      if ((attribute != (const ImageAttribute *) NULL) &&
2993
0
          (attribute->value != (char *) NULL))
2994
0
        {
2995
0
          (void) sscanf(attribute->value,"%lu",&input_colorspace);
2996
0
          if (image->logging)
2997
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2998
0
                                  "  Input colorspace=%lu",input_colorspace);
2999
0
        }
3000
3001
0
      if (input_colorspace == (unsigned long) jpeg_info.in_color_space)
3002
0
        {
3003
          /* Retrieve input sampling factors */
3004
0
          attribute=GetImageAttribute(image,"JPEG-Sampling-factors");
3005
0
          if ((attribute != (const ImageAttribute *) NULL) &&
3006
0
              (attribute->value != (char *) NULL))
3007
0
            {
3008
0
              sampling_factors=attribute->value;
3009
0
              if (image->logging)
3010
0
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3011
0
                                      "  Input sampling-factors=%s",sampling_factors);
3012
0
            }
3013
0
        }
3014
0
      else
3015
0
        {
3016
0
          if (image->logging)
3017
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3018
0
                                  "  Input colorspace (%lu) != Output colorspace (%d)",
3019
0
                                  input_colorspace,jpeg_info.in_color_space);
3020
0
        }
3021
0
    }
3022
3023
717
  jpeg_set_defaults(&jpeg_info);
3024
3025
  /*
3026
    Determine bit depth (valid range in 8-16).
3027
  */
3028
717
  {
3029
717
    int
3030
717
      sample_size;
3031
3032
717
    sample_size=sizeof(JSAMPLE)*8;
3033
717
    if (sample_size > 8)
3034
0
      sample_size=12;
3035
717
    if ((jpeg_info.data_precision != 12) &&
3036
726
        (image->depth <= 8))
3037
705
      sample_size=8;
3038
717
    jpeg_info.data_precision=sample_size;
3039
717
  }
3040
3041
  /*
3042
    Allow the user to set/override the data precision (8/12/16)
3043
  */
3044
717
  if ((value=AccessDefinition(image_info,"jpeg","data-precision")))
3045
0
    {
3046
0
      unsigned int data_precision_prop = 0;
3047
0
      if (sscanf(value,"%u",&data_precision_prop) == 1)
3048
0
        {
3049
0
          switch(data_precision_prop)
3050
0
            {
3051
0
            default:
3052
0
            case 8:
3053
0
              jpeg_info.data_precision=8;
3054
0
              break;
3055
0
#if defined(HAVE_JPEG12_WRITE_SCANLINES) && HAVE_JPEG12_WRITE_SCANLINES
3056
0
            case 12:
3057
0
              jpeg_info.data_precision=12;
3058
0
              break;
3059
0
#endif /* if defined(HAVE_JPEG12_WRITE_SCANLINES) && HAVE_JPEG12_WRITE_SCANLINES */
3060
0
#if defined(HAVE_JPEG16_WRITE_SCANLINES) && HAVE_JPEG16_WRITE_SCANLINES
3061
0
#if defined(HAVE_JPEG_ENABLE_LOSSLESS) && HAVE_JPEG_ENABLE_LOSSLESS
3062
0
#if defined(C_LOSSLESS_SUPPORTED)
3063
0
            case 16:
3064
0
              jpeg_info.data_precision=16;
3065
0
              break;
3066
0
#endif /* if defined(C_LOSSLESS_SUPPORTED) */
3067
0
#endif /* if defined(HAVE_JPEG_ENABLE_LOSSLESS) && HAVE_JPEG_ENABLE_LOSSLESS */
3068
0
#endif /* if defined(HAVE_JPEG16_WRITE_SCANLINES) && HAVE_JPEG16_WRITE_SCANLINES */
3069
0
            }
3070
0
          if (image->logging)
3071
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3072
0
                                  "  Set data precision: %u", jpeg_info.data_precision);
3073
0
        }
3074
0
    }
3075
717
  if ((image->x_resolution == 0) || (image->y_resolution == 0))
3076
723
    {
3077
723
      image->x_resolution=72.0;
3078
723
      image->y_resolution=72.0;
3079
723
      image->units=PixelsPerInchResolution;
3080
723
    }
3081
717
  if (image_info->density != (char *) NULL)
3082
0
    {
3083
0
      int
3084
0
        count;
3085
3086
      /* FIXME: density should not be set via image_info->density
3087
         but removing this support may break some applications. */
3088
0
      count=GetMagickDimension(image_info->density,&image->x_resolution,
3089
0
                               &image->y_resolution,NULL,NULL);
3090
0
      if (count == 1 )
3091
0
        image->y_resolution=image->x_resolution;
3092
0
    }
3093
717
  jpeg_info.density_unit=1;  /* default to DPI */
3094
717
  if (image->logging)
3095
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3096
0
                          "Image resolution: %ld,%ld",(long) image->x_resolution,
3097
0
                          (long) image->y_resolution);
3098
726
  if ((image->x_resolution >= 0) && (image->x_resolution < (double) SHRT_MAX) &&
3099
725
      (image->y_resolution >= 0) && (image->y_resolution < (double) SHRT_MAX))
3100
724
    {
3101
      /*
3102
        Set image resolution.
3103
      */
3104
724
      jpeg_info.write_JFIF_header=True;
3105
724
      jpeg_info.X_density=(short) image->x_resolution;
3106
724
      jpeg_info.Y_density=(short) image->y_resolution;
3107
724
      if (image->units == PixelsPerInchResolution)
3108
723
        jpeg_info.density_unit=1;
3109
724
      if (image->units == PixelsPerCentimeterResolution)
3110
1
        jpeg_info.density_unit=2;
3111
724
    }
3112
3113
717
  {
3114
717
    const char
3115
717
      *value;
3116
3117
    /*
3118
      Allow the user to select the DCT encoding algorithm.
3119
    */
3120
717
    if ((value=AccessDefinition(image_info,"jpeg","dct-method")))
3121
0
      {
3122
0
        if (LocaleCompare(value,"ISLOW") == 0)
3123
0
          {
3124
0
            jpeg_info.dct_method=JDCT_ISLOW;
3125
0
            if (image->logging)
3126
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3127
0
                                    "  Set DCT method ISLOW");
3128
0
          }
3129
0
        else if (LocaleCompare(value,"IFAST") == 0)
3130
0
          {
3131
0
            jpeg_info.dct_method=JDCT_IFAST;
3132
0
            if (image->logging)
3133
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3134
0
                                    "  Set DCT method IFAST");
3135
0
          }
3136
0
        else if (LocaleCompare(value,"FLOAT") == 0)
3137
0
          {
3138
0
            jpeg_info.dct_method=JDCT_FLOAT;
3139
0
            if (image->logging)
3140
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3141
0
                                    "  Set DCT method FLOAT");
3142
0
          }
3143
0
        else if (LocaleCompare(value,"DEFAULT") == 0)
3144
0
          {
3145
0
            jpeg_info.dct_method=JDCT_DEFAULT;
3146
0
            if (image->logging)
3147
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3148
0
                                    "  Set DCT method DEFAULT");
3149
0
          }
3150
0
        else if (LocaleCompare(value,"FASTEST") == 0)
3151
0
          {
3152
0
            jpeg_info.dct_method=JDCT_FASTEST;
3153
0
            if (image->logging)
3154
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3155
0
                                    "  Set DCT method FASTEST");
3156
0
          }
3157
0
      }
3158
717
  }
3159
3160
717
  {
3161
717
    const char
3162
717
      *value;
3163
3164
717
    huffman_memory = 0;
3165
3166
717
#if defined(C_ARITH_CODING_SUPPORTED)
3167
    /*
3168
      Allow the user to turn on/off arithmetic coder.
3169
    */
3170
717
    if ((value=AccessDefinition(image_info,"jpeg","arithmetic-coding")))
3171
0
      {
3172
0
        if (LocaleCompare(value,"FALSE") == 0)
3173
0
          {
3174
0
            jpeg_info.arith_code = False;
3175
0
            if (image->logging)
3176
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3177
0
                                    "  Disabled arithmetic coding");
3178
0
          }
3179
0
        else
3180
0
          {
3181
0
            jpeg_info.arith_code = True;
3182
0
            if (image->logging)
3183
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3184
0
                                    "  Enabled arithmetic coding");
3185
0
          }
3186
0
      }
3187
717
    if (!jpeg_info.arith_code)     /* jpeg_info.optimize_coding must not be set to enable arithmetic. */
3188
726
#endif /* if defined(C_ARITH_CODING_SUPPORTED) */
3189
726
      {
3190
726
        if ((value=AccessDefinition(image_info,"jpeg","optimize-coding")))
3191
0
          {
3192
0
            if (LocaleCompare(value,"FALSE") == 0)
3193
0
              {
3194
0
                jpeg_info.optimize_coding=MagickFalse;
3195
0
                if (image->logging)
3196
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3197
0
                                        "  Disabled optimize coding");
3198
0
              }
3199
0
            else
3200
0
              {
3201
0
                jpeg_info.optimize_coding=MagickTrue;
3202
0
                if (image->logging)
3203
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3204
0
                                        "  Enabled optimize coding");
3205
0
              }
3206
0
          }
3207
726
        else
3208
726
          {
3209
            /*
3210
              Huffman optimization requires that the whole image be buffered in
3211
              memory.  Since this is such a large consumer, obtain a memory
3212
              resource for the memory to be consumed.  If the memory resource
3213
              fails to be acquired, then don't enable huffman optimization.
3214
            */
3215
726
            huffman_memory=(magick_int64_t) jpeg_info.input_components*
3216
726
              image->columns*image->rows*sizeof(JSAMPLE);
3217
726
            jpeg_info.optimize_coding=AcquireMagickResource(MemoryResource,
3218
726
                                                            huffman_memory);
3219
726
          }
3220
726
        if (!jpeg_info.optimize_coding)
3221
0
          huffman_memory=0;
3222
726
        if (image->logging)
3223
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3224
0
                                "  Huffman optimization is %s",
3225
0
                                (jpeg_info.optimize_coding ? "enabled" : "disabled"));
3226
726
      }
3227
717
  }
3228
3229
717
#if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
3230
717
  if (image_info->interlace == LineInterlace)
3231
0
    jpeg_simple_progression(&jpeg_info);
3232
717
  if (image->logging)
3233
0
    {
3234
0
      if (image_info->interlace == LineInterlace)
3235
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3236
0
                              "Interlace: progressive");
3237
0
      else
3238
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3239
0
                              "Interlace: nonprogressive");
3240
0
    }
3241
#else
3242
  if (image->logging)
3243
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3244
                          "Interlace: nonprogressive");
3245
#endif
3246
717
  if (image->logging)
3247
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3248
0
                          "Compression: %s",
3249
0
                          CompressionTypeToString(image->compression));
3250
717
  if (image->compression == LosslessJPEGCompression)
3251
0
    {
3252
0
#if defined(C_LOSSLESS_SUPPORTED)
3253
0
        {
3254
0
          int
3255
0
            point_transform,
3256
0
            predictor;
3257
3258
0
          predictor=1;  /* range 1-7 */
3259
0
          point_transform=0;  /* range 0 to precision-1 */
3260
3261
          /*
3262
            Right-shift the input samples by the specified number of
3263
            bits as a form of color quantization.  Useful range of 0
3264
            to precision-1.  Use zero for true lossless compression!
3265
           */
3266
0
          if ((value=AccessDefinition(image_info,"jpeg","lossless-precision")))
3267
0
            {
3268
0
              int point_transform_v = 0;
3269
0
              if ((sscanf(value,"%u",&point_transform_v) == 1) && (point_transform_v >= 0))
3270
0
                point_transform = point_transform_v;
3271
0
            }
3272
3273
0
          if ((value=AccessDefinition(image_info,"jpeg","lossless-predictor")))
3274
0
            {
3275
0
              int predictor_v = predictor;
3276
0
              if ((sscanf(value,"%u",&predictor_v) == 1) && (predictor_v >= 0))
3277
0
                predictor = predictor_v;
3278
0
            }
3279
3280
0
          if (image->logging)
3281
0
            {
3282
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3283
0
                "Compression: lossless");
3284
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3285
0
                "DPCM Predictor: %d",predictor);
3286
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3287
0
                "DPCM Point Transform: %d",point_transform);
3288
0
            }
3289
#if !defined(LIBJPEG_TURBO_VERSION_NUMBER)
3290
          jpeg_simple_lossless(&jpeg_info, predictor, point_transform);
3291
#elif defined(LIBJPEG_TURBO_VERSION_NUMBER)
3292
          jpeg_enable_lossless(&jpeg_info, predictor, point_transform);
3293
0
#endif
3294
0
        }
3295
#else
3296
        {
3297
          jpeg_set_quality(&jpeg_info,100,True);
3298
          if (image->logging)
3299
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
3300
        }
3301
#endif
3302
0
    }
3303
717
  else
3304
717
    {
3305
717
      jpeg_set_quality(&jpeg_info,(int) quality,True);
3306
717
      if (image->logging)
3307
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %lu",
3308
0
          quality);
3309
717
    }
3310
3311
717
  if (sampling_factors != (char *) NULL)
3312
0
    {
3313
0
      double
3314
0
        hs[4]={1.0, 1.0, 1.0, 1.0},
3315
0
        vs[4]={1.0, 1.0, 1.0, 1.0};
3316
3317
0
      long
3318
0
        count;
3319
3320
      /*
3321
        Set sampling factors.
3322
      */
3323
0
      count=sscanf(sampling_factors,"%lfx%lf,%lfx%lf,%lfx%lf,%lfx%lf",
3324
0
                   &hs[0],&vs[0],&hs[1],&vs[1],&hs[2],&vs[2],&hs[3],&vs[3]);
3325
3326
0
      if (count%2 == 1)
3327
0
        vs[count/2]=hs[count/2];
3328
3329
0
      for (i=0; i < 4; i++)
3330
0
        {
3331
0
          jpeg_info.comp_info[i].h_samp_factor=(int) hs[i];
3332
0
          jpeg_info.comp_info[i].v_samp_factor=(int) vs[i];
3333
0
        }
3334
0
      for (; i < MAX_COMPONENTS; i++)
3335
0
        {
3336
0
          jpeg_info.comp_info[i].h_samp_factor=1;
3337
0
          jpeg_info.comp_info[i].v_samp_factor=1;
3338
0
        }
3339
0
    }
3340
717
  else
3341
717
    {
3342
717
      if (quality >= 90)
3343
0
        for (i=0; i < MAX_COMPONENTS; i++)
3344
0
          {
3345
0
            jpeg_info.comp_info[i].h_samp_factor=1;
3346
0
            jpeg_info.comp_info[i].v_samp_factor=1;
3347
0
          }
3348
717
    }
3349
3350
717
  if (image->logging)
3351
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3352
0
                          "Starting JPEG compression");
3353
717
  jpeg_start_compress(&jpeg_info,True);
3354
717
  if (image->logging)
3355
0
    {
3356
0
      if (image->storage_class == PseudoClass)
3357
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3358
0
                              "Storage class: PseudoClass");
3359
0
      else
3360
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3361
0
                              "Storage class: DirectClass");
3362
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %u",
3363
0
                            image->depth);
3364
0
      if (image->colors)
3365
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3366
0
                              "Number of colors: %u",image->colors);
3367
0
      else
3368
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3369
0
                              "Number of colors: unspecified");
3370
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3371
0
                            "JPEG data precision: %d",(int) jpeg_info.data_precision);
3372
0
      if (IsCMYKColorspace(image_info->colorspace))
3373
0
        {
3374
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3375
0
                                "Storage class: DirectClass");
3376
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3377
0
                                "Colorspace: CMYK");
3378
0
        }
3379
0
      else if (IsYCbCrColorspace(image_info->colorspace))
3380
0
        {
3381
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3382
0
                                "Colorspace: YCbCr");
3383
0
        }
3384
0
      if (IsCMYKColorspace(image->colorspace))
3385
0
        {
3386
          /* A CMYK space */
3387
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3388
0
                                "Colorspace: CMYK");
3389
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3390
0
                                "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
3391
0
                                jpeg_info.comp_info[0].h_samp_factor,
3392
0
                                jpeg_info.comp_info[0].v_samp_factor,
3393
0
                                jpeg_info.comp_info[1].h_samp_factor,
3394
0
                                jpeg_info.comp_info[1].v_samp_factor,
3395
0
                                jpeg_info.comp_info[2].h_samp_factor,
3396
0
                                jpeg_info.comp_info[2].v_samp_factor,
3397
0
                                jpeg_info.comp_info[3].h_samp_factor,
3398
0
                                jpeg_info.comp_info[3].v_samp_factor);
3399
0
        }
3400
0
      else if (IsGrayColorspace(image->colorspace))
3401
0
        {
3402
          /* A gray space */
3403
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3404
0
                                "Colorspace: GRAY");
3405
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3406
0
                                "Sampling factors: %dx%d",
3407
0
                                jpeg_info.comp_info[0].h_samp_factor,
3408
0
                                jpeg_info.comp_info[0].v_samp_factor);
3409
0
        }
3410
0
      else if (IsRGBCompatibleColorspace(image->colorspace))
3411
0
        {
3412
          /* An RGB space */
3413
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3414
0
                                " Image colorspace is RGB");
3415
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3416
0
                                "Sampling factors: %dx%d,%dx%d,%dx%d",
3417
0
                                jpeg_info.comp_info[0].h_samp_factor,
3418
0
                                jpeg_info.comp_info[0].v_samp_factor,
3419
0
                                jpeg_info.comp_info[1].h_samp_factor,
3420
0
                                jpeg_info.comp_info[1].v_samp_factor,
3421
0
                                jpeg_info.comp_info[2].h_samp_factor,
3422
0
                                jpeg_info.comp_info[2].v_samp_factor);
3423
0
        }
3424
0
      else if (IsYCbCrColorspace(image->colorspace))
3425
0
        {
3426
          /* A YCbCr space */
3427
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3428
0
                                "Colorspace: YCbCr");
3429
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3430
0
                                "Sampling factors: %dx%d,%dx%d,%dx%d",
3431
0
                                jpeg_info.comp_info[0].h_samp_factor,
3432
0
                                jpeg_info.comp_info[0].v_samp_factor,
3433
0
                                jpeg_info.comp_info[1].h_samp_factor,
3434
0
                                jpeg_info.comp_info[1].v_samp_factor,
3435
0
                                jpeg_info.comp_info[2].h_samp_factor,
3436
0
                                jpeg_info.comp_info[2].v_samp_factor);
3437
0
        }
3438
0
      else
3439
0
        {
3440
          /* Some other color space */
3441
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
3442
0
                                image->colorspace);
3443
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3444
0
                                "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
3445
0
                                jpeg_info.comp_info[0].h_samp_factor,
3446
0
                                jpeg_info.comp_info[0].v_samp_factor,
3447
0
                                jpeg_info.comp_info[1].h_samp_factor,
3448
0
                                jpeg_info.comp_info[1].v_samp_factor,
3449
0
                                jpeg_info.comp_info[2].h_samp_factor,
3450
0
                                jpeg_info.comp_info[2].v_samp_factor,
3451
0
                                jpeg_info.comp_info[3].h_samp_factor,
3452
0
                                jpeg_info.comp_info[3].v_samp_factor);
3453
0
        }
3454
0
    }
3455
  /*
3456
    Write JPEG profiles.
3457
  */
3458
717
  attribute=GetImageAttribute(image,"comment");
3459
717
  if ((attribute != (const ImageAttribute *) NULL) &&
3460
21
      (attribute->value != (char *) NULL))
3461
57
    for (i=0; i < strlen(attribute->value); i+=65533L)
3462
36
      jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) attribute->value+
3463
36
                        i,(int) Min(strlen(attribute->value+i),65533L));
3464
#if 0
3465
  WriteICCProfile(&jpeg_info,image);
3466
  WriteIPTCProfile(&jpeg_info,image);
3467
  WriteXMPProfile(&jpeg_info,image);
3468
#endif
3469
717
  WriteProfiles(&jpeg_info,image);
3470
  /*
3471
    Convert MIFF to JPEG raster pixels.
3472
  */
3473
717
  switch (jpeg_info.data_precision)
3474
717
    {
3475
0
#if defined(HAVE_JPEG16_WRITE_SCANLINES) && HAVE_JPEG16_WRITE_SCANLINES
3476
0
#if defined(HAVE_JPEG_ENABLE_LOSSLESS) && HAVE_JPEG_ENABLE_LOSSLESS
3477
0
#if defined(C_LOSSLESS_SUPPORTED)
3478
0
    case 16:
3479
0
      jpeg_pixels.t.j16 =
3480
0
        MagickAllocateResourceLimitedClearedArray(J16SAMPLE *,
3481
0
                                                  jpeg_info.input_components,
3482
0
                                                  MagickArraySize(image->columns,
3483
0
                                                                  sizeof(J16SAMPLE)));
3484
0
      break;
3485
0
#endif /* if defined(C_LOSSLESS_SUPPORTED) */
3486
0
#endif /* if defined(HAVE_JPEG_ENABLE_LOSSLESS) && HAVE_JPEG_ENABLE_LOSSLESS */
3487
0
#endif /* if defined(HAVE_JPEG16_WRITE_SCANLINES) && HAVE_JPEG16_WRITE_SCANLINES */
3488
0
#if defined(HAVE_JPEG12_WRITE_SCANLINES) && HAVE_JPEG12_WRITE_SCANLINES
3489
0
    case 12:
3490
0
      jpeg_pixels.t.j12 =
3491
0
        MagickAllocateResourceLimitedClearedArray(J12SAMPLE *,
3492
0
                                                  jpeg_info.input_components,
3493
0
                                                  MagickArraySize(image->columns,
3494
0
                                                                  sizeof(J12SAMPLE)));
3495
0
      break;
3496
0
#endif /* if defined(HAVE_JPEG12_WRITE_SCANLINES) && HAVE_JPEG12_WRITE_SCANLINES */
3497
726
    default:
3498
726
      {
3499
726
        jpeg_pixels.t.j=
3500
726
          MagickAllocateResourceLimitedArray(JSAMPLE *,
3501
726
                                             jpeg_info.input_components,
3502
726
                                             MagickArraySize(image->columns,
3503
726
                                                             sizeof(JSAMPLE)));
3504
726
      }
3505
717
    }
3506
726
  if (jpeg_pixels.t.v == (JSAMPLE *) NULL)
3507
0
    {
3508
0
      if (huffman_memory)
3509
0
        LiberateMagickResource(MemoryResource,huffman_memory);
3510
0
      ThrowJPEGWriterException(ResourceLimitError,MemoryAllocationFailed,image);
3511
0
    }
3512
726
  client_data->jpeg_pixels = &jpeg_pixels;
3513
3514
726
  if (image->logging)
3515
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3516
0
                          "Writing %d components, %u bits per component,"
3517
0
                          " with colorspace %s...",
3518
0
                          jpeg_info.input_components,
3519
0
                          jpeg_info.data_precision,
3520
0
                          JPEGColorSpaceToString(jpeg_info.in_color_space));
3521
3522
232k
  for (y=0; y < (long) image->rows; y++)
3523
232k
    {
3524
232k
      p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
3525
232k
      if (p == (const PixelPacket *) NULL)
3526
0
        break;
3527
3528
232k
#if defined(HAVE_JPEG16_WRITE_SCANLINES) && HAVE_JPEG16_WRITE_SCANLINES
3529
232k
#if defined(HAVE_JPEG_ENABLE_LOSSLESS) && HAVE_JPEG_ENABLE_LOSSLESS
3530
232k
#if defined(C_LOSSLESS_SUPPORTED)
3531
232k
      if (jpeg_info.data_precision == 16)
3532
0
        {
3533
0
          {
3534
0
            J16SAMPROW
3535
0
              scanline[1];
3536
3537
0
            if (jpeg_info.in_color_space == JCS_GRAYSCALE)
3538
0
              { /* Start deep JCS_GRAYSCALE */
3539
0
                if (image->is_grayscale)
3540
0
                  {
3541
0
                    i=0;
3542
0
                    for (x=0; x < (long) image->columns; x++)
3543
0
                      {
3544
0
                        jpeg_pixels.t.j16[i++]=(J16SAMPLE)(ScaleQuantumToShort(GetGraySample(p)));
3545
0
                        p++;
3546
0
                      }
3547
0
                  }
3548
0
                else
3549
0
                  {
3550
0
                    i=0;
3551
0
                    for (x=0; x < (long) image->columns; x++)
3552
0
                      {
3553
0
                        jpeg_pixels.t.j16[i++] = (J16SAMPLE)(ScaleQuantumToShort(PixelIntensityToQuantum(p)));
3554
0
                        p++;
3555
0
                      }
3556
0
                  }
3557
0
              } /* End deep JCS_GRAYSCALE */
3558
0
            else if ((jpeg_info.in_color_space == JCS_RGB) ||
3559
0
                     (jpeg_info.in_color_space == JCS_YCbCr))
3560
0
              { /* Start deep JCS_RGB || JCS_YCbCr */
3561
0
                i=0;
3562
0
                for (x=0; x < (long) image->columns; x++)
3563
0
                  {
3564
0
                    jpeg_pixels.t.j16[i++] = (J16SAMPLE)(ScaleQuantumToShort(p->red));
3565
0
                    jpeg_pixels.t.j16[i++] = (J16SAMPLE)(ScaleQuantumToShort(p->green));
3566
0
                    jpeg_pixels.t.j16[i++] = (J16SAMPLE)(ScaleQuantumToShort(p->blue));
3567
0
                    p++;
3568
0
                  }
3569
0
              } /* End deep JCS_RGB || JCS_YCbCr */
3570
0
            else if (jpeg_info.in_color_space == JCS_CMYK)
3571
0
              { /* Start deep JCS_CMYK */
3572
0
                i=0;
3573
0
                for (x=0; x < (long) image->columns; x++)
3574
0
                  {
3575
0
                    jpeg_pixels.t.j16[i++] = (J16SAMPLE)(65535U-ScaleQuantumToShort(p->red));
3576
0
                    jpeg_pixels.t.j16[i++] = (J16SAMPLE)(65535U-ScaleQuantumToShort(p->green));
3577
0
                    jpeg_pixels.t.j16[i++] = (J16SAMPLE)(65535U-ScaleQuantumToShort(p->blue));
3578
0
                    jpeg_pixels.t.j16[i++] = (J16SAMPLE)(65535U-ScaleQuantumToShort(p->opacity));
3579
0
                    p++;
3580
0
                  }
3581
0
              } /* End deep JCS_CMYK */
3582
3583
0
            scanline[0]=(J16SAMPROW) jpeg_pixels.t.j16;
3584
0
            (void) jpeg16_write_scanlines(&jpeg_info,scanline,1);
3585
0
          }
3586
0
        } else
3587
232k
#endif /* if defined(C_LOSSLESS_SUPPORTED) */
3588
232k
#endif /* if defined(HAVE_JPEG_ENABLE_LOSSLESS) && HAVE_JPEG_ENABLE_LOSSLESS */
3589
232k
#endif /* if defined(HAVE_JPEG16_WRITE_SCANLINES) && HAVE_JPEG16_WRITE_SCANLINES */
3590
3591
232k
#if defined(HAVE_JPEG12_WRITE_SCANLINES) && HAVE_JPEG12_WRITE_SCANLINES
3592
232k
        if (jpeg_info.data_precision == 12)
3593
0
          {
3594
0
            J12SAMPROW
3595
0
              scanline[1];
3596
3597
0
            if (jpeg_info.in_color_space == JCS_GRAYSCALE)
3598
0
              { /* Start deep JCS_GRAYSCALE */
3599
0
                if (image->is_grayscale)
3600
0
                  {
3601
0
                    i=0;
3602
0
                    for (x=0; x < (long) image->columns; x++)
3603
0
                      {
3604
0
                        jpeg_pixels.t.j12[i++] = (J12SAMPLE)(ScaleQuantumToShort(GetGraySample(p))/16);
3605
0
                        p++;
3606
0
                      }
3607
0
                  }
3608
0
                else
3609
0
                  {
3610
0
                    i=0;
3611
0
                    for (x=0; x < (long) image->columns; x++)
3612
0
                      {
3613
0
                        jpeg_pixels.t.j12[i++] = (J12SAMPLE)(ScaleQuantumToShort(PixelIntensityToQuantum(p))/16);
3614
0
                        p++;
3615
0
                      }
3616
0
                  }
3617
0
              } /* End deep JCS_GRAYSCALE */
3618
0
            else if ((jpeg_info.in_color_space == JCS_RGB) ||
3619
0
                     (jpeg_info.in_color_space == JCS_YCbCr))
3620
0
              { /* Start deep JCS_RGB || JCS_YCbCr */
3621
0
                i=0;
3622
0
                for (x=0; x < (long) image->columns; x++)
3623
0
                  {
3624
0
                    jpeg_pixels.t.j12[i++] = (J12SAMPLE)(ScaleQuantumToShort(p->red)/16);
3625
0
                    jpeg_pixels.t.j12[i++] = (J12SAMPLE)(ScaleQuantumToShort(p->green)/16);
3626
0
                    jpeg_pixels.t.j12[i++] = (J12SAMPLE)(ScaleQuantumToShort(p->blue)/16);
3627
0
                    p++;
3628
0
                  }
3629
0
              } /* End deep JCS_RGB || JCS_YCbCr */
3630
0
            else if (jpeg_info.in_color_space == JCS_CMYK)
3631
0
              { /* Start deep JCS_CMYK */
3632
0
                i=0;
3633
0
                for (x=0; x < (long) image->columns; x++)
3634
0
                  {
3635
0
                    jpeg_pixels.t.j12[i++] = (J12SAMPLE)(4095U-ScaleQuantumToShort(p->red)/16);
3636
0
                    jpeg_pixels.t.j12[i++] = (J12SAMPLE)(4095U-ScaleQuantumToShort(p->green)/16);
3637
0
                    jpeg_pixels.t.j12[i++] = (J12SAMPLE)(4095U-ScaleQuantumToShort(p->blue)/16);
3638
0
                    jpeg_pixels.t.j12[i++] = (J12SAMPLE)(4095U-ScaleQuantumToShort(p->opacity)/16);
3639
0
                    p++;
3640
0
                  }
3641
0
              } /* End deep JCS_CMYK */
3642
3643
0
            scanline[0]=(J12SAMPROW) jpeg_pixels.t.j12;
3644
0
            (void) jpeg12_write_scanlines(&jpeg_info,scanline,1);
3645
0
          } else
3646
232k
#endif /* if defined(HAVE_JPEG12_WRITE_SCANLINES) && HAVE_JPEG12_WRITE_SCANLINES */
3647
232k
          {
3648
232k
            JSAMPROW
3649
232k
              scanline[1];
3650
3651
232k
            if (jpeg_info.in_color_space == JCS_GRAYSCALE)
3652
166k
              { /* Start traditional JCS_GRAYSCALE */
3653
166k
                if (image->is_grayscale)
3654
166k
                  {
3655
166k
                    i=0;
3656
141M
                    for (x=0; x < (long) image->columns; x++)
3657
141M
                      {
3658
141M
                        jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(GetGraySample(p)));
3659
141M
                        p++;
3660
141M
                      }
3661
166k
                  }
3662
0
                else
3663
0
                  {
3664
0
                    i=0;
3665
0
                    for (x=0; x < (long) image->columns; x++)
3666
0
                      {
3667
0
                        jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(PixelIntensityToQuantum(p)));
3668
0
                        p++;
3669
0
                      }
3670
0
                  }
3671
166k
              } /* End traditional JCS_GRAYSCALE */
3672
65.8k
            else if ((jpeg_info.in_color_space == JCS_RGB) ||
3673
0
                     (jpeg_info.in_color_space == JCS_YCbCr))
3674
65.8k
              { /* Start traditional JCS_RGB || JCS_YCbCr */
3675
65.8k
                i=0;
3676
23.8M
                for (x=0; x < (long) image->columns; x++)
3677
23.7M
                  {
3678
23.7M
                    jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(p->red));
3679
23.7M
                    jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(p->green));
3680
23.7M
                    jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(p->blue));
3681
23.7M
                    p++;
3682
23.7M
                  }
3683
65.8k
              } /* End traditional JCS_RGB || JCS_YCbCr */
3684
0
            else if (jpeg_info.in_color_space == JCS_CMYK)
3685
0
              { /* Start traditional JCS_CMYK */
3686
0
                i=0;
3687
0
                for (x=0; x < (long) image->columns; x++)
3688
0
                  {
3689
0
                    jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(MaxRGB-p->red));
3690
0
                    jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(MaxRGB-p->green));
3691
0
                    jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(MaxRGB-p->blue));
3692
0
                    jpeg_pixels.t.j[i++]=(JSAMPLE)(ScaleQuantumToChar(MaxRGB-p->opacity));
3693
0
                    p++;
3694
0
                  }
3695
0
              } /* End traditional JCS_CMYK */
3696
3697
232k
            scanline[0]=(JSAMPROW) jpeg_pixels.t.j;
3698
232k
            (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
3699
232k
#if !USE_LIBJPEG_PROGRESS
3700
232k
            if (QuantumTick(y,image->rows))
3701
79.8k
              if (!MagickMonitorFormatted(y,image->rows,&image->exception,
3702
79.8k
                                          SaveImageText,image->filename,
3703
79.8k
                                          image->columns,image->rows))
3704
0
                break;
3705
232k
#endif /* !USE_LIBJPEG_PROGRESS */
3706
232k
          }
3707
232k
    }
3708
3709
726
  if (image->logging)
3710
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3711
0
                          "Finishing JPEG compression");
3712
726
  jpeg_finish_compress(&jpeg_info);
3713
  /*
3714
    Free memory.
3715
  */
3716
726
  if (huffman_memory)
3717
717
    LiberateMagickResource(MemoryResource,huffman_memory);
3718
726
  client_data=FreeMagickClientData(client_data);
3719
726
  jpeg_destroy_compress(&jpeg_info);
3720
  /* MagickFreeResourceLimitedMemory(jpeg_pixels); */
3721
726
  status &= CloseBlob(image);
3722
726
  return(status);
3723
726
}
3724
#endif