Coverage Report

Created: 2026-07-20 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/jpeg.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                        JJJJJ  PPPP   EEEEE   GGGG                           %
7
%                          J    P   P  E      G                               %
8
%                          J    PPPP   EEE    G  GG                           %
9
%                        J J    P      E      G   G                           %
10
%                        JJJ    P      EEEEE   GGG                            %
11
%                                                                             %
12
%                                                                             %
13
%                       Read/Write JPEG Image Format                          %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                John Cristy                                  %
17
%                                 July 1992                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/license/                                         %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
% This software is based in part on the work of the Independent JPEG Group.
37
% See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38
% licensing restrictions.  Blob support contributed by Glenn Randers-Pehrson.
39
%
40
%
41
*/
42

43
/*
44
  Include declarations.
45
*/
46
#include "MagickCore/studio.h"
47
#include "MagickCore/artifact.h"
48
#include "MagickCore/attribute.h"
49
#include "MagickCore/blob.h"
50
#include "MagickCore/blob-private.h"
51
#include "MagickCore/cache.h"
52
#include "MagickCore/color.h"
53
#include "MagickCore/colormap-private.h"
54
#include "MagickCore/color-private.h"
55
#include "MagickCore/colormap.h"
56
#include "MagickCore/colorspace.h"
57
#include "MagickCore/colorspace-private.h"
58
#include "MagickCore/constitute.h"
59
#include "MagickCore/exception.h"
60
#include "MagickCore/exception-private.h"
61
#include "MagickCore/geometry.h"
62
#include "MagickCore/image.h"
63
#include "MagickCore/image-private.h"
64
#include "MagickCore/list.h"
65
#include "MagickCore/log.h"
66
#include "MagickCore/magick.h"
67
#include "MagickCore/memory_.h"
68
#include "MagickCore/memory-private.h"
69
#include "MagickCore/module.h"
70
#include "MagickCore/monitor.h"
71
#include "MagickCore/monitor-private.h"
72
#include "MagickCore/option.h"
73
#include "MagickCore/option-private.h"
74
#include "MagickCore/pixel-accessor.h"
75
#include "MagickCore/policy.h"
76
#include "MagickCore/profile.h"
77
#include "MagickCore/profile-private.h"
78
#include "MagickCore/property.h"
79
#include "MagickCore/quantum-private.h"
80
#include "MagickCore/resource_.h"
81
#include "MagickCore/semaphore.h"
82
#include "MagickCore/splay-tree.h"
83
#include "MagickCore/static.h"
84
#include "MagickCore/string_.h"
85
#include "MagickCore/string-private.h"
86
#include "MagickCore/token.h"
87
#include "MagickCore/utility.h"
88
#include "MagickCore/xml-tree.h"
89
#include "MagickCore/xml-tree-private.h"
90
#include "coders/coders-private.h"
91
#include <setjmp.h>
92
#if defined(MAGICKCORE_JPEG_DELEGATE)
93
#define JPEG_INTERNAL_OPTIONS
94
#if defined(__MINGW32__)
95
# define XMD_H 1  /* Avoid conflicting typedef for INT32 */
96
#endif
97
#undef HAVE_STDLIB_H
98
#include "jpeglib.h"
99
#include "jerror.h"
100
#endif
101

102
/*
103
  Define declarations.
104
*/
105
11.1k
#define COMMENT_INDEX  0
106
1.70k
#define APP_INDEX  0
107
1.70k
#define APP_MARKER  (JPEG_APP0+APP_INDEX)
108
1.35M
#define ICC_INDEX  2
109
81.4k
#define ICC_MARKER  (JPEG_APP0+ICC_INDEX)
110
41.1k
#define ICC_PROFILE  "ICC_PROFILE"
111
1.26M
#define IPTC_INDEX  13
112
82.9k
#define IPTC_MARKER  (JPEG_APP0+IPTC_INDEX)
113
3.89M
#define MaxJPEGProfiles  16
114
36.5M
#define MaxJPEGScans  1024
115

116
/*
117
  Typedef declarations.
118
*/
119
#if defined(MAGICKCORE_JPEG_DELEGATE)
120
typedef struct _DestinationManager
121
{
122
  struct jpeg_destination_mgr
123
    manager;
124
125
  Image
126
    *image;
127
128
  JOCTET
129
    *buffer;
130
} DestinationManager;
131
132
typedef struct _JPEGClientInfo
133
{
134
  jmp_buf
135
    error_recovery;
136
137
  Image
138
    *image;
139
140
  MagickBooleanType
141
    detect_uhdr,
142
    finished,
143
    skip_icc_profiles,
144
    skip_app_profiles,
145
    uhdr_metadata;
146
147
  StringInfo
148
    *profiles[MaxJPEGProfiles+1];
149
150
  ExceptionInfo
151
    *exception;
152
} JPEGClientInfo;
153
154
typedef struct _SourceManager
155
{
156
  struct jpeg_source_mgr
157
    manager;
158
159
  Image
160
    *image;
161
162
  JOCTET
163
    *buffer;
164
165
  boolean
166
    start_of_blob;
167
} SourceManager;
168
#endif
169
170
typedef struct _QuantizationTable
171
{
172
  char
173
    *slot,
174
    *description;
175
176
  size_t
177
    width,
178
    height;
179
180
  double
181
    divisor;
182
183
  unsigned int
184
    *levels;
185
} QuantizationTable;
186

187
/*
188
  Const declarations.
189
*/
190
#if defined(MAGICKCORE_JPEG_DELEGATE)
191
typedef enum
192
{
193
  JPEGGainmapSignatureAPP1 = 0x01,
194
  JPEGGainmapSignatureAPP2 = 0x02
195
} JPEGGainmapSignatureContext;
196
197
typedef struct _JPEGGainmapSignature
198
{
199
  const char
200
    *signature;
201
202
  unsigned int
203
    contexts;
204
} JPEGGainmapSignature;
205
206
static const char
207
  xmp_namespace[] = "http://ns.adobe.com/xap/1.0/";
208
209
static const JPEGGainmapSignature
210
  gainmap_signatures[] =
211
  {
212
    { "http://ns.adobe.com/hdr-gain-map/1.0/", JPEGGainmapSignatureAPP1 },
213
    { "http://ns.google.com/photos/1.0/gainmap/", JPEGGainmapSignatureAPP1 },
214
    { "urn:iso:std:iso:ts:21496:-1", JPEGGainmapSignatureAPP2 }
215
  };
216
#endif
217

218
/*
219
  Forward declarations.
220
*/
221
#if defined(MAGICKCORE_JPEG_DELEGATE)
222
static MagickBooleanType
223
  WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
224
#endif
225

226
/*
227
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228
%                                                                             %
229
%                                                                             %
230
%                                                                             %
231
%   I s J P E G                                                               %
232
%                                                                             %
233
%                                                                             %
234
%                                                                             %
235
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236
%
237
%  IsJPEG() returns MagickTrue if the image format type, identified by the
238
%  magick string, is JPEG.
239
%
240
%  The format of the IsJPEG  method is:
241
%
242
%      MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
243
%
244
%  A description of each parameter follows:
245
%
246
%    o magick: compare image format pattern against these bytes.
247
%
248
%    o length: Specifies the length of the magick string.
249
%
250
*/
251
static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
252
0
{
253
0
  if (length < 3)
254
0
    return(MagickFalse);
255
0
  if (memcmp(magick,"\377\330\377",3) == 0)
256
0
    return(MagickTrue);
257
0
  return(MagickFalse);
258
0
}
259
260
#if defined(MAGICKCORE_JPEG_DELEGATE)
261
static MagickBooleanType IsGainmapSignatureContext(
262
  const JPEGGainmapSignature *gainmap_signature,
263
  const JPEGGainmapSignatureContext context)
264
78.7k
{
265
78.7k
  if ((gainmap_signature->contexts & (unsigned int) context) == 0)
266
43.9k
    return(MagickFalse);
267
34.7k
  return(MagickTrue);
268
78.7k
}
269
270
static MagickBooleanType IsJPEGProfileMatching(const unsigned char *profile,
271
  const size_t length,const char *signature)
272
16.8k
{
273
16.8k
  size_t
274
16.8k
    i,
275
16.8k
    signature_length;
276
277
16.8k
  signature_length=strlen(signature);
278
16.8k
  if (length < signature_length)
279
9.85k
    return(MagickFalse);
280
366k
  for (i=0; i <= (length-signature_length); i++)
281
359k
    if (memcmp(profile+i,signature,signature_length) == 0)
282
605
      return(MagickTrue);
283
6.35k
  return(MagickFalse);
284
6.96k
}
285
286
static const char *GetGainmapSignatureWithPrefix(const unsigned char *profile,
287
  const size_t length,const JPEGGainmapSignatureContext context)
288
17.9k
{
289
17.9k
  size_t
290
17.9k
    i;
291
292
67.0k
  for (i=0; i < (sizeof(gainmap_signatures)/sizeof(*gainmap_signatures)); i++)
293
53.8k
  {
294
53.8k
    const char
295
53.8k
      *signature;
296
297
53.8k
    size_t
298
53.8k
      signature_length;
299
300
53.8k
    if (IsGainmapSignatureContext(gainmap_signatures+i,context) == MagickFalse)
301
35.9k
      continue;
302
17.9k
    signature=gainmap_signatures[i].signature;
303
17.9k
    signature_length=strlen(signature);
304
17.9k
    if ((length <= signature_length) &&
305
17.9k
        (memcmp(profile,signature,length) == 0))
306
4.83k
      return(signature);
307
17.9k
  }
308
13.1k
  return((const char *) NULL);
309
17.9k
}
310
311
static size_t GetMaxGainmapSignatureLength(
312
  const JPEGGainmapSignatureContext context)
313
0
{
314
0
  size_t
315
0
    i,
316
0
    max_signature_length = 0;
317
318
0
  for (i=0; i < (sizeof(gainmap_signatures)/sizeof(*gainmap_signatures)); i++)
319
0
  {
320
0
    size_t
321
0
      signature_length;
322
323
0
    if (IsGainmapSignatureContext(gainmap_signatures+i,context) == MagickFalse)
324
0
      continue;
325
0
    signature_length=strlen(gainmap_signatures[i].signature);
326
0
    if (signature_length > max_signature_length)
327
0
      max_signature_length=signature_length;
328
0
  }
329
0
  return(max_signature_length);
330
0
}
331
332
static MagickBooleanType IsGainmapSignatureWindowMatching(
333
  const unsigned char *window,const size_t length,
334
  const JPEGGainmapSignatureContext context)
335
0
{
336
0
  size_t
337
0
    i;
338
339
0
  for (i=0; i < (sizeof(gainmap_signatures)/sizeof(*gainmap_signatures)); i++)
340
0
  {
341
0
    const char
342
0
      *signature;
343
344
0
    size_t
345
0
      signature_length;
346
347
0
    if (IsGainmapSignatureContext(gainmap_signatures+i,context) == MagickFalse)
348
0
      continue;
349
0
    signature=gainmap_signatures[i].signature;
350
0
    signature_length=strlen(signature);
351
0
    if ((length >= signature_length) &&
352
0
        (memcmp(window+length-signature_length,signature,signature_length) ==
353
0
          0))
354
0
      return(MagickTrue);
355
0
  }
356
0
  return(MagickFalse);
357
0
}
358
359
static MagickBooleanType IsUltraHDRJPEGProfile(const unsigned char *profile,
360
  const size_t length)
361
8.61k
{
362
8.61k
  size_t
363
8.61k
    i;
364
365
32.8k
  for (i=0; i < (sizeof(gainmap_signatures)/sizeof(*gainmap_signatures)); i++)
366
24.8k
    if ((IsGainmapSignatureContext(gainmap_signatures+i,
367
24.8k
        JPEGGainmapSignatureAPP1) != MagickFalse) &&
368
16.8k
        (IsJPEGProfileMatching(profile,length,gainmap_signatures[i].signature) !=
369
16.8k
        MagickFalse))
370
605
      return(MagickTrue);
371
8.01k
  return(MagickFalse);
372
8.61k
}
373
374
static MagickBooleanType IsJPEGXMPProfile(const unsigned char *profile,
375
  const size_t length)
376
96.2k
{
377
96.2k
  if (length <= strlen(xmp_namespace))
378
48.0k
    return(MagickFalse);
379
48.2k
  if (LocaleNCompare((const char *) profile,xmp_namespace,
380
48.2k
      strlen(xmp_namespace)-1) == 0)
381
17.2k
    return(MagickTrue);
382
30.9k
  return(MagickFalse);
383
48.2k
}
384
385
#if defined(MAGICKCORE_UHDR_DELEGATE)
386
static void SetUltraHDRCoderFilename(ImageInfo *uhdr_info,
387
  const char *filename)
388
{
389
  if (LocaleNCompare(filename,"UHDR:",5) == 0)
390
    (void) CopyMagickString(uhdr_info->filename,filename,MagickPathExtent);
391
  else
392
    (void) FormatLocaleString(uhdr_info->filename,MagickPathExtent,
393
      "UHDR:%s",filename);
394
  (void) CopyMagickString(uhdr_info->magick,"UHDR",MagickPathExtent);
395
}
396
397
static MagickBooleanType IsUltraHDRJPEGAutoRoutingEnabled(
398
  const ImageInfo *image_info,const PolicyRights rights)
399
{
400
  const char
401
    *option;
402
403
  option=GetImageOption(image_info,"jpeg:detect-uhdr");
404
  if (IsStringFalse(option) != MagickFalse)
405
    return(MagickFalse);
406
  if (IsRightsAuthorized(CoderPolicyDomain,rights,"UHDR") == MagickFalse)
407
    return(MagickFalse);
408
  if (IsRightsAuthorized(ModulePolicyDomain,rights,"UHDr") == MagickFalse)
409
    return(MagickFalse);
410
  return(MagickTrue);
411
}
412
413
static MagickBooleanType IsUltraHDRJPEGReadOptionsCompatible(
414
  const ImageInfo *image_info)
415
{
416
  if (GetImageOption(image_info,"jpeg:size") != (const char *) NULL)
417
    return(MagickFalse);
418
  if (GetImageOption(image_info,"jpeg:colors") != (const char *) NULL)
419
    return(MagickFalse);
420
  if (GetImageOption(image_info,"jpeg:block-smoothing") != (const char *) NULL)
421
    return(MagickFalse);
422
  if (GetImageOption(image_info,"jpeg:dct-method") != (const char *) NULL)
423
    return(MagickFalse);
424
  if (GetImageOption(image_info,"jpeg:fancy-upsampling") !=
425
      (const char *) NULL)
426
    return(MagickFalse);
427
  return(MagickTrue);
428
}
429
430
static Image *ReadUltraHDRJPEGImage(const ImageInfo *image_info,
431
  ExceptionInfo *exception)
432
{
433
  Image
434
    *images;
435
436
  ImageInfo
437
    *uhdr_info;
438
439
  uhdr_info=CloneImageInfo(image_info);
440
  SetUltraHDRCoderFilename(uhdr_info,image_info->filename);
441
  (void) SetImageOption(uhdr_info,"jpeg:detect-uhdr","false");
442
  images=ReadImage(uhdr_info,exception);
443
  uhdr_info=DestroyImageInfo(uhdr_info);
444
  return(images);
445
}
446
447
static MagickBooleanType WriteUltraHDRJPEGImage(const ImageInfo *image_info,
448
  Image *image,ExceptionInfo *exception)
449
{
450
  ImageInfo
451
    *uhdr_info;
452
453
  MagickBooleanType
454
    status;
455
456
  uhdr_info=CloneImageInfo(image_info);
457
  SetUltraHDRCoderFilename(uhdr_info,image_info->filename);
458
  (void) SetImageOption(uhdr_info,"jpeg:detect-uhdr","false");
459
  status=WriteImage(uhdr_info,image,exception);
460
  uhdr_info=DestroyImageInfo(uhdr_info);
461
  return(status);
462
}
463
#endif
464
#endif
465

466
#if defined(MAGICKCORE_JPEG_DELEGATE)
467
/*
468
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469
%                                                                             %
470
%                                                                             %
471
%                                                                             %
472
%   R e a d J P E G I m a g e                                                 %
473
%                                                                             %
474
%                                                                             %
475
%                                                                             %
476
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477
%
478
%  ReadJPEGImage() reads a JPEG image file and returns it.  It allocates
479
%  the memory necessary for the new Image structure and returns a pointer to
480
%  the new image.
481
%
482
%  The format of the ReadJPEGImage method is:
483
%
484
%      Image *ReadJPEGImage(const ImageInfo *image_info,
485
%        ExceptionInfo *exception)
486
%
487
%  A description of each parameter follows:
488
%
489
%    o image_info: the image info.
490
%
491
%    o exception: return any errors or warnings in this structure.
492
%
493
*/
494
495
static inline Quantum JPEGGetQuantum(const struct jpeg_decompress_struct *jpeg_info,
496
  QuantumAny range,const JSAMPLE *p)
497
20.4G
{
498
20.4G
  if (jpeg_info->data_precision == 8)
499
15.7G
    return ScaleCharToQuantum(*p);
500
4.68G
  else if (jpeg_info->data_precision == 16)
501
459M
    return ScaleShortToQuantum(*(unsigned short *) p);
502
4.22G
  else if (jpeg_info->data_precision < 8)
503
247M
    return ScaleAnyToQuantum(*p,range);
504
3.98G
  else
505
3.98G
    return ScaleAnyToQuantum(*(unsigned short *) p,range);
506
20.4G
}
507
508
static boolean FillInputBuffer(const j_decompress_ptr compress_info)
509
34.3M
{
510
34.3M
  SourceManager
511
34.3M
    *source;
512
513
34.3M
  source=(SourceManager *) compress_info->src;
514
34.3M
  source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
515
34.3M
    MagickMinBufferExtent,source->buffer);
516
34.3M
  if (source->manager.bytes_in_buffer == 0)
517
34.3M
    {
518
34.3M
      if (source->start_of_blob != FALSE)
519
133
        ERREXIT(compress_info,JERR_INPUT_EMPTY);
520
34.3M
      WARNMS(compress_info,JWRN_JPEG_EOF);
521
34.3M
      source->buffer[0]=(JOCTET) 0xff;
522
34.3M
      source->buffer[1]=(JOCTET) JPEG_EOI;
523
34.3M
      source->manager.bytes_in_buffer=2;
524
34.3M
    }
525
34.3M
  source->manager.next_input_byte=source->buffer;
526
34.3M
  source->start_of_blob=FALSE;
527
34.3M
  return(TRUE);
