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