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-2021 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/script/license.php                               %
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/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/splay-tree.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/string_.h"
83 #include "MagickCore/string-private.h"
84 #include "MagickCore/token.h"
85 #include "MagickCore/utility.h"
86 #include "MagickCore/xml-tree.h"
87 #include "MagickCore/xml-tree-private.h"
88 #include <setjmp.h>
89 #if defined(MAGICKCORE_JPEG_DELEGATE)
90 #define JPEG_INTERNAL_OPTIONS
91 #if defined(__MINGW32__)
92 # define XMD_H 1  /* Avoid conflicting typedef for INT32 */
93 #endif
94 #undef HAVE_STDLIB_H
95 #include "jpeglib.h"
96 #include "jerror.h"
97 #endif
98 
99 /*
100   Define declarations.
101 */
102 #define COMMENT_INDEX  0
103 #define ICC_INDEX  2
104 #define ICC_MARKER  (JPEG_APP0+ICC_INDEX)
105 #define ICC_PROFILE  "ICC_PROFILE"
106 #define IPTC_INDEX  13
107 #define IPTC_MARKER  (JPEG_APP0+IPTC_INDEX)
108 #define XML_INDEX  1
109 #define XML_MARKER  (JPEG_APP0+XML_INDEX)
110 #define MaxJPEGScans  1024
111 
112 /*
113   Typedef declarations.
114 */
115 #if defined(MAGICKCORE_JPEG_DELEGATE)
116 typedef struct _DestinationManager
117 {
118   struct jpeg_destination_mgr
119     manager;
120 
121   Image
122     *image;
123 
124   JOCTET
125     *buffer;
126 } DestinationManager;
127 
128 typedef struct _ErrorManager
129 {
130   jmp_buf
131     error_recovery;
132 
133   Image
134     *image;
135 
136   MagickBooleanType
137     finished;
138 
139   StringInfo
140     *profiles[16];
141 
142   ExceptionInfo
143     *exception;
144 } ErrorManager;
145 
146 typedef struct _SourceManager
147 {
148   struct jpeg_source_mgr
149     manager;
150 
151   Image
152     *image;
153 
154   JOCTET
155     *buffer;
156 
157   boolean
158     start_of_blob;
159 } SourceManager;
160 #endif
161 
162 typedef struct _QuantizationTable
163 {
164   char
165     *slot,
166     *description;
167 
168   size_t
169     width,
170     height;
171 
172   double
173     divisor;
174 
175   unsigned int
176     *levels;
177 } QuantizationTable;
178 
179 /*
180   Const declarations.
181 */
182 static const char
183   xmp_namespace[] = "http://ns.adobe.com/xap/1.0/ ";
184 #define XmpNamespaceExtent 28
185 
186 /*
187   Forward declarations.
188 */
189 #if defined(MAGICKCORE_JPEG_DELEGATE)
190 static MagickBooleanType
191   WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
192 #endif
193 
194 /*
195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 %                                                                             %
197 %                                                                             %
198 %                                                                             %
199 %   I s J P E G                                                               %
200 %                                                                             %
201 %                                                                             %
202 %                                                                             %
203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204 %
205 %  IsJPEG() returns MagickTrue if the image format type, identified by the
206 %  magick string, is JPEG.
207 %
208 %  The format of the IsJPEG  method is:
209 %
210 %      MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
211 %
212 %  A description of each parameter follows:
213 %
214 %    o magick: compare image format pattern against these bytes.
215 %
216 %    o length: Specifies the length of the magick string.
217 %
218 */
IsJPEG(const unsigned char * magick,const size_t length)219 static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
220 {
221   if (length < 3)
222     return(MagickFalse);
223   if (memcmp(magick,"\377\330\377",3) == 0)
224     return(MagickTrue);
225   return(MagickFalse);
226 }
227 
228 #if defined(MAGICKCORE_JPEG_DELEGATE)
229 /*
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 %                                                                             %
232 %                                                                             %
233 %                                                                             %
234 %   R e a d J P E G I m a g e                                                 %
235 %                                                                             %
236 %                                                                             %
237 %                                                                             %
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 %
240 %  ReadJPEGImage() reads a JPEG image file and returns it.  It allocates
241 %  the memory necessary for the new Image structure and returns a pointer to
242 %  the new image.
243 %
244 %  The format of the ReadJPEGImage method is:
245 %
246 %      Image *ReadJPEGImage(const ImageInfo *image_info,
247 %        ExceptionInfo *exception)
248 %
249 %  A description of each parameter follows:
250 %
251 %    o image_info: the image info.
252 %
253 %    o exception: return any errors or warnings in this structure.
254 %
255 */
256 
FillInputBuffer(j_decompress_ptr cinfo)257 static boolean FillInputBuffer(j_decompress_ptr cinfo)
258 {
259   SourceManager
260     *source;
261 
262   source=(SourceManager *) cinfo->src;
263   source->manager.bytes_in_buffer=(size_t) ReadBlob(source->image,
264     MagickMinBufferExtent,source->buffer);
265   if (source->manager.bytes_in_buffer == 0)
266     {
267       if (source->start_of_blob != FALSE)
268         ERREXIT(cinfo,JERR_INPUT_EMPTY);
269       WARNMS(cinfo,JWRN_JPEG_EOF);
270       source->buffer[0]=(JOCTET) 0xff;
271       source->buffer[1]=(JOCTET) JPEG_EOI;
272       source->manager.bytes_in_buffer=2;
273     }
274   source->manager.next_input_byte=source->buffer;
275   source->start_of_blob=FALSE;
276   return(TRUE);
277 }
278 
GetCharacter(j_decompress_ptr jpeg_info)279 static int GetCharacter(j_decompress_ptr jpeg_info)
280 {
281   if (jpeg_info->src->bytes_in_buffer == 0)
282     {
283       (void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
284       if (jpeg_info->err->msg_code == JWRN_JPEG_EOF)
285         return(EOF);
286     }
287   jpeg_info->src->bytes_in_buffer--;
288   return((int) GETJOCTET(*jpeg_info->src->next_input_byte++));
289 }
290 
InitializeSource(j_decompress_ptr cinfo)291 static void InitializeSource(j_decompress_ptr cinfo)
292 {
293   SourceManager
294     *source;
295 
296   source=(SourceManager *) cinfo->src;
297   source->start_of_blob=TRUE;
298 }
299 
IsITUFaxImage(const Image * image)300 static MagickBooleanType IsITUFaxImage(const Image *image)
301 {
302   const StringInfo
303     *profile;
304 
305   const unsigned char
306     *datum;
307 
308   profile=GetImageProfile(image,"8bim");
309   if (profile == (const StringInfo *) NULL)
310     return(MagickFalse);
311   if (GetStringInfoLength(profile) < 5)
312     return(MagickFalse);
313   datum=GetStringInfoDatum(profile);
314   if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
315       (datum[3] == 0x41) && (datum[4] == 0x58))
316     return(MagickTrue);
317   return(MagickFalse);
318 }
319 
JPEGErrorHandler(j_common_ptr jpeg_info)320 static void JPEGErrorHandler(j_common_ptr jpeg_info)
321 {
322   char
323     message[JMSG_LENGTH_MAX];
324 
325   ErrorManager
326     *error_manager;
327 
328   ExceptionInfo
329     *exception;
330 
331   Image
332     *image;
333 
334   *message='\0';
335   error_manager=(ErrorManager *) jpeg_info->client_data;
336   image=error_manager->image;
337   exception=error_manager->exception;
338   (jpeg_info->err->format_message)(jpeg_info,message);
339   if (image->debug != MagickFalse)
340     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
341       "[%s] JPEG Trace: \"%s\"",image->filename,message);
342   if (error_manager->finished != MagickFalse)
343     (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageWarning,
344       (char *) message,"`%s'",image->filename);
345   else
346     (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
347       (char *) message,"`%s'",image->filename);
348   longjmp(error_manager->error_recovery,1);
349 }
350 
JPEGProgressHandler(j_common_ptr jpeg_info)351 static void JPEGProgressHandler(j_common_ptr jpeg_info)
352 {
353   ErrorManager
354     *error_manager;
355 
356   ExceptionInfo
357     *exception;
358 
359   Image
360     *image;
361 
362   error_manager=(ErrorManager *) jpeg_info->client_data;
363   image=error_manager->image;
364   exception=error_manager->exception;
365   if (jpeg_info->is_decompressor == 0)
366     return;
367   if (((j_decompress_ptr) jpeg_info)->input_scan_number < MaxJPEGScans)
368     return;
369   (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
370     "too many scans","`%s'",image->filename);
371   longjmp(error_manager->error_recovery,1);
372 }
373 
JPEGWarningHandler(j_common_ptr jpeg_info,int level)374 static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
375 {
376 #define JPEGExcessiveWarnings  1000
377 
378   char
379     message[JMSG_LENGTH_MAX];
380 
381   ErrorManager
382     *error_manager;
383 
384   ExceptionInfo
385     *exception;
386 
387   Image
388     *image;
389 
390   *message='\0';
391   error_manager=(ErrorManager *) jpeg_info->client_data;
392   exception=error_manager->exception;
393   image=error_manager->image;
394   if (level < 0)
395     {
396       /*
397         Process warning message.
398       */
399       (jpeg_info->err->format_message)(jpeg_info,message);
400       if (jpeg_info->err->num_warnings++ < JPEGExcessiveWarnings)
401         ThrowBinaryException(CorruptImageWarning,(char *) message,
402           image->filename);
403     }
404   else
405     if ((image->debug != MagickFalse) &&
406         (level >= jpeg_info->err->trace_level))
407       {
408         /*
409           Process trace message.
410         */
411         (jpeg_info->err->format_message)(jpeg_info,message);
412         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
413           "[%s] JPEG Trace: \"%s\"",image->filename,message);
414       }
415   return(MagickTrue);
416 }
417 
ReadProfileData(j_decompress_ptr jpeg_info,const size_t index,const size_t length)418 static boolean ReadProfileData(j_decompress_ptr jpeg_info,const size_t index,
419   const size_t length)
420 {
421   ErrorManager
422     *error_manager;
423 
424   ExceptionInfo
425     *exception;
426 
427   Image
428     *image;
429 
430   unsigned char
431     *p;
432 
433   ssize_t
434     i;
435 
436   error_manager=(ErrorManager *) jpeg_info->client_data;
437   exception=error_manager->exception;
438   image=error_manager->image;
439   if (error_manager->profiles[index] == (StringInfo *) NULL)
440     {
441       error_manager->profiles[index]=BlobToStringInfo((const void *) NULL,
442         length);
443       if (error_manager->profiles[index] == (StringInfo *) NULL)
444         {
445           (void) ThrowMagickException(exception,GetMagickModule(),
446             ResourceLimitError,"MemoryAllocationFailed","`%s'",
447             image->filename);
448           return(FALSE);
449         }
450       p=GetStringInfoDatum(error_manager->profiles[index]);
451     }
452   else
453     {
454       size_t
455         current_length;
456 
457       current_length=GetStringInfoLength(error_manager->profiles[index]);
458       SetStringInfoLength(error_manager->profiles[index],current_length+
459         length);
460       p=GetStringInfoDatum(error_manager->profiles[index])+current_length;
461     }
462   for (i=0; i < (ssize_t) length; i++)
463   {
464     int
465       c;
466 
467     c=GetCharacter(jpeg_info);
468     if (c == EOF)
469       break;
470     *p++=(unsigned char) c;
471   }
472   if (i != (ssize_t) length)
473     {
474       (void) ThrowMagickException(exception,GetMagickModule(),
475         CorruptImageError,"InsufficientImageDataInFile","`%s'",
476         image->filename);
477       return(FALSE);
478     }
479   *p='\0';
480   if (image->debug != MagickFalse)
481     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
482       "Profile[%.20g]: %.20g bytes",(double) index,(double) length);
483   return(TRUE);
484 }
485 
ReadComment(j_decompress_ptr jpeg_info)486 static boolean ReadComment(j_decompress_ptr jpeg_info)
487 {
488 #define GetProfileLength(jpeg_info,length) \
489 { \
490   int \
491     c[2]; \
492 \
493   length=0; \
494   c[0]=GetCharacter(jpeg_info); \
495   c[1]=GetCharacter(jpeg_info); \
496   if ((c[0] >= 0) && (c[1] >= 0)) \
497     length=(size_t) ((c[0] << 8) | c[1]); \
498 }
499 
500   size_t
501     length;
502 
503   /*
504     Determine length of comment.
505   */
506   GetProfileLength(jpeg_info,length);
507   if (length <= 2)
508     return(TRUE);
509   length-=2;
510   return(ReadProfileData(jpeg_info,COMMENT_INDEX,length));
511 }
512 
ReadICCProfile(j_decompress_ptr jpeg_info)513 static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
514 {
515   char
516     magick[13];
517 
518   ssize_t
519     i;
520 
521   size_t
522     length;
523 
524   /*
525     Read color profile.
526   */
527   GetProfileLength(jpeg_info,length);
528   if (length <= 2)
529     return(TRUE);
530   length-=2;
531   if (length <= 14)
532     {
533       while (length-- > 0)
534         if (GetCharacter(jpeg_info) == EOF)
535           break;
536       return(TRUE);
537     }
538   for (i=0; i < 12; i++)
539     magick[i]=(char) GetCharacter(jpeg_info);
540   magick[i]='\0';
541   if (LocaleCompare(magick,ICC_PROFILE) != 0)
542     {
543       /*
544         Not a ICC profile, return.
545       */
546       for (i=0; i < (ssize_t) (length-12); i++)
547         if (GetCharacter(jpeg_info) == EOF)
548           break;
549       return(TRUE);
550     }
551   (void) GetCharacter(jpeg_info);  /* id */
552   (void) GetCharacter(jpeg_info);  /* markers */
553   length-=14;
554   return(ReadProfileData(jpeg_info,ICC_INDEX,length));
555 }
556 
ReadIPTCProfile(j_decompress_ptr jpeg_info)557 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
558 {
559   char
560     magick[MagickPathExtent];
561 
562   ssize_t
563     i;
564 
565   size_t
566     length;
567 
568   /*
569     Determine length of binary data stored here.
570   */
571   GetProfileLength(jpeg_info,length);
572   if (length <= 2)
573     return(TRUE);
574   length-=2;
575   if (length <= 14)
576     {
577       while (length-- > 0)
578         if (GetCharacter(jpeg_info) == EOF)
579           break;
580       return(TRUE);
581     }
582   /*
583     Validate that this was written as a Photoshop resource format slug.
584   */
585   for (i=0; i < 10; i++)
586     magick[i]=(char) GetCharacter(jpeg_info);
587   magick[10]='\0';
588   length-=10;
589   if (length <= 10)
590     return(TRUE);
591   if (LocaleCompare(magick,"Photoshop ") != 0)
592     {
593       /*
594         Not a IPTC profile, return.
595       */
596       for (i=0; i < (ssize_t) length; i++)
597         if (GetCharacter(jpeg_info) == EOF)
598           break;
599       return(TRUE);
600     }
601   /*
602     Remove the version number.
603   */
604   for (i=0; i < 4; i++)
605     if (GetCharacter(jpeg_info) == EOF)
606       break;
607   if (length <= 11)
608     return(TRUE);
609   length-=4;
610   return(ReadProfileData(jpeg_info,IPTC_INDEX,length));
611 }
612 
ReadProfile(j_decompress_ptr jpeg_info)613 static boolean ReadProfile(j_decompress_ptr jpeg_info)
614 {
615   int
616     marker;
617 
618   size_t
619     length;
620 
621   /*
622     Read generic profile.
623   */
624   GetProfileLength(jpeg_info,length);
625   if (length <= 2)
626     return(TRUE);
627   length-=2;
628   marker=jpeg_info->unread_marker-JPEG_APP0;
629   return(ReadProfileData(jpeg_info,marker,length));
630 }
631 
ReadXmlProfile(j_decompress_ptr jpeg_info)632 static boolean ReadXmlProfile(j_decompress_ptr jpeg_info)
633 {
634   ErrorManager
635     *error_manager;
636 
637   ExceptionInfo
638     *exception;
639 
640   Image
641     *image;
642 
643   MagickBooleanType
644     status;
645 
646   unsigned char
647     *p;
648 
649   size_t
650     length;
651 
652   StringInfo
653     *profile;
654 
655   GetProfileLength(jpeg_info,length);
656   if (length <= 2)
657     return(TRUE);
658   length-=2;
659   if (ReadProfileData(jpeg_info,XML_INDEX,length) == FALSE)
660     return(FALSE);
661   error_manager=(ErrorManager *) jpeg_info->client_data;
662   exception=error_manager->exception;
663   image=error_manager->image;
664   profile=error_manager->profiles[XML_INDEX];
665   p=GetStringInfoDatum(profile);
666   length=GetStringInfoLength(profile);
667   status=MagickTrue;
668   if ((length > XmpNamespaceExtent) &&
669       (LocaleNCompare((char *) p,xmp_namespace,XmpNamespaceExtent-1) == 0))
670     {
671       ssize_t
672         j;
673 
674       /*
675         Extract namespace from XMP profile.
676       */
677       p=GetStringInfoDatum(profile)+XmpNamespaceExtent;
678       for (j=XmpNamespaceExtent; j < (ssize_t) length; j++)
679       {
680         if (*p == '\0')
681           break;
682         p++;
683       }
684       if (j < (ssize_t) length)
685         (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
686       status=SetImageProfile(image,"xmp",profile,exception);
687     }
688   else
689     if (length > 4)
690       {
691         if ((LocaleNCompare((char *) p,"exif",4) == 0) ||
692             (LocaleNCompare((char *) p,"MM",2) == 0) ||
693             (LocaleNCompare((char *) p,"II",2) == 0))
694           status=SetImageProfile(image,"exif",profile,exception);
695       }
696     else
697       status=SetImageProfile(image,"app1",profile,exception);
698   error_manager->profiles[XML_INDEX]=DestroyStringInfo(
699     error_manager->profiles[XML_INDEX]);
700   return(status != MagickFalse ? TRUE : FALSE);
701 }
702 
SkipInputData(j_decompress_ptr cinfo,long number_bytes)703 static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
704 {
705   SourceManager
706     *source;
707 
708   if (number_bytes <= 0)
709     return;
710   source=(SourceManager *) cinfo->src;
711   while (number_bytes > (long) source->manager.bytes_in_buffer)
712   {
713     number_bytes-=(long) source->manager.bytes_in_buffer;
714     (void) FillInputBuffer(cinfo);
715   }
716   source->manager.next_input_byte+=number_bytes;
717   source->manager.bytes_in_buffer-=number_bytes;
718 }
719 
TerminateSource(j_decompress_ptr cinfo)720 static void TerminateSource(j_decompress_ptr cinfo)
721 {
722   (void) cinfo;
723 }
724 
JPEGSourceManager(j_decompress_ptr cinfo,Image * image)725 static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
726 {
727   SourceManager
728     *source;
729 
730   cinfo->src=(struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
731     ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(SourceManager));
732   source=(SourceManager *) cinfo->src;
733   source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
734     ((j_common_ptr) cinfo,JPOOL_IMAGE,MagickMinBufferExtent*sizeof(JOCTET));
735   source=(SourceManager *) cinfo->src;
736   source->manager.init_source=InitializeSource;
737   source->manager.fill_input_buffer=FillInputBuffer;
738   source->manager.skip_input_data=SkipInputData;
739   source->manager.resync_to_restart=jpeg_resync_to_restart;
740   source->manager.term_source=TerminateSource;
741   source->manager.bytes_in_buffer=0;
742   source->manager.next_input_byte=NULL;
743   source->image=image;
744 }
745 
JPEGSetImageQuality(struct jpeg_decompress_struct * jpeg_info,Image * image)746 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
747   Image *image)
748 {
749   image->quality=UndefinedCompressionQuality;
750 #if defined(D_PROGRESSIVE_SUPPORTED)
751   if (image->compression == LosslessJPEGCompression)
752     {
753       image->quality=100;
754       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
755         "Quality: 100 (lossless)");
756     }
757   else
758 #endif
759   {
760     ssize_t
761       j,
762       qvalue,
763       sum;
764 
765     ssize_t
766       i;
767 
768     /*
769       Determine the JPEG compression quality from the quantization tables.
770     */
771     sum=0;
772     for (i=0; i < NUM_QUANT_TBLS; i++)
773     {
774       if (jpeg_info->quant_tbl_ptrs[i] != NULL)
775         for (j=0; j < DCTSIZE2; j++)
776           sum+=jpeg_info->quant_tbl_ptrs[i]->quantval[j];
777     }
778     if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
779         (jpeg_info->quant_tbl_ptrs[1] != NULL))
780       {
781         ssize_t
782           hash[101] =
783           {
784             1020, 1015,  932,  848,  780,  735,  702,  679,  660,  645,
785              632,  623,  613,  607,  600,  594,  589,  585,  581,  571,
786              555,  542,  529,  514,  494,  474,  457,  439,  424,  410,
787              397,  386,  373,  364,  351,  341,  334,  324,  317,  309,
788              299,  294,  287,  279,  274,  267,  262,  257,  251,  247,
789              243,  237,  232,  227,  222,  217,  213,  207,  202,  198,
790              192,  188,  183,  177,  173,  168,  163,  157,  153,  148,
791              143,  139,  132,  128,  125,  119,  115,  108,  104,   99,
792               94,   90,   84,   79,   74,   70,   64,   59,   55,   49,
793               45,   40,   34,   30,   25,   20,   15,   11,    6,    4,
794                0
795           },
796           sums[101] =
797           {
798             32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104,
799             27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946,
800             23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998,
801             16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702,
802             12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208,
803              9928,  9747,  9564,  9369,  9193,  9017,  8822,  8639,  8458,
804              8270,  8084,  7896,  7710,  7527,  7347,  7156,  6977,  6788,
805              6607,  6422,  6236,  6054,  5867,  5684,  5495,  5305,  5128,
806              4945,  4751,  4638,  4442,  4248,  4065,  3888,  3698,  3509,
807              3326,  3139,  2957,  2775,  2586,  2405,  2216,  2037,  1846,
808              1666,  1483,  1297,  1109,   927,   735,   554,   375,   201,
809               128,     0
810           };
811 
812         qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
813           jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
814           jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
815           jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
816         for (i=0; i < 100; i++)
817         {
818           if ((qvalue < hash[i]) && (sum < sums[i]))
819             continue;
820           if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
821             image->quality=(size_t) i+1;
822           if (image->debug != MagickFalse)
823             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
824               "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
825               (sum <= sums[i]) ? "exact" : "approximate");
826           break;
827         }
828       }
829     else
830       if (jpeg_info->quant_tbl_ptrs[0] != NULL)
831         {
832           ssize_t
833             hash[101] =
834             {
835               510,  505,  422,  380,  355,  338,  326,  318,  311,  305,
836               300,  297,  293,  291,  288,  286,  284,  283,  281,  280,
837               279,  278,  277,  273,  262,  251,  243,  233,  225,  218,
838               211,  205,  198,  193,  186,  181,  177,  172,  168,  164,
839               158,  156,  152,  148,  145,  142,  139,  136,  133,  131,
840               129,  126,  123,  120,  118,  115,  113,  110,  107,  105,
841               102,  100,   97,   94,   92,   89,   87,   83,   81,   79,
842                76,   74,   70,   68,   66,   63,   61,   57,   55,   52,
843                50,   48,   44,   42,   39,   37,   34,   31,   29,   26,
844                24,   21,   18,   16,   13,   11,    8,    6,    3,    2,
845                 0
846             },
847             sums[101] =
848             {
849               16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859,
850               12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027,  9679,
851                9368,  9056,  8680,  8331,  7995,  7668,  7376,  7084,  6823,
852                6562,  6345,  6125,  5939,  5756,  5571,  5421,  5240,  5086,
853                4976,  4829,  4719,  4616,  4463,  4393,  4280,  4166,  4092,
854                3980,  3909,  3835,  3755,  3688,  3621,  3541,  3467,  3396,
855                3323,  3247,  3170,  3096,  3021,  2952,  2874,  2804,  2727,
856                2657,  2583,  2509,  2437,  2362,  2290,  2211,  2136,  2068,
857                1996,  1915,  1858,  1773,  1692,  1620,  1552,  1477,  1398,
858                1326,  1251,  1179,  1109,  1031,   961,   884,   814,   736,
859                 667,   592,   518,   441,   369,   292,   221,   151,    86,
860                  64,     0
861             };
862 
863           qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
864             jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
865           for (i=0; i < 100; i++)
866           {
867             if ((qvalue < hash[i]) && (sum < sums[i]))
868               continue;
869             if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
870               image->quality=(size_t)i+1;
871             if (image->debug != MagickFalse)
872               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
873                 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
874                 (sum <= sums[i]) ? "exact" : "approximate");
875             break;
876           }
877         }
878   }
879 }
880 
JPEGSetImageSamplingFactor(struct jpeg_decompress_struct * jpeg_info,Image * image,ExceptionInfo * exception)881 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info,  Image *image,ExceptionInfo *exception)
882 {
883   char
884     sampling_factor[MagickPathExtent];
885 
886   switch (jpeg_info->out_color_space)
887   {
888     case JCS_CMYK:
889     {
890       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
891       (void) FormatLocaleString(sampling_factor,MagickPathExtent,
892         "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
893         jpeg_info->comp_info[0].v_samp_factor,
894         jpeg_info->comp_info[1].h_samp_factor,
895         jpeg_info->comp_info[1].v_samp_factor,
896         jpeg_info->comp_info[2].h_samp_factor,
897         jpeg_info->comp_info[2].v_samp_factor,
898         jpeg_info->comp_info[3].h_samp_factor,
899         jpeg_info->comp_info[3].v_samp_factor);
900       break;
901     }
902     case JCS_GRAYSCALE:
903     {
904       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
905         "Colorspace: GRAYSCALE");
906       (void) FormatLocaleString(sampling_factor,MagickPathExtent,"%dx%d",
907         jpeg_info->comp_info[0].h_samp_factor,
908         jpeg_info->comp_info[0].v_samp_factor);
909       break;
910     }
911     case JCS_RGB:
912     {
913       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
914       (void) FormatLocaleString(sampling_factor,MagickPathExtent,
915         "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
916         jpeg_info->comp_info[0].v_samp_factor,
917         jpeg_info->comp_info[1].h_samp_factor,
918         jpeg_info->comp_info[1].v_samp_factor,
919         jpeg_info->comp_info[2].h_samp_factor,
920         jpeg_info->comp_info[2].v_samp_factor);
921       break;
922     }
923     default:
924     {
925       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
926         jpeg_info->out_color_space);
927       (void) FormatLocaleString(sampling_factor,MagickPathExtent,
928         "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
929         jpeg_info->comp_info[0].v_samp_factor,
930         jpeg_info->comp_info[1].h_samp_factor,
931         jpeg_info->comp_info[1].v_samp_factor,
932         jpeg_info->comp_info[2].h_samp_factor,
933         jpeg_info->comp_info[2].v_samp_factor,
934         jpeg_info->comp_info[3].h_samp_factor,
935         jpeg_info->comp_info[3].v_samp_factor);
936       break;
937     }
938   }
939   (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor,
940     exception);
941   (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
942     sampling_factor);
943 }
944 
JPEGDestroyDecompress(j_decompress_ptr jpeg_info)945 static void JPEGDestroyDecompress(j_decompress_ptr jpeg_info)
946 {
947   ErrorManager
948     *error_manager;
949 
950   size_t
951     i;
952 
953   error_manager=(ErrorManager *) jpeg_info->client_data;
954   for (i=0; i < 16; i++)
955   {
956     if (error_manager->profiles[i] != (StringInfo *) NULL)
957       error_manager->profiles[i]=DestroyStringInfo(error_manager->profiles[i]);
958   }
959   jpeg_destroy_decompress(jpeg_info);
960 }
961 
JPEGSetImageProfiles(ErrorManager * error_manager)962 static MagickBooleanType JPEGSetImageProfiles(ErrorManager *error_manager)
963 {
964   ExceptionInfo
965     *exception;
966 
967   Image
968     *image;
969 
970   MagickBooleanType
971     status;
972 
973   unsigned char
974     *p;
975 
976   ssize_t
977     i;
978 
979   StringInfo
980     *profile;
981 
982   exception=error_manager->exception;
983   image=error_manager->image;
984   status=MagickTrue;
985   for (i=0; i < 16; i++)
986   {
987     profile=error_manager->profiles[i];
988     if (profile == (StringInfo *) NULL)
989       continue;
990     switch (i)
991     {
992       case COMMENT_INDEX:
993       {
994         p=GetStringInfoDatum(profile);
995         status=SetImageProperty(image,"comment",(const char *) p,exception);
996         break;
997       }
998       case ICC_INDEX:
999       {
1000         status=SetImageProfile(image,"icc",profile,exception);
1001         break;
1002       }
1003       case IPTC_INDEX:
1004       {
1005         /*
1006           The IPTC profile is actually an 8bim.
1007         */
1008         status=SetImageProfile(image,"8bim",profile,exception);
1009         break;
1010       }
1011       default:
1012       {
1013         char
1014           name[6];
1015 
1016         (void) FormatLocaleString(name,sizeof(name),"APP%d",(int) i);
1017         status=SetImageProfile(image,name,profile,exception);
1018         break;
1019       }
1020     }
1021     error_manager->profiles[i]=DestroyStringInfo(error_manager->profiles[i]);
1022     if (status == MagickFalse)
1023       break;
1024   }
1025   return(status);
1026 }
1027 
ReadJPEGImage_(const ImageInfo * image_info,struct jpeg_decompress_struct * jpeg_info,ExceptionInfo * exception)1028 static Image *ReadJPEGImage_(const ImageInfo *image_info,
1029   struct jpeg_decompress_struct *jpeg_info,ExceptionInfo *exception)
1030 {
1031   char
1032     value[MagickPathExtent];
1033 
1034   const char
1035     *dct_method,
1036     *option;
1037 
1038   ErrorManager
1039     error_manager;
1040 
1041   Image
1042     *image;
1043 
1044   JSAMPLE
1045     *volatile jpeg_pixels;
1046 
1047   JSAMPROW
1048     scanline[1];
1049 
1050   MagickBooleanType
1051     debug,
1052     status;
1053 
1054   MagickSizeType
1055     number_pixels;
1056 
1057   MemoryInfo
1058     *memory_info;
1059 
1060   Quantum
1061     index;
1062 
1063   ssize_t
1064     i;
1065 
1066   struct jpeg_error_mgr
1067     jpeg_error;
1068 
1069   struct jpeg_progress_mgr
1070     jpeg_progress;
1071 
1072   JSAMPLE
1073     *p;
1074 
1075   size_t
1076     units;
1077 
1078   ssize_t
1079     y;
1080 
1081   /*
1082     Open image file.
1083   */
1084   assert(image_info != (const ImageInfo *) NULL);
1085   assert(image_info->signature == MagickCoreSignature);
1086   if (image_info->debug != MagickFalse)
1087     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1088       image_info->filename);
1089   assert(exception != (ExceptionInfo *) NULL);
1090   assert(exception->signature == MagickCoreSignature);
1091   debug=IsEventLogging();
1092   (void) debug;
1093   image=AcquireImage(image_info,exception);
1094   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1095   if (status == MagickFalse)
1096     {
1097       image=DestroyImageList(image);
1098       return((Image *) NULL);
1099     }
1100   /*
1101     Verify that file size large enough to contain a JPEG datastream.
1102   */
1103   if (GetBlobSize(image) < 107)
1104     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
1105   /*
1106     Initialize JPEG parameters.
1107   */
1108   (void) memset(&error_manager,0,sizeof(error_manager));
1109   (void) memset(jpeg_info,0,sizeof(*jpeg_info));
1110   (void) memset(&jpeg_error,0,sizeof(jpeg_error));
1111   (void) memset(&jpeg_progress,0,sizeof(jpeg_progress));
1112   jpeg_info->err=jpeg_std_error(&jpeg_error);
1113   jpeg_info->err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1114   jpeg_info->err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1115   memory_info=(MemoryInfo *) NULL;
1116   error_manager.exception=exception;
1117   error_manager.image=image;
1118   if (setjmp(error_manager.error_recovery) != 0)
1119     {
1120       JPEGDestroyDecompress(jpeg_info);
1121       (void) CloseBlob(image);
1122       if (exception->severity < ErrorException)
1123         return(GetFirstImageInList(image));
1124       return(DestroyImage(image));
1125     }
1126   jpeg_info->client_data=(void *) &error_manager;
1127   jpeg_create_decompress(jpeg_info);
1128   if (GetMaxMemoryRequest() != ~0UL)
1129     jpeg_info->mem->max_memory_to_use=(long) GetMaxMemoryRequest();
1130   jpeg_progress.progress_monitor=(void (*)(j_common_ptr)) JPEGProgressHandler;
1131   jpeg_info->progress=(&jpeg_progress);
1132   JPEGSourceManager(jpeg_info,image);
1133   jpeg_set_marker_processor(jpeg_info,JPEG_COM,ReadComment);
1134   option=GetImageOption(image_info,"profile:skip");
1135   if (IsOptionMember("ICC",option) == MagickFalse)
1136     jpeg_set_marker_processor(jpeg_info,ICC_MARKER,ReadICCProfile);
1137   if (IsOptionMember("IPTC",option) == MagickFalse)
1138     jpeg_set_marker_processor(jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1139   if (IsOptionMember("APP",option) == MagickFalse)
1140     jpeg_set_marker_processor(jpeg_info,XML_MARKER,ReadXmlProfile);
1141   for (i=3; i < 16; i++)
1142     /* APP14 is ignored because this will change the colors of the image */
1143     if (i != IPTC_INDEX && i != 14)
1144       if (IsOptionMember("APP",option) == MagickFalse)
1145         jpeg_set_marker_processor(jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1146   i=(ssize_t) jpeg_read_header(jpeg_info,TRUE);
1147   if (IsYCbCrCompatibleColorspace(image_info->colorspace) != MagickFalse)
1148     jpeg_info->out_color_space=JCS_YCbCr;
1149   /*
1150     Set image resolution.
1151   */
1152   units=0;
1153   if ((jpeg_info->saw_JFIF_marker != 0) && (jpeg_info->X_density != 1) &&
1154       (jpeg_info->Y_density != 1))
1155     {
1156       image->resolution.x=(double) jpeg_info->X_density;
1157       image->resolution.y=(double) jpeg_info->Y_density;
1158       units=(size_t) jpeg_info->density_unit;
1159     }
1160   if (units == 1)
1161     image->units=PixelsPerInchResolution;
1162   if (units == 2)
1163     image->units=PixelsPerCentimeterResolution;
1164   number_pixels=(MagickSizeType) image->columns*image->rows;
1165   option=GetImageOption(image_info,"jpeg:size");
1166   if ((option != (const char *) NULL) &&
1167       (jpeg_info->out_color_space != JCS_YCbCr))
1168     {
1169       double
1170         scale_factor;
1171 
1172       GeometryInfo
1173         geometry_info;
1174 
1175       MagickStatusType
1176         flags;
1177 
1178       /*
1179         Scale the image.
1180       */
1181       flags=ParseGeometry(option,&geometry_info);
1182       if ((flags & SigmaValue) == 0)
1183         geometry_info.sigma=geometry_info.rho;
1184       jpeg_calc_output_dimensions(jpeg_info);
1185       image->magick_columns=jpeg_info->output_width;
1186       image->magick_rows=jpeg_info->output_height;
1187       scale_factor=1.0;
1188       if (geometry_info.rho != 0.0)
1189         scale_factor=jpeg_info->output_width/geometry_info.rho;
1190       if ((geometry_info.sigma != 0.0) &&
1191           (scale_factor > (jpeg_info->output_height/geometry_info.sigma)))
1192         scale_factor=jpeg_info->output_height/geometry_info.sigma;
1193       jpeg_info->scale_num=1U;
1194       jpeg_info->scale_denom=(unsigned int) scale_factor;
1195       jpeg_calc_output_dimensions(jpeg_info);
1196       if (image->debug != MagickFalse)
1197         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1198           "Scale factor: %.20g",(double) scale_factor);
1199     }
1200 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1201 #if defined(D_LOSSLESS_SUPPORTED)
1202   image->interlace=jpeg_info->process == JPROC_PROGRESSIVE ?
1203     JPEGInterlace : NoInterlace;
1204   image->compression=jpeg_info->process == JPROC_LOSSLESS ?
1205     LosslessJPEGCompression : JPEGCompression;
1206   if (jpeg_info->data_precision > 8)
1207     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1208       "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1209       image->filename);
1210   if (jpeg_info->data_precision == 16)
1211     jpeg_info->data_precision=12;
1212 #else
1213   image->interlace=jpeg_info->progressive_mode != 0 ? JPEGInterlace :
1214     NoInterlace;
1215   image->compression=JPEGCompression;
1216 #endif
1217 #else
1218   image->compression=JPEGCompression;
1219   image->interlace=JPEGInterlace;
1220 #endif
1221   option=GetImageOption(image_info,"jpeg:colors");
1222   if (option != (const char *) NULL)
1223     {
1224       /*
1225         Let the JPEG library quantize the image.
1226       */
1227       jpeg_info->quantize_colors=TRUE;
1228       jpeg_info->desired_number_of_colors=(int) StringToUnsignedLong(option);
1229     }
1230   option=GetImageOption(image_info,"jpeg:block-smoothing");
1231   if (option != (const char *) NULL)
1232     jpeg_info->do_block_smoothing=IsStringTrue(option) != MagickFalse ? TRUE :
1233       FALSE;
1234   dct_method=GetImageOption(image_info,"jpeg:dct-method");
1235   if (dct_method != (const char *) NULL)
1236     switch (*dct_method)
1237     {
1238       case 'D':
1239       case 'd':
1240       {
1241         if (LocaleCompare(dct_method,"default") == 0)
1242           jpeg_info->dct_method=JDCT_DEFAULT;
1243         break;
1244       }
1245       case 'F':
1246       case 'f':
1247       {
1248         if (LocaleCompare(dct_method,"fastest") == 0)
1249           jpeg_info->dct_method=JDCT_FASTEST;
1250         if (LocaleCompare(dct_method,"float") == 0)
1251           jpeg_info->dct_method=JDCT_FLOAT;
1252         break;
1253       }
1254       case 'I':
1255       case 'i':
1256       {
1257         if (LocaleCompare(dct_method,"ifast") == 0)
1258           jpeg_info->dct_method=JDCT_IFAST;
1259         if (LocaleCompare(dct_method,"islow") == 0)
1260           jpeg_info->dct_method=JDCT_ISLOW;
1261         break;
1262       }
1263     }
1264   option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1265   if (option != (const char *) NULL)
1266     jpeg_info->do_fancy_upsampling=IsStringTrue(option) != MagickFalse ? TRUE :
1267       FALSE;
1268   jpeg_calc_output_dimensions(jpeg_info);
1269   image->columns=jpeg_info->output_width;
1270   image->rows=jpeg_info->output_height;
1271   image->depth=(size_t) jpeg_info->data_precision;
1272   switch (jpeg_info->out_color_space)
1273   {
1274     case JCS_RGB:
1275     default:
1276     {
1277       (void) SetImageColorspace(image,sRGBColorspace,exception);
1278       break;
1279     }
1280     case JCS_GRAYSCALE:
1281     {
1282       (void) SetImageColorspace(image,GRAYColorspace,exception);
1283       break;
1284     }
1285     case JCS_YCbCr:
1286     {
1287       (void) SetImageColorspace(image,YCbCrColorspace,exception);
1288       break;
1289     }
1290     case JCS_CMYK:
1291     {
1292       (void) SetImageColorspace(image,CMYKColorspace,exception);
1293       break;
1294     }
1295   }
1296   if (IsITUFaxImage(image) != MagickFalse)
1297     {
1298       (void) SetImageColorspace(image,LabColorspace,exception);
1299       jpeg_info->out_color_space=JCS_YCbCr;
1300     }
1301   option=GetImageOption(image_info,"jpeg:colors");
1302   if (option != (const char *) NULL)
1303     if (AcquireImageColormap(image,StringToUnsignedLong(option),exception) == MagickFalse)
1304       {
1305         JPEGDestroyDecompress(jpeg_info);
1306         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1307       }
1308   if ((jpeg_info->output_components == 1) && (jpeg_info->quantize_colors == 0))
1309     {
1310       size_t
1311         colors;
1312 
1313       colors=(size_t) GetQuantumRange(image->depth)+1;
1314       if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1315         {
1316           JPEGDestroyDecompress(jpeg_info);
1317           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1318         }
1319     }
1320   if (image->debug != MagickFalse)
1321     {
1322       if (image->interlace != NoInterlace)
1323         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1324           "Interlace: progressive");
1325       else
1326         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1327           "Interlace: nonprogressive");
1328       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1329         (int) jpeg_info->data_precision);
1330       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1331         (int) jpeg_info->output_width,(int) jpeg_info->output_height);
1332     }
1333   JPEGSetImageQuality(jpeg_info,image);
1334   JPEGSetImageSamplingFactor(jpeg_info,image,exception);
1335   (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
1336     jpeg_info->out_color_space);
1337   (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1338 #if defined(D_ARITH_CODING_SUPPORTED)
1339   if (jpeg_info->arith_code == TRUE)
1340     (void) SetImageProperty(image,"jpeg:coding","arithmetic",exception);
1341 #endif
1342   if (JPEGSetImageProfiles(&error_manager) == MagickFalse)
1343     {
1344       JPEGDestroyDecompress(jpeg_info);
1345       return(DestroyImageList(image));
1346     }
1347   if (image_info->ping != MagickFalse)
1348     {
1349       JPEGDestroyDecompress(jpeg_info);
1350       (void) CloseBlob(image);
1351       return(GetFirstImageInList(image));
1352     }
1353   status=SetImageExtent(image,image->columns,image->rows,exception);
1354   if (status == MagickFalse)
1355     {
1356       JPEGDestroyDecompress(jpeg_info);
1357       return(DestroyImageList(image));
1358     }
1359   (void) jpeg_start_decompress(jpeg_info);
1360   if ((jpeg_info->output_components != 1) &&
1361       (jpeg_info->output_components != 3) && (jpeg_info->output_components != 4))
1362     {
1363       JPEGDestroyDecompress(jpeg_info);
1364       ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1365     }
1366   memory_info=AcquireVirtualMemory((size_t) image->columns,
1367     jpeg_info->output_components*sizeof(*jpeg_pixels));
1368   if (memory_info == (MemoryInfo *) NULL)
1369     {
1370       JPEGDestroyDecompress(jpeg_info);
1371       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1372     }
1373   jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1374   (void) memset(jpeg_pixels,0,image->columns*
1375     jpeg_info->output_components*sizeof(*jpeg_pixels));
1376   /*
1377     Convert JPEG pixels to pixel packets.
1378   */
1379   if (setjmp(error_manager.error_recovery) != 0)
1380     {
1381       if (memory_info != (MemoryInfo *) NULL)
1382         memory_info=RelinquishVirtualMemory(memory_info);
1383       JPEGDestroyDecompress(jpeg_info);
1384       (void) CloseBlob(image);
1385       number_pixels=(MagickSizeType) image->columns*image->rows;
1386       if (number_pixels != 0)
1387         return(GetFirstImageInList(image));
1388       return(DestroyImage(image));
1389     }
1390   if (jpeg_info->quantize_colors != 0)
1391     {
1392       image->colors=(size_t) jpeg_info->actual_number_of_colors;
1393       if (jpeg_info->out_color_space == JCS_GRAYSCALE)
1394         for (i=0; i < (ssize_t) image->colors; i++)
1395         {
1396           image->colormap[i].red=(double) ScaleCharToQuantum(
1397             jpeg_info->colormap[0][i]);
1398           image->colormap[i].green=image->colormap[i].red;
1399           image->colormap[i].blue=image->colormap[i].red;
1400           image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1401         }
1402       else
1403         for (i=0; i < (ssize_t) image->colors; i++)
1404         {
1405           image->colormap[i].red=(double) ScaleCharToQuantum(
1406             jpeg_info->colormap[0][i]);
1407           image->colormap[i].green=(double) ScaleCharToQuantum(
1408             jpeg_info->colormap[1][i]);
1409           image->colormap[i].blue=(double) ScaleCharToQuantum(
1410             jpeg_info->colormap[2][i]);
1411           image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1412         }
1413     }
1414   scanline[0]=(JSAMPROW) jpeg_pixels;
1415   for (y=0; y < (ssize_t) image->rows; y++)
1416   {
1417     ssize_t
1418       x;
1419 
1420     Quantum
1421       *magick_restrict q;
1422 
1423     if (jpeg_read_scanlines(jpeg_info,scanline,1) != 1)
1424       {
1425         (void) ThrowMagickException(exception,GetMagickModule(),
1426           CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1427         continue;
1428       }
1429     p=jpeg_pixels;
1430     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1431     if (q == (Quantum *) NULL)
1432       break;
1433     if (jpeg_info->data_precision > 8)
1434       {
1435         unsigned short
1436           scale;
1437 
1438         scale=65535/(unsigned short) GetQuantumRange((size_t)
1439           jpeg_info->data_precision);
1440         if (jpeg_info->output_components == 1)
1441           for (x=0; x < (ssize_t) image->columns; x++)
1442           {
1443             ssize_t
1444               pixel;
1445 
1446             pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1447             index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1448             SetPixelIndex(image,index,q);
1449             SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1450             p++;
1451             q+=GetPixelChannels(image);
1452           }
1453         else
1454           if (image->colorspace != CMYKColorspace)
1455             for (x=0; x < (ssize_t) image->columns; x++)
1456             {
1457               SetPixelRed(image,ScaleShortToQuantum(
1458                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1459               SetPixelGreen(image,ScaleShortToQuantum(
1460                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1461               SetPixelBlue(image,ScaleShortToQuantum(
1462                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1463               SetPixelAlpha(image,OpaqueAlpha,q);
1464               q+=GetPixelChannels(image);
1465             }
1466           else
1467             for (x=0; x < (ssize_t) image->columns; x++)
1468             {
1469               SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1470                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1471               SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1472                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1473               SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1474                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1475               SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1476                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1477               SetPixelAlpha(image,OpaqueAlpha,q);
1478               q+=GetPixelChannels(image);
1479             }
1480       }
1481     else
1482       if (jpeg_info->output_components == 1)
1483         for (x=0; x < (ssize_t) image->columns; x++)
1484         {
1485           ssize_t
1486             pixel;
1487 
1488           pixel=(ssize_t) GETJSAMPLE(*p);
1489           index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1490           SetPixelIndex(image,index,q);
1491           SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1492           p++;
1493           q+=GetPixelChannels(image);
1494         }
1495       else
1496         if (image->colorspace != CMYKColorspace)
1497           for (x=0; x < (ssize_t) image->columns; x++)
1498           {
1499             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1500               GETJSAMPLE(*p++)),q);
1501             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1502               GETJSAMPLE(*p++)),q);
1503             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1504               GETJSAMPLE(*p++)),q);
1505             SetPixelAlpha(image,OpaqueAlpha,q);
1506             q+=GetPixelChannels(image);
1507           }
1508         else
1509           for (x=0; x < (ssize_t) image->columns; x++)
1510           {
1511             SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1512               (unsigned char) GETJSAMPLE(*p++)),q);
1513             SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1514               (unsigned char) GETJSAMPLE(*p++)),q);
1515             SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1516               (unsigned char) GETJSAMPLE(*p++)),q);
1517             SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1518               (unsigned char) GETJSAMPLE(*p++)),q);
1519             SetPixelAlpha(image,OpaqueAlpha,q);
1520             q+=GetPixelChannels(image);
1521           }
1522     if (SyncAuthenticPixels(image,exception) == MagickFalse)
1523       break;
1524     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1525       image->rows);
1526     if (status == MagickFalse)
1527       {
1528         jpeg_abort_decompress(jpeg_info);
1529         break;
1530       }
1531   }
1532   if (status != MagickFalse)
1533     {
1534       error_manager.finished=MagickTrue;
1535       if (setjmp(error_manager.error_recovery) == 0)
1536         (void) jpeg_finish_decompress(jpeg_info);
1537     }
1538   /*
1539     Free jpeg resources.
1540   */
1541   JPEGDestroyDecompress(jpeg_info);
1542   memory_info=RelinquishVirtualMemory(memory_info);
1543   (void) CloseBlob(image);
1544   return(GetFirstImageInList(image));
1545 }
1546 
ReadJPEGImage(const ImageInfo * image_info,ExceptionInfo * exception)1547 static Image *ReadJPEGImage(const ImageInfo *image_info,
1548   ExceptionInfo *exception)
1549 {
1550   struct jpeg_decompress_struct
1551     jpeg_info;
1552 
1553   return(ReadJPEGImage_(image_info,&jpeg_info,exception));
1554 }
1555 #endif
1556 
1557 /*
1558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559 %                                                                             %
1560 %                                                                             %
1561 %                                                                             %
1562 %   R e g i s t e r J P E G I m a g e                                         %
1563 %                                                                             %
1564 %                                                                             %
1565 %                                                                             %
1566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567 %
1568 %  RegisterJPEGImage() adds properties for the JPEG image format to
1569 %  the list of supported formats.  The properties include the image format
1570 %  tag, a method to read and/or write the format, whether the format
1571 %  supports the saving of more than one frame to the same file or blob,
1572 %  whether the format supports native in-memory I/O, and a brief
1573 %  description of the format.
1574 %
1575 %  The format of the RegisterJPEGImage method is:
1576 %
1577 %      size_t RegisterJPEGImage(void)
1578 %
1579 */
RegisterJPEGImage(void)1580 ModuleExport size_t RegisterJPEGImage(void)
1581 {
1582 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1583 #define JPEGStringify(macro_or_string)  JPEGStringifyArg(macro_or_string)
1584 #define JPEGStringifyArg(contents)  #contents
1585 
1586   char
1587     version[MagickPathExtent];
1588 
1589   MagickInfo
1590     *entry;
1591 
1592   *version='\0';
1593 #if defined(LIBJPEG_TURBO_VERSION)
1594   (void) CopyMagickString(version,"libjpeg-turbo " JPEGStringify(
1595     LIBJPEG_TURBO_VERSION),MagickPathExtent);
1596 #elif defined(JPEG_LIB_VERSION)
1597   (void) FormatLocaleString(version,MagickPathExtent,"libjpeg %d",
1598     JPEG_LIB_VERSION);
1599 #endif
1600   entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1601 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1602   entry->flags^=CoderDecoderThreadSupportFlag;
1603 #endif
1604 #if defined(MAGICKCORE_JPEG_DELEGATE)
1605   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1606   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1607 #endif
1608   entry->magick=(IsImageFormatHandler *) IsJPEG;
1609   entry->flags|=CoderDecoderSeekableStreamFlag;
1610   entry->flags^=CoderAdjoinFlag;
1611   entry->flags^=CoderUseExtensionFlag;
1612   if (*version != '\0')
1613     entry->version=ConstantString(version);
1614   entry->mime_type=ConstantString("image/jpeg");
1615   (void) RegisterMagickInfo(entry);
1616   entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1617 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1618   entry->flags^=CoderDecoderThreadSupportFlag;
1619 #endif
1620 #if defined(MAGICKCORE_JPEG_DELEGATE)
1621   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1622   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1623 #endif
1624   entry->magick=(IsImageFormatHandler *) IsJPEG;
1625   entry->flags|=CoderDecoderSeekableStreamFlag;
1626   entry->flags^=CoderAdjoinFlag;
1627   if (*version != '\0')
1628     entry->version=ConstantString(version);
1629   entry->mime_type=ConstantString("image/jpeg");
1630   (void) RegisterMagickInfo(entry);
1631   entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1632 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1633   entry->flags^=CoderDecoderThreadSupportFlag;
1634 #endif
1635 #if defined(MAGICKCORE_JPEG_DELEGATE)
1636   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1637   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1638 #endif
1639   entry->flags|=CoderDecoderSeekableStreamFlag;
1640   entry->flags^=CoderAdjoinFlag;
1641   entry->flags^=CoderUseExtensionFlag;
1642   if (*version != '\0')
1643     entry->version=ConstantString(version);
1644   entry->mime_type=ConstantString("image/jpeg");
1645   (void) RegisterMagickInfo(entry);
1646   entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1647 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1648   entry->flags^=CoderDecoderThreadSupportFlag;
1649 #endif
1650 #if defined(MAGICKCORE_JPEG_DELEGATE)
1651   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1652   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1653 #endif
1654   entry->flags|=CoderDecoderSeekableStreamFlag;
1655   entry->flags^=CoderAdjoinFlag;
1656   entry->flags^=CoderUseExtensionFlag;
1657   if (*version != '\0')
1658     entry->version=ConstantString(version);
1659   entry->mime_type=ConstantString("image/jpeg");
1660   (void) RegisterMagickInfo(entry);
1661   entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1662 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1663   entry->flags^=CoderDecoderThreadSupportFlag;
1664 #endif
1665 #if defined(MAGICKCORE_JPEG_DELEGATE)
1666   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1667   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1668 #endif
1669   entry->flags|=CoderDecoderSeekableStreamFlag;
1670   entry->flags^=CoderAdjoinFlag;
1671   entry->flags^=CoderUseExtensionFlag;
1672   if (*version != '\0')
1673     entry->version=ConstantString(version);
1674   entry->mime_type=ConstantString("image/jpeg");
1675   (void) RegisterMagickInfo(entry);
1676   return(MagickImageCoderSignature);
1677 }
1678 
1679 /*
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1681 %                                                                             %
1682 %                                                                             %
1683 %                                                                             %
1684 %   U n r e g i s t e r J P E G I m a g e                                     %
1685 %                                                                             %
1686 %                                                                             %
1687 %                                                                             %
1688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1689 %
1690 %  UnregisterJPEGImage() removes format registrations made by the
1691 %  JPEG module from the list of supported formats.
1692 %
1693 %  The format of the UnregisterJPEGImage method is:
1694 %
1695 %      UnregisterJPEGImage(void)
1696 %
1697 */
UnregisterJPEGImage(void)1698 ModuleExport void UnregisterJPEGImage(void)
1699 {
1700   (void) UnregisterMagickInfo("PJPG");
1701   (void) UnregisterMagickInfo("JPS");
1702   (void) UnregisterMagickInfo("JPG");
1703   (void) UnregisterMagickInfo("JPEG");
1704   (void) UnregisterMagickInfo("JPE");
1705 }
1706 
1707 #if defined(MAGICKCORE_JPEG_DELEGATE)
1708 /*
1709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1710 %                                                                             %
1711 %                                                                             %
1712 %                                                                             %
1713 %  W r i t e J P E G I m a g e                                                %
1714 %                                                                             %
1715 %                                                                             %
1716 %                                                                             %
1717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1718 %
1719 %  WriteJPEGImage() writes a JPEG image file and returns it.  It
1720 %  allocates the memory necessary for the new Image structure and returns a
1721 %  pointer to the new image.
1722 %
1723 %  The format of the WriteJPEGImage method is:
1724 %
1725 %      MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1726 %        Image *image,ExceptionInfo *exception)
1727 %
1728 %  A description of each parameter follows:
1729 %
1730 %    o image_info: the image info.
1731 %
1732 %    o jpeg_image:  The image.
1733 %
1734 %    o exception: return any errors or warnings in this structure.
1735 %
1736 */
1737 
DestroyQuantizationTable(QuantizationTable * table)1738 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1739 {
1740   assert(table != (QuantizationTable *) NULL);
1741   if (table->slot != (char *) NULL)
1742     table->slot=DestroyString(table->slot);
1743   if (table->description != (char *) NULL)
1744     table->description=DestroyString(table->description);
1745   if (table->levels != (unsigned int *) NULL)
1746     table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1747   table=(QuantizationTable *) RelinquishMagickMemory(table);
1748   return(table);
1749 }
1750 
EmptyOutputBuffer(j_compress_ptr cinfo)1751 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1752 {
1753   DestinationManager
1754     *destination;
1755 
1756   destination=(DestinationManager *) cinfo->dest;
1757   destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1758     MagickMinBufferExtent,destination->buffer);
1759   if (destination->manager.free_in_buffer != MagickMinBufferExtent)
1760     ERREXIT(cinfo,JERR_FILE_WRITE);
1761   destination->manager.next_output_byte=destination->buffer;
1762   return(TRUE);
1763 }
1764 
GetQuantizationTable(const char * filename,const char * slot,ExceptionInfo * exception)1765 static QuantizationTable *GetQuantizationTable(const char *filename,
1766   const char *slot,ExceptionInfo *exception)
1767 {
1768   char
1769     *p,
1770     *xml;
1771 
1772   const char
1773     *attribute,
1774     *content;
1775 
1776   double
1777     value;
1778 
1779   ssize_t
1780     i;
1781 
1782   ssize_t
1783     j;
1784 
1785   QuantizationTable
1786     *table;
1787 
1788   size_t
1789     length;
1790 
1791   XMLTreeInfo
1792     *description,
1793     *levels,
1794     *quantization_tables,
1795     *table_iterator;
1796 
1797   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1798     "Loading quantization tables \"%s\" ...",filename);
1799   table=(QuantizationTable *) NULL;
1800   xml=FileToString(filename,~0UL,exception);
1801   if (xml == (char *) NULL)
1802     return(table);
1803   quantization_tables=NewXMLTree(xml,exception);
1804   if (quantization_tables == (XMLTreeInfo *) NULL)
1805     {
1806       xml=DestroyString(xml);
1807       return(table);
1808     }
1809   for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1810        table_iterator != (XMLTreeInfo *) NULL;
1811        table_iterator=GetNextXMLTreeTag(table_iterator))
1812   {
1813     attribute=GetXMLTreeAttribute(table_iterator,"slot");
1814     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1815       break;
1816     attribute=GetXMLTreeAttribute(table_iterator,"alias");
1817     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1818       break;
1819   }
1820   if (table_iterator == (XMLTreeInfo *) NULL)
1821     {
1822       xml=DestroyString(xml);
1823       return(table);
1824     }
1825   description=GetXMLTreeChild(table_iterator,"description");
1826   if (description == (XMLTreeInfo *) NULL)
1827     {
1828       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1829         "XmlMissingElement","<description>, slot \"%s\"",slot);
1830       quantization_tables=DestroyXMLTree(quantization_tables);
1831       xml=DestroyString(xml);
1832       return(table);
1833     }
1834   levels=GetXMLTreeChild(table_iterator,"levels");
1835   if (levels == (XMLTreeInfo *) NULL)
1836     {
1837       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1838         "XmlMissingElement","<levels>, slot \"%s\"",slot);
1839       quantization_tables=DestroyXMLTree(quantization_tables);
1840       xml=DestroyString(xml);
1841       return(table);
1842     }
1843   table=(QuantizationTable *) AcquireCriticalMemory(sizeof(*table));
1844   table->slot=(char *) NULL;
1845   table->description=(char *) NULL;
1846   table->levels=(unsigned int *) NULL;
1847   attribute=GetXMLTreeAttribute(table_iterator,"slot");
1848   if (attribute != (char *) NULL)
1849     table->slot=ConstantString(attribute);
1850   content=GetXMLTreeContent(description);
1851   if (content != (char *) NULL)
1852     table->description=ConstantString(content);
1853   attribute=GetXMLTreeAttribute(levels,"width");
1854   if (attribute == (char *) NULL)
1855     {
1856       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1857         "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1858       quantization_tables=DestroyXMLTree(quantization_tables);
1859       table=DestroyQuantizationTable(table);
1860       xml=DestroyString(xml);
1861       return(table);
1862     }
1863   table->width=StringToUnsignedLong(attribute);
1864   if (table->width == 0)
1865     {
1866       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1867        "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1868       quantization_tables=DestroyXMLTree(quantization_tables);
1869       table=DestroyQuantizationTable(table);
1870       xml=DestroyString(xml);
1871       return(table);
1872     }
1873   attribute=GetXMLTreeAttribute(levels,"height");
1874   if (attribute == (char *) NULL)
1875     {
1876       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1877         "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1878       quantization_tables=DestroyXMLTree(quantization_tables);
1879       table=DestroyQuantizationTable(table);
1880       xml=DestroyString(xml);
1881       return(table);
1882     }
1883   table->height=StringToUnsignedLong(attribute);
1884   if (table->height == 0)
1885     {
1886       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1887         "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1888       quantization_tables=DestroyXMLTree(quantization_tables);
1889       table=DestroyQuantizationTable(table);
1890       xml=DestroyString(xml);
1891       return(table);
1892     }
1893   attribute=GetXMLTreeAttribute(levels,"divisor");
1894   if (attribute == (char *) NULL)
1895     {
1896       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1897         "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1898       quantization_tables=DestroyXMLTree(quantization_tables);
1899       table=DestroyQuantizationTable(table);
1900       xml=DestroyString(xml);
1901       return(table);
1902     }
1903   table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1904   if (table->divisor == 0.0)
1905     {
1906       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1907         "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1908       quantization_tables=DestroyXMLTree(quantization_tables);
1909       table=DestroyQuantizationTable(table);
1910       xml=DestroyString(xml);
1911       return(table);
1912     }
1913   content=GetXMLTreeContent(levels);
1914   if (content == (char *) NULL)
1915     {
1916       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1917         "XmlMissingContent","<levels>, table \"%s\"",slot);
1918       quantization_tables=DestroyXMLTree(quantization_tables);
1919       table=DestroyQuantizationTable(table);
1920       xml=DestroyString(xml);
1921       return(table);
1922     }
1923   length=(size_t) table->width*table->height;
1924   if (length < 64)
1925     length=64;
1926   table->levels=(unsigned int *) AcquireQuantumMemory(length,
1927     sizeof(*table->levels));
1928   if (table->levels == (unsigned int *) NULL)
1929     ThrowFatalException(ResourceLimitFatalError,
1930       "UnableToAcquireQuantizationTable");
1931   for (i=0; i < (ssize_t) (table->width*table->height); i++)
1932   {
1933     table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1934       table->divisor+0.5);
1935     while (isspace((int) ((unsigned char) *p)) != 0)
1936       p++;
1937     if (*p == ',')
1938       p++;
1939     content=p;
1940   }
1941   value=InterpretLocaleValue(content,&p);
1942   (void) value;
1943   if (p != content)
1944     {
1945       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1946         "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1947      quantization_tables=DestroyXMLTree(quantization_tables);
1948      table=DestroyQuantizationTable(table);
1949      xml=DestroyString(xml);
1950      return(table);
1951    }
1952   for (j=i; j < 64; j++)
1953     table->levels[j]=table->levels[j-1];
1954   quantization_tables=DestroyXMLTree(quantization_tables);
1955   xml=DestroyString(xml);
1956   return(table);
1957 }
1958 
InitializeDestination(j_compress_ptr cinfo)1959 static void InitializeDestination(j_compress_ptr cinfo)
1960 {
1961   DestinationManager
1962     *destination;
1963 
1964   destination=(DestinationManager *) cinfo->dest;
1965   destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1966     ((j_common_ptr) cinfo,JPOOL_IMAGE,MagickMinBufferExtent*sizeof(JOCTET));
1967   destination->manager.next_output_byte=destination->buffer;
1968   destination->manager.free_in_buffer=MagickMinBufferExtent;
1969 }
1970 
TerminateDestination(j_compress_ptr cinfo)1971 static void TerminateDestination(j_compress_ptr cinfo)
1972 {
1973   DestinationManager
1974     *destination;
1975 
1976   destination=(DestinationManager *) cinfo->dest;
1977   if ((MagickMinBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1978     {
1979       ssize_t
1980         count;
1981 
1982       count=WriteBlob(destination->image,MagickMinBufferExtent-
1983         destination->manager.free_in_buffer,destination->buffer);
1984       if (count != (ssize_t)
1985           (MagickMinBufferExtent-destination->manager.free_in_buffer))
1986         ERREXIT(cinfo,JERR_FILE_WRITE);
1987     }
1988 }
1989 
WriteProfile(j_compress_ptr jpeg_info,Image * image,ExceptionInfo * exception)1990 static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
1991   ExceptionInfo *exception)
1992 {
1993   const char
1994     *name;
1995 
1996   const StringInfo
1997     *profile;
1998 
1999   MagickBooleanType
2000     iptc;
2001 
2002   ssize_t
2003     i;
2004 
2005   size_t
2006     length,
2007     tag_length;
2008 
2009   StringInfo
2010     *custom_profile;
2011 
2012   /*
2013     Save image profile as a APP marker.
2014   */
2015   iptc=MagickFalse;
2016   custom_profile=AcquireStringInfo(65535L);
2017   ResetImageProfileIterator(image);
2018   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2019   {
2020     profile=GetImageProfile(image,name);
2021     length=GetStringInfoLength(profile);
2022     if (LocaleNCompare(name,"APP",3) == 0)
2023       {
2024         int
2025           id;
2026 
2027         id=JPEG_APP0+StringToInteger(name+3);
2028         for (i=0; i < (ssize_t) length; i+=65533L)
2029            jpeg_write_marker(jpeg_info,id,GetStringInfoDatum(profile)+i,
2030              (unsigned int) MagickMin(length-i,65533));
2031       }
2032     if (LocaleCompare(name,"EXIF") == 0)
2033       {
2034         length=GetStringInfoLength(profile);
2035         if (length > 65533L)
2036           {
2037             (void) ThrowMagickException(exception,GetMagickModule(),
2038               CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
2039               image->filename);
2040             length=65533L;
2041           }
2042         jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
2043           (unsigned int) length);
2044       }
2045     if (LocaleCompare(name,"ICC") == 0)
2046       {
2047         unsigned char
2048           *p;
2049 
2050         tag_length=strlen(ICC_PROFILE);
2051         p=GetStringInfoDatum(custom_profile);
2052         (void) memcpy(p,ICC_PROFILE,tag_length);
2053         p[tag_length]='\0';
2054         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
2055         {
2056           length=MagickMin(GetStringInfoLength(profile)-i,65519L);
2057           p[12]=(unsigned char) ((i/65519L)+1);
2058           p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
2059           (void) memcpy(p+tag_length+3,GetStringInfoDatum(profile)+i,
2060             length);
2061           jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
2062             custom_profile),(unsigned int) (length+tag_length+3));
2063         }
2064       }
2065     if (((LocaleCompare(name,"IPTC") == 0) ||
2066         (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
2067       {
2068         unsigned char
2069           *p;
2070 
2071         size_t
2072           roundup;
2073 
2074         iptc=MagickTrue;
2075         p=GetStringInfoDatum(custom_profile);
2076         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
2077         {
2078           length=MagickMin(GetStringInfoLength(profile)-i,65500L);
2079           roundup=(size_t) (length & 0x01);
2080           if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
2081             {
2082               (void) memcpy(p,"Photoshop 3.0 ",14);
2083               tag_length=14;
2084             }
2085           else
2086             {
2087               (void) memcpy(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2088               tag_length=26;
2089               p[24]=(unsigned char) (length >> 8);
2090               p[25]=(unsigned char) (length & 0xff);
2091             }
2092           p[13]=0x00;
2093           (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2094           if (roundup != 0)
2095             p[length+tag_length]='\0';
2096           jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2097             custom_profile),(unsigned int) (length+tag_length+roundup));
2098         }
2099       }
2100    if ((LocaleCompare(name,"XMP") == 0) &&
2101        (GetStringInfoLength(profile) < (65533 - sizeof(xmp_namespace))))
2102       {
2103         StringInfo
2104           *xmp_profile;
2105 
2106         /*
2107           Add namespace to XMP profile.
2108         */
2109         xmp_profile=StringToStringInfo(xmp_namespace);
2110         if (xmp_profile != (StringInfo *) NULL)
2111           {
2112             ConcatenateStringInfo(xmp_profile,profile);
2113             GetStringInfoDatum(xmp_profile)[XmpNamespaceExtent]='\0';
2114             length=GetStringInfoLength(xmp_profile);
2115             jpeg_write_marker(jpeg_info,XML_MARKER,
2116               GetStringInfoDatum(xmp_profile),(unsigned int) length);
2117             xmp_profile=DestroyStringInfo(xmp_profile);
2118           }
2119       }
2120     if (image->debug != MagickFalse)
2121       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2122         "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2123     name=GetNextImageProfile(image);
2124   }
2125   custom_profile=DestroyStringInfo(custom_profile);
2126 }
2127 
JPEGDestinationManager(j_compress_ptr cinfo,Image * image)2128 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2129 {
2130   DestinationManager
2131     *destination;
2132 
2133   cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2134     ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2135   destination=(DestinationManager *) cinfo->dest;
2136   destination->manager.init_destination=InitializeDestination;
2137   destination->manager.empty_output_buffer=EmptyOutputBuffer;
2138   destination->manager.term_destination=TerminateDestination;
2139   destination->image=image;
2140 }
2141 
SamplingFactorToList(const char * text)2142 static char **SamplingFactorToList(const char *text)
2143 {
2144   char
2145     **textlist;
2146 
2147   char
2148     *q;
2149 
2150   const char
2151     *p;
2152 
2153   ssize_t
2154     i;
2155 
2156   if (text == (char *) NULL)
2157     return((char **) NULL);
2158   /*
2159     Convert string to an ASCII list.
2160   */
2161   textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2162     sizeof(*textlist));
2163   if (textlist == (char **) NULL)
2164     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2165   p=text;
2166   for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2167   {
2168     for (q=(char *) p; *q != '\0'; q++)
2169       if (*q == ',')
2170         break;
2171     textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2172       sizeof(*textlist[i]));
2173     if (textlist[i] == (char *) NULL)
2174       ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2175     (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2176     if (*q == '\r')
2177       q++;
2178     if (*q == '\0')
2179       break;
2180     p=q+1;
2181   }
2182   for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2183     textlist[i]=ConstantString("1x1");
2184   return(textlist);
2185 }
2186 
WriteJPEGImage_(const ImageInfo * image_info,Image * image,struct jpeg_compress_struct * jpeg_info,ExceptionInfo * exception)2187 static MagickBooleanType WriteJPEGImage_(const ImageInfo *image_info,
2188   Image *image,struct jpeg_compress_struct *jpeg_info,ExceptionInfo *exception)
2189 {
2190   const char
2191     *dct_method,
2192     *option,
2193     *sampling_factor,
2194     *value;
2195 
2196   ErrorManager
2197     error_manager;
2198 
2199   Image
2200     *volatile volatile_image;
2201 
2202   int
2203     colorspace,
2204     quality;
2205 
2206   JSAMPLE
2207     *volatile jpeg_pixels;
2208 
2209   JSAMPROW
2210     scanline[1];
2211 
2212   MagickBooleanType
2213     status;
2214 
2215   MemoryInfo
2216     *memory_info;
2217 
2218   JSAMPLE
2219     *q;
2220 
2221   ssize_t
2222     i;
2223 
2224   ssize_t
2225     y;
2226 
2227   struct jpeg_error_mgr
2228     jpeg_error;
2229 
2230   unsigned short
2231     scale;
2232 
2233   /*
2234     Open image file.
2235   */
2236   assert(image_info != (const ImageInfo *) NULL);
2237   assert(image_info->signature == MagickCoreSignature);
2238   assert(image != (Image *) NULL);
2239   assert(image->signature == MagickCoreSignature);
2240   if (image->debug != MagickFalse)
2241     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2242   assert(exception != (ExceptionInfo *) NULL);
2243   assert(exception->signature == MagickCoreSignature);
2244   if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2245       (image->next != (Image *) NULL))
2246     image=AppendImages(image,MagickFalse,exception);
2247   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2248   if (status == MagickFalse)
2249     return(status);
2250   /*
2251     Initialize JPEG parameters.
2252   */
2253   (void) memset(&error_manager,0,sizeof(error_manager));
2254   (void) memset(jpeg_info,0,sizeof(*jpeg_info));
2255   (void) memset(&jpeg_error,0,sizeof(jpeg_error));
2256   volatile_image=image;
2257   jpeg_info->client_data=(void *) volatile_image;
2258   jpeg_info->err=jpeg_std_error(&jpeg_error);
2259   jpeg_info->err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2260   jpeg_info->err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2261   error_manager.exception=exception;
2262   error_manager.image=volatile_image;
2263   memory_info=(MemoryInfo *) NULL;
2264   if (setjmp(error_manager.error_recovery) != 0)
2265     {
2266       jpeg_destroy_compress(jpeg_info);
2267       (void) CloseBlob(volatile_image);
2268       return(MagickFalse);
2269     }
2270   jpeg_info->client_data=(void *) &error_manager;
2271   jpeg_create_compress(jpeg_info);
2272   JPEGDestinationManager(jpeg_info,image);
2273   if ((image->columns != (unsigned int) image->columns) ||
2274       (image->rows != (unsigned int) image->rows))
2275     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2276   jpeg_info->image_width=(unsigned int) image->columns;
2277   jpeg_info->image_height=(unsigned int) image->rows;
2278   jpeg_info->input_components=3;
2279   jpeg_info->data_precision=8;
2280   jpeg_info->in_color_space=JCS_RGB;
2281   switch (image->colorspace)
2282   {
2283     case CMYKColorspace:
2284     {
2285       jpeg_info->input_components=4;
2286       jpeg_info->in_color_space=JCS_CMYK;
2287       break;
2288     }
2289     case YCbCrColorspace:
2290     case Rec601YCbCrColorspace:
2291     case Rec709YCbCrColorspace:
2292     {
2293       jpeg_info->in_color_space=JCS_YCbCr;
2294       break;
2295     }
2296     case LinearGRAYColorspace:
2297     case GRAYColorspace:
2298     {
2299       if (image_info->type == TrueColorType)
2300         break;
2301       jpeg_info->input_components=1;
2302       jpeg_info->in_color_space=JCS_GRAYSCALE;
2303       break;
2304     }
2305     default:
2306     {
2307       (void) TransformImageColorspace(image,sRGBColorspace,exception);
2308       if (image_info->type == TrueColorType)
2309         break;
2310       if (SetImageGray(image,exception) != MagickFalse)
2311         {
2312           jpeg_info->input_components=1;
2313           jpeg_info->in_color_space=JCS_GRAYSCALE;
2314         }
2315       break;
2316     }
2317   }
2318   jpeg_set_defaults(jpeg_info);
2319   if (jpeg_info->in_color_space == JCS_CMYK)
2320     jpeg_set_colorspace(jpeg_info,JCS_YCCK);
2321   if ((jpeg_info->data_precision != 12) && (image->depth <= 8))
2322     jpeg_info->data_precision=8;
2323   else
2324     jpeg_info->data_precision=BITS_IN_JSAMPLE;
2325   if (image->debug != MagickFalse)
2326     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2327       "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2328   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2329     {
2330       /*
2331         Set image resolution.
2332       */
2333       jpeg_info->write_JFIF_header=TRUE;
2334       jpeg_info->X_density=(UINT16) image->resolution.x;
2335       jpeg_info->Y_density=(UINT16) image->resolution.y;
2336       /*
2337         Set image resolution units.
2338       */
2339       if (image->units == PixelsPerInchResolution)
2340         jpeg_info->density_unit=(UINT8) 1;
2341       if (image->units == PixelsPerCentimeterResolution)
2342         jpeg_info->density_unit=(UINT8) 2;
2343     }
2344   dct_method=GetImageOption(image_info,"jpeg:dct-method");
2345   if (dct_method != (const char *) NULL)
2346     switch (*dct_method)
2347     {
2348       case 'D':
2349       case 'd':
2350       {
2351         if (LocaleCompare(dct_method,"default") == 0)
2352           jpeg_info->dct_method=JDCT_DEFAULT;
2353         break;
2354       }
2355       case 'F':
2356       case 'f':
2357       {
2358         if (LocaleCompare(dct_method,"fastest") == 0)
2359           jpeg_info->dct_method=JDCT_FASTEST;
2360         if (LocaleCompare(dct_method,"float") == 0)
2361           jpeg_info->dct_method=JDCT_FLOAT;
2362         break;
2363       }
2364       case 'I':
2365       case 'i':
2366       {
2367         if (LocaleCompare(dct_method,"ifast") == 0)
2368           jpeg_info->dct_method=JDCT_IFAST;
2369         if (LocaleCompare(dct_method,"islow") == 0)
2370           jpeg_info->dct_method=JDCT_ISLOW;
2371         break;
2372       }
2373     }
2374   option=GetImageOption(image_info,"jpeg:optimize-coding");
2375   if (option != (const char *) NULL)
2376     jpeg_info->optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2377       FALSE;
2378   else
2379     {
2380       MagickSizeType
2381         length;
2382 
2383       length=(MagickSizeType) jpeg_info->input_components*image->columns*
2384         image->rows*sizeof(JSAMPLE);
2385       if (length == (MagickSizeType) ((size_t) length))
2386         {
2387           /*
2388             Perform optimization only if available memory resources permit it.
2389           */
2390           status=AcquireMagickResource(MemoryResource,length);
2391           if (status != MagickFalse)
2392             RelinquishMagickResource(MemoryResource,length);
2393           jpeg_info->optimize_coding=status == MagickFalse ? FALSE : TRUE;
2394         }
2395     }
2396 #if defined(C_ARITH_CODING_SUPPORTED)
2397   option=GetImageOption(image_info,"jpeg:arithmetic-coding");
2398   if (IsStringTrue(option) != MagickFalse)
2399     {
2400       jpeg_info->arith_code=TRUE;
2401       jpeg_info->optimize_coding=FALSE;  /* not supported */
2402     }
2403 #endif
2404 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2405   if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2406       (image_info->interlace != NoInterlace))
2407     {
2408       if (image->debug != MagickFalse)
2409         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2410           "Interlace: progressive");
2411       jpeg_simple_progression(jpeg_info);
2412     }
2413   else
2414     if (image->debug != MagickFalse)
2415       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2416         "Interlace: non-progressive");
2417 #else
2418   if (image->debug != MagickFalse)
2419     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2420       "Interlace: nonprogressive");
2421 #endif
2422   quality=92;
2423   if ((image_info->compression != LosslessJPEGCompression) &&
2424       (image->quality <= 100))
2425     {
2426       if (image->quality != UndefinedCompressionQuality)
2427         quality=(int) image->quality;
2428       if (image->debug != MagickFalse)
2429         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2430           (double) image->quality);
2431     }
2432   else
2433     {
2434 #if !defined(C_LOSSLESS_SUPPORTED)
2435       quality=100;
2436       if (image->debug != MagickFalse)
2437         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2438 #else
2439       if (image->quality < 100)
2440         (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2441           "LosslessToLossyJPEGConversion","`%s'",image->filename);
2442       else
2443         {
2444           int
2445             point_transform,
2446             predictor;
2447 
2448           predictor=image->quality/100;  /* range 1-7 */
2449           point_transform=image->quality % 20;  /* range 0-15 */
2450           jpeg_simple_lossless(jpeg_info,predictor,point_transform);
2451           if (image->debug != MagickFalse)
2452             {
2453               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2454                 "Compression: lossless");
2455               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2456                 "Predictor: %d",predictor);
2457               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2458                 "Point Transform: %d",point_transform);
2459             }
2460         }
2461 #endif
2462     }
2463   option=GetImageOption(image_info,"jpeg:extent");
2464   if (option != (const char *) NULL)
2465     {
2466       Image
2467         *jpeg_image;
2468 
2469       ImageInfo
2470         *extent_info;
2471 
2472       extent_info=CloneImageInfo(image_info);
2473       extent_info->blob=NULL;
2474       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2475       if (jpeg_image != (Image *) NULL)
2476         {
2477           MagickSizeType
2478             extent;
2479 
2480           size_t
2481             maximum,
2482             minimum;
2483 
2484           /*
2485             Search for compression quality that does not exceed image extent.
2486           */
2487           extent_info->quality=0;
2488           extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2489           (void) DeleteImageOption(extent_info,"jpeg:extent");
2490           (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2491           maximum=image_info->quality;
2492           if (maximum < 2)
2493             maximum=101;
2494           for (minimum=2; minimum < maximum; )
2495           {
2496             (void) AcquireUniqueFilename(jpeg_image->filename);
2497             jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2498             status=WriteJPEGImage(extent_info,jpeg_image,exception);
2499             if (GetBlobSize(jpeg_image) <= extent)
2500               minimum=jpeg_image->quality+1;
2501             else
2502               maximum=jpeg_image->quality-1;
2503             (void) RelinquishUniqueFileResource(jpeg_image->filename);
2504           }
2505           quality=(int) minimum-1;
2506           jpeg_image=DestroyImage(jpeg_image);
2507         }
2508       extent_info=DestroyImageInfo(extent_info);
2509     }
2510   jpeg_set_quality(jpeg_info,quality,TRUE);
2511   if ((dct_method == (const char *) NULL) && (quality <= 90))
2512     jpeg_info->dct_method=JDCT_IFAST;
2513 #if (JPEG_LIB_VERSION >= 70)
2514   option=GetImageOption(image_info,"quality");
2515   if (option != (const char *) NULL)
2516     {
2517       GeometryInfo
2518         geometry_info;
2519 
2520       int
2521         flags;
2522 
2523       /*
2524         Set quality scaling for luminance and chrominance separately.
2525       */
2526       flags=ParseGeometry(option,&geometry_info);
2527       if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2528         {
2529           jpeg_info->q_scale_factor[0]=jpeg_quality_scaling((int)
2530             (geometry_info.rho+0.5));
2531           jpeg_info->q_scale_factor[1]=jpeg_quality_scaling((int)
2532             (geometry_info.sigma+0.5));
2533           jpeg_default_qtables(jpeg_info,TRUE);
2534         }
2535     }
2536 #endif
2537   colorspace=jpeg_info->in_color_space;
2538   value=GetImageOption(image_info,"jpeg:colorspace");
2539   if (value == (char *) NULL)
2540     value=GetImageProperty(image,"jpeg:colorspace",exception);
2541   if (value != (char *) NULL)
2542     colorspace=StringToInteger(value);
2543   sampling_factor=(const char *) NULL;
2544   if ((J_COLOR_SPACE) colorspace == jpeg_info->in_color_space)
2545     {
2546       value=GetImageOption(image_info,"jpeg:sampling-factor");
2547       if (value == (char *) NULL)
2548         value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2549       if (value != (char *) NULL)
2550         {
2551           sampling_factor=value;
2552           if (image->debug != MagickFalse)
2553             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2554               "  Input sampling-factors=%s",sampling_factor);
2555         }
2556     }
2557   value=GetImageOption(image_info,"jpeg:sampling-factor");
2558   if (image_info->sampling_factor != (char *) NULL)
2559     sampling_factor=image_info->sampling_factor;
2560   if (sampling_factor == (const char *) NULL)
2561     {
2562       if (quality >= 90)
2563         for (i=0; i < MAX_COMPONENTS; i++)
2564         {
2565           jpeg_info->comp_info[i].h_samp_factor=1;
2566           jpeg_info->comp_info[i].v_samp_factor=1;
2567         }
2568     }
2569   else
2570     {
2571       char
2572         **factors;
2573 
2574       GeometryInfo
2575         geometry_info;
2576 
2577       MagickStatusType
2578         flags;
2579 
2580       /*
2581         Set sampling factor.
2582       */
2583       i=0;
2584       factors=SamplingFactorToList(sampling_factor);
2585       if (factors != (char **) NULL)
2586         {
2587           for (i=0; i < MAX_COMPONENTS; i++)
2588           {
2589             if (factors[i] == (char *) NULL)
2590               break;
2591             flags=ParseGeometry(factors[i],&geometry_info);
2592             if ((flags & SigmaValue) == 0)
2593               geometry_info.sigma=geometry_info.rho;
2594             jpeg_info->comp_info[i].h_samp_factor=(int) geometry_info.rho;
2595             jpeg_info->comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2596             factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2597           }
2598           factors=(char **) RelinquishMagickMemory(factors);
2599         }
2600       for ( ; i < MAX_COMPONENTS; i++)
2601       {
2602         jpeg_info->comp_info[i].h_samp_factor=1;
2603         jpeg_info->comp_info[i].v_samp_factor=1;
2604       }
2605     }
2606   option=GetImageOption(image_info,"jpeg:q-table");
2607   if (option != (const char *) NULL)
2608     {
2609       QuantizationTable
2610         *table;
2611 
2612       /*
2613         Custom quantization tables.
2614       */
2615       table=GetQuantizationTable(option,"0",exception);
2616       if (table != (QuantizationTable *) NULL)
2617         {
2618           for (i=0; i < MAX_COMPONENTS; i++)
2619             jpeg_info->comp_info[i].quant_tbl_no=0;
2620           jpeg_add_quant_table(jpeg_info,0,table->levels,
2621             jpeg_quality_scaling(quality),0);
2622           table=DestroyQuantizationTable(table);
2623         }
2624       table=GetQuantizationTable(option,"1",exception);
2625       if (table != (QuantizationTable *) NULL)
2626         {
2627           for (i=1; i < MAX_COMPONENTS; i++)
2628             jpeg_info->comp_info[i].quant_tbl_no=1;
2629           jpeg_add_quant_table(jpeg_info,1,table->levels,
2630             jpeg_quality_scaling(quality),0);
2631           table=DestroyQuantizationTable(table);
2632         }
2633       table=GetQuantizationTable(option,"2",exception);
2634       if (table != (QuantizationTable *) NULL)
2635         {
2636           for (i=2; i < MAX_COMPONENTS; i++)
2637             jpeg_info->comp_info[i].quant_tbl_no=2;
2638           jpeg_add_quant_table(jpeg_info,2,table->levels,
2639             jpeg_quality_scaling(quality),0);
2640           table=DestroyQuantizationTable(table);
2641         }
2642       table=GetQuantizationTable(option,"3",exception);
2643       if (table != (QuantizationTable *) NULL)
2644         {
2645           for (i=3; i < MAX_COMPONENTS; i++)
2646             jpeg_info->comp_info[i].quant_tbl_no=3;
2647           jpeg_add_quant_table(jpeg_info,3,table->levels,
2648             jpeg_quality_scaling(quality),0);
2649           table=DestroyQuantizationTable(table);
2650         }
2651     }
2652   jpeg_start_compress(jpeg_info,TRUE);
2653   if (image->debug != MagickFalse)
2654     {
2655       if (image->storage_class == PseudoClass)
2656         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2657           "Storage class: PseudoClass");
2658       else
2659         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2660           "Storage class: DirectClass");
2661       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2662         (double) image->depth);
2663       if (image->colors != 0)
2664         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2665           "Number of colors: %.20g",(double) image->colors);
2666       else
2667         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2668           "Number of colors: unspecified");
2669       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2670         "JPEG data precision: %d",(int) jpeg_info->data_precision);
2671       switch (image->colorspace)
2672       {
2673         case CMYKColorspace:
2674         {
2675           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2676             "Storage class: DirectClass");
2677           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2678             "Colorspace: CMYK");
2679           break;
2680         }
2681         case YCbCrColorspace:
2682         case Rec601YCbCrColorspace:
2683         case Rec709YCbCrColorspace:
2684         {
2685           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2686             "Colorspace: YCbCr");
2687           break;
2688         }
2689         default:
2690           break;
2691       }
2692       switch (image->colorspace)
2693       {
2694         case CMYKColorspace:
2695         {
2696           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2697             "Colorspace: CMYK");
2698           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2699             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2700             jpeg_info->comp_info[0].h_samp_factor,
2701             jpeg_info->comp_info[0].v_samp_factor,
2702             jpeg_info->comp_info[1].h_samp_factor,
2703             jpeg_info->comp_info[1].v_samp_factor,
2704             jpeg_info->comp_info[2].h_samp_factor,
2705             jpeg_info->comp_info[2].v_samp_factor,
2706             jpeg_info->comp_info[3].h_samp_factor,
2707             jpeg_info->comp_info[3].v_samp_factor);
2708           break;
2709         }
2710         case GRAYColorspace:
2711         {
2712           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2713             "Colorspace: GRAY");
2714           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2715             "Sampling factors: %dx%d",jpeg_info->comp_info[0].h_samp_factor,
2716             jpeg_info->comp_info[0].v_samp_factor);
2717           break;
2718         }
2719         case sRGBColorspace:
2720         case RGBColorspace:
2721         {
2722           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2723             "Image colorspace is RGB");
2724           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2725             "Sampling factors: %dx%d,%dx%d,%dx%d",
2726             jpeg_info->comp_info[0].h_samp_factor,
2727             jpeg_info->comp_info[0].v_samp_factor,
2728             jpeg_info->comp_info[1].h_samp_factor,
2729             jpeg_info->comp_info[1].v_samp_factor,
2730             jpeg_info->comp_info[2].h_samp_factor,
2731             jpeg_info->comp_info[2].v_samp_factor);
2732           break;
2733         }
2734         case YCbCrColorspace:
2735         case Rec601YCbCrColorspace:
2736         case Rec709YCbCrColorspace:
2737         {
2738           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2739             "Colorspace: YCbCr");
2740           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2741             "Sampling factors: %dx%d,%dx%d,%dx%d",
2742             jpeg_info->comp_info[0].h_samp_factor,
2743             jpeg_info->comp_info[0].v_samp_factor,
2744             jpeg_info->comp_info[1].h_samp_factor,
2745             jpeg_info->comp_info[1].v_samp_factor,
2746             jpeg_info->comp_info[2].h_samp_factor,
2747             jpeg_info->comp_info[2].v_samp_factor);
2748           break;
2749         }
2750         default:
2751         {
2752           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2753             image->colorspace);
2754           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2755             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2756             jpeg_info->comp_info[0].h_samp_factor,
2757             jpeg_info->comp_info[0].v_samp_factor,
2758             jpeg_info->comp_info[1].h_samp_factor,
2759             jpeg_info->comp_info[1].v_samp_factor,
2760             jpeg_info->comp_info[2].h_samp_factor,
2761             jpeg_info->comp_info[2].v_samp_factor,
2762             jpeg_info->comp_info[3].h_samp_factor,
2763             jpeg_info->comp_info[3].v_samp_factor);
2764           break;
2765         }
2766       }
2767     }
2768   /*
2769     Write JPEG profiles.
2770   */
2771   value=GetImageProperty(image,"comment",exception);
2772   if (value != (char *) NULL)
2773     {
2774       size_t
2775         length;
2776 
2777       length=strlen(value);
2778       for (i=0; i < (ssize_t) length; i+=65533L)
2779         jpeg_write_marker(jpeg_info,JPEG_COM,(unsigned char *) value+i,
2780           (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2781     }
2782   if (image->profiles != (void *) NULL)
2783     WriteProfile(jpeg_info,image,exception);
2784   /*
2785     Convert MIFF to JPEG raster pixels.
2786   */
2787   memory_info=AcquireVirtualMemory((size_t) image->columns,
2788     jpeg_info->input_components*sizeof(*jpeg_pixels));
2789   if (memory_info == (MemoryInfo *) NULL)
2790     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2791   jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2792   if (setjmp(error_manager.error_recovery) != 0)
2793     {
2794       jpeg_destroy_compress(jpeg_info);
2795       if (memory_info != (MemoryInfo *) NULL)
2796         memory_info=RelinquishVirtualMemory(memory_info);
2797       (void) CloseBlob(image);
2798       return(MagickFalse);
2799     }
2800   scanline[0]=(JSAMPROW) jpeg_pixels;
2801   scale=65535/(unsigned short) GetQuantumRange((size_t)
2802     jpeg_info->data_precision);
2803   if (scale == 0)
2804     scale=1;
2805   if (jpeg_info->data_precision <= 8)
2806     {
2807       if ((jpeg_info->in_color_space == JCS_RGB) ||
2808           (jpeg_info->in_color_space == JCS_YCbCr))
2809         for (y=0; y < (ssize_t) image->rows; y++)
2810         {
2811           const Quantum
2812             *p;
2813 
2814           ssize_t
2815             x;
2816 
2817           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2818           if (p == (const Quantum *) NULL)
2819             break;
2820           q=jpeg_pixels;
2821           for (x=0; x < (ssize_t) image->columns; x++)
2822           {
2823             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2824             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2825             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2826             p+=GetPixelChannels(image);
2827           }
2828           (void) jpeg_write_scanlines(jpeg_info,scanline,1);
2829           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2830             image->rows);
2831           if (status == MagickFalse)
2832             break;
2833         }
2834       else
2835         if (jpeg_info->in_color_space == JCS_GRAYSCALE)
2836           for (y=0; y < (ssize_t) image->rows; y++)
2837           {
2838             const Quantum
2839               *p;
2840 
2841             ssize_t
2842               x;
2843 
2844             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2845             if (p == (const Quantum *) NULL)
2846               break;
2847             q=jpeg_pixels;
2848             for (x=0; x < (ssize_t) image->columns; x++)
2849             {
2850               *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2851                 image,p)));
2852               p+=GetPixelChannels(image);
2853             }
2854             (void) jpeg_write_scanlines(jpeg_info,scanline,1);
2855             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2856               image->rows);
2857             if (status == MagickFalse)
2858               break;
2859             }
2860         else
2861           for (y=0; y < (ssize_t) image->rows; y++)
2862           {
2863             const Quantum
2864               *p;
2865 
2866             ssize_t
2867               x;
2868 
2869             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2870             if (p == (const Quantum *) NULL)
2871               break;
2872             q=jpeg_pixels;
2873             for (x=0; x < (ssize_t) image->columns; x++)
2874             {
2875               /*
2876                 Convert DirectClass packets to contiguous CMYK scanlines.
2877               */
2878               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2879                 GetPixelCyan(image,p))));
2880               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2881                 GetPixelMagenta(image,p))));
2882               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2883                 GetPixelYellow(image,p))));
2884               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2885                 GetPixelBlack(image,p))));
2886               p+=GetPixelChannels(image);
2887             }
2888             (void) jpeg_write_scanlines(jpeg_info,scanline,1);
2889             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2890               image->rows);
2891             if (status == MagickFalse)
2892               break;
2893           }
2894     }
2895   else
2896     if (jpeg_info->in_color_space == JCS_GRAYSCALE)
2897       for (y=0; y < (ssize_t) image->rows; y++)
2898       {
2899         const Quantum
2900           *p;
2901 
2902         ssize_t
2903           x;
2904 
2905         p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2906         if (p == (const Quantum *) NULL)
2907           break;
2908         q=jpeg_pixels;
2909         for (x=0; x < (ssize_t) image->columns; x++)
2910         {
2911           *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2912             p)))/scale);
2913           p+=GetPixelChannels(image);
2914         }
2915         (void) jpeg_write_scanlines(jpeg_info,scanline,1);
2916         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2917           image->rows);
2918         if (status == MagickFalse)
2919           break;
2920       }
2921     else
2922       if ((jpeg_info->in_color_space == JCS_RGB) ||
2923           (jpeg_info->in_color_space == JCS_YCbCr))
2924         for (y=0; y < (ssize_t) image->rows; y++)
2925         {
2926           const Quantum
2927             *p;
2928 
2929           ssize_t
2930             x;
2931 
2932           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2933           if (p == (const Quantum *) NULL)
2934             break;
2935           q=jpeg_pixels;
2936           for (x=0; x < (ssize_t) image->columns; x++)
2937           {
2938             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2939             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2940             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2941             p+=GetPixelChannels(image);
2942           }
2943           (void) jpeg_write_scanlines(jpeg_info,scanline,1);
2944           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2945             image->rows);
2946           if (status == MagickFalse)
2947             break;
2948         }
2949       else
2950         for (y=0; y < (ssize_t) image->rows; y++)
2951         {
2952           const Quantum
2953             *p;
2954 
2955           ssize_t
2956             x;
2957 
2958           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2959           if (p == (const Quantum *) NULL)
2960             break;
2961           q=jpeg_pixels;
2962           for (x=0; x < (ssize_t) image->columns; x++)
2963           {
2964             /*
2965               Convert DirectClass packets to contiguous CMYK scanlines.
2966             */
2967             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2968               image,p))/scale);
2969             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2970               image,p))/scale);
2971             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2972               image,p))/scale);
2973             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2974               image,p))/scale);
2975             p+=GetPixelChannels(image);
2976           }
2977           (void) jpeg_write_scanlines(jpeg_info,scanline,1);
2978           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2979             image->rows);
2980           if (status == MagickFalse)
2981             break;
2982         }
2983   if (y == (ssize_t) image->rows)
2984     jpeg_finish_compress(jpeg_info);
2985   /*
2986     Relinquish resources.
2987   */
2988   jpeg_destroy_compress(jpeg_info);
2989   memory_info=RelinquishVirtualMemory(memory_info);
2990   (void) CloseBlob(image);
2991   return(MagickTrue);
2992 }
2993 
WriteJPEGImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)2994 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2995   Image *image,ExceptionInfo *exception)
2996 {
2997   struct jpeg_compress_struct
2998     jpeg_info;
2999 
3000   return(WriteJPEGImage_(image_info,image,&jpeg_info,exception));
3001 }
3002 #endif
3003