528
34.3M
}
529
530
static int GetCharacter(j_decompress_ptr jpeg_info)
531
10.7M
{
532
10.7M
  if (jpeg_info->src->bytes_in_buffer == 0)
533
6.95k
    {
534
6.95k
      (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
535
6.95k
      if (jpeg_info->err->msg_code == JWRN_JPEG_EOF)
536
6.95k
        return(EOF);
537
6.95k
    }
538
10.7M
  jpeg_info->src->bytes_in_buffer--;
539
10.7M
  return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
540
10.7M
}
541
542
static void InitializeSource(j_decompress_ptr compress_info)
543
81.3k
{
544
81.3k
  SourceManager
545
81.3k
    *source;
546
547
81.3k
  source=(SourceManager *) compress_info->src;
548
81.3k
  source->start_of_blob=TRUE;
549
81.3k
}
550
551
static MagickBooleanType IsAspectRatio(const j_decompress_ptr compress_info)
552
710
{
553
710
  if (compress_info->density_unit != 0)
554
418
    return(MagickFalse);
555
292
  if ((compress_info->X_density == 1) && (compress_info->Y_density == 1))
556
11
    return(MagickTrue);
557
281
  if ((compress_info->X_density == 3) && (compress_info->Y_density == 2))
558
11
    return(MagickTrue);
559
270
  if ((compress_info->X_density == 4) && (compress_info->Y_density == 3))
560
20
    return(MagickTrue);
561
250
  if ((compress_info->X_density == 16) && (compress_info->Y_density == 9))
562
11
    return(MagickTrue);
563
239
  if ((compress_info->X_density == 16) && (compress_info->Y_density == 10))
564
7
    return(MagickTrue);
565
232
  return(MagickFalse);
566
239
}
567
568
static MagickBooleanType IsITUFaxImage(const Image *image)
569
65.9k
{
570
65.9k
  const StringInfo
571
65.9k
    *profile;
572
573
65.9k
  const unsigned char
574
65.9k
    *datum;
575
576
65.9k
  profile=GetImageProfile(image,"8bim");
577
65.9k
  if (profile == (const StringInfo *) NULL)
578
64.1k
    return(MagickFalse);
579
1.77k
  if (GetStringInfoLength(profile) < 5)
580
0
    return(MagickFalse);
581
1.77k
  datum=GetStringInfoDatum(profile);
582
1.77k
  if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
583
401
      (datum[3] == 0x41) && (datum[4] == 0x58))
584
366
    return(MagickTrue);
585
1.41k
  return(MagickFalse);
586
1.77k
}
587
588
static void JPEGErrorHandler(j_common_ptr jpeg_info)
589
37.3k
{
590
37.3k
  char
591
37.3k
    message[JMSG_LENGTH_MAX];
592
593
37.3k
  ExceptionInfo
594
37.3k
    *exception;
595
596
37.3k
  Image
597
37.3k
    *image;
598
599
37.3k
  JPEGClientInfo
600
37.3k
    *client_info;
601
602
37.3k
  *message='\0';
603
37.3k
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
604
37.3k
  image=client_info->image;
605
37.3k
  exception=client_info->exception;
606
37.3k
  (jpeg_info->err->format_message)(jpeg_info,message);
607
37.3k
  if (image->debug != MagickFalse)
608
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
609
0
      "[%s] JPEG Trace: \"%s\"",image->filename,message);
610
37.3k
  if (client_info->finished != MagickFalse)
611
5.04k
    (void) ThrowMagickException(exception,GetMagickModule(),
612
5.04k
      CorruptImageWarning,(char *) message,"`%s'",image->filename);
613
32.3k
  else
614
32.3k
    (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
615
32.3k
      (char *) message,"`%s'",image->filename);
616
37.3k
  longjmp(client_info->error_recovery,1);
617
37.3k
}
618
619
static void JPEGProgressHandler(j_common_ptr jpeg_info)
620
36.5M
{
621
36.5M
  ExceptionInfo
622
36.5M
    *exception;
623
624
36.5M
  Image
625
36.5M
    *image;
626
627
36.5M
  JPEGClientInfo
628
36.5M
    *client_info;
629
630
36.5M
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
631
36.5M
  image=client_info->image;
632
36.5M
  exception=client_info->exception;
633
36.5M
  if (jpeg_info->is_decompressor == 0)
634
0
    return;
635
36.5M
  if (((j_decompress_ptr) jpeg_info)->input_scan_number < MaxJPEGScans)
636
36.5M
    return;
637
0
  (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
638
0
    "too many scans","`%s'",image->filename);
639
0
  longjmp(client_info->error_recovery,1);
640
36.5M
}
641
642
static void JPEGWarningHandler(j_common_ptr jpeg_info,int level)
643
56.9M
{
644
56.9M
#define JPEGExcessiveWarnings  1000
645
646
56.9M
  char
647
56.9M
    message[JMSG_LENGTH_MAX];
648
649
56.9M
  ExceptionInfo
650
56.9M
    *exception;
651
652
56.9M
  Image
653
56.9M
    *image;
654
655
56.9M
  JPEGClientInfo
656
56.9M
    *client_info;
657
658
56.9M
  *message='\0';
659
56.9M
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
660
56.9M
  exception=client_info->exception;
661
56.9M
  image=client_info->image;
662
56.9M
  if (level < 0)
663
47.6M
    {
664
      /*
665
        Process warning message.
666
      */
667
47.6M
      (jpeg_info->err->format_message)(jpeg_info,message);
668
47.6M
      if (jpeg_info->err->num_warnings++ < JPEGExcessiveWarnings)
669
4.14M
        (void) ThrowMagickException(exception,GetMagickModule(),
670
4.14M
          CorruptImageWarning,message,"`%s'",image->filename);
671
47.6M
    }
672
9.29M
  else
673
9.29M
    if (level >= jpeg_info->err->trace_level)
674
9.29M
      {
675
        /*
676
          Process trace message.
677
        */
678
9.29M
        (jpeg_info->err->format_message)(jpeg_info,message);
679
9.29M
        if ((image != (Image *) NULL) && (image->debug != MagickFalse))
680
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
681
0
            "[%s] JPEG Trace: \"%s\"",image->filename,message);
682
9.29M
      }
683
56.9M
}
684
685
static MagickBooleanType ReadProfilePayload(j_decompress_ptr jpeg_info,
686
  const int index,const size_t length)
687
114k
{
688
114k
  ExceptionInfo
689
114k
    *exception;
690
691
114k
  Image
692
114k
    *image;
693
694
114k
  JPEGClientInfo
695
114k
    *client_info;
696
697
114k
  size_t
698
114k
    offset = 0;
699
700
114k
  ssize_t
701
114k
    i;
702
703
114k
  unsigned char
704
114k
    *p;
705
706
114k
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
707
114k
  exception=client_info->exception;
708
114k
  image=client_info->image;
709
114k
  if ((index < 0) || (index > MaxJPEGProfiles))
710
0
    {
711
0
      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
712
0
        "TooManyProfiles","`%s'",image->filename);
713
0
      return(MagickFalse);
714
0
    }
715
114k
  if (client_info->profiles[index] == (StringInfo *) NULL)
716
62.5k
    client_info->profiles[index]=AcquireStringInfo(length);
717
51.6k
  else
718
51.6k
    {
719
51.6k
      offset=GetStringInfoLength(client_info->profiles[index]);
720
51.6k
      SetStringInfoLength(client_info->profiles[index],offset+length);
721
51.6k
    }
722
114k
  p=GetStringInfoDatum(client_info->profiles[index])+offset;
723
9.28M
  for (i=0; i < (ssize_t) length; i++)
724
9.17M
  {
725
9.17M
    int
726
9.17M
      c;
727
728
9.17M
    c=GetCharacter(jpeg_info);
729
9.17M
    if (c == EOF)
730
2.72k
      break;
731
9.17M
    *p++=(unsigned char) c;
732
9.17M
  }
733
114k
  if (i != (ssize_t) length)
734
2.72k
    {
735
2.72k
      (void) ThrowMagickException(exception,GetMagickModule(),
736
2.72k
        CorruptImageError,"InsufficientImageDataInFile","`%s'",image->filename);
737
2.72k
      return(MagickFalse);
738
2.72k
    }
739
111k
  *p='\0';
740
111k
  if (image->debug != MagickFalse)
741
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
742
0
      "Profile[%.17g]: %.17g bytes",(double) index,(double) length);
743
111k
  return(MagickTrue);
744
114k
}
745
746
static void ThrowJPEGProfileEOFException(j_decompress_ptr jpeg_info)
747
1.00k
{
748
1.00k
  JPEGClientInfo
749
1.00k
    *client_info;
750
751
1.00k
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
752
1.00k
  (void) ThrowMagickException(client_info->exception,GetMagickModule(),
753
1.00k
    CorruptImageError,"InsufficientImageDataInFile","`%s'",
754
1.00k
    client_info->image->filename);
755
1.00k
}
756
757
static MagickBooleanType SkipProfilePayload(j_decompress_ptr jpeg_info,
758
  const size_t length)
759
17.8k
{
760
17.8k
  if (length == 0)
761
1.76k
    return(MagickTrue);
762
16.1k
  (*jpeg_info->src->skip_input_data)(jpeg_info,(long) length);
763
16.1k
  if (jpeg_info->err->msg_code == JWRN_JPEG_EOF)
764
934
    {
765
934
      ThrowJPEGProfileEOFException(jpeg_info);
766
934
      return(MagickFalse);
767
934
    }
768
15.1k
  return(MagickTrue);
769
16.1k
}
770
771
static MagickBooleanType ReadUltraHDRAPP1Profile(j_decompress_ptr jpeg_info,
772
  const size_t length)
773
0
{
774
0
  char
775
0
    xmp_signature[MagickPathExtent];
776
777
0
  int
778
0
    c;
779
780
0
  JPEGClientInfo
781
0
    *client_info;
782
783
0
  size_t
784
0
    i,
785
0
    max_signature_length,
786
0
    signature_length,
787
0
    window_length;
788
789
0
  unsigned char
790
0
    window[MagickPathExtent];
791
792
0
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
793
0
  signature_length=strlen(xmp_namespace)-1;
794
0
  if (length <= signature_length)
795
0
    return(SkipProfilePayload(jpeg_info,length));
796
0
  for (i=0; i < signature_length; i++)
797
0
  {
798
0
    c=GetCharacter(jpeg_info);
799
0
    if (c == EOF)
800
0
      {
801
0
        ThrowJPEGProfileEOFException(jpeg_info);
802
0
        return(MagickFalse);
803
0
      }
804
0
    xmp_signature[i]=(char) c;
805
0
  }
806
0
  xmp_signature[i]='\0';
807
0
  if (LocaleNCompare(xmp_signature,xmp_namespace,signature_length) != 0)
808
0
    return(SkipProfilePayload(jpeg_info,length-signature_length));
809
0
  max_signature_length=GetMaxGainmapSignatureLength(JPEGGainmapSignatureAPP1);
810
0
  window_length=0;
811
0
  for (i=signature_length; i < length; i++)
812
0
  {
813
0
    c=GetCharacter(jpeg_info);
814
0
    if (c == EOF)
815
0
      {
816
0
        ThrowJPEGProfileEOFException(jpeg_info);
817
0
        return(MagickFalse);
818
0
      }
819
0
    if (window_length < max_signature_length)
820
0
      window[window_length++]=(unsigned char) c;
821
0
    else
822
0
      {
823
0
        (void) memmove(window,window+1,max_signature_length-1);
824
0
        window[max_signature_length-1]=(unsigned char) c;
825
0
      }
826
0
    if (IsGainmapSignatureWindowMatching(window,window_length,
827
0
        JPEGGainmapSignatureAPP1) != MagickFalse)
828
0
      {
829
0
        client_info->uhdr_metadata=MagickTrue;
830
0
        (void) SetImageArtifact(client_info->image,"jpeg:hdrgm","true");
831
0
        return(SkipProfilePayload(jpeg_info,length-i-1));
832
0
      }
833
0
  }
834
0
  return(MagickTrue);
835
0
}
836
837
static MagickBooleanType ReadSkippedAPPProfile(j_decompress_ptr jpeg_info,
838
  const int marker,const size_t length)
839
0
{
840
0
  JPEGClientInfo
841
0
    *client_info;
842
843
0
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
844
0
  if ((marker == 1) && (client_info->detect_uhdr != MagickFalse))
845
0
    return(ReadUltraHDRAPP1Profile(jpeg_info,length));
846
0
  return(SkipProfilePayload(jpeg_info,length));
847
0
}
848
849
static boolean ReadComment(j_decompress_ptr jpeg_info)
850
9.70k
{
851
189k
#define GetProfileLength(jpeg_info,length) \
852
189k
do \
853
189k
{ \
854
189k
  int \
855
189k
    c; \
856
189k
 \
857
189k
  if (((c=GetCharacter(jpeg_info)) == EOF) || (c < 0)) \
858
189k
    length=0; \
859
189k
  else \
860
189k
    { \
861
188k
      length=(size_t) (256*c); \
862
188k
      if (((c=GetCharacter(jpeg_info)) == EOF) || (c < 0)) \
863
188k
        length=0; \
864
188k
      else \
865
188k
        length+=(unsigned char) c; \
866
188k
    } \
867
189k
} while(0)
868
869
9.70k
  ExceptionInfo
870
9.70k
    *exception;
871
872
9.70k
  Image
873
9.70k
    *image;
874
875
9.70k
  JPEGClientInfo
876
9.70k
    *client_info;
877
878
9.70k
  MagickBooleanType
879
9.70k
    status;
880
881
9.70k
  size_t
882
9.70k
    length;
883
884
  /*
885
    Determine length of comment.
886
  */
887
9.70k
  GetProfileLength(jpeg_info,length);
888
9.70k
  if (length <= 2)
889
3.71k
    return(TRUE);
890
5.98k
  length-=2;
891
5.98k
  status=ReadProfilePayload(jpeg_info,COMMENT_INDEX,length);
892
5.98k
  if (status == MagickFalse)
893
821
    return(FALSE);
894
5.16k
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
895
5.16k
  image=client_info->image;
896
5.16k
  exception=client_info->exception;
897
5.16k
  status=SetImageProperty(image,"comment",(const char *) GetStringInfoDatum(
898
5.16k
    client_info->profiles[COMMENT_INDEX]),exception);
899
5.16k
  return(status == MagickFalse ? FALSE : TRUE);
900
5.98k
}
901
902
static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
903
49.5k
{
904
49.5k
  char
905
49.5k
    magick[13];
906
907
49.5k
  ExceptionInfo
908
49.5k
    *exception;
909
910
49.5k
  Image
911
49.5k
    *image;
912
913
49.5k
  JPEGClientInfo
914
49.5k
    *client_info;
915
916
49.5k
  MagickBooleanType
917
49.5k
    status;
918
919
49.5k
  size_t
920
49.5k
    length;
921
922
49.5k
  ssize_t
923
49.5k
    i;
924
925
  /*
926
    Read color profile.
927
  */
928
49.5k
  GetProfileLength(jpeg_info,length);
929
49.5k
  if (length <= 2)
930
4.57k
    return(TRUE);
931
44.9k
  length-=2;
932
44.9k
  if (length <= 14)
933
3.82k
    {
934
22.3k
      while (length-- > 0)
935
18.5k
        if (GetCharacter(jpeg_info) == EOF)
936
41
          break;
937
3.82k
      return(TRUE);
938
3.82k
    }
939
534k
  for (i=0; i < 12; i++)
940
493k
    magick[i]=(char) GetCharacter(jpeg_info);
941
41.1k
  magick[i]='\0';
942
41.1k
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
943
41.1k
  if (LocaleCompare(magick,ICC_PROFILE) != 0)
944
19.6k
    {
945
19.6k
      const char
946
19.6k
        *gainmap_signature;
947
948
19.6k
      const size_t
949
19.6k
        prefix_length = 12;
950
951
19.6k
      if (LocaleCompare(magick,"MPF") == 0)
952
1.65k
        {
953
1.65k
          if (client_info->skip_icc_profiles != MagickFalse)
954
0
            return(SkipProfilePayload(jpeg_info,length-prefix_length) !=
955
0
              MagickFalse ? TRUE : FALSE);
956
          /*
957
            Multi-picture support (Future).
958
          */
959
1.65k
          status=ReadProfilePayload(jpeg_info,ICC_INDEX,length-prefix_length);
960
1.65k
          if (status == MagickFalse)
961
10
            return(FALSE);
962
1.64k
          status=SetImageProfile(client_info->image,"MPF",
963
1.64k
            client_info->profiles[ICC_INDEX],client_info->exception);
964
1.64k
          client_info->profiles[ICC_INDEX]=DestroyStringInfo(
965
1.64k
            client_info->profiles[ICC_INDEX]);
966
1.64k
          return(TRUE);
967
1.65k
        }
968
17.9k
      gainmap_signature=GetGainmapSignatureWithPrefix((const unsigned char *)
969
17.9k
        magick,prefix_length,JPEGGainmapSignatureAPP2);
970
17.9k
      if (gainmap_signature != (const char *) NULL)
971
4.83k
        {
972
4.83k
          if (client_info->detect_uhdr != MagickFalse)
973
4.83k
            {
974
4.83k
              MagickBooleanType
975
4.83k
                signature_match = MagickFalse;
976
977
4.83k
              size_t
978
4.83k
                signature_length;
979
980
4.83k
              signature_length=strlen(gainmap_signature);
981
4.83k
              if (length >= signature_length)
982
3.08k
                {
983
3.08k
                  signature_match=MagickTrue;
984
3.08k
                  for (i=(ssize_t) prefix_length;
985
48.5k
                       i < (ssize_t) signature_length; i++)
986
45.5k
                  {
987
45.5k
                    int
988
45.5k
                      c;
989
990
45.5k
                    c=GetCharacter(jpeg_info);
991
45.5k
                    if (c == EOF)
992
74
                      {
993
74
                        ThrowJPEGProfileEOFException(jpeg_info);
994
74
                        return(FALSE);
995
74
                      }
996
45.5k
                    if (c != (int) ((unsigned char) gainmap_signature[i]))
997
40.7k
                      signature_match=MagickFalse;
998
45.5k
                  }
999
3.01k
                  if (signature_match != MagickFalse)
1000
99
                    {
1001
99
                      client_info->uhdr_metadata=MagickTrue;
1002
99
                      (void) SetImageArtifact(client_info->image,"jpeg:hdrgm",
1003
99
                        "true");
1004
99
                    }
1005
3.01k
                  return(SkipProfilePayload(jpeg_info,length-signature_length)
1006
3.01k
                    != MagickFalse ? TRUE : FALSE);
1007
3.08k
                }
1008
4.83k
            }
1009
1.75k
          return(SkipProfilePayload(jpeg_info,length-prefix_length) !=
1010
1.75k
            MagickFalse ? TRUE : FALSE);
1011
4.83k
        }
1012
      /*
1013
        Not a ICC profile, return.
1014
      */
1015
13.1k
      return(SkipProfilePayload(jpeg_info,length-prefix_length) != MagickFalse ?
1016
12.3k
        TRUE : FALSE);
1017
17.9k
    }
1018
21.5k
  (void) GetCharacter(jpeg_info);  /* id */
1019
21.5k
  (void) GetCharacter(jpeg_info);  /* markers */
1020
21.5k
  length-=14;
1021
21.5k
  image=client_info->image;
1022
21.5k
  exception=client_info->exception;
1023
21.5k
  if (client_info->skip_icc_profiles != MagickFalse)
1024
0
    return(SkipProfilePayload(jpeg_info,length) != MagickFalse ? TRUE : FALSE);
1025
21.5k
  status=ReadProfilePayload(jpeg_info,ICC_INDEX,length);
1026
21.5k
  if (status == MagickFalse)
1027
85
    return(FALSE);
1028
21.4k
  status=SetImageProfile(image,"icc",client_info->profiles[ICC_INDEX],
1029
21.4k
    exception);
1030
21.4k
  return(status == MagickFalse ? FALSE : TRUE);
1031
21.5k
}
1032
1033
static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
1034
42.0k
{
1035
42.0k
  char
1036
42.0k
    magick[MagickPathExtent];
1037
1038
42.0k
  ExceptionInfo
1039
42.0k
    *exception;
1040
1041
42.0k
  Image
1042
42.0k
    *image;
1043
1044
42.0k
  JPEGClientInfo
1045
42.0k
    *client_info;
1046
1047
42.0k
  MagickBooleanType
1048
42.0k
    status;
1049
1050
42.0k
  size_t
1051
42.0k
    length;
1052
1053
42.0k
  ssize_t
1054
42.0k
    i;
1055
1056
  /*
1057
    Determine length of binary data stored here.
1058
  */
1059
42.0k
  GetProfileLength(jpeg_info,length);
1060
42.0k
  if (length <= 2)
1061
3.84k
    return(TRUE);
1062
38.2k
  length-=2;
1063
38.2k
  if (length <= 14)
1064
4.12k
    {
1065
18.8k
      while (length-- > 0)
1066
14.7k
        if (GetCharacter(jpeg_info) == EOF)
1067
51
          break;
1068
4.12k
      return(TRUE);
1069
4.12k
    }
1070
  /*
1071
    Validate that this was written as a Photoshop resource format slug.
1072
  */
1073
375k
  for (i=0; i < 10; i++)
1074
341k
    magick[i]=(char) GetCharacter(jpeg_info);
1075
34.1k
  magick[10]='\0';
1076
34.1k
  length-=10;
1077
34.1k
  if (length <= 10)
1078
6.60k
    return(TRUE);
1079
27.5k
  if (LocaleCompare(magick,"Photoshop ") != 0)
1080
5.18k
    {
1081
      /*
1082
        Not a IPTC profile, return.
1083
      */
1084
185k
      for (i=0; i < (ssize_t) length; i++)
1085
180k
        if (GetCharacter(jpeg_info) == EOF)
1086
630
          break;
1087
5.18k
      return(TRUE);
1088
5.18k
    }
1089
  /*
1090
    Remove the version number.
1091
  */
1092
22.3k
  if (length <= 15)
1093
1.78k
    return(TRUE);
1094
102k
  for (i=0; i < 4; i++)
1095
81.9k
    if (GetCharacter(jpeg_info) == EOF)
1096
103
      break;
1097
20.5k
  if (length <= 11)
1098
0
    return(TRUE);
1099
20.5k
  length-=4;
1100
20.5k
  status=ReadProfilePayload(jpeg_info,IPTC_INDEX,length);
1101
20.5k
  if (status == MagickFalse)
1102
238
    return(FALSE);
1103
20.3k
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
1104
20.3k
  image=client_info->image;
1105
20.3k
  exception=client_info->exception;
1106
20.3k
  status=SetImageProfile(image,"8bim",client_info->profiles[IPTC_INDEX],
1107
20.3k
    exception);
1108
20.3k
  return(status == MagickFalse ? FALSE : TRUE);
1109
20.5k
}
1110
1111
static boolean ReadAPPProfiles(j_decompress_ptr jpeg_info)
1112
87.9k
{
1113
87.9k
  ExceptionInfo
1114
87.9k
    *exception;
1115
1116
87.9k
  Image
1117
87.9k
    *image;
1118
1119
87.9k
  int
1120
87.9k
    marker;
1121
1122
87.9k
  JPEGClientInfo
1123
87.9k
    *client_info;
1124
1125
87.9k
  MagickBooleanType
1126
87.9k
    status;
1127
1128
87.9k
  size_t
1129
87.9k
    length,
1130
87.9k
    offset = 0;
1131
1132
87.9k
  StringInfo
1133
87.9k
    *profile;
1134
1135
87.9k
  unsigned char
1136
87.9k
    *p;
1137
1138
  /*
1139
    Read generic profile.
1140
  */
1141
87.9k
  GetProfileLength(jpeg_info,length);
1142
87.9k
  if (length <= 2)
1143
23.5k
    return(TRUE);
1144
64.4k
  length-=2;
1145
64.4k
  marker=jpeg_info->unread_marker-JPEG_APP0;
1146
64.4k
  client_info=(JPEGClientInfo *) jpeg_info->client_data;
1147
64.4k
  image=client_info->image;
1148
64.4k
  exception=client_info->exception;
1149
64.4k
  if (client_info->skip_app_profiles != MagickFalse)
1150
0
    return(ReadSkippedAPPProfile(jpeg_info,marker,length) != MagickFalse ?
1151
0
      TRUE : FALSE);
1152
64.4k
  if (client_info->profiles[marker] != (StringInfo *) NULL)
1153
13.9k
    offset=GetStringInfoLength(client_info->profiles[marker]);
1154
64.4k
  status=ReadProfilePayload(jpeg_info,marker,length);
1155
64.4k
  if (status == MagickFalse)
1156
1.57k
    return(FALSE);
1157
62.8k
  p=GetStringInfoDatum(client_info->profiles[marker])+offset;
1158
62.8k
  if ((marker == 1) &&
1159
48.1k
      (client_info->detect_uhdr != MagickFalse) &&
1160
48.1k
      (IsJPEGXMPProfile(p,length) != MagickFalse) &&
1161
8.61k
      (IsUltraHDRJPEGProfile(p,length) != MagickFalse))
1162
605
    {
1163
605
      client_info->uhdr_metadata=MagickTrue;
1164
605
      (void) SetImageArtifact(image,"jpeg:hdrgm","true");
1165
605
    }
1166
62.8k
  if (marker != 1)
1167
14.7k
    return(TRUE);
1168
48.1k
  if (IsJPEGXMPProfile(p,length) != MagickFalse)
1169
8.61k
    {
1170
8.61k
      size_t
1171
8.61k
        i;
1172
1173
      /*
1174
        Extract XMP profile minus the namespace header.
1175
      */
1176
302k
      for (i=0; i < length; i++)
1177
300k
      {
1178
300k
        if (*p == '\0')
1179
6.34k
          break;
1180
294k
        p++;
1181
294k
      }
1182
8.61k
      if (i != length)
1183
6.34k
        {
1184
6.34k
          profile=AcquireProfileStringInfo("xmp",length,exception);
1185
6.34k
          if (profile != (StringInfo*) NULL)
1186
6.34k
            {
1187
6.34k
              (void) memcpy(GetStringInfoDatum(profile),p+1,length-i-1);
1188
6.34k
              SetStringInfoLength(profile,length-i-1);
1189
6.34k
              status=SetImageProfilePrivate(image,profile,exception);
1190
6.34k
            }
1191
6.34k
          client_info->profiles[marker]=DestroyStringInfo(
1192
6.34k
            client_info->profiles[marker]);
1193
6.34k
        }
1194
8.61k
    }
1195
39.4k
  else
1196
39.4k
    {
1197
39.4k
      status=SetImageProfile(image,"app1",client_info->profiles[marker],
1198
39.4k
        exception);
1199
39.4k
      client_info->profiles[marker]=DestroyStringInfo(
1200
39.4k
        client_info->profiles[marker]);
1201
39.4k
    }
1202
48.1k
  return(status == MagickFalse ? FALSE : TRUE);
1203
62.8k
}
1204
1205
static void SkipInputData(j_decompress_ptr compress_info,long number_bytes)
1206
29.2k
{
1207
29.2k
  SourceManager
1208
29.2k
    *source;
1209
1210
29.2k
  if (number_bytes <= 0)
1211
0
    return;
1212
29.2k
  source=(SourceManager *) compress_info->src;
1213
34.1M
  while (number_bytes > (long) source->manager.bytes_in_buffer)
1214
34.1M
  {
1215
34.1M
    number_bytes-=(long) source->manager.bytes_in_buffer;
1216
34.1M
    (void) FillInputBuffer(compress_info);
1217
34.1M
  }
1218
29.2k
  source->manager.next_input_byte+=number_bytes;
1219
29.2k
  source->manager.bytes_in_buffer-=(size_t) number_bytes;
1220
29.2k
}
1221
1222
static void TerminateSource(j_decompress_ptr compress_info)
1223
40.2k
{
1224
40.2k
  (void) compress_info;
1225
40.2k
}
1226
1227
static void JPEGSourceManager(j_decompress_ptr compress_info,Image *image)
1228
81.3k
{
1229
81.3k
  SourceManager
1230
81.3k
    *source;
1231
1232
81.3k
  compress_info->src=(struct jpeg_source_mgr *)
1233
81.3k
    (*compress_info->mem->alloc_small) ((j_common_ptr) compress_info,
1234
81.3k
    JPOOL_IMAGE,sizeof(SourceManager));
1235
81.3k
  source=(SourceManager *) compress_info->src;
1236
81.3k
  source->buffer=(JOCTET *) (*compress_info->mem->alloc_small) ((j_common_ptr)
1237
81.3k
    compress_info,JPOOL_IMAGE,MagickMinBufferExtent*sizeof(JOCTET));
1238
81.3k
  source=(SourceManager *) compress_info->src;
1239
81.3k
  source->manager.init_source=InitializeSource;
1240
81.3k
  source->manager.fill_input_buffer=FillInputBuffer;
1241
81.3k
  source->manager.skip_input_data=SkipInputData;
1242
81.3k
  source->manager.resync_to_restart=jpeg_resync_to_restart;
1243
81.3k
  source->manager.term_source=TerminateSource;
1244
81.3k
  source->manager.bytes_in_buffer=0;
1245
81.3k
  source->manager.next_input_byte=NULL;
1246
81.3k
  source->image=image;
1247
81.3k
}
1248
1249
static void JPEGSetImageQuality(const struct jpeg_decompress_struct *jpeg_info,
1250
  Image *image)
