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