1251
65.9k
{
1252
65.9k
  image->quality=UndefinedCompressionQuality;
1253
65.9k
#if defined(D_PROGRESSIVE_SUPPORTED)
1254
65.9k
  if (image->compression == LosslessJPEGCompression)
1255
0
    {
1256
0
      image->quality=100;
1257
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1258
0
        "Quality: 100 (lossless)");
1259
0
    }
1260
65.9k
  else
1261
65.9k
#endif
1262
65.9k
  {
1263
65.9k
    ssize_t
1264
65.9k
      i,
1265
65.9k
      j,
1266
65.9k
      qvalue,
1267
65.9k
      sum;
1268
1269
    /*
1270
      Determine the JPEG compression quality from the quantization tables.
1271
    */
1272
65.9k
    sum=0;
1273
329k
    for (i=0; i < NUM_QUANT_TBLS; i++)
1274
263k
    {
1275
263k
      if (jpeg_info->quant_tbl_ptrs[i] != NULL)
1276
3.26M
        for (j=0; j < DCTSIZE2; j++)
1277
3.21M
          sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
1278
263k
    }
1279
65.9k
    if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
1280
38.4k
        (jpeg_info->quant_tbl_ptrs[1] != NULL))
1281
3.11k
      {
1282
3.11k
        ssize_t
1283
3.11k
          hash[101] =
1284
3.11k
          {
1285
3.11k
            1020, 1015,  932,  848,  780,  735,  702,  679,  660,  645,
1286
3.11k
             632,  623,  613,  607,  600,  594,  589,  585,  581,  571,
1287
3.11k
             555,  542,  529,  514,  494,  474,  457,  439,  424,  410,
1288
3.11k
             397,  386,  373,  364,  351,  341,  334,  324,  317,  309,
1289
3.11k
             299,  294,  287,  279,  274,  267,  262,  257,  251,  247,
1290
3.11k
             243,  237,  232,  227,  222,  217,  213,  207,  202,  198,
1291
3.11k
             192,  188,  183,  177,  173,  168,  163,  157,  153,  148,
1292
3.11k
             143,  139,  132,  128,  125,  119,  115,  108,  104,   99,
1293
3.11k
              94,   90,   84,   79,   74,   70,   64,   59,   55,   49,
1294
3.11k
              45,   40,   34,   30,   25,   20,   15,   11,    6,    4,
1295
3.11k
               0
1296
3.11k
          },
1297
3.11k
          sums[101] =
1298
3.11k
          {
1299
3.11k
            32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
1300
3.11k
            27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
1301
3.11k
            23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
1302
3.11k
            16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
1303
3.11k
            12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
1304
3.11k
             9928,  9747,  9564,  9369,  9193,  9017,  8822,  8639,  8458,
1305
3.11k
             8270,  8084,  7896,  7710,  7527,  7347,  7156,  6977,  6788,
1306
3.11k
             6607,  6422,  6236,  6054,  5867,  5684,  5495,  5305,  5128,
1307
3.11k
             4945,  4751,  4638,  4442,  4248,  4065,  3888,  3698,  3509,
1308
3.11k
             3326,  3139,  2957,  2775,  2586,  2405,  2216,  2037,  1846,
1309
3.11k
             1666,  1483,  1297,  1109,   927,   735,   554,   375,   201,
1310
3.11k
              128,     0
1311
3.11k
          };
1312
1313
3.11k
        qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
1314
3.11k
          jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
1315
3.11k
          jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
1316
3.11k
          jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
1317
107k
        for (i=0; i < 100; i++)
1318
107k
        {
1319
107k
          if ((qvalue < hash[i]) && (sum < sums[i]))
1320
104k
            continue;
1321
3.09k
          if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
1322
562
            image->quality=(size_t) i+1;
1323
3.09k
          if (image->debug != MagickFalse)
1324
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1325
0
              "Quality: %.17g (%s)",(double) i+1,(qvalue <= hash[i]) &&
1326
0
              (sum <= sums[i]) ? "exact" : "approximate");
1327
3.09k
          break;
1328
107k
        }
1329
3.11k
      }
1330
62.8k
    else
1331
62.8k
      if (jpeg_info->quant_tbl_ptrs[0] != NULL)
1332
35.3k
        {
1333
35.3k
          ssize_t
1334
35.3k
            hash[101] =
1335
35.3k
            {
1336
35.3k
              510,  505,  422,  380,  355,  338,  326,  318,  311,  305,
1337
35.3k
              300,  297,  293,  291,  288,  286,  284,  283,  281,  280,
1338
35.3k
              279,  278,  277,  273,  262,  251,  243,  233,  225,  218,
1339
35.3k
              211,  205,  198,  193,  186,  181,  177,  172,  168,  164,
1340
35.3k
              158,  156,  152,  148,  145,  142,  139,  136,  133,  131,
1341
35.3k
              129,  126,  123,  120,  118,  115,  113,  110,  107,  105,
1342
35.3k
              102,  100,   97,   94,   92,   89,   87,   83,   81,   79,
1343
35.3k
               76,   74,   70,   68,   66,   63,   61,   57,   55,   52,
1344
35.3k
               50,   48,   44,   42,   39,   37,   34,   31,   29,   26,
1345
35.3k
               24,   21,   18,   16,   13,   11,    8,    6,    3,    2,
1346
35.3k
                0
1347
35.3k
            },
1348
35.3k
            sums[101] =
1349
35.3k
            {
1350
35.3k
              16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
1351
35.3k
              12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027,  9679,
1352
35.3k
               9368,  9056,  8680,  8331,  7995,  7668,  7376,  7084,  6823,
1353
35.3k
               6562,  6345,  6125,  5939,  5756,  5571,  5421,  5240,  5086,
1354
35.3k
               4976,  4829,  4719,  4616,  4463,  4393,  4280,  4166,  4092,
1355
35.3k
               3980,  3909,  3835,  3755,  3688,  3621,  3541,  3467,  3396,
1356
35.3k
               3323,  3247,  3170,  3096,  3021,  2952,  2874,  2804,  2727,
1357
35.3k
               2657,  2583,  2509,  2437,  2362,  2290,  2211,  2136,  2068,
1358
35.3k
               1996,  1915,  1858,  1773,  1692,  1620,  1552,  1477,  1398,
1359
35.3k
               1326,  1251,  1179,  1109,  1031,   961,   884,   814,   736,
1360
35.3k
                667,   592,   518,   441,   369,   292,   221,   151,    86,
1361
35.3k
                 64,     0
1362
35.3k
            };
1363
1364
35.3k
          qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
1365
35.3k
            jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
1366
910k
          for (i=0; i < 100; i++)
1367
910k
          {
1368
910k
            if ((qvalue < hash[i]) && (sum < sums[i]))
1369
875k
              continue;
1370
35.2k
            if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
1371
5.63k
              image->quality=(size_t) i+1;
1372
35.2k
            if (image->debug != MagickFalse)
1373
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1374
0
                "Quality: %.17g (%s)",(double) i+1,(qvalue <= hash[i]) &&
1375
0
                (sum <= sums[i]) ? "exact" : "approximate");
1376
35.2k
            break;
1377
910k
          }
1378
35.3k
        }
1379
65.9k
  }
1380
65.9k
}
1381
1382
static void JPEGSetImageSamplingFactor(const struct jpeg_decompress_struct *jpeg_info,
1383
  Image *image,ExceptionInfo *exception)
1384
65.9k
{
1385
65.9k
  char
1386
65.9k
    sampling_factor[MagickPathExtent];
1387
1388
65.9k
  switch (jpeg_info->out_color_space)
1389
65.9k
  {
1390
14.1k
    case JCS_CMYK:
1391
14.1k
    {
1392
14.1k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
1393
14.1k
      (void) FormatLocaleString(sampling_factor,MagickPathExtent,
1394
14.1k
        "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
1395
14.1k
        jpeg_info->comp_info[0].v_samp_factor,
1396
14.1k
        jpeg_info->comp_info[1].h_samp_factor,
1397
14.1k
        jpeg_info->comp_info[1].v_samp_factor,
1398
14.1k
        jpeg_info->comp_info[2].h_samp_factor,
1399
14.1k
        jpeg_info->comp_info[2].v_samp_factor,
1400
14.1k
        jpeg_info->comp_info[3].h_samp_factor,
1401
14.1k
        jpeg_info->comp_info[3].v_samp_factor);
1402
14.1k
      break;
1403
0
    }
1404
29.7k
    case JCS_GRAYSCALE:
1405
29.7k
    {
1406
29.7k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1407
29.7k
        "Colorspace: GRAYSCALE");
1408
29.7k
      (void) FormatLocaleString(sampling_factor,MagickPathExtent,"%dx%d",
1409
29.7k
        jpeg_info->comp_info[0].h_samp_factor,
1410
29.7k
        jpeg_info->comp_info[0].v_samp_factor);
1411
29.7k
      break;
1412
0
    }
1413
16.0k
    case JCS_RGB:
1414
16.0k
    {
1415
16.0k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
1416
16.0k
      (void) FormatLocaleString(sampling_factor,MagickPathExtent,
1417
16.0k
        "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
1418
16.0k
        jpeg_info->comp_info[0].v_samp_factor,
1419
16.0k
        jpeg_info->comp_info[1].h_samp_factor,
1420
16.0k
        jpeg_info->comp_info[1].v_samp_factor,
1421
16.0k
        jpeg_info->comp_info[2].h_samp_factor,
1422
16.0k
        jpeg_info->comp_info[2].v_samp_factor);
1423
16.0k
      break;
1424
0
    }
1425
6.02k
    default:
1426
6.02k
    {
1427
6.02k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
1428
6.02k
        jpeg_info->out_color_space);
1429
6.02k
      (void) FormatLocaleString(sampling_factor,MagickPathExtent,
1430
6.02k
        "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
1431
6.02k
        jpeg_info->comp_info[0].v_samp_factor,
1432
6.02k
        jpeg_info->comp_info[1].h_samp_factor,
1433
6.02k
        jpeg_info->comp_info[1].v_samp_factor,
1434
6.02k
        jpeg_info->comp_info[2].h_samp_factor,
1435
6.02k
        jpeg_info->comp_info[2].v_samp_factor,
1436
6.02k
        jpeg_info->comp_info[3].h_samp_factor,
1437
6.02k
        jpeg_info->comp_info[3].v_samp_factor);
1438
6.02k
      break;
1439
0
    }
1440
65.9k
  }
1441
65.9k
  (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
1442
65.9k
    exception);
1443
65.9k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
1444
65.9k
    sampling_factor);
1445
65.9k
}
1446
1447
static JPEGClientInfo *JPEGCleanup(struct jpeg_decompress_struct *jpeg_info,
1448
  JPEGClientInfo *client_info)
1449
81.3k
{
1450
81.3k
  size_t
1451
81.3k
    i;
1452
1453
81.3k
  if (client_info != (JPEGClientInfo *) NULL)
1454
81.3k
    {
1455
1.38M
      for (i=0; i < MaxJPEGProfiles; i++)
1456
1.30M
      {
1457
1.30M
        if (client_info->profiles[i] != (StringInfo *) NULL)
1458
9.45k
          client_info->profiles[i]=DestroyStringInfo(client_info->profiles[i]);
1459
1.30M
      }
1460
81.3k
      client_info=(JPEGClientInfo *) RelinquishMagickMemory(client_info);
1461
81.3k
    }
1462
81.3k
  jpeg_destroy_decompress(jpeg_info);
1463
81.3k
  return(client_info);
1464
81.3k
}
1465
1466
static void JPEGDestroyImageProfiles(JPEGClientInfo *client_info)
1467
65.9k
{
1468
65.9k
  ssize_t
1469
65.9k
    i;
1470
1471
65.9k
  StringInfo
1472
65.9k
    *profile;
1473
1474
1.12M
  for (i=0; i < MaxJPEGProfiles; i++)
1475
1.05M
  {
1476
1.05M
    profile=client_info->profiles[i];
1477
1.05M
    if (profile == (StringInfo *) NULL)
1478
1.04M
      continue;
1479
5.57k
    client_info->profiles[i]=DestroyStringInfo(client_info->profiles[i]);
1480
5.57k
  }
1481
65.9k
}
1482
1483
static Image *ReadOneJPEGImage(const ImageInfo *image_info,
1484
  struct jpeg_decompress_struct *jpeg_info,MagickOffsetType *offset,
1485
  ExceptionInfo *exception)
1486
82.1k
{
1487
82.1k
  char
1488
82.1k
    value[MagickPathExtent];
1489
1490
82.1k
  const char
1491
82.1k
    *dct_method,
1492
82.1k
    *option;
1493
1494
82.1k
  Image
1495
82.1k
    *image;
1496
1497
82.1k
  JPEGClientInfo
1498
82.1k
    *client_info = (JPEGClientInfo *) NULL;
1499
1500
82.1k
  JSAMPLE
1501
82.1k
    *volatile jpeg_pixels,
1502
82.1k
    *p;
1503
1504
82.1k
  MagickBooleanType
1505
82.1k
    status;
1506
1507
82.1k
  MagickSizeType
1508
82.1k
    number_pixels;
1509
1510
82.1k
  MemoryInfo
1511
82.1k
    *memory_info;
1512
1513
82.1k
  QuantumAny
1514
82.1k
    range;
1515
1516
82.1k
  size_t
1517
82.1k
    bytes_per_pixel,
1518
82.1k
    max_memory_to_use;
1519
1520
82.1k
  ssize_t
1521
82.1k
    i,
1522
82.1k
    y;
1523
1524
82.1k
  struct jpeg_error_mgr
1525
82.1k
    jpeg_error;
1526
1527
82.1k
  struct jpeg_progress_mgr
1528
82.1k
    jpeg_progress;
1529
1530
  /*
1531
    Open image file.
1532
  */
1533
82.1k
  image=AcquireImage(image_info,exception);
1534
82.1k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1535
82.1k
  if (status == MagickFalse)
1536
0
    {
1537
0
      image=DestroyImageList(image);
1538
0
      return((Image *) NULL);
1539
0
    }
1540
82.1k
  if (*offset != 0)
1541
0
    (void) SeekBlob(image,*offset,SEEK_SET);
1542
  /*
1543
    Verify that file size large enough to contain a JPEG datastream.
1544
  */
1545
82.1k
  if (GetBlobSize(image) < 107)
1546
81.3k
    ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
1547
  /*
1548
    Initialize JPEG parameters.
1549
  */
1550
81.3k
  client_info=(JPEGClientInfo *) AcquireMagickMemory(sizeof(*client_info));
1551
81.3k
  if (client_info == (JPEGClientInfo *) NULL)
1552
81.3k
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1553
81.3k
  (void) memset(client_info,0,sizeof(*client_info));
1554
81.3k
  (void) memset(jpeg_info,0,sizeof(*jpeg_info));
1555
81.3k
  (void) memset(&jpeg_error,0,sizeof(jpeg_error));
1556
81.3k
  (void) memset(&jpeg_progress,0,sizeof(jpeg_progress));
1557
81.3k
  jpeg_info->err=jpeg_std_error(&jpeg_error);
1558
81.3k
  jpeg_info->err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1559
81.3k
  jpeg_info->err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1560
81.3k
  memory_info=(MemoryInfo *) NULL;
1561
81.3k
  client_info->exception=exception;
1562
81.3k
  client_info->image=image;
1563
81.3k
  option=GetImageOption(image_info,"profile:skip");
1564
81.3k
  client_info->skip_icc_profiles=IsOptionMember("ICC",option) != MagickFalse ?
1565
81.3k
    MagickTrue : MagickFalse;
1566
81.3k
  client_info->skip_app_profiles=IsOptionMember("APP",option) != MagickFalse ?
1567
81.3k
    MagickTrue : MagickFalse;
1568
81.3k
  client_info->detect_uhdr=IsStringFalse(GetImageOption(image_info,
1569
81.3k
    "jpeg:detect-uhdr")) == MagickFalse ? MagickTrue : MagickFalse;
1570
81.3k
  if (setjmp(client_info->error_recovery) != 0)
1571
25.6k
    {
1572
25.6k
      client_info=JPEGCleanup(jpeg_info,client_info);
1573
25.6k
      (void) CloseBlob(image);
1574
25.6k
      if (exception->severity < ErrorException)
1575
0
        return(GetFirstImageInList(image));
1576
25.6k
      return(DestroyImage(image));
1577
25.6k
    }
1578
55.7k
  jpeg_info->client_data=(void *) client_info;
1579
55.7k
  jpeg_create_decompress(jpeg_info);
1580
55.7k
  max_memory_to_use=GetMaxMemoryRequest();
1581
55.7k
  if (max_memory_to_use < (size_t) LONG_MAX)
1582
81.3k
    jpeg_info->mem->max_memory_to_use=(long) max_memory_to_use;
1583
55.7k
  jpeg_progress.progress_monitor=(void (*)(j_common_ptr)) JPEGProgressHandler;
1584
55.7k
  jpeg_info->progress=(&jpeg_progress);
1585
55.7k
  JPEGSourceManager(jpeg_info,image);
1586
55.7k
  jpeg_set_marker_processor(jpeg_info,JPEG_COM,ReadComment);
1587
1.27M
  for (i=1; i < MaxJPEGProfiles; i++)
1588
1.22M
  {
1589
1.22M
    if (i == ICC_INDEX)
1590
81.3k
      {
1591
81.3k
        if ((client_info->skip_icc_profiles == MagickFalse) ||
1592
0
            (client_info->detect_uhdr != MagickFalse))
1593
81.3k
          jpeg_set_marker_processor(jpeg_info,ICC_MARKER,ReadICCProfile);
1594
81.3k
      }
1595
1.13M
    else if (i == IPTC_INDEX)
1596
81.3k
      {
1597
81.3k
        if (IsOptionMember("IPTC",option) == MagickFalse)
1598
81.3k
          jpeg_set_marker_processor(jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1599
81.3k
      }
1600
1.05M
    else if (i != 14)
1601
976k
      {
1602
        /*
1603
          Ignore APP14 as this will change the colors of the image.
1604
        */
1605
976k
        if ((client_info->skip_app_profiles == MagickFalse) ||
1606
0
            ((i == 1) && (client_info->detect_uhdr != MagickFalse)))
1607
976k
          jpeg_set_marker_processor(jpeg_info,(int) (JPEG_APP0+i),
1608
976k
            ReadAPPProfiles);
1609
976k
      }
1610
1.22M
  }
1611
55.7k
  (void) jpeg_read_header(jpeg_info,TRUE);
1612
#if defined(MAGICKCORE_UHDR_DELEGATE)
1613
  if ((client_info->uhdr_metadata != MagickFalse) && (*offset == 0) &&
1614
      (GetBlobStreamData(image) != (const unsigned char *) NULL) &&
1615
      (GetBlobSize(image) != 0) &&
1616
      (LocaleCompare(image_info->magick,"MPO") != 0) &&
1617
      (IsUltraHDRJPEGReadOptionsCompatible(image_info) != MagickFalse) &&
1618
      (IsUltraHDRJPEGAutoRoutingEnabled(image_info,ReadPolicyRights) !=
1619
        MagickFalse))
1620
    {
1621
      const char
1622
        *sampling_factor;
1623
1624
      ExceptionInfo
1625
        *uhdr_exception;
1626
1627
      Image
1628
        *uhdr_image;
1629
1630
      JPEGSetImageQuality(jpeg_info,image);
1631
      JPEGSetImageSamplingFactor(jpeg_info,image,exception);
1632
      if (jpeg_info->saw_JFIF_marker != 0)
1633
        {
1634
          if (jpeg_info->density_unit == 1)
1635
            image->units=PixelsPerInchResolution;
1636
          else if (jpeg_info->density_unit == 2)
1637
            image->units=PixelsPerCentimeterResolution;
1638
          if (IsAspectRatio(jpeg_info) == MagickFalse)
1639
            {
1640
              if (jpeg_info->X_density != 0)
1641
                image->resolution.x=(double) jpeg_info->X_density;
1642
              if (jpeg_info->Y_density != 0)
1643
                image->resolution.y=(double) jpeg_info->Y_density;
1644
            }
1645
        }
1646
      uhdr_exception=AcquireExceptionInfo();
1647
      uhdr_image=ReadUltraHDRJPEGImage(image_info,uhdr_exception);
1648
      if (uhdr_image != (Image *) NULL)
1649
        {
1650
          (void) SetImageArtifact(uhdr_image,"jpeg:hdrgm","true");
1651
          if (image->quality != UndefinedCompressionQuality)
1652
            uhdr_image->quality=image->quality;
1653
          uhdr_image->resolution=image->resolution;
1654
          uhdr_image->units=image->units;
1655
          sampling_factor=GetImageProperty(image,"jpeg:sampling-factor",
1656
            exception);
1657
          if (sampling_factor != (const char *) NULL)
1658
            (void) SetImageProperty(uhdr_image,"jpeg:sampling-factor",
1659
              sampling_factor,exception);
1660
          InheritException(exception,uhdr_exception);
1661
          uhdr_exception=DestroyExceptionInfo(uhdr_exception);
1662
          client_info=JPEGCleanup(jpeg_info,client_info);
1663
          (void) CloseBlob(image);
1664
          image=DestroyImage(image);
1665
          return(uhdr_image);
1666
        }
1667
      uhdr_exception=DestroyExceptionInfo(uhdr_exception);
1668
      (void) DeleteImageArtifact(image,"jpeg:hdrgm");
1669
    }
1670
#endif
1671
55.7k
  if (IsYCbCrCompatibleColorspace(image_info->colorspace) != MagickFalse)
1672
0
    jpeg_info->out_color_space=JCS_YCbCr;
1673
  /*
1674
    Set image resolution.
1675
  */
1676
55.7k
  if (jpeg_info->saw_JFIF_marker != 0)
1677
710
    {
1678
710
      if (jpeg_info->density_unit == 1)
1679
73
        image->units=PixelsPerInchResolution;
1680
637
      else if (jpeg_info->density_unit == 2)
1681
175
        image->units = PixelsPerCentimeterResolution;
1682
710
      if (IsAspectRatio(jpeg_info) == MagickFalse)
1683
650
        {
1684
650
          if (jpeg_info->X_density != 0)
1685
598
            image->resolution.x=(double) jpeg_info->X_density;
1686
650
          if (jpeg_info->Y_density != 0)
1687
556
            image->resolution.y=(double) jpeg_info->Y_density;
1688
650
        }
1689
710
    }
1690
55.7k
  number_pixels=(MagickSizeType) image->columns*image->rows;
1691
55.7k
  option=GetImageOption(image_info,"jpeg:size");
1692
55.7k
  if ((option != (const char *) NULL) &&
1693
0
      (jpeg_info->out_color_space != JCS_YCbCr))
1694
0
    {
1695
0
      double
1696
0
        scale_factor;
1697
1698
0
      GeometryInfo
1699
0
        geometry_info;
1700
1701
0
      MagickStatusType
1702
0
        flags;
1703
1704
      /*
1705
        Scale the image.
1706
      */
1707
0
      flags=ParseGeometry(option,&geometry_info);
1708
0
      if ((flags & SigmaValue) == 0)
1709
0
        geometry_info.sigma=geometry_info.rho;
1710
0
      jpeg_calc_output_dimensions(jpeg_info);
1711
0
      image->magick_columns=jpeg_info->output_width;
1712
0
      image->magick_rows=jpeg_info->output_height;
1713
0
      scale_factor=1.0;
1714
0
      if (geometry_info.rho != 0.0)
1715
0
        scale_factor=jpeg_info->output_width/geometry_info.rho;
1716
0
      if ((geometry_info.sigma != 0.0) &&
1717
0
          (scale_factor > (jpeg_info->output_height/geometry_info.sigma)))
1718
0
        scale_factor=jpeg_info->output_height/geometry_info.sigma;
1719
0
#if defined(LIBJPEG_TURBO_VERSION_NUMBER) || (JPEG_LIB_VERSION >= 70)
1720
0
      jpeg_info->scale_num=(unsigned int) (8.0/scale_factor+0.5);
1721
0
      if (jpeg_info->scale_num > 16U)
1722
0
        jpeg_info->scale_num=16U;
1723
0
      if (jpeg_info->scale_num < 1U)
1724
0
        jpeg_info->scale_num=1U;
1725
0
      jpeg_info->scale_denom=8U;
1726
#else
1727
      jpeg_info->scale_num=1U;
1728
      jpeg_info->scale_denom=(unsigned int) scale_factor;
1729
#endif
1730
0
      jpeg_calc_output_dimensions(jpeg_info);
1731
0
      if (image->debug != MagickFalse)
1732
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1733
0
          "Scale factor: %.17g",(double) scale_factor);
1734
0
    }
1735
55.7k
#if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1736
#if !defined(LIBJPEG_TURBO_VERSION_NUMBER) && defined(D_LOSSLESS_SUPPORTED)
1737
  image->interlace=jpeg_info->process == JPROC_PROGRESSIVE ?
1738
    JPEGInterlace : NoInterlace;
1739
  image->compression=jpeg_info->process == JPROC_LOSSLESS ?
1740
    LosslessJPEGCompression : JPEGCompression;
1741
  if (jpeg_info->data_precision > 8)
1742
    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1743
      "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1744
      image->filename);
1745
  if (jpeg_info->data_precision == 16)
1746
    jpeg_info->data_precision=12;
1747
#else
1748
55.7k
  image->interlace=jpeg_info->progressive_mode != 0 ? JPEGInterlace :
1749
55.7k
    NoInterlace;
1750
55.7k
  image->compression=JPEGCompression;
1751
55.7k
#endif
1752
#else
1753
  image->compression=JPEGCompression;
1754
  image->interlace=JPEGInterlace;
1755
#endif
1756
55.7k
  option=GetImageOption(image_info,"jpeg:colors");
1757
55.7k
  if (option != (const char *) NULL)
1758
0
    {
1759
      /*
1760
        Let the JPEG library quantize the image.
1761
      */
1762
0
      jpeg_info->quantize_colors=TRUE;
1763
0
      jpeg_info->desired_number_of_colors=StringToInteger(option);
1764
0
    }
1765
55.7k
  option=GetImageOption(image_info,"jpeg:block-smoothing");
1766
55.7k
  if (option != (const char *) NULL)
1767
0
    jpeg_info->do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1768
0
      FALSE;
1769
55.7k
  dct_method=GetImageOption(image_info,"jpeg:dct-method");
1770
55.7k
  if (dct_method != (const char *) NULL)
1771
0
    switch (*dct_method)
1772
0
    {
1773
0
      case 'D':
1774
0
      case 'd':
1775
0
      {
1776
0
        if (LocaleCompare(dct_method,"default") == 0)
1777
0
          jpeg_info->dct_method=JDCT_DEFAULT;
1778
0
        break;
1779
0
      }
1780
0
      case 'F':
1781
0
      case 'f':
1782
0
      {
1783
0
        if (LocaleCompare(dct_method,"fastest") == 0)
1784
0
          jpeg_info->dct_method=JDCT_FASTEST;
1785
0
        if (LocaleCompare(dct_method,"float") == 0)
1786
0
          jpeg_info->dct_method=JDCT_FLOAT;
1787
0
        break;
1788
0
      }
1789
0
      case 'I':
1790
0
      case 'i':
1791
0
      {
1792
0
        if (LocaleCompare(dct_method,"ifast") == 0)
1793
0
          jpeg_info->dct_method=JDCT_IFAST;
1794
0
        if (LocaleCompare(dct_method,"islow") == 0)
1795
0
          jpeg_info->dct_method=JDCT_ISLOW;
1796
0
        break;
1797
0
      }
1798
0
    }
1799
55.7k
  option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1800
55.7k
  if (option != (const char *) NULL)
1801
0
    jpeg_info->do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1802
0
      FALSE;
1803
55.7k
  jpeg_calc_output_dimensions(jpeg_info);
1804
55.7k
  image->columns=jpeg_info->output_width;
1805
55.7k
  image->rows=jpeg_info->output_height;
1806
55.7k
  image->depth=(size_t) jpeg_info->data_precision;
1807
55.7k
  if (IsITUFaxImage(image) != MagickFalse)
1808
366
    {
1809
366
      (void) SetImageColorspace(image,LabColorspace,exception);
1810
366
      jpeg_info->out_color_space=JCS_YCbCr;
1811
366
    }
1812
55.3k
  else
1813
55.3k
    {
1814
55.3k
      switch (jpeg_info->out_color_space)
1815
55.3k
      {
1816
16.0k
        case JCS_RGB:
1817
21.6k
        default:
1818
21.6k
        {
1819
21.6k
          (void) SetImageColorspace(image,sRGBColorspace,exception);
1820
21.6k
          break;
1821
16.0k
        }
1822
29.7k
        case JCS_GRAYSCALE:
1823
29.7k
        {
1824
29.7k
          (void) SetImageColorspace(image,GRAYColorspace,exception);
1825
29.7k
          break;
1826
16.0k
        }
1827
0
        case JCS_YCbCr:
1828
0
        {
1829
0
          (void) SetImageColorspace(image,YCbCrColorspace,exception);
1830
0
          break;
1831
16.0k
        }
1832
14.1k
        case JCS_CMYK:
1833
14.1k
        {
1834
14.1k
          (void) SetImageColorspace(image,CMYKColorspace,exception);
1835
14.1k
          break;
1836
16.0k
        }
1837
55.3k
      }
1838
55.3k
    }
1839
65.9k
  option=GetImageOption(image_info,"jpeg:colors");
1840
65.9k
  if (option != (const char *) NULL)
1841
0
    if (AcquireImageColormap(image,StringToUnsignedLong(option),exception) == MagickFalse)
1842
0
      {
1843
0
        client_info=JPEGCleanup(jpeg_info,client_info);
1844
0
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1845
0
      }
1846
65.9k
  if ((jpeg_info->output_components == 1) && (jpeg_info->quantize_colors == 0))
1847
29.7k
    {
1848
29.7k
      size_t
1849
29.7k
        colors;
1850
1851
29.7k
      colors=(size_t) GetQuantumRange((size_t) jpeg_info->data_precision)+1;
1852
29.7k
      if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1853
0
        {
1854
0
          client_info=JPEGCleanup(jpeg_info,client_info);
1855
0
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1856
0
        }
1857
29.7k
    }
1858
65.9k
  if (image->debug != MagickFalse)
1859
0
    {
1860
0
      if (image->interlace != NoInterlace)
1861
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1862
0
          "Interlace: progressive");
1863
0
      else
1864
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1865
0
          "Interlace: nonprogressive");
1866
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1867
0
        (int) jpeg_info->data_precision);
1868
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1869
0
        (int) jpeg_info->output_width,(int) jpeg_info->output_height);
1870
0
    }
1871
65.9k
  JPEGSetImageQuality(jpeg_info,image);
1872
65.9k
  JPEGSetImageSamplingFactor(jpeg_info,image,exception);
1873
65.9k
  (void) FormatLocaleString(value,MagickPathExtent,"%.17g",(double)
1874
65.9k
    jpeg_info->out_color_space);
1875
65.9k
  (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1876
65.9k
#if defined(D_ARITH_CODING_SUPPORTED)
1877
65.9k
  if (jpeg_info->arith_code == TRUE)
1878
28.1k
    (void) SetImageProperty(image,"jpeg:arithmetic-coding","true",exception);
1879
65.9k
#endif
1880
65.9k
  JPEGDestroyImageProfiles(client_info);
1881
65.9k
  *offset=TellBlob(image);
1882
65.9k
  if (image_info->ping != MagickFalse)
1883
59
    {
1884
59
      client_info=JPEGCleanup(jpeg_info,client_info);
1885
59
      (void) CloseBlob(image);
1886
59
      return(GetFirstImageInList(image));
1887
59
    }
1888
65.8k
  status=SetImageExtent(image,image->columns,image->rows,exception);
1889
65.8k
  if (status == MagickFalse)
1890
618
    {
1891
618
      client_info=JPEGCleanup(jpeg_info,client_info);
1892
618
      return(DestroyImageList(image));
1893
618
    }
1894
65.2k
  (void) jpeg_start_decompress(jpeg_info);
1895
65.2k
  if ((jpeg_info->output_components != 1) &&
1896
26.9k
      (jpeg_info->output_components != 3) &&
1897
13.3k
      (jpeg_info->output_components != 4))
1898
2.66k
    {
1899
2.66k
      client_info=JPEGCleanup(jpeg_info,client_info);
1900
2.66k
      ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1901
0
    }
1902
62.5k
  bytes_per_pixel=((size_t) jpeg_info->data_precision+7)/8;
1903
62.5k
  memory_info=AcquireVirtualMemory((size_t) image->columns,
1904
62.5k
    (size_t) jpeg_info->output_components*bytes_per_pixel);
1905
62.5k
  if (memory_info == (MemoryInfo *) NULL)
1906
0
    {
1907
0
      client_info=JPEGCleanup(jpeg_info,client_info);
1908
0
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1909
0
    }
1910
62.5k
  jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1911
62.5k
  (void) memset(jpeg_pixels,0,(size_t) (image->columns*
1912
62.5k
    (size_t) jpeg_info->output_components*sizeof(*jpeg_pixels)));
1913
  /*
1914
    Convert JPEG pixels to pixel packets.
1915
  */
1916
62.5k
  if (setjmp(client_info->error_recovery) != 0)
1917
6.59k
    {
1918
6.59k
      if (memory_info != (MemoryInfo *) NULL)
1919
6.59k
        memory_info=RelinquishVirtualMemory(memory_info);
1920
6.59k
      client_info=JPEGCleanup(jpeg_info,client_info);
1921
6.59k
      (void) CloseBlob(image);
1922
6.59k
      number_pixels=(MagickSizeType) image->columns*image->rows;
1923
6.59k
      if (number_pixels != 0)
1924
6.59k
        return(GetFirstImageInList(image));
1925
0
      return(DestroyImage(image));
1926
6.59k
    }
1927
55.9k
  if (jpeg_info->quantize_colors != 0)
1928
0
    {
1929
0
      image->colors=(size_t) jpeg_info->actual_number_of_colors;
1930
0
      if (jpeg_info->out_color_space == JCS_GRAYSCALE)
1931
0
        for (i=0; i < (ssize_t) image->colors; i++)
1932
0
        {
1933
0
          image->colormap[i].red=(double) ScaleCharToQuantum(
1934
0
            jpeg_info->colormap[0][i]);
1935
0
          image->colormap[i].green=image->colormap[i].red;
1936
0
          image->colormap[i].blue=image->colormap[i].red;
1937
0
          image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1938
0
        }
1939
0
      else
1940
0
        for (i=0; i < (ssize_t) image->colors; i++)
1941
0
        {
1942
0
          image->colormap[i].red=(double) ScaleCharToQuantum(
1943
0
            jpeg_info->colormap[0][i]);
1944
0
          image->colormap[i].green=(double) ScaleCharToQuantum(
1945
0
            jpeg_info->colormap[1][i]);
1946
0
          image->colormap[i].blue=(double) ScaleCharToQuantum(
1947
0
            jpeg_info->colormap[2][i]);
1948
0
          image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1949
0
        }
1950
0
    }
1951
55.9k
  range=GetQuantumRange(jpeg_info->data_precision);
1952
23.1M
  for (y=0; y < (ssize_t) image->rows; y++)
1953
23.1M
  {
1954
23.1M
    JDIMENSION
1955
23.1M
      number_scanlines = 0;
1956
1957
23.1M
    Quantum
1958
23.1M
      *magick_restrict q;
1959
1960
23.1M
    ssize_t
1961
23.1M
      x;
1962
1963
    /*
1964
      Uncompress one JPEG scanline.
1965
    */
1966
23.1M
    if (jpeg_info->data_precision > 12)
1967
697k
      {
1968
697k
#if defined(MAGICKCORE_HAVE_JPEG16_READ_SCANLINES)
1969
697k
        number_scanlines=jpeg16_read_scanlines(jpeg_info,(J16SAMPROW *)
1970
697k
          &jpeg_pixels,1);
1971
697k
#endif
1972
697k
      }
1973
22.4M
    else if (jpeg_info->data_precision > 8)
1974
6.07M
      {
1975
6.07M
#if defined(MAGICKCORE_HAVE_JPEG12_READ_SCANLINES)
1976
6.07M
        number_scanlines=jpeg12_read_scanlines(jpeg_info,(J12SAMPROW *)
1977
6.07M
          &jpeg_pixels,1);
1978
6.07M
#endif
1979
6.07M
      }
1980
16.3M
    else
1981
16.3M
      {
1982
16.3M
        number_scanlines=jpeg_read_scanlines(jpeg_info,(JSAMPROW *)
1983
16.3M
          &jpeg_pixels,1);
1984
16.3M
      }
1985
23.1M
    if (number_scanlines != 1)
1986
0
      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
1987
0
        "AnErrorHasOccurredReadingFromFile","`%s'",image->filename);
1988
    /*
1989
      Transfer image pixels from JPEG buffer.
1990
    */
1991
23.1M
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1992
23.1M
    if (q == (Quantum *) NULL)
1993
0
      break;
1994
23.1M
    p=jpeg_pixels;
1995
23.1M
    switch (jpeg_info->output_components)
1996
23.1M
    {
1997
14.8M
      case 1:
1998
14.8M
      {
1999
        /*
2000
          Grayscale.
2001
        */
2002
11.2G
        for (x=0; x < (ssize_t) image->columns; x++)
2003
11.2G
        {
2004
11.2G
          Quantum
2005
11.2G
            index;
2006
2007
11.2G
          unsigned short
2008
11.2G
            pixel;
2009
2010
11.2G
          if (jpeg_info->data_precision > 8)
2011
3.33G
            pixel=(*(unsigned short *) p);
2012
7.89G
          else
2013
7.89G
            pixel=(*(JSAMPLE *) p);
2014
2015
11.2G
          index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
2016
11.2G
          SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
2017
11.2G
          SetPixelIndex(image,index,q);
2018
11.2G
          p+=(ptrdiff_t) bytes_per_pixel;
2019
11.2G
          q+=(ptrdiff_t) GetPixelChannels(image);
2020
11.2G
        }
2021
14.8M
        break;
2022
0
      }
2023
2.88M
      case 4:
2024
2.88M
      {
2025
        /*
2026
          CMYK.
2027
        */
2028
1.31G
        for (x=0; x < (ssize_t) image->columns; x++)
2029
1.31G
        {
2030
1.31G
          SetPixelCyan(image,QuantumRange-JPEGGetQuantum(jpeg_info,range,p),q);
2031
1.31G
          p+=(ptrdiff_t) bytes_per_pixel;
2032
1.31G
          SetPixelMagenta(image,QuantumRange-JPEGGetQuantum(jpeg_info,range,p),q);
2033
1.31G
          p+=(ptrdiff_t) bytes_per_pixel;
2034
1.31G
          SetPixelYellow(image,QuantumRange-JPEGGetQuantum(jpeg_info,range,p),q);
2035
1.31G
          p+=(ptrdiff_t) bytes_per_pixel;
2036
1.31G
          SetPixelBlack(image,QuantumRange-JPEGGetQuantum(jpeg_info,range,p),q);
2037
1.31G
          p+=(ptrdiff_t) bytes_per_pixel;
2038
1.31G
          SetPixelAlpha(image,OpaqueAlpha,q);
2039
1.31G
          q+=(ptrdiff_t) GetPixelChannels(image);
2040
1.31G
        }
2041
2.88M
        break;
2042
0
      }
2043
5.42M
      default:
2044
5.42M
      {
2045
        /*
2046
          RGB || YCC.
2047
        */
2048
5.07G
        for (x=0; x < (ssize_t) image->columns; x++)
2049
5.07G
        {
2050
5.07G
          SetPixelRed(image,JPEGGetQuantum(jpeg_info,range,p),q);
2051
5.07G
          p+=(ptrdiff_t) bytes_per_pixel;
2052
5.07G
          SetPixelGreen(image,JPEGGetQuantum(jpeg_info,range,p),q);
2053
5.07G
          p+=(ptrdiff_t) bytes_per_pixel;
2054
5.07G
          SetPixelBlue(image,JPEGGetQuantum(jpeg_info,range,p),q);
2055
5.07G
          p+=(ptrdiff_t) bytes_per_pixel;
2056
5.07G
          SetPixelAlpha(image,OpaqueAlpha,q);
2057
5.07G
          q+=(ptrdiff_t) GetPixelChannels(image);
2058
5.07G
        }
2059
5.42M
        break;
2060
0
      }
2061
23.1M
    }
2062
23.1M
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
2063
0
      break;
2064
23.1M
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2065
23.1M
      image->rows);
2066
23.1M
    if (status == MagickFalse)
2067
0
      {
2068
0
        jpeg_abort_decompress(jpeg_info);
2069
0
        break;
2070
0
      }
2071
23.1M
  }
2072
49.4k
  if (status != MagickFalse)
2073
45.8k
    {
2074
45.8k
      client_info->finished=MagickTrue;
2075
45.8k
      if (setjmp(client_info->error_recovery) == 0)
2076
45.8k
        (void) jpeg_finish_decompress(jpeg_info);
2077
45.8k
    }
2078
  /*
2079
    Free jpeg resources.
2080
  */
2081
49.4k
  client_info=JPEGCleanup(jpeg_info,client_info);
2082
49.4k
  memory_info=RelinquishVirtualMemory(memory_info);
2083
49.4k
  if (CloseBlob(image) == MagickFalse)
2084
0
    status=MagickFalse;
2085
49.4k
  if (status == MagickFalse)
2086
0
    return(DestroyImageList(image));
2087
49.4k
  return(GetFirstImageInList(image));
2088
49.4k
}
2089
2090
static MagickBooleanType ReadMPOImages(const ImageInfo *image_info,
2091
  struct jpeg_decompress_struct *jpeg_info,Image *images,
2092
  const MagickOffsetType start_offset,ExceptionInfo *exception)
2093
2
{
2094
2
#define BUFFER_SIZE  8192
2095
2
#define SIGNATURE_SIZE 4
2096
2097
2
  Image
2098
2
    *image;
2099
2100
2
  MagickBooleanType
2101
2
    status;
2102
2103
2
  MagickOffsetType
2104
2
    offset = start_offset;
2105
2106
2
  ssize_t
2107
2
    count,
2108
2
    j = 0;
2109
2110
2
  MagickBooleanType
2111
2
    is_blob_readable;
2112
2113
2
  unsigned char
2114
2
    alt_signature[SIGNATURE_SIZE] = {0xff, 0xd8, 0xff, 0xe1},
2115
2
    buffer[BUFFER_SIZE],
2116
2
    signature[SIGNATURE_SIZE] = {0xff, 0xd8, 0xff, 0xe0};
2117
2118
  /*
2119
    Read multi-picture object images.
2120
  */
2121
2
  image=AcquireImage(image_info,exception);
2122
2
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2123
2
  if (status == MagickFalse)
2124
0
    {
2125
0
      image=DestroyImageList(image);
2126
0
      return(MagickFalse);
2127
0
    }
2128
2
  is_blob_readable=MagickTrue;
2129
2
  (void) SeekBlob(image,offset,SEEK_SET);
2130
2
  while ((is_blob_readable != MagickFalse) &&
2131
2
         (count=ReadBlob(image,BUFFER_SIZE,buffer)) != 0)
2132
0
  {
2133
0
    ssize_t
2134
0
      i;
2135
2136
0
    for (i=0; i < count; i++)
2137
0
    {
2138
0
      Image
2139
0
        *jpeg_image;
2140
2141
0
      MagickOffsetType
2142
0
        old_offset;
2143
2144
0
      if ((buffer[i] != signature[j]) && (buffer[i] != alt_signature[j]))
2145
0
        {
2146
0
          j=0;
2147
0
          continue;
2148
0
        }
2149
0
      if (++j != SIGNATURE_SIZE)
2150
0
        continue;
2151
0
      offset+=i-SIGNATURE_SIZE+1;
2152
0
      old_offset=offset;
2153
0
      (void) CloseBlob(image);
2154
0
      is_blob_readable=MagickFalse;
2155
0
      jpeg_image=ReadOneJPEGImage(image_info,jpeg_info,&offset,exception);
2156
0
      if (jpeg_image != (Image *) NULL)
2157
0
        AppendImageToList(&images,jpeg_image);
2158
0
      if (offset <= old_offset)
2159
0
        break;
2160
0
      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2161
0
      if (status == MagickFalse)
2162
0
        break;
2163
0
      is_blob_readable=MagickTrue;
2164
0
      (void) SeekBlob(image,offset,SEEK_SET);
2165
0
      count=0;
2166
0
      j=0;
2167
0
      break;
2168
0
    }
2169
0
    offset+=count;
2170
0
  }
2171
2
  (void) CloseBlob(image);
2172
2
  image=DestroyImageList(image);
2173
2
  return(status);
2174
2
}
2175
2176
static Image *ReadJPEGImage(const ImageInfo *image_info,
2177
  ExceptionInfo *exception)
2178
82.1k
{
2179
82.1k
  Image
2180
82.1k
    *images;
2181
2182
82.1k
  struct jpeg_decompress_struct
2183
82.1k
    jpeg_info;
2184
2185
82.1k
  MagickOffsetType
2186
82.1k
    offset;
2187
2188
82.1k
  assert(image_info != (const ImageInfo *) NULL);
2189
82.1k
  assert(image_info->signature == MagickCoreSignature);
2190
82.1k
  assert(exception != (ExceptionInfo *) NULL);
2191
82.1k
  assert(exception->signature == MagickCoreSignature);
2192
82.1k
  if (IsEventLogging() != MagickFalse)
2193
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2194
0
      image_info->filename);
2195
82.1k
  offset=0;
2196
82.1k
  images=ReadOneJPEGImage(image_info,&jpeg_info,&offset,exception);
2197
82.1k
  if ((images != (Image *) NULL) &&
2198
52.4k
      (LocaleCompare(image_info->magick,"MPO") == 0))
2199
4.38k
    {
2200
4.38k
      const StringInfo
2201
4.38k
        *profile;
2202
2203
      /*
2204
        Check for multi-picture object.
2205
      */
2206
4.38k
      profile=GetImageProfile(images,"MPF");
2207
4.38k
      if (profile != (const StringInfo *) NULL)
2208
2
        (void) ReadMPOImages(image_info,&jpeg_info,images,offset,exception);
2209
4.38k
    }
2210
82.1k
  return(images);
2211
82.1k
}
2212
#endif
2213

2214
/*
2215
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216
%                                                                             %
2217
%                                                                             %
2218
%                                                                             %
2219
%   R e g i s t e r J P E G I m a g e                                         %
2220
%                                                                             %
2221
%                                                                             %
2222
%                                                                             %
2223
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2224
%
2225
%  RegisterJPEGImage() adds properties for the JPEG image format to
2226
%  the list of supported formats.  The properties include the image format
2227
%  tag, a method to read and/or write the format, whether the format
2228
%  supports the saving of more than one frame to the same file or blob,
2229
%  whether the format supports native in-memory I/O, and a brief
2230
%  description of the format.
2231
%
2232
%  The format of the RegisterJPEGImage method is:
2233
%
2234
%      size_t RegisterJPEGImage(void)
2235
%
2236
*/
2237
ModuleExport size_t RegisterJPEGImage(void)
2238
24
{
2239
144
#define JPEGDescription "Joint Photographic Experts Group JFIF format"
2240
24
#define JPEGStringify(macro_or_string)  JPEGStringifyArg(macro_or_string)
2241
24
#define JPEGStringifyArg(contents)  #contents
2242
2243
24
  char
2244
24
    version[MagickPathExtent];
2245
2246
24
  MagickInfo
2247
24
    *entry;
2248
2249
24
  *version='\0';
2250
24
#if defined(LIBJPEG_TURBO_VERSION)
2251
24
  (void) CopyMagickString(version,"libjpeg-turbo " JPEGStringify(
2252
24
    LIBJPEG_TURBO_VERSION),MagickPathExtent);
2253
#elif defined(JPEG_LIB_VERSION)
2254
  (void) FormatLocaleString(version,MagickPathExtent,"libjpeg %d",
2255
    JPEG_LIB_VERSION);
2256
#endif
2257
24
  entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
2258
#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
2259
  entry->flags^=CoderDecoderThreadSupportFlag;
2260
#endif
2261
24
#if defined(MAGICKCORE_JPEG_DELEGATE)
2262
24
  entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
2263
24
  entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
2264
24
#endif
2265
24
  entry->magick=(IsImageFormatHandler *) IsJPEG;
2266
24
  entry->flags|=CoderDecoderSeekableStreamFlag;
2267
24
  entry->flags^=CoderAdjoinFlag;
2268
24
  entry->flags^=CoderUseExtensionFlag;
2269
24
  if (*version != '\0')
2270
24
    entry->version=ConstantString(version);
2271
24
  entry->mime_type=ConstantString("image/jpeg");
2272
24
  (void) RegisterMagickInfo(entry);
2273
24
  entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
2274
#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
2275
  entry->flags^=CoderDecoderThreadSupportFlag;
2276
#endif
2277
24
#if defined(MAGICKCORE_JPEG_DELEGATE)
2278
24
  entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
2279
24
  entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
2280
24
#endif
2281
24
  entry->magick=(IsImageFormatHandler *) IsJPEG;
2282
24
  entry->flags|=CoderDecoderSeekableStreamFlag;
2283
24
  entry->flags^=CoderAdjoinFlag;
2284
24
  if (*version != '\0')
2285
24
    entry->version=ConstantString(version);
2286
24
  entry->mime_type=ConstantString("image/jpeg");
2287
24
  (void) RegisterMagickInfo(entry);
2288
24
  entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
2289
#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
2290
  entry->flags^=CoderDecoderThreadSupportFlag;
2291
#endif
2292
24
#if defined(MAGICKCORE_JPEG_DELEGATE)
2293
24
  entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
2294
24
  entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
2295
24
#endif
2296
24
  entry->flags|=CoderDecoderSeekableStreamFlag;
2297
24
  entry->flags^=CoderAdjoinFlag;
2298
24
  entry->flags^=CoderUseExtensionFlag;
2299
24
  if (*version != '\0')
2300
24
    entry->version=ConstantString(version);
2301
24
  entry->mime_type=ConstantString("image/jpeg");
2302
24
  (void) RegisterMagickInfo(entry);
2303
24
  entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
2304
#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
2305
  entry->flags^=CoderDecoderThreadSupportFlag;
2306
#endif
2307
24
#if defined(MAGICKCORE_JPEG_DELEGATE)
2308
24
  entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
2309
24
  entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
2310
24
#endif
2311
24
  entry->flags|=CoderDecoderSeekableStreamFlag;
2312
24
  entry->flags^=CoderAdjoinFlag;
2313
24
  entry->flags^=CoderUseExtensionFlag;
2314
24
  if (*version != '\0')
2315
24
    entry->version=ConstantString(version);
2316
24
  entry->mime_type=ConstantString("image/jpeg");
2317
24
  (void) RegisterMagickInfo(entry);
2318
24
  entry=AcquireMagickInfo("JPEG","MPO",JPEGDescription);
2319
#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
2320
  entry->flags^=CoderDecoderThreadSupportFlag;
2321
#endif
2322
24
#if defined(MAGICKCORE_JPEG_DELEGATE)
2323
24
  entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
2324
24
#endif
2325
24
  entry->magick=(IsImageFormatHandler *) IsJPEG;
2326
24
  entry->flags|=CoderDecoderSeekableStreamFlag;
2327
24
  if (*version != '\0')
2328
24
    entry->version=ConstantString(version);
2329
24
  entry->mime_type=ConstantString("image/jpeg");
2330
24
  (void) RegisterMagickInfo(entry);
2331
24
  entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
2332
#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
2333
  entry->flags^=CoderDecoderThreadSupportFlag;
2334
#endif
2335
24
#if defined(MAGICKCORE_JPEG_DELEGATE)
2336
24
  entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
2337
24
  entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
2338
24
#endif
2339
24
  entry->flags|=CoderDecoderSeekableStreamFlag;
2340
24
  entry->flags^=CoderAdjoinFlag;
2341
24
  entry->flags^=CoderUseExtensionFlag;
2342
24
  if (*version != '\0')
2343
24
    entry->version=ConstantString(version);
2344
24
  entry->mime_type=ConstantString("image/jpeg");
2345
24
  (void) RegisterMagickInfo(entry);
2346
24
  return(MagickImageCoderSignature);
2347
24
}
2348

2349
/*
2350
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2351
%                                                                             %
2352
%                                                                             %
2353
%                                                                             %
2354
%   U n r e g i s t e r J P E G I m a g e                                     %
2355
%                                                                             %
2356
%                                                                             %
2357
%                                                                             %
2358
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2359
%
2360
%  UnregisterJPEGImage() removes format registrations made by the
2361
%  JPEG module from the list of supported formats.
2362
%
2363
%  The format of the UnregisterJPEGImage method is:
2364
%
2365
%      UnregisterJPEGImage(void)
2366
%
2367
*/
2368
ModuleExport void UnregisterJPEGImage(void)
2369
0
{
2370
0
  (void) UnregisterMagickInfo("PJPG");
2371
0
  (void) UnregisterMagickInfo("MPO");
2372
0
  (void) UnregisterMagickInfo("JPS");
2373
0
  (void) UnregisterMagickInfo("JPG");
2374
0
  (void) UnregisterMagickInfo("JPEG");
2375
0
  (void) UnregisterMagickInfo("JPE");
2376
0
}
2377

2378
#if defined(MAGICKCORE_JPEG_DELEGATE)
2379
/*
2380
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381
%                                                                             %
2382
%                                                                             %
2383
%                                                                             %
2384
%  W r i t e J P E G I m a g e                                                %
2385
%                                                                             %
2386
%                                                                             %
2387
%                                                                             %
2388
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389
%
2390
%  WriteJPEGImage() writes a JPEG image file and returns it.  It
2391
%  allocates the memory necessary for the new Image structure and returns a
2392
%  pointer to the new image.
2393
%
2394
%  The format of the WriteJPEGImage method is:
2395
%
2396
%      MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2397
%        Image *image,ExceptionInfo *exception)
2398
%
2399
%  A description of each parameter follows:
2400
%
2401
%    o image_info: the image info.
2402
%
2403
%    o jpeg_image:  The image.
2404
%
2405
%    o exception: return any errors or warnings in this structure.
2406
%
2407
*/
2408
2409
static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
2410
0
{
2411
0
  assert(table != (QuantizationTable *) NULL);
2412
0
  if (table->slot != (char *) NULL)
2413
0
    table->slot=DestroyString(table->slot);
2414
0
  if (table->description != (char *) NULL)
2415
0
    table->description=DestroyString(table->description);
2416
0
  if (table->levels != (unsigned int *) NULL)
2417
0
    table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
2418
0
  table=(QuantizationTable *) RelinquishMagickMemory(table);
2419
0
  return(table);
2420
0
}
2421
2422
static boolean EmptyOutputBuffer(j_compress_ptr compress_info)
2423
232k
{
2424
232k
  DestinationManager
2425
232k
    *destination;
2426
2427
232k
  destination=(DestinationManager *) compress_info->dest;
2428
232k
  destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
2429
232k
    MagickMinBufferExtent,destination->buffer);
2430
232k
  if (destination->manager.free_in_buffer != MagickMinBufferExtent)
2431
0
    ERREXIT(compress_info,JERR_FILE_WRITE);
2432
232k
  destination->manager.next_output_byte=destination->buffer;
2433
232k
  return(TRUE);
2434
232k
}
2435
2436
static QuantizationTable *GetQuantizationTable(const char *filename,
2437
  const char *slot,ExceptionInfo *exception)
2438
0
{
2439
0
  char
2440
0
    *p,
2441
0
    *xml;
2442
2443
0
  const char
2444
0
    *attribute,
2445
0
    *content;
2446
2447
0
  double
2448
0
    value;
2449
2450
0
  QuantizationTable
2451
0
    *table;
2452
2453
0
  size_t
2454
0
    length;
2455
2456
0
  ssize_t
2457
0
    i,
2458
0
    j;
2459
2460
0
  XMLTreeInfo
2461
0
    *description,
2462
0
    *levels,
2463
0
    *quantization_tables,
2464
0
    *table_iterator;
2465
2466
0
  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2467
0
    "Loading quantization tables \"%s\" ...",filename);
2468
0
  table=(QuantizationTable *) NULL;
2469
0
  xml=FileToString(filename,~0UL,exception);
2470
0
  if (xml == (char *) NULL)
2471
0
    return(table);
2472
0
  quantization_tables=NewXMLTree(xml,exception);
2473
0
  if (quantization_tables == (XMLTreeInfo *) NULL)
2474
0
    {
2475
0
      xml=DestroyString(xml);
2476
0
      return(table);
2477
0
    }
2478
0
  for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
2479
0
       table_iterator != (XMLTreeInfo *) NULL;
2480
0
       table_iterator=GetNextXMLTreeTag(table_iterator))
2481
0
  {
2482
0
    attribute=GetXMLTreeAttribute(table_iterator,"slot");
2483
0
    if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
2484
0
      break;
2485
0
    attribute=GetXMLTreeAttribute(table_iterator,"alias");
2486
0
    if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
2487
0
      break;
2488
0
  }
2489
0
  if (table_iterator == (XMLTreeInfo *) NULL)
2490
0
    {
2491
0
      xml=DestroyString(xml);
2492
0
      return(table);
2493
0
    }
2494
0
  description=GetXMLTreeChild(table_iterator,"description");
2495
0
  if (description == (XMLTreeInfo *) NULL)
2496
0
    {
2497
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2498
0
        "XmlMissingElement","<description>, slot \"%s\"",slot);
2499
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2500
0
      xml=DestroyString(xml);
2501
0
      return(table);
2502
0
    }
2503
0
  levels=GetXMLTreeChild(table_iterator,"levels");
2504
0
  if (levels == (XMLTreeInfo *) NULL)
2505
0
    {
2506
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2507
0
        "XmlMissingElement","<levels>, slot \"%s\"",slot);
2508
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2509
0
      xml=DestroyString(xml);
2510
0
      return(table);
2511
0
    }
2512
0
  table=(QuantizationTable *) AcquireCriticalMemory(sizeof(*table));
2513
0
  table->slot=(char *) NULL;
2514
0
  table->description=(char *) NULL;
2515
0
  table->levels=(unsigned int *) NULL;
2516
0
  attribute=GetXMLTreeAttribute(table_iterator,"slot");
2517
0
  if (attribute != (char *) NULL)
2518
0
    table->slot=ConstantString(attribute);
2519
0
  content=GetXMLTreeContent(description);
2520
0
  if (content != (char *) NULL)
2521
0
    table->description=ConstantString(content);
2522
0
  attribute=GetXMLTreeAttribute(levels,"width");
2523
0
  if (attribute == (char *) NULL)
2524
0
    {
2525
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2526
0
        "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
2527
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2528
0
      table=DestroyQuantizationTable(table);
2529
0
      xml=DestroyString(xml);
2530
0
      return(table);
2531
0
    }
2532
0
  table->width=StringToUnsignedLong(attribute);
2533
0
  if (table->width == 0)
2534
0
    {
2535
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2536
0
       "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
2537
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2538
0
      table=DestroyQuantizationTable(table);
2539
0
      xml=DestroyString(xml);
2540
0
      return(table);
2541
0
    }
2542
0
  attribute=GetXMLTreeAttribute(levels,"height");
2543
0
  if (attribute == (char *) NULL)
2544
0
    {
2545
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2546
0
        "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
2547
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2548
0
      table=DestroyQuantizationTable(table);
2549
0
      xml=DestroyString(xml);
2550
0
      return(table);
2551
0
    }
2552
0
  table->height=StringToUnsignedLong(attribute);
2553
0
  if (table->height == 0)
2554
0
    {
2555
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2556
0
        "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
2557
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2558
0
      table=DestroyQuantizationTable(table);
2559
0
      xml=DestroyString(xml);
2560
0
      return(table);
2561
0
    }
2562
0
  attribute=GetXMLTreeAttribute(levels,"divisor");
2563
0
  if (attribute == (char *) NULL)
2564
0
    {
2565
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2566
0
        "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
2567
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2568
0
      table=DestroyQuantizationTable(table);
2569
0
      xml=DestroyString(xml);
2570
0
      return(table);
2571
0
    }
2572
0
  table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
2573
0
  if (table->divisor == 0.0)
2574
0
    {
2575
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2576
0
        "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
2577
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2578
0
      table=DestroyQuantizationTable(table);
2579
0
      xml=DestroyString(xml);
2580
0
      return(table);
2581
0
    }
2582
0
  content=GetXMLTreeContent(levels);
2583
0
  if (content == (char *) NULL)
2584
0
    {
2585
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2586
0
        "XmlMissingContent","<levels>, table \"%s\"",slot);
2587
0
      quantization_tables=DestroyXMLTree(quantization_tables);
2588
0
      table=DestroyQuantizationTable(table);
2589
0
      xml=DestroyString(xml);
2590
0
      return(table);
2591
0
    }
2592
0
  length=(size_t) table->width*table->height;
2593
0
  if (length < 64)
2594
0
    length=64;
2595
0
  table->levels=(unsigned int *) AcquireQuantumMemory(length,
2596
0
    sizeof(*table->levels));
2597
0
  if (table->levels == (unsigned int *) NULL)
2598
0
    ThrowFatalException(ResourceLimitFatalError,
2599
0
      "UnableToAcquireQuantizationTable");
2600
0
  for (i=0; i < (ssize_t) (table->width*table->height); i++)
2601
0
  {
2602
0
    table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
2603
0
      table->divisor+0.5);
2604
0
    while (isspace((int) ((unsigned char) *p)) != 0)
2605
0
      p++;
2606
0
    if (*p == ',')
2607
0
      p++;
2608
0
    content=p;
2609
0
  }
2610
0
  value=InterpretLocaleValue(content,&p);
2611
0
  (void) value;
2612
0
  if (p != content)
2613
0
    {
2614
0
      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2615
0
        "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
2616
0
     quantization_tables=DestroyXMLTree(quantization_tables);
2617
0
     table=DestroyQuantizationTable(table);
2618
0
     xml=DestroyString(xml);
2619
0
     return(table);
2620
0
   }
2621
0
  for (j=i; j < 64; j++)
2622
0
    table->levels[j]=table->levels[j-1];
2623
0
  quantization_tables=DestroyXMLTree(quantization_tables);
2624
0
  xml=DestroyString(xml);
2625
0
  return(table);
2626
0
}
2627
2628
static void InitializeDestination(j_compress_ptr compress_info)
2629
5.84k
{
2630
5.84k
  DestinationManager
2631
5.84k
    *destination;
2632
2633
5.84k
  destination=(DestinationManager *) compress_info->dest;
2634
5.84k
  destination->buffer=(JOCTET *) (*compress_info->mem->alloc_small) (
2635
5.84k
    (j_common_ptr) compress_info,JPOOL_IMAGE,MagickMinBufferExtent*
2636
5.84k
    sizeof(JOCTET));
2637
5.84k
  destination->manager.next_output_byte=destination->buffer;
2638
5.84k
  destination->manager.free_in_buffer=MagickMinBufferExtent;
2639
5.84k
}
2640
2641
static void TerminateDestination(j_compress_ptr compress_info)
2642
5.75k
{
2643
5.75k
  DestinationManager
2644
5.75k
    *destination;
2645
2646
5.75k
  destination=(DestinationManager *) compress_info->dest;
2647
5.75k
  if ((MagickMinBufferExtent-(int) destination->manager.free_in_buffer) > 0)
2648
5.75k
    {
2649
5.75k
      ssize_t
2650
5.75k
        count;
2651
2652
5.75k
      count=WriteBlob(destination->image,MagickMinBufferExtent-
2653
5.75k
        destination->manager.free_in_buffer,destination->buffer);
2654
5.75k
      if (count != (ssize_t)
2655
5.75k
          (MagickMinBufferExtent-destination->manager.free_in_buffer))
2656
0
        ERREXIT(compress_info,JERR_FILE_WRITE);
2657
5.75k
    }
2658
5.75k
}
2659
2660
static void WriteProfiles(j_compress_ptr jpeg_info,Image *image,
2661
  ExceptionInfo *exception)
2662
2.63k
{
2663
2.63k
  const char
2664
2.63k
    *name;
2665
2666
2.63k
  const StringInfo
2667
2.63k
    *profile;
2668
2669
2.63k
  MagickBooleanType
2670
2.63k
    iptc;
2671
2672
2.63k
  ssize_t
2673
2.63k
    i;
2674
2675
2.63k
  size_t
2676
2.63k
    length,
2677
2.63k
    tag_length;
2678
2679
2.63k
  StringInfo
2680
2.63k
    *custom_profile;
2681
2682
  /*
2683
    Save image profile as a APP marker.
2684
  */
2685
2.63k
  iptc=MagickFalse;
2686
2.63k
  custom_profile=AcquireStringInfo(65535L);
2687
2.63k
  ResetImageProfileIterator(image);
2688
5.90k
  for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2689
3.27k
  {
2690
3.27k
    profile=GetImageProfile(image,name);
2691
3.27k
    length=GetStringInfoLength(profile);
2692
3.27k
    if (LocaleNCompare(name,"APP",3) == 0)
2693
54
      {
2694
54
        int
2695
54
          marker;
2696
2697
54
        marker=APP_MARKER+StringToInteger(name+3);
2698
108
        for (i=0; i < (ssize_t) length; i+=65533L)
2699
54
           jpeg_write_marker(jpeg_info,marker,GetStringInfoDatum(profile)+i,
2700
54
             MagickMin((unsigned int) (length-i),65533));
2701
54
      }
2702
3.21k
    else if (LocaleCompare(name,"EXIF") == 0)
2703
1.64k
      {
2704
1.64k
        if (length > 65533L)
2705
0
          (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2706
0
            "ExifProfileSizeExceedsLimit","`%s'",image->filename);
2707
1.64k
        else
2708
1.64k
          jpeg_write_marker(jpeg_info,APP_MARKER+1,GetStringInfoDatum(profile),
2709
1.64k
            (unsigned int) length);
2710
1.64k
      }
2711
1.57k
    else if (LocaleCompare(name,"ICC") == 0)
2712
20
      {
2713
20
        unsigned char
2714
20
          *p;
2715
2716
20
        tag_length=strlen(ICC_PROFILE);
2717
20
        p=GetStringInfoDatum(custom_profile);
2718
20
        (void) memcpy(p,ICC_PROFILE,tag_length);
2719
20
        p[tag_length]='\0';
2720
40
        for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
2721
20
        {
2722
20
          length=(size_t) MagickMin((ssize_t) GetStringInfoLength(profile)-i,
2723
20
            65519L);
2724
20
          p[12]=(unsigned char) ((i/65519L)+1);
2725
20
          p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
2726
20
          (void) memcpy(p+tag_length+3,GetStringInfoDatum(profile)+i,
2727
20
            length);
2728
20
          jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
2729
20
            custom_profile),(unsigned int) (length+tag_length+3));
2730
20
        }
2731
20
      }
2732
1.55k
    else if (((LocaleCompare(name,"IPTC") == 0) ||
2733
1.54k
        (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
2734
1.53k
      {
2735
1.53k
        size_t
2736
1.53k
          roundup;
2737
2738
1.53k
        unsigned char
2739
1.53k
          *p;
2740
2741
1.53k
        iptc=MagickTrue;
2742
1.53k
        p=GetStringInfoDatum(custom_profile);
2743
3.06k
        for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
2744
1.53k
        {
2745
1.53k
          length=(size_t) MagickMin((ssize_t) GetStringInfoLength(profile)-i,
2746
1.53k
            65500L);
2747
1.53k
          roundup=(size_t) (length & 0x01);
2748
1.53k
          if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
2749
511
            {
2750
511
              (void) memcpy(p,"Photoshop 3.0 ",14);
2751
511
              tag_length=14;
2752
511
            }
2753
1.02k
          else
2754
1.02k
            {
2755
1.02k
              (void) memcpy(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2756
1.02k
              tag_length=26;
2757
1.02k
              p[24]=(unsigned char) (length >> 8);
2758
1.02k
              p[25]=(unsigned char) (length & 0xff);
2759
1.02k
            }
2760
1.53k
          p[13]=0x00;
2761
1.53k
          (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2762
1.53k
          if (roundup != 0)
2763
771
            p[length+tag_length]='\0';
2764
1.53k
          jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2765
1.53k
            custom_profile),(unsigned int) (length+tag_length+roundup));
2766
1.53k
        }
2767
1.53k
      }
2768
18
    else if (LocaleCompare(name,"XMP") == 0)
2769
0
      {
2770
0
        StringInfo
2771
0
          *xmp_profile;
2772
2773
        /*
2774
          Add namespace to XMP profile.
2775
        */
2776
0
        xmp_profile=StringToStringInfo(xmp_namespace);
2777
0
        SetStringInfoLength(xmp_profile,strlen(xmp_namespace)+1);
2778
0
        ConcatenateStringInfo(xmp_profile,profile);
2779
0
        GetStringInfoDatum(xmp_profile)[strlen(xmp_namespace)]='\0';
2780
0
        length=GetStringInfoLength(xmp_profile);
2781
0
        for (i=0; i < (ssize_t) length; i+=65533L)
2782
0
          jpeg_write_marker(jpeg_info,APP_MARKER+1,GetStringInfoDatum(
2783
0
            xmp_profile)+i,MagickMin((unsigned int) (length-i),65533));
2784
0
        xmp_profile=DestroyStringInfo(xmp_profile);
2785
0
      }
2786
3.27k
    if (image->debug != MagickFalse)
2787
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2788
0
        "%s profile: %.17g bytes",name,(double) GetStringInfoLength(profile));
2789
3.27k
    name=GetNextImageProfile(image);
2790
3.27k
  }
2791
2.63k
  custom_profile=DestroyStringInfo(custom_profile);
2792
2.63k
}
2793
2794
static void JPEGDestinationManager(j_compress_ptr compress_info,Image * image)
2795
5.84k
{
2796
5.84k
  DestinationManager
2797
5.84k
    *destination;
2798
2799
5.84k
  compress_info->dest=(struct jpeg_destination_mgr *) (*
2800
5.84k
    compress_info->mem->alloc_small) ((j_common_ptr) compress_info,JPOOL_IMAGE,
2801
5.84k
    sizeof(DestinationManager));
2802
5.84k
  destination=(DestinationManager *) compress_info->dest;
2803
5.84k
  destination->manager.init_destination=InitializeDestination;
2804
5.84k
  destination->manager.empty_output_buffer=EmptyOutputBuffer;
2805
5.84k
  destination->manager.term_destination=TerminateDestination;
2806
5.84k
  destination->image=image;
2807
5.84k
}
2808
2809
static char **SamplingFactorToList(const char *text)
2810
5.44k
{
2811
5.44k
  char
2812
5.44k
    *q,
2813
5.44k
    **textlist;
2814
2815
5.44k
  const char
2816
5.44k
    *p;
2817
2818
5.44k
  ssize_t
2819
5.44k
    i;
2820
2821
  /*
2822
    Convert string to an ASCII list.
2823
  */
2824
5.44k
  if (text == (char *) NULL)
2825
0
    return((char **) NULL);
2826
5.44k
  textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2827
5.44k
    sizeof(*textlist));
2828
5.44k
  if (textlist == (char **) NULL)
2829
5.44k
    ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2830
5.44k
  p=text;
2831
12.1k
  for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2832
12.1k
  {
2833
48.4k
    for (q=(char *) p; *q != '\0'; q++)
2834
42.9k
      if (*q == ',')
2835
6.66k
        break;
2836
12.1k
    textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2837
12.1k
      sizeof(*textlist[i]));
2838
12.1k
    if (textlist[i] == (char *) NULL)
2839
12.1k
      ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2840
12.1k
    (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2841
12.1k
    if (*q == '\r')
2842
0
      q++;
2843
12.1k
    if (*q == '\0')
2844
5.44k
      break;
2845
6.66k
    p=q+1;
2846
6.66k
  }
2847
47.7k
  for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2848
42.2k
    textlist[i]=ConstantString("1x1");
2849
5.44k
  return(textlist);
2850
5.44k
}
2851
2852
static inline void JPEGSetSample(const struct jpeg_compress_struct *jpeg_info,
2853
  const Quantum pixel,QuantumAny range,JSAMPLE *q)
2854
14.8G
{
2855
14.8G
  if (jpeg_info->data_precision == 8)
2856
14.8G
    *q=(JSAMPLE) ScaleQuantumToChar(pixel);
2857
0
  else if (jpeg_info->data_precision == 16)
2858
0
    (*(unsigned short *) q)=(unsigned short) ScaleQuantumToShort(pixel);
2859
0
  else if (jpeg_info->data_precision < 8)
2860
0
    *q=(JSAMPLE) ScaleQuantumToAny(pixel,range);
2861
0
  else
2862
0
    (*(unsigned short *) q)=(unsigned short) ScaleQuantumToAny(pixel,range);
2863
14.8G
}
2864
2865
static MagickBooleanType WriteJPEGImage_(const ImageInfo *image_info,
2866
  Image *myImage,struct jpeg_compress_struct *jpeg_info,
2867
  ExceptionInfo *exception)
2868
5.84k
{
2869
5.84k
#define ThrowJPEGWriterException(exception,message) \
2870
0
{ \
2871
0
  if (client_info != (JPEGClientInfo *) NULL) \
2872
0
    client_info=(JPEGClientInfo *) RelinquishMagickMemory(client_info); \
2873
0
  ThrowWriterException((exception),(message)); \
2874
0
}
2875
2876
5.84k
  const char
2877
5.84k
    *dct_method,
2878
5.84k
    *option,
2879
5.84k
    *sampling_factor,
2880
5.84k
    *value;
2881
2882
5.84k
  Image
2883
5.84k
    *volatile image = (Image *) NULL,
2884
5.84k
    *volatile jps_image = (Image *) NULL,
2885
5.84k
    *volatile volatile_image = (Image *) NULL;
2886
2887
5.84k
  int
2888
5.84k
    colorspace,
2889
5.84k
    quality;
2890
2891
5.84k
  JPEGClientInfo
2892
5.84k
    *client_info = (JPEGClientInfo *) NULL;
2893
2894
5.84k
  JSAMPLE
2895
5.84k
    *volatile jpeg_pixels,
2896
5.84k
    *q;
2897
2898
5.84k
  MagickBooleanType
2899
5.84k
    status;
2900
2901
5.84k
  MemoryInfo
2902
5.84k
    *memory_info;
2903
2904
5.84k
  QuantumAny
2905
5.84k
    range;
2906
2907
5.84k
  ssize_t
2908
5.84k
    bytes_per_pixel,
2909
5.84k
    i,
2910
5.84k
    y;
2911
2912
5.84k
  struct jpeg_error_mgr
2913
5.84k
    jpeg_error;
2914
2915
  /*
2916
    Open image file.
2917
  */
2918
5.84k
  assert(image_info != (const ImageInfo *) NULL);
2919
5.84k
  assert(image_info->signature == MagickCoreSignature);
2920
5.84k
  assert(myImage != (Image *) NULL);
2921
5.84k
  assert(myImage->signature == MagickCoreSignature);
2922
5.84k
  assert(exception != (ExceptionInfo *) NULL);
2923
5.84k
  assert(exception->signature == MagickCoreSignature);
2924
5.84k
  image=myImage;
2925
5.84k
  if (IsEventLogging() != MagickFalse)
2926
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2927
5.84k
  if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2928
1.21k
      (image->next != (Image *) NULL))
2929
0
    {
2930
0
      jps_image=AppendImages(image,MagickFalse,exception);
2931
0
      if (jps_image != (Image *) NULL)
2932
0
        image=jps_image;
2933
0
    }
2934
5.84k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2935
5.84k
  if (status == MagickFalse)
2936
0
    {
2937
0
      if (jps_image != (Image *) NULL)
2938
0
        jps_image=DestroyImage(jps_image);
2939
0
      return(status);
2940
0
    }
2941
  /*
2942
    Initialize JPEG parameters.
2943
  */
2944
5.84k
  client_info=(JPEGClientInfo *) AcquireMagickMemory(sizeof(*client_info));
2945
5.84k
  if (client_info == (JPEGClientInfo *) NULL)
2946
5.84k
    ThrowJPEGWriterException(ResourceLimitError,"MemoryAllocationFailed");
2947
5.84k
  (void) memset(client_info,0,sizeof(*client_info));
2948
5.84k
  (void) memset(jpeg_info,0,sizeof(*jpeg_info));
2949
5.84k
  (void) memset(&jpeg_error,0,sizeof(jpeg_error));
2950
5.84k
  jpeg_info->err=jpeg_std_error(&jpeg_error);
2951
5.84k
  jpeg_info->err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2952
5.84k
  jpeg_info->err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2953
5.84k
  client_info->exception=exception;
2954
5.84k
  volatile_image=image;
2955
5.84k
  client_info->image=volatile_image;
2956
5.84k
  jpeg_info->client_data=(void *) client_info;
2957
5.84k
  memory_info=(MemoryInfo *) NULL;
2958
5.84k
  if (setjmp(client_info->error_recovery) != 0)
2959
88
    {
2960
88
      jpeg_destroy_compress(jpeg_info);
2961
88
      client_info=(JPEGClientInfo *) RelinquishMagickMemory(client_info);
2962
88
      (void) CloseBlob(image);
2963
88
      if (jps_image != (Image *) NULL)
2964
0
        jps_image=DestroyImage(jps_image);
2965
88
      return(MagickFalse);
2966
88
    }
2967
5.75k
  jpeg_create_compress(jpeg_info);
2968
5.75k
  JPEGDestinationManager(jpeg_info,image);
2969
5.75k
  if ((image->columns != (unsigned int) image->columns) ||
2970
5.84k
      (image->rows != (unsigned int) image->rows))
2971
5.75k
    ThrowJPEGWriterException(ImageError,"WidthOrHeightExceedsLimit");
2972
5.75k
  jpeg_info->image_width=(unsigned int) image->columns;
2973
5.75k
  jpeg_info->image_height=(unsigned int) image->rows;
2974
5.75k
  jpeg_info->input_components=3;
2975
5.75k
  jpeg_info->data_precision=8;
2976
5.75k
  option=GetImageOption(image_info,"jpeg:high-bit-depth");
2977
5.75k
  if (IsStringTrue(option) != MagickFalse)
2978
0
    {
2979
0
#if defined(C_LOSSLESS_SUPPORTED)
2980
0
      if (image_info->compression == LosslessJPEGCompression)
2981
0
        {
2982
0
#if defined(LIBJPEG_TURBO_VERSION_NUMBER) && LIBJPEG_TURBO_VERSION_NUMBER >= 3000090
2983
0
          if (image_info->quality >= 100)
2984
0
            jpeg_info->data_precision=(int) image->depth;
2985
0
          else
2986
0
#endif
2987
0
          if (image->depth > 12)
2988
0
            jpeg_info->data_precision=16;
2989
0
          else if (image->depth > 8)
2990
0
            jpeg_info->data_precision=12;
2991
0
        }
2992
0
      else
2993
0
#endif
2994
0
        {
2995
0
#if defined(MAGICKCORE_HAVE_JPEG12_WRITE_SCANLINES)
2996
0
          if (image->depth > 8)
2997
0
            jpeg_info->data_precision=12;
2998
0
#endif
2999
0
        }
3000
0
    }
3001
5.75k
  jpeg_info->in_color_space=JCS_RGB;
3002
5.75k
  switch (image->colorspace)
3003
5.75k
  {
3004
527
    case CMYKColorspace:
3005
527
    {
3006
527
      jpeg_info->input_components=4;
3007
527
      jpeg_info->in_color_space=JCS_CMYK;
3008
527
      break;
3009
0
    }
3010
0
    case YCbCrColorspace:
3011
0
    case Rec601YCbCrColorspace:
3012
0
    case Rec709YCbCrColorspace:
3013
0
    {
3014
0
      jpeg_info->in_color_space=JCS_YCbCr;
3015
0
      break;
3016
0
    }
3017
0
    case LinearGRAYColorspace:
3018
2.36k
    case GRAYColorspace:
3019
2.36k
    {
3020
2.36k
      if (image_info->type == TrueColorType)
3021
0
        break;
3022
2.36k
      jpeg_info->input_components=1;
3023
2.36k
      jpeg_info->in_color_space=JCS_GRAYSCALE;
3024
2.36k
      break;
3025
2.36k
    }
3026
2.94k
    default:
3027
2.94k
    {
3028
2.94k
      if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
3029
222
        (void) TransformImageColorspace(image,sRGBColorspace,exception);
3030
2.94k
      if (image_info->type == TrueColorType)
3031
0
        break;
3032
2.94k
      if (IdentifyImageCoderGray(image,exception) != MagickFalse)
3033
183
        {
3034
183
          jpeg_info->input_components=1;
3035
183
          jpeg_info->in_color_space=JCS_GRAYSCALE;
3036
183
        }
3037
2.94k
      break;
3038
2.94k
    }
3039
5.75k
  }
3040
5.84k
  jpeg_set_defaults(jpeg_info);
3041
5.84k
  option=GetImageOption(image_info,"jpeg:restart-interval");
3042
5.84k
  if (option != (const char *) NULL)
3043
0
    jpeg_info->restart_interval=StringToInteger(option);
3044
5.84k
  if (jpeg_info->in_color_space == JCS_CMYK)
3045
527
    jpeg_set_colorspace(jpeg_info,JCS_YCCK);
3046
5.84k
  if (image->debug != MagickFalse)
3047
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3048
0
      "Image resolution: %.17g,%.17g",image->resolution.x,image->resolution.y);
3049
5.84k
  if ((image->resolution.x > 0) && (image->resolution.x < (double) SHRT_MAX) &&
3050
160
      (image->resolution.y > 0) && (image->resolution.y < (double) SHRT_MAX))
3051
118
    {
3052
118
      UINT16
3053
118
        x_density=(UINT16) image->resolution.x,
3054
118
        y_density=(UINT16) image->resolution.y;
3055
3056
118
      if ((x_density > 0) && (y_density > 0))
3057
94
        {
3058
          /*
3059
            Set image resolution.
3060
          */
3061
94
          jpeg_info->write_JFIF_header=TRUE;
3062
94
          jpeg_info->X_density=x_density;
3063
94
          jpeg_info->Y_density=y_density;
3064
          /*
3065
            Set image resolution units.
3066
          */
3067
94
          if (image->units == PixelsPerInchResolution)
3068
14
            jpeg_info->density_unit=(UINT8) 1;
3069
80
          else if (image->units == PixelsPerCentimeterResolution)
3070
32
            jpeg_info->density_unit=(UINT8) 2;
3071
94
        }
3072
118
    }
3073
5.84k
  dct_method=GetImageOption(image_info,"jpeg:dct-method");
3074
5.84k
  if (dct_method != (const char *) NULL)
3075
0
    switch (*dct_method)
3076
0
    {
3077
0
      case 'D':
3078
0
      case 'd':
3079
0
      {
3080
0
        if (LocaleCompare(dct_method,"default") == 0)
3081
0
          jpeg_info->dct_method=JDCT_DEFAULT;
3082
0
        break;
3083
0
      }
3084
0
      case 'F':
3085
0
      case 'f':
3086
0
      {
3087
0
        if (LocaleCompare(dct_method,"fastest") == 0)
3088
0
          jpeg_info->dct_method=JDCT_FASTEST;
3089
0
        if (LocaleCompare(dct_method,"float") == 0)
3090
0
          jpeg_info->dct_method=JDCT_FLOAT;
3091
0
        break;
3092
0
      }
3093
0
      case 'I':
3094
0
      case 'i':
3095
0
      {
3096
0
        if (LocaleCompare(dct_method,"ifast") == 0)
3097
0
          jpeg_info->dct_method=JDCT_IFAST;
3098
0
        if (LocaleCompare(dct_method,"islow") == 0)
3099
0
          jpeg_info->dct_method=JDCT_ISLOW;
3100
0
        break;
3101
0
      }
3102
0
    }
3103
5.84k
  option=GetImageOption(image_info,"jpeg:optimize-coding");
3104
5.84k
  if (option != (const char *) NULL)
3105
0
    jpeg_info->optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
3106
0
      FALSE;
3107
5.84k
  else
3108
5.84k
    {
3109
5.84k
      MagickSizeType
3110
5.84k
        length;
3111
3112
5.84k
      length=(MagickSizeType) jpeg_info->input_components*image->columns*
3113
5.84k
        image->rows*sizeof(JSAMPLE);
3114
5.84k
      if (length == (MagickSizeType) ((size_t) length))
3115
5.84k
        {
3116
          /*
3117
            Perform optimization only if available memory resources permit it.
3118
          */
3119
5.84k
          status=AcquireMagickResource(MemoryResource,length);
3120
5.84k
          if (status != MagickFalse)
3121
5.84k
            RelinquishMagickResource(MemoryResource,length);
3122
5.84k
          jpeg_info->optimize_coding=status == MagickFalse ? FALSE : TRUE;
3123
5.84k
        }
3124
5.84k
    }
3125
5.84k
#if defined(C_ARITH_CODING_SUPPORTED)
3126
5.84k
  option=GetImageOption(image_info,"jpeg:arithmetic-coding");
3127
5.84k
  if (IsStringTrue(option) != MagickFalse)
3128
0
    {
3129
0
      jpeg_info->arith_code=TRUE;
3130
0
      jpeg_info->optimize_coding=FALSE;  /* not supported */
3131
0
    }
3132
5.84k
#endif
3133
5.84k
#if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
3134
5.84k
  if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
3135
4.74k
      (image_info->interlace != NoInterlace))
3136
1.10k
    {
3137
1.10k
      if (image->debug != MagickFalse)
3138
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3139
0
          "Interlace: progressive");
3140
1.10k
      jpeg_simple_progression(jpeg_info);
3141
1.10k
    }
3142
4.74k
  else
3143
4.74k
    if (image->debug != MagickFalse)
3144
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3145
0
        "Interlace: non-progressive");
3146
#else
3147
  if (image->debug != MagickFalse)
3148
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3149
      "Interlace: nonprogressive");
3150
#endif
3151
5.84k
  quality=92;
3152
5.84k
  if ((image_info->compression != LosslessJPEGCompression) &&
3153
5.84k
      (image->quality <= 100))
3154
5.84k
    {
3155
5.84k
      if (image->quality != UndefinedCompressionQuality)
3156
1.32k
        quality=(int) image->quality;
3157
5.84k
      if (image->debug != MagickFalse)
3158
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.17g",
3159
0
          (double) image->quality);
3160
5.84k
    }
3161
0
  else
3162
0
    {
3163
0
#if defined(C_LOSSLESS_SUPPORTED)
3164
0
      if (image->quality < 100)
3165
0
        (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
3166
0
          "LosslessToLossyJPEGConversion","`%s'",image->filename);
3167
0
      else
3168
0
        {
3169
0
          int
3170
0
            point_transform,
3171
0
            predictor;
3172
3173
0
          predictor=(int) image->quality/100;  /* range 1-7 */
3174
0
          point_transform=image->quality % 20;  /* range 0-15 */
3175
#if defined(MAGICKCORE_HAVE_JPEG_SIMPLE_LOSSLESS)
3176
          jpeg_simple_lossless(jpeg_info,predictor,point_transform);
3177
#endif
3178
0
#if defined(MAGICKCORE_HAVE_JPEG_ENABLE_LOSSLESS)
3179
0
          jpeg_enable_lossless(jpeg_info,predictor,point_transform);
3180
0
#endif
3181
0
          if (image->debug != MagickFalse)
3182
0
            {
3183
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3184
0
                "Compression: lossless");
3185
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3186
0
                "Predictor: %d",predictor);
3187
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3188
0
                "Point Transform: %d",point_transform);
3189
0
            }
3190
0
        }
3191
#else
3192
      quality=100;
3193
      if (image->debug != MagickFalse)
3194
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
3195
#endif
3196
0
    }
3197
5.84k
  option=GetImageOption(image_info,"jpeg:extent");
3198
5.84k
  if (option != (const char *) NULL)
3199
0
    {
3200
0
      Image
3201
0
        *jpeg_image;
3202
3203
0
      ImageInfo
3204
0
        *extent_info;
3205
3206
0
      extent_info=CloneImageInfo(image_info);
3207
0
      extent_info->blob=NULL;
3208
0
      jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
3209
0
      if (jpeg_image != (Image *) NULL)
3210
0
        {
3211
0
          MagickSizeType
3212
0
            extent;
3213
3214
0
          size_t
3215
0
            maximum,
3216
0
            minimum;
3217
3218
          /*
3219
            Search for compression quality that does not exceed image extent.
3220
          */
3221
0
          extent_info->quality=0;
3222
0
          extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
3223
0
          (void) DeleteImageOption(extent_info,"jpeg:extent");
3224
0
          (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
3225
0
          maximum=image_info->quality;
3226
0
          if (maximum < 2)
3227
0
            maximum=101;
3228
0
          for (minimum=2; minimum < maximum; )
3229
0
          {
3230
0
            (void) AcquireUniqueFilename(jpeg_image->filename);
3231
0
            jpeg_image->quality=minimum+(maximum-minimum+1)/2;
3232
0
            status=WriteJPEGImage(extent_info,jpeg_image,exception);
3233
0
            (void) RelinquishUniqueFileResource(jpeg_image->filename);
3234
0
            if (status == MagickFalse)
3235
0
              break;
3236
0
            if (GetBlobSize(jpeg_image) <= extent)
3237
0
              minimum=jpeg_image->quality+1;
3238
0
            else
3239
0
              maximum=jpeg_image->quality-1;
3240
0
          }
3241
0
          while (minimum > 2)
3242
0
          {
3243
0
            (void) AcquireUniqueFilename(jpeg_image->filename);
3244
0
            jpeg_image->quality=minimum--;
3245
0
            status=WriteJPEGImage(extent_info,jpeg_image,exception);
3246
0
            (void) RelinquishUniqueFileResource(jpeg_image->filename);
3247
0
            if (status == MagickFalse)
3248
0
              continue;
3249
0
            if (GetBlobSize(jpeg_image) <= extent)
3250
0
              break;
3251
0
          }
3252
0
          quality=(int) minimum;
3253
0
          jpeg_image=DestroyImage(jpeg_image);
3254
0
        }
3255
0
      extent_info=DestroyImageInfo(extent_info);
3256
0
    }
3257
5.84k
  jpeg_set_quality(jpeg_info,quality,TRUE);
3258
5.84k
  if ((dct_method == (const char *) NULL) && (quality <= 90))
3259
1.24k
    jpeg_info->dct_method=JDCT_IFAST;
3260
#if (JPEG_LIB_VERSION >= 70)
3261
  option=GetImageOption(image_info,"quality");
3262
  if (option != (const char *) NULL)
3263
    {
3264
      GeometryInfo
3265
        geometry_info;
3266
3267
      int
3268
        flags;
3269
3270
      /*
3271
        Set quality scaling for luminance and chrominance separately.
3272
      */
3273
      flags=ParseGeometry(option,&geometry_info);
3274
      if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
3275
        {
3276
          jpeg_info->q_scale_factor[0]=jpeg_quality_scaling((int)
3277
            (geometry_info.rho+0.5));
3278
          jpeg_info->q_scale_factor[1]=jpeg_quality_scaling((int)
3279
            (geometry_info.sigma+0.5));
3280
          jpeg_default_qtables(jpeg_info,TRUE);
3281
        }
3282
    }
3283
#endif
3284
5.84k
  colorspace=(int) jpeg_info->in_color_space;
3285
5.84k
  value=GetImageOption(image_info,"jpeg:colorspace");
3286
5.84k
  if (value == (char *) NULL)
3287
5.84k
    value=GetImageProperty(image,"jpeg:colorspace",exception);
3288
5.84k
  if (value != (char *) NULL)
3289
5.84k
    colorspace=StringToInteger(value);
3290
5.84k
  sampling_factor=(const char *) NULL;
3291
5.84k
  if ((J_COLOR_SPACE) colorspace == jpeg_info->in_color_space)
3292
5.44k
    {
3293
5.44k
      value=GetImageOption(image_info,"jpeg:sampling-factor");
3294
5.44k
      if (value == (char *) NULL)
3295
5.44k
        value=GetImageProperty(image,"jpeg:sampling-factor",exception);
3296
5.44k
      if (value != (char *) NULL)
3297
5.44k
        {
3298
5.44k
          sampling_factor=value;
3299
5.44k
          if (image->debug != MagickFalse)
3300
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3301
0
              "  Input sampling-factors=%s",sampling_factor);
3302
5.44k
        }
3303
5.44k
    }
3304
5.84k
  value=GetImageOption(image_info,"jpeg:sampling-factor");
3305
5.84k
  if (image_info->sampling_factor != (char *) NULL)
3306
0
    sampling_factor=image_info->sampling_factor;
3307
5.84k
  if (sampling_factor == (const char *) NULL)
3308
405
    {
3309
405
      if (quality >= 90)
3310
3.59k
        for (i=0; i < MAX_COMPONENTS; i++)
3311
3.27k
        {
3312
3.27k
          jpeg_info->comp_info[i].h_samp_factor=1;
3313
3.27k
          jpeg_info->comp_info[i].v_samp_factor=1;
3314
3.27k
        }
3315
405
    }
3316
5.44k
  else
3317
5.44k
    {
3318
5.44k
      char
3319
5.44k
        **factors;
3320
3321
5.44k
      GeometryInfo
3322
5.44k
        geometry_info;
3323
3324
5.44k
      MagickStatusType
3325
5.44k
        flags;
3326
3327
      /*
3328
        Set sampling factor.
3329
      */
3330
5.44k
      i=0;
3331
5.44k
      factors=SamplingFactorToList(sampling_factor);
3332
5.44k
      if (factors != (char **) NULL)
3333
5.44k
        {
3334
59.8k
          for (i=0; i < MAX_COMPONENTS; i++)
3335
54.4k
          {
3336
54.4k
            if (factors[i] == (char *) NULL)
3337
0
              break;
3338
54.4k
            flags=ParseGeometry(factors[i],&geometry_info);
3339
54.4k
            if ((flags & SigmaValue) == 0)
3340
0
              geometry_info.sigma=geometry_info.rho;
3341
54.4k
            jpeg_info->comp_info[i].h_samp_factor=(int) geometry_info.rho;
3342
54.4k
            jpeg_info->comp_info[i].v_samp_factor=(int) geometry_info.sigma;
3343
54.4k
            factors[i]=(char *) RelinquishMagickMemory(factors[i]);
3344
54.4k
          }
3345
5.44k
          factors=(char **) RelinquishMagickMemory(factors);
3346
5.44k
        }
3347
5.44k
      for ( ; i < MAX_COMPONENTS; i++)
3348
0
      {
3349
0
        jpeg_info->comp_info[i].h_samp_factor=1;
3350
0
        jpeg_info->comp_info[i].v_samp_factor=1;
3351
0
      }
3352
5.44k
    }
3353
5.84k
  option=GetImageOption(image_info,"jpeg:q-table");
3354
5.84k
  if (option != (const char *) NULL)
3355
0
    {
3356
0
      QuantizationTable
3357
0
        *table;
3358
3359
      /*
3360
        Custom quantization tables.
3361
      */
3362
0
      table=GetQuantizationTable(option,"0",exception);
3363
0
      if (table != (QuantizationTable *) NULL)
3364
0
        {
3365
0
          for (i=0; i < MAX_COMPONENTS; i++)
3366
0
            jpeg_info->comp_info[i].quant_tbl_no=0;
3367
0
          jpeg_add_quant_table(jpeg_info,0,table->levels,
3368
0
            jpeg_quality_scaling(quality),0);
3369
0
          table=DestroyQuantizationTable(table);
3370
0
        }
3371
0
      table=GetQuantizationTable(option,"1",exception);
3372
0
      if (table != (QuantizationTable *) NULL)
3373
0
        {
3374
0
          for (i=1; i < MAX_COMPONENTS; i++)
3375
0
            jpeg_info->comp_info[i].quant_tbl_no=1;
3376
0
          jpeg_add_quant_table(jpeg_info,1,table->levels,
3377
0
            jpeg_quality_scaling(quality),0);
3378
0
          table=DestroyQuantizationTable(table);
3379
0
        }
3380
0
      table=GetQuantizationTable(option,"2",exception);
3381
0
      if (table != (QuantizationTable *) NULL)
3382
0
        {
3383
0
          for (i=2; i < MAX_COMPONENTS; i++)
3384
0
            jpeg_info->comp_info[i].quant_tbl_no=2;
3385
0
          jpeg_add_quant_table(jpeg_info,2,table->levels,
3386
0
            jpeg_quality_scaling(quality),0);
3387
0
          table=DestroyQuantizationTable(table);
3388
0
        }
3389
0
      table=GetQuantizationTable(option,"3",exception);
3390
0
      if (table != (QuantizationTable *) NULL)
3391
0
        {
3392
0
          for (i=3; i < MAX_COMPONENTS; i++)
3393
0
            jpeg_info->comp_info[i].quant_tbl_no=3;
3394
0
          jpeg_add_quant_table(jpeg_info,3,table->levels,
3395
0
            jpeg_quality_scaling(quality),0);
3396
0
          table=DestroyQuantizationTable(table);
3397
0
        }
3398
0
    }
3399
5.84k
  jpeg_start_compress(jpeg_info,TRUE);
3400
5.84k
  if (image->debug != MagickFalse)
3401
0
    {
3402
0
      if (image->storage_class == PseudoClass)
3403
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3404
0
          "Storage class: PseudoClass");
3405
0
      else
3406
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3407
0
          "Storage class: DirectClass");
3408
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.17g",
3409
0
        (double) image->depth);
3410
0
      if (image->colors != 0)
3411
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3412
0
          "Number of colors: %.17g",(double) image->colors);
3413
0
      else
3414
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3415
0
          "Number of colors: unspecified");
3416
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3417
0
        "JPEG data precision: %d",(int) jpeg_info->data_precision);
3418
0
      switch (jpeg_info->in_color_space)
3419
0
      {
3420
0
        case JCS_CMYK:
3421
0
        {
3422
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3423
0
            "Colorspace: CMYK");
3424
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3425
0
            "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
3426
0
            jpeg_info->comp_info[0].h_samp_factor,
3427
0
            jpeg_info->comp_info[0].v_samp_factor,
3428
0
            jpeg_info->comp_info[1].h_samp_factor,
3429
0
            jpeg_info->comp_info[1].v_samp_factor,
3430
0
            jpeg_info->comp_info[2].h_samp_factor,
3431
0
            jpeg_info->comp_info[2].v_samp_factor,
3432
0
            jpeg_info->comp_info[3].h_samp_factor,
3433
0
            jpeg_info->comp_info[3].v_samp_factor);
3434
0
          break;
3435
0
        }
3436
0
        case JCS_GRAYSCALE:
3437
0
        {
3438
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3439
0
            "Colorspace: GRAY");
3440
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3441
0
            "Sampling factors: %dx%d",jpeg_info->comp_info[0].h_samp_factor,
3442
0
            jpeg_info->comp_info[0].v_samp_factor);
3443
0
          break;
3444
0
        }
3445
0
        case JCS_UNKNOWN:
3446
0
        {
3447
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3448
0
            "Colorspace: RGB");
3449
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3450
0
            "Sampling factors: %dx%d,%dx%d,%dx%d",
3451
0
            jpeg_info->comp_info[0].h_samp_factor,
3452
0
            jpeg_info->comp_info[0].v_samp_factor,
3453
0
            jpeg_info->comp_info[1].h_samp_factor,
3454
0
            jpeg_info->comp_info[1].v_samp_factor,
3455
0
            jpeg_info->comp_info[2].h_samp_factor,
3456
0
            jpeg_info->comp_info[2].v_samp_factor);
3457
0
          break;
3458
0
        }
3459
0
        case JCS_YCbCr:
3460
0
        {
3461
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3462
0
            "Colorspace: YCbCr");
3463
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3464
0
            "Sampling factors: %dx%d,%dx%d,%dx%d",
3465
0
            jpeg_info->comp_info[0].h_samp_factor,
3466
0
            jpeg_info->comp_info[0].v_samp_factor,
3467
0
            jpeg_info->comp_info[1].h_samp_factor,
3468
0
            jpeg_info->comp_info[1].v_samp_factor,
3469
0
            jpeg_info->comp_info[2].h_samp_factor,
3470
0
            jpeg_info->comp_info[2].v_samp_factor);
3471
0
          break;
3472
0
        }
3473
0
        default: break;
3474
0
      }
3475
0
    }
3476
  /*
3477
    Write JPEG profiles.
3478
  */
3479
5.84k
  value=GetImageProperty(image,"comment",exception);
3480
5.84k
  if (value != (char *) NULL)
3481
33
    {
3482
33
      size_t
3483
33
        length;
3484
3485
33
      length=strlen(value);
3486
59
      for (i=0; i < (ssize_t) length; i+=65533L)
3487
26
        jpeg_write_marker(jpeg_info,JPEG_COM,(unsigned char *) value+i,
3488
26
          (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
3489
33
    }
3490
5.84k
  if (image->profiles != (void *) NULL)
3491
2.63k
    WriteProfiles(jpeg_info,image,exception);
3492
  /*
3493
    Convert MIFF to JPEG raster pixels.
3494
  */
3495
5.84k
  bytes_per_pixel=(jpeg_info->data_precision+7)/8;
3496
5.84k
  memory_info=AcquireVirtualMemory((size_t) image->columns,
3497
5.84k
    (size_t) (jpeg_info->input_components*bytes_per_pixel));
3498
5.84k
  if (memory_info == (MemoryInfo *) NULL)
3499
5.84k
    ThrowJPEGWriterException(ResourceLimitError,"MemoryAllocationFailed");
3500
5.84k
  jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
3501
5.84k
  if (setjmp(client_info->error_recovery) != 0)
3502
0
    {
3503
0
      jpeg_destroy_compress(jpeg_info);
3504
0
      client_info=(JPEGClientInfo *) RelinquishMagickMemory(client_info);
3505
0
      if (memory_info != (MemoryInfo *) NULL)
3506
0
        memory_info=RelinquishVirtualMemory(memory_info);
3507
0
      (void) CloseBlob(image);
3508
0
      if (jps_image != (Image *) NULL)
3509
0
        jps_image=DestroyImage(jps_image);
3510
0
      return(MagickFalse);
3511
0
    }
3512
5.84k
  range=GetQuantumRange(jpeg_info->data_precision);
3513
5.37M
  for (y=0; y < (ssize_t) image->rows; y++)
3514
5.37M
  {
3515
5.37M
    const Quantum
3516
5.37M
      *p;
3517
3518
5.37M
    JDIMENSION
3519
5.37M
      number_scanlines = 0;
3520
3521
5.37M
    ssize_t
3522
5.37M
      x;
3523
3524
    /*
3525
      Transfer image pixel to JPEG buffer.
3526
    */
3527
5.37M
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3528
5.37M
    if (p == (const Quantum *) NULL)
3529
0
      break;
3530
5.37M
    q=jpeg_pixels;
3531
5.37M
    switch (jpeg_info->input_components)
3532
5.37M
    {
3533
2.83M
      case 1:
3534
2.83M
      {
3535
        /*
3536
          Grayscale.
3537
        */
3538
3.77G
        for (x=0; x < (ssize_t) image->columns; x++)
3539
3.76G
        {
3540
3.76G
          JPEGSetSample(jpeg_info,ClampToQuantum(GetPixelLuma(image,p)),range,
3541
3.76G
            q);
3542
3.76G
          q+=(ptrdiff_t) bytes_per_pixel;
3543
3.76G
          p+=(ptrdiff_t) GetPixelChannels(image);
3544
3.76G
        }
3545
2.83M
        break;
3546
0
      }
3547
215k
      case 4:
3548
215k
      {
3549
        /*
3550
          CMYK.
3551
        */
3552
200M
        for (x=0; x < (ssize_t) image->columns; x++)
3553
200M
        {
3554
          /*
3555
            Convert DirectClass packets to contiguous CMYK scanlines.
3556
          */
3557
200M
          JPEGSetSample(jpeg_info,(Quantum) ((QuantumRange-
3558
200M
            GetPixelCyan(image,p))),range,q);
3559
200M
          q+=(ptrdiff_t) bytes_per_pixel;
3560
200M
          JPEGSetSample(jpeg_info,(Quantum) ((QuantumRange-
3561
200M
            GetPixelMagenta(image,p))),range,q);
3562
200M
          q+=(ptrdiff_t) bytes_per_pixel;
3563
200M
          JPEGSetSample(jpeg_info,(Quantum) ((QuantumRange-
3564
200M
            GetPixelYellow(image,p))),range,q);
3565
200M
          q+=(ptrdiff_t) bytes_per_pixel;
3566
200M
          JPEGSetSample(jpeg_info,(Quantum) ((QuantumRange-
3567
200M
            GetPixelBlack(image,p))),range,q);
3568
200M
          q+=(ptrdiff_t) bytes_per_pixel;
3569
200M
          p+=(ptrdiff_t) GetPixelChannels(image);
3570
200M
        }
3571
215k
        break;
3572
0
      }
3573
2.32M
      default:
3574
2.32M
      {
3575
        /*
3576
          RGB || YCC.
3577
        */
3578
3.43G
        for (x=0; x < (ssize_t) image->columns; x++)
3579
3.43G
        {
3580
3.43G
          JPEGSetSample(jpeg_info,GetPixelRed(image,p),range,q);
3581
3.43G
          q+=(ptrdiff_t) bytes_per_pixel;
3582
3.43G
          JPEGSetSample(jpeg_info,GetPixelGreen(image,p),range,q);
3583
3.43G
          q+=(ptrdiff_t) bytes_per_pixel;
3584
3.43G
          JPEGSetSample(jpeg_info,GetPixelBlue(image,p),range,q);
3585
3.43G
          q+=(ptrdiff_t) bytes_per_pixel;
3586
3.43G
          p+=(ptrdiff_t) GetPixelChannels(image);
3587
3.43G
        }
3588
2.32M
        break;
3589
0
      }
3590
5.37M
    }
3591
    /*
3592
      Compress one JPEG scanline.
3593
    */
3594
5.37M
    if (jpeg_info->data_precision > 12)
3595
0
      {
3596
0
#if defined(MAGICKCORE_HAVE_JPEG16_WRITE_SCANLINES)
3597
0
        number_scanlines=jpeg16_write_scanlines(jpeg_info,(J16SAMPROW *)
3598
0
          &jpeg_pixels,1);
3599
0
#endif
3600
0
      }
3601
5.37M
    else if (jpeg_info->data_precision > 8)
3602
0
      {
3603
0
#if defined(MAGICKCORE_HAVE_JPEG12_WRITE_SCANLINES)
3604
0
        number_scanlines=jpeg12_write_scanlines(jpeg_info,(J12SAMPROW *)
3605
0
          &jpeg_pixels,1);
3606
0
#endif
3607
0
      }
3608
5.37M
    else
3609
5.37M
      {
3610
5.37M
        number_scanlines=jpeg_write_scanlines(jpeg_info,(JSAMPROW *)
3611
5.37M
          &jpeg_pixels,1);
3612
5.37M
      }
3613
5.37M
    if (number_scanlines != 1)
3614
0
      (void) ThrowMagickException(exception,GetMagickModule(),
3615
0
        CorruptImageError,"AnErrorHasOccurredWritingToFile","`%s'",
3616
0
        image->filename);
3617
5.37M
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3618
5.37M
      image->rows);
3619
5.37M
    if (status == MagickFalse)
3620
0
      break;
3621
5.37M
  }
3622
  /*
3623
    Relinquish resources.
3624
  */
3625
5.84k
  jpeg_finish_compress(jpeg_info);
3626
5.84k
  jpeg_destroy_compress(jpeg_info);
3627
5.84k
  client_info=(JPEGClientInfo *) RelinquishMagickMemory(client_info);
3628
5.84k
  memory_info=RelinquishVirtualMemory(memory_info);
3629
5.84k
  if (CloseBlob(image) == MagickFalse)
3630
0
    status=MagickFalse;
3631
5.84k
  if (jps_image != (Image *) NULL)
3632
0
    jps_image=DestroyImage(jps_image);
3633
5.84k
  return(status);
3634
5.84k
}
3635
3636
static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
3637
  Image *image,ExceptionInfo *exception)
3638
5.84k
{
3639
5.84k
  struct jpeg_compress_struct
3640
5.84k
    jpeg_info;
3641
3642
#if defined(MAGICKCORE_UHDR_DELEGATE)
3643
  if ((GetImageProfile(image,"hdrgm") != (const StringInfo *) NULL) &&
3644
      (GetImageOption(image_info,"jpeg:extent") == (const char *) NULL) &&
3645
      (IsUltraHDRJPEGAutoRoutingEnabled(image_info,WritePolicyRights) !=
3646
        MagickFalse))
3647
    return(WriteUltraHDRJPEGImage(image_info,image,exception));
3648
#endif
3649
5.84k
  return(WriteJPEGImage_(image_info,image,&jpeg_info,exception));
3650
5.84k
}
3651
#endif