]> granicus.if.org Git - imagemagick/blob - coders/jpeg.c
020ffaac692d8a81533fff594468f9d151d662bb
[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 defined(D_ARITH_CODING_SUPPORTED)
1341   if (jpeg_info.arith_code == TRUE)
1342     (void) SetImageProperty(image,"jpeg:coding","arithmetic",exception);
1343 #endif
1344   if (image_info->ping != MagickFalse)
1345     {
1346       jpeg_destroy_decompress(&jpeg_info);
1347       (void) CloseBlob(image);
1348       return(GetFirstImageInList(image));
1349     }
1350   status=SetImageExtent(image,image->columns,image->rows,exception);
1351   if (status == MagickFalse)
1352     {
1353       jpeg_destroy_decompress(&jpeg_info);
1354       return(DestroyImageList(image));
1355     }
1356   (void) jpeg_start_decompress(&jpeg_info);
1357   if ((jpeg_info.output_components != 1) &&
1358       (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
1359     {
1360       jpeg_destroy_decompress(&jpeg_info);
1361       ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
1362     }
1363   memory_info=AcquireVirtualMemory((size_t) image->columns,
1364     jpeg_info.output_components*sizeof(*jpeg_pixels));
1365   if (memory_info == (MemoryInfo *) NULL)
1366     {
1367       jpeg_destroy_decompress(&jpeg_info);
1368       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1369     }
1370   jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1371   (void) memset(jpeg_pixels,0,image->columns*
1372     jpeg_info.output_components*sizeof(*jpeg_pixels));
1373   /*
1374     Convert JPEG pixels to pixel packets.
1375   */
1376   if (setjmp(error_manager.error_recovery) != 0)
1377     {
1378       if (memory_info != (MemoryInfo *) NULL)
1379         memory_info=RelinquishVirtualMemory(memory_info);
1380       jpeg_destroy_decompress(&jpeg_info);
1381       (void) CloseBlob(image);
1382       number_pixels=(MagickSizeType) image->columns*image->rows;
1383       if (number_pixels != 0)
1384         return(GetFirstImageInList(image));
1385       return(DestroyImage(image));
1386     }
1387   if (jpeg_info.quantize_colors != 0)
1388     {
1389       image->colors=(size_t) jpeg_info.actual_number_of_colors;
1390       if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1391         for (i=0; i < (ssize_t) image->colors; i++)
1392         {
1393           image->colormap[i].red=(double) ScaleCharToQuantum(
1394             jpeg_info.colormap[0][i]);
1395           image->colormap[i].green=image->colormap[i].red;
1396           image->colormap[i].blue=image->colormap[i].red;
1397           image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1398         }
1399       else
1400         for (i=0; i < (ssize_t) image->colors; i++)
1401         {
1402           image->colormap[i].red=(double) ScaleCharToQuantum(
1403             jpeg_info.colormap[0][i]);
1404           image->colormap[i].green=(double) ScaleCharToQuantum(
1405             jpeg_info.colormap[1][i]);
1406           image->colormap[i].blue=(double) ScaleCharToQuantum(
1407             jpeg_info.colormap[2][i]);
1408           image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
1409         }
1410     }
1411   scanline[0]=(JSAMPROW) jpeg_pixels;
1412   for (y=0; y < (ssize_t) image->rows; y++)
1413   {
1414     register ssize_t
1415       x;
1416
1417     register Quantum
1418       *magick_restrict q;
1419
1420     if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1421       {
1422         (void) ThrowMagickException(exception,GetMagickModule(),
1423           CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1424         continue;
1425       }
1426     p=jpeg_pixels;
1427     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1428     if (q == (Quantum *) NULL)
1429       break;
1430     if (jpeg_info.data_precision > 8)
1431       {
1432         unsigned short
1433           scale;
1434
1435         scale=65535/(unsigned short) GetQuantumRange((size_t)
1436           jpeg_info.data_precision);
1437         if (jpeg_info.output_components == 1)
1438           for (x=0; x < (ssize_t) image->columns; x++)
1439           {
1440             ssize_t
1441               pixel;
1442
1443             pixel=(ssize_t) (scale*GETJSAMPLE(*p));
1444             index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1445             SetPixelIndex(image,index,q);
1446             SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1447             p++;
1448             q+=GetPixelChannels(image);
1449           }
1450         else
1451           if (image->colorspace != CMYKColorspace)
1452             for (x=0; x < (ssize_t) image->columns; x++)
1453             {
1454               SetPixelRed(image,ScaleShortToQuantum(
1455                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1456               SetPixelGreen(image,ScaleShortToQuantum(
1457                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1458               SetPixelBlue(image,ScaleShortToQuantum(
1459                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1460               SetPixelAlpha(image,OpaqueAlpha,q);
1461               q+=GetPixelChannels(image);
1462             }
1463           else
1464             for (x=0; x < (ssize_t) image->columns; x++)
1465             {
1466               SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1467                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1468               SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1469                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1470               SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1471                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1472               SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1473                 (unsigned short) (scale*GETJSAMPLE(*p++))),q);
1474               SetPixelAlpha(image,OpaqueAlpha,q);
1475               q+=GetPixelChannels(image);
1476             }
1477       }
1478     else
1479       if (jpeg_info.output_components == 1)
1480         for (x=0; x < (ssize_t) image->columns; x++)
1481         {
1482           ssize_t
1483             pixel;
1484
1485           pixel=(ssize_t) GETJSAMPLE(*p);
1486           index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
1487           SetPixelIndex(image,index,q);
1488           SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
1489           p++;
1490           q+=GetPixelChannels(image);
1491         }
1492       else
1493         if (image->colorspace != CMYKColorspace)
1494           for (x=0; x < (ssize_t) image->columns; x++)
1495           {
1496             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1497               GETJSAMPLE(*p++)),q);
1498             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1499               GETJSAMPLE(*p++)),q);
1500             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1501               GETJSAMPLE(*p++)),q);
1502             SetPixelAlpha(image,OpaqueAlpha,q);
1503             q+=GetPixelChannels(image);
1504           }
1505         else
1506           for (x=0; x < (ssize_t) image->columns; x++)
1507           {
1508             SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1509               (unsigned char) GETJSAMPLE(*p++)),q);
1510             SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1511               (unsigned char) GETJSAMPLE(*p++)),q);
1512             SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1513               (unsigned char) GETJSAMPLE(*p++)),q);
1514             SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1515               (unsigned char) GETJSAMPLE(*p++)),q);
1516             SetPixelAlpha(image,OpaqueAlpha,q);
1517             q+=GetPixelChannels(image);
1518           }
1519     if (SyncAuthenticPixels(image,exception) == MagickFalse)
1520       break;
1521     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1522       image->rows);
1523     if (status == MagickFalse)
1524       {
1525         jpeg_abort_decompress(&jpeg_info);
1526         break;
1527       }
1528   }
1529   if (status != MagickFalse)
1530     {
1531       error_manager.finished=MagickTrue;
1532       if (setjmp(error_manager.error_recovery) == 0)
1533         (void) jpeg_finish_decompress(&jpeg_info);
1534     }
1535   /*
1536     Free jpeg resources.
1537   */
1538   jpeg_destroy_decompress(&jpeg_info);
1539   memory_info=RelinquishVirtualMemory(memory_info);
1540   (void) CloseBlob(image);
1541   return(GetFirstImageInList(image));
1542 }
1543 #endif
1544 \f
1545 /*
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547 %                                                                             %
1548 %                                                                             %
1549 %                                                                             %
1550 %   R e g i s t e r J P E G I m a g e                                         %
1551 %                                                                             %
1552 %                                                                             %
1553 %                                                                             %
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555 %
1556 %  RegisterJPEGImage() adds properties for the JPEG image format to
1557 %  the list of supported formats.  The properties include the image format
1558 %  tag, a method to read and/or write the format, whether the format
1559 %  supports the saving of more than one frame to the same file or blob,
1560 %  whether the format supports native in-memory I/O, and a brief
1561 %  description of the format.
1562 %
1563 %  The format of the RegisterJPEGImage method is:
1564 %
1565 %      size_t RegisterJPEGImage(void)
1566 %
1567 */
1568 ModuleExport size_t RegisterJPEGImage(void)
1569 {
1570 #define JPEGDescription "Joint Photographic Experts Group JFIF format"
1571 #define JPEGStringify(macro_or_string)  JPEGStringifyArg(macro_or_string)
1572 #define JPEGStringifyArg(contents)  #contents
1573
1574   char
1575     version[MagickPathExtent];
1576
1577   MagickInfo
1578     *entry;
1579
1580   *version='\0';
1581 #if defined(LIBJPEG_TURBO_VERSION)
1582   (void) CopyMagickString(version,"libjpeg-turbo " JPEGStringify(
1583     LIBJPEG_TURBO_VERSION),MagickPathExtent);
1584 #elif defined(JPEG_LIB_VERSION)
1585   (void) FormatLocaleString(version,MagickPathExtent,"libjpeg %d",
1586     JPEG_LIB_VERSION);
1587 #endif
1588   entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
1589 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1590   entry->flags^=CoderDecoderThreadSupportFlag;
1591 #endif
1592 #if defined(MAGICKCORE_JPEG_DELEGATE)
1593   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1594   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1595 #endif
1596   entry->magick=(IsImageFormatHandler *) IsJPEG;
1597   entry->flags|=CoderDecoderSeekableStreamFlag;
1598   entry->flags^=CoderAdjoinFlag;
1599   entry->flags^=CoderUseExtensionFlag;
1600   if (*version != '\0')
1601     entry->version=ConstantString(version);
1602   entry->mime_type=ConstantString("image/jpeg");
1603   (void) RegisterMagickInfo(entry);
1604   entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
1605 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1606   entry->flags^=CoderDecoderThreadSupportFlag;
1607 #endif
1608 #if defined(MAGICKCORE_JPEG_DELEGATE)
1609   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1610   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1611 #endif
1612   entry->magick=(IsImageFormatHandler *) IsJPEG;
1613   entry->flags|=CoderDecoderSeekableStreamFlag;
1614   entry->flags^=CoderAdjoinFlag;
1615   if (*version != '\0')
1616     entry->version=ConstantString(version);
1617   entry->mime_type=ConstantString("image/jpeg");
1618   (void) RegisterMagickInfo(entry);
1619   entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
1620 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1621   entry->flags^=CoderDecoderThreadSupportFlag;
1622 #endif
1623 #if defined(MAGICKCORE_JPEG_DELEGATE)
1624   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1625   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1626 #endif
1627   entry->flags|=CoderDecoderSeekableStreamFlag;
1628   entry->flags^=CoderAdjoinFlag;
1629   entry->flags^=CoderUseExtensionFlag;
1630   if (*version != '\0')
1631     entry->version=ConstantString(version);
1632   entry->mime_type=ConstantString("image/jpeg");
1633   (void) RegisterMagickInfo(entry);
1634   entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
1635 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1636   entry->flags^=CoderDecoderThreadSupportFlag;
1637 #endif
1638 #if defined(MAGICKCORE_JPEG_DELEGATE)
1639   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1640   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1641 #endif
1642   entry->flags|=CoderDecoderSeekableStreamFlag;
1643   entry->flags^=CoderAdjoinFlag;
1644   entry->flags^=CoderUseExtensionFlag;
1645   if (*version != '\0')
1646     entry->version=ConstantString(version);
1647   entry->mime_type=ConstantString("image/jpeg");
1648   (void) RegisterMagickInfo(entry);
1649   entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
1650 #if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
1651   entry->flags^=CoderDecoderThreadSupportFlag;
1652 #endif
1653 #if defined(MAGICKCORE_JPEG_DELEGATE)
1654   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1655   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1656 #endif
1657   entry->flags|=CoderDecoderSeekableStreamFlag;
1658   entry->flags^=CoderAdjoinFlag;
1659   entry->flags^=CoderUseExtensionFlag;
1660   if (*version != '\0')
1661     entry->version=ConstantString(version);
1662   entry->mime_type=ConstantString("image/jpeg");
1663   (void) RegisterMagickInfo(entry);
1664   return(MagickImageCoderSignature);
1665 }
1666 \f
1667 /*
1668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1669 %                                                                             %
1670 %                                                                             %
1671 %                                                                             %
1672 %   U n r e g i s t e r J P E G I m a g e                                     %
1673 %                                                                             %
1674 %                                                                             %
1675 %                                                                             %
1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677 %
1678 %  UnregisterJPEGImage() removes format registrations made by the
1679 %  JPEG module from the list of supported formats.
1680 %
1681 %  The format of the UnregisterJPEGImage method is:
1682 %
1683 %      UnregisterJPEGImage(void)
1684 %
1685 */
1686 ModuleExport void UnregisterJPEGImage(void)
1687 {
1688   (void) UnregisterMagickInfo("PJPG");
1689   (void) UnregisterMagickInfo("JPS");
1690   (void) UnregisterMagickInfo("JPG");
1691   (void) UnregisterMagickInfo("JPEG");
1692   (void) UnregisterMagickInfo("JPE");
1693 }
1694 \f
1695 #if defined(MAGICKCORE_JPEG_DELEGATE)
1696 /*
1697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1698 %                                                                             %
1699 %                                                                             %
1700 %                                                                             %
1701 %  W r i t e J P E G I m a g e                                                %
1702 %                                                                             %
1703 %                                                                             %
1704 %                                                                             %
1705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706 %
1707 %  WriteJPEGImage() writes a JPEG image file and returns it.  It
1708 %  allocates the memory necessary for the new Image structure and returns a
1709 %  pointer to the new image.
1710 %
1711 %  The format of the WriteJPEGImage method is:
1712 %
1713 %      MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1714 %        Image *image,ExceptionInfo *exception)
1715 %
1716 %  A description of each parameter follows:
1717 %
1718 %    o image_info: the image info.
1719 %
1720 %    o jpeg_image:  The image.
1721 %
1722 %    o exception: return any errors or warnings in this structure.
1723 %
1724 */
1725
1726 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1727 {
1728   assert(table != (QuantizationTable *) NULL);
1729   if (table->slot != (char *) NULL)
1730     table->slot=DestroyString(table->slot);
1731   if (table->description != (char *) NULL)
1732     table->description=DestroyString(table->description);
1733   if (table->levels != (unsigned int *) NULL)
1734     table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1735   table=(QuantizationTable *) RelinquishMagickMemory(table);
1736   return(table);
1737 }
1738
1739 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1740 {
1741   DestinationManager
1742     *destination;
1743
1744   destination=(DestinationManager *) cinfo->dest;
1745   destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1746     MaxBufferExtent,destination->buffer);
1747   if (destination->manager.free_in_buffer != MaxBufferExtent)
1748     ERREXIT(cinfo,JERR_FILE_WRITE);
1749   destination->manager.next_output_byte=destination->buffer;
1750   return(TRUE);
1751 }
1752
1753 static QuantizationTable *GetQuantizationTable(const char *filename,
1754   const char *slot,ExceptionInfo *exception)
1755 {
1756   char
1757     *p,
1758     *xml;
1759
1760   const char
1761     *attribute,
1762     *content;
1763
1764   double
1765     value;
1766
1767   register ssize_t
1768     i;
1769
1770   ssize_t
1771     j;
1772
1773   QuantizationTable
1774     *table;
1775
1776   size_t
1777     length;
1778
1779   XMLTreeInfo
1780     *description,
1781     *levels,
1782     *quantization_tables,
1783     *table_iterator;
1784
1785   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1786     "Loading quantization tables \"%s\" ...",filename);
1787   table=(QuantizationTable *) NULL;
1788   xml=FileToString(filename,~0UL,exception);
1789   if (xml == (char *) NULL)
1790     return(table);
1791   quantization_tables=NewXMLTree(xml,exception);
1792   if (quantization_tables == (XMLTreeInfo *) NULL)
1793     {
1794       xml=DestroyString(xml);
1795       return(table);
1796     }
1797   for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1798        table_iterator != (XMLTreeInfo *) NULL;
1799        table_iterator=GetNextXMLTreeTag(table_iterator))
1800   {
1801     attribute=GetXMLTreeAttribute(table_iterator,"slot");
1802     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1803       break;
1804     attribute=GetXMLTreeAttribute(table_iterator,"alias");
1805     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1806       break;
1807   }
1808   if (table_iterator == (XMLTreeInfo *) NULL)
1809     {
1810       xml=DestroyString(xml);
1811       return(table);
1812     }
1813   description=GetXMLTreeChild(table_iterator,"description");
1814   if (description == (XMLTreeInfo *) NULL)
1815     {
1816       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1817         "XmlMissingElement","<description>, slot \"%s\"",slot);
1818       quantization_tables=DestroyXMLTree(quantization_tables);
1819       xml=DestroyString(xml);
1820       return(table);
1821     }
1822   levels=GetXMLTreeChild(table_iterator,"levels");
1823   if (levels == (XMLTreeInfo *) NULL)
1824     {
1825       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1826         "XmlMissingElement","<levels>, slot \"%s\"",slot);
1827       quantization_tables=DestroyXMLTree(quantization_tables);
1828       xml=DestroyString(xml);
1829       return(table);
1830     }
1831   table=(QuantizationTable *) AcquireCriticalMemory(sizeof(*table));
1832   table->slot=(char *) NULL;
1833   table->description=(char *) NULL;
1834   table->levels=(unsigned int *) NULL;
1835   attribute=GetXMLTreeAttribute(table_iterator,"slot");
1836   if (attribute != (char *) NULL)
1837     table->slot=ConstantString(attribute);
1838   content=GetXMLTreeContent(description);
1839   if (content != (char *) NULL)
1840     table->description=ConstantString(content);
1841   attribute=GetXMLTreeAttribute(levels,"width");
1842   if (attribute == (char *) NULL)
1843     {
1844       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1845         "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
1846       quantization_tables=DestroyXMLTree(quantization_tables);
1847       table=DestroyQuantizationTable(table);
1848       xml=DestroyString(xml);
1849       return(table);
1850     }
1851   table->width=StringToUnsignedLong(attribute);
1852   if (table->width == 0)
1853     {
1854       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1855        "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
1856       quantization_tables=DestroyXMLTree(quantization_tables);
1857       table=DestroyQuantizationTable(table);
1858       xml=DestroyString(xml);
1859       return(table);
1860     }
1861   attribute=GetXMLTreeAttribute(levels,"height");
1862   if (attribute == (char *) NULL)
1863     {
1864       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1865         "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
1866       quantization_tables=DestroyXMLTree(quantization_tables);
1867       table=DestroyQuantizationTable(table);
1868       xml=DestroyString(xml);
1869       return(table);
1870     }
1871   table->height=StringToUnsignedLong(attribute);
1872   if (table->height == 0)
1873     {
1874       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1875         "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
1876       quantization_tables=DestroyXMLTree(quantization_tables);
1877       table=DestroyQuantizationTable(table);
1878       xml=DestroyString(xml);
1879       return(table);
1880     }
1881   attribute=GetXMLTreeAttribute(levels,"divisor");
1882   if (attribute == (char *) NULL)
1883     {
1884       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1885         "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
1886       quantization_tables=DestroyXMLTree(quantization_tables);
1887       table=DestroyQuantizationTable(table);
1888       xml=DestroyString(xml);
1889       return(table);
1890     }
1891   table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1892   if (table->divisor == 0.0)
1893     {
1894       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1895         "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
1896       quantization_tables=DestroyXMLTree(quantization_tables);
1897       table=DestroyQuantizationTable(table);
1898       xml=DestroyString(xml);
1899       return(table);
1900     }
1901   content=GetXMLTreeContent(levels);
1902   if (content == (char *) NULL)
1903     {
1904       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1905         "XmlMissingContent","<levels>, table \"%s\"",slot);
1906       quantization_tables=DestroyXMLTree(quantization_tables);
1907       table=DestroyQuantizationTable(table);
1908       xml=DestroyString(xml);
1909       return(table);
1910     }
1911   length=(size_t) table->width*table->height;
1912   if (length < 64)
1913     length=64;
1914   table->levels=(unsigned int *) AcquireQuantumMemory(length,
1915     sizeof(*table->levels));
1916   if (table->levels == (unsigned int *) NULL)
1917     ThrowFatalException(ResourceLimitFatalError,
1918       "UnableToAcquireQuantizationTable");
1919   for (i=0; i < (ssize_t) (table->width*table->height); i++)
1920   {
1921     table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1922       table->divisor+0.5);
1923     while (isspace((int) ((unsigned char) *p)) != 0)
1924       p++;
1925     if (*p == ',')
1926       p++;
1927     content=p;
1928   }
1929   value=InterpretLocaleValue(content,&p);
1930   (void) value;
1931   if (p != content)
1932     {
1933       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1934         "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
1935      quantization_tables=DestroyXMLTree(quantization_tables);
1936      table=DestroyQuantizationTable(table);
1937      xml=DestroyString(xml);
1938      return(table);
1939    }
1940   for (j=i; j < 64; j++)
1941     table->levels[j]=table->levels[j-1];
1942   quantization_tables=DestroyXMLTree(quantization_tables);
1943   xml=DestroyString(xml);
1944   return(table);
1945 }
1946
1947 static void InitializeDestination(j_compress_ptr cinfo)
1948 {
1949   DestinationManager
1950     *destination;
1951
1952   destination=(DestinationManager *) cinfo->dest;
1953   destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1954     ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1955   destination->manager.next_output_byte=destination->buffer;
1956   destination->manager.free_in_buffer=MaxBufferExtent;
1957 }
1958
1959 static void TerminateDestination(j_compress_ptr cinfo)
1960 {
1961   DestinationManager
1962     *destination;
1963
1964   destination=(DestinationManager *) cinfo->dest;
1965   if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1966     {
1967       ssize_t
1968         count;
1969
1970       count=WriteBlob(destination->image,MaxBufferExtent-
1971         destination->manager.free_in_buffer,destination->buffer);
1972       if (count != (ssize_t)
1973           (MaxBufferExtent-destination->manager.free_in_buffer))
1974         ERREXIT(cinfo,JERR_FILE_WRITE);
1975     }
1976 }
1977
1978 static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
1979   ExceptionInfo *exception)
1980 {
1981   const char
1982     *name;
1983
1984   const StringInfo
1985     *profile;
1986
1987   MagickBooleanType
1988     iptc;
1989
1990   register ssize_t
1991     i;
1992
1993   size_t
1994     length,
1995     tag_length;
1996
1997   StringInfo
1998     *custom_profile;
1999
2000   /*
2001     Save image profile as a APP marker.
2002   */
2003   iptc=MagickFalse;
2004   custom_profile=AcquireStringInfo(65535L);
2005   ResetImageProfileIterator(image);
2006   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2007   {
2008     profile=GetImageProfile(image,name);
2009     if (LocaleCompare(name,"EXIF") == 0)
2010       {
2011         length=GetStringInfoLength(profile);
2012         if (length > 65533L)
2013           {
2014             (void) ThrowMagickException(exception,GetMagickModule(),
2015               CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
2016               image->filename);
2017             length=65533L;
2018           }
2019         jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
2020           (unsigned int) length);
2021       }
2022     if (LocaleCompare(name,"ICC") == 0)
2023       {
2024         register unsigned char
2025           *p;
2026
2027         tag_length=strlen(ICC_PROFILE);
2028         p=GetStringInfoDatum(custom_profile);
2029         (void) memcpy(p,ICC_PROFILE,tag_length);
2030         p[tag_length]='\0';
2031         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
2032         {
2033           length=MagickMin(GetStringInfoLength(profile)-i,65519L);
2034           p[12]=(unsigned char) ((i/65519L)+1);
2035           p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
2036           (void) memcpy(p+tag_length+3,GetStringInfoDatum(profile)+i,
2037             length);
2038           jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
2039             custom_profile),(unsigned int) (length+tag_length+3));
2040         }
2041       }
2042     if (((LocaleCompare(name,"IPTC") == 0) ||
2043         (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
2044       {
2045         register unsigned char
2046           *p;
2047
2048         size_t
2049           roundup;
2050
2051         iptc=MagickTrue;
2052         p=GetStringInfoDatum(custom_profile);
2053         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
2054         {
2055           length=MagickMin(GetStringInfoLength(profile)-i,65500L);
2056           roundup=(size_t) (length & 0x01);
2057           if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
2058             {
2059               (void) memcpy(p,"Photoshop 3.0 ",14);
2060               tag_length=14;
2061             }
2062           else
2063             {
2064               (void) memcpy(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
2065               tag_length=26;
2066               p[24]=(unsigned char) (length >> 8);
2067               p[25]=(unsigned char) (length & 0xff);
2068             }
2069           p[13]=0x00;
2070           (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
2071           if (roundup != 0)
2072             p[length+tag_length]='\0';
2073           jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
2074             custom_profile),(unsigned int) (length+tag_length+roundup));
2075         }
2076       }
2077     if (LocaleCompare(name,"XMP") == 0)
2078       {
2079         StringInfo
2080           *xmp_profile;
2081
2082         /*
2083           Add namespace to XMP profile.
2084         */
2085         xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
2086         if (xmp_profile != (StringInfo *) NULL)
2087           {
2088             if (profile != (StringInfo *) NULL)
2089               ConcatenateStringInfo(xmp_profile,profile);
2090             GetStringInfoDatum(xmp_profile)[28]='\0';
2091             for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
2092             {
2093               length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
2094               jpeg_write_marker(jpeg_info,XML_MARKER,
2095                 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
2096             }
2097             xmp_profile=DestroyStringInfo(xmp_profile);
2098           }
2099       }
2100     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2101       "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
2102     name=GetNextImageProfile(image);
2103   }
2104   custom_profile=DestroyStringInfo(custom_profile);
2105 }
2106
2107 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
2108 {
2109   DestinationManager
2110     *destination;
2111
2112   cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
2113     ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2114   destination=(DestinationManager *) cinfo->dest;
2115   destination->manager.init_destination=InitializeDestination;
2116   destination->manager.empty_output_buffer=EmptyOutputBuffer;
2117   destination->manager.term_destination=TerminateDestination;
2118   destination->image=image;
2119 }
2120
2121 static char **SamplingFactorToList(const char *text)
2122 {
2123   char
2124     **textlist;
2125
2126   register char
2127     *q;
2128
2129   register const char
2130     *p;
2131
2132   register ssize_t
2133     i;
2134
2135   if (text == (char *) NULL)
2136     return((char **) NULL);
2137   /*
2138     Convert string to an ASCII list.
2139   */
2140   textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
2141     sizeof(*textlist));
2142   if (textlist == (char **) NULL)
2143     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2144   p=text;
2145   for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
2146   {
2147     for (q=(char *) p; *q != '\0'; q++)
2148       if (*q == ',')
2149         break;
2150     textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
2151       sizeof(*textlist[i]));
2152     if (textlist[i] == (char *) NULL)
2153       ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2154     (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2155     if (*q == '\r')
2156       q++;
2157     if (*q == '\0')
2158       break;
2159     p=q+1;
2160   }
2161   for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
2162     textlist[i]=ConstantString("1x1");
2163   return(textlist);
2164 }
2165
2166 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2167   Image *image,ExceptionInfo *exception)
2168 {
2169   const char
2170     *option,
2171     *sampling_factor,
2172     *value;
2173
2174   ErrorManager
2175     error_manager;
2176
2177   Image
2178     *volatile volatile_image;
2179
2180   int
2181     colorspace,
2182     quality;
2183
2184   JSAMPLE
2185     *volatile jpeg_pixels;
2186
2187   JSAMPROW
2188     scanline[1];
2189
2190   MagickBooleanType
2191     status;
2192
2193   MemoryInfo
2194     *memory_info;
2195
2196   register JSAMPLE
2197     *q;
2198
2199   register ssize_t
2200     i;
2201
2202   ssize_t
2203     y;
2204
2205   struct jpeg_compress_struct
2206     jpeg_info;
2207
2208   struct jpeg_error_mgr
2209     jpeg_error;
2210
2211   unsigned short
2212     scale;
2213
2214   /*
2215     Open image file.
2216   */
2217   assert(image_info != (const ImageInfo *) NULL);
2218   assert(image_info->signature == MagickCoreSignature);
2219   assert(image != (Image *) NULL);
2220   assert(image->signature == MagickCoreSignature);
2221   if (image->debug != MagickFalse)
2222     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2223   assert(exception != (ExceptionInfo *) NULL);
2224   assert(exception->signature == MagickCoreSignature);
2225   if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
2226       (image->next != (Image *) NULL))
2227     image=AppendImages(image,MagickFalse,exception);
2228   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2229   if (status == MagickFalse)
2230     return(status);
2231   /*
2232     Initialize JPEG parameters.
2233   */
2234   (void) memset(&error_manager,0,sizeof(error_manager));
2235   (void) memset(&jpeg_info,0,sizeof(jpeg_info));
2236   (void) memset(&jpeg_error,0,sizeof(jpeg_error));
2237   volatile_image=image;
2238   jpeg_info.client_data=(void *) volatile_image;
2239   jpeg_info.err=jpeg_std_error(&jpeg_error);
2240   jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2241   jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2242   error_manager.exception=exception;
2243   error_manager.image=volatile_image;
2244   memory_info=(MemoryInfo *) NULL;
2245   if (setjmp(error_manager.error_recovery) != 0)
2246     {
2247       jpeg_destroy_compress(&jpeg_info);
2248       (void) CloseBlob(volatile_image);
2249       return(MagickFalse);
2250     }
2251   jpeg_info.client_data=(void *) &error_manager;
2252   jpeg_create_compress(&jpeg_info);
2253   JPEGDestinationManager(&jpeg_info,image);
2254   if ((image->columns != (unsigned int) image->columns) ||
2255       (image->rows != (unsigned int) image->rows))
2256     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2257   jpeg_info.image_width=(unsigned int) image->columns;
2258   jpeg_info.image_height=(unsigned int) image->rows;
2259   jpeg_info.input_components=3;
2260   jpeg_info.data_precision=8;
2261   jpeg_info.in_color_space=JCS_RGB;
2262   switch (image->colorspace)
2263   {
2264     case CMYKColorspace:
2265     {
2266       jpeg_info.input_components=4;
2267       jpeg_info.in_color_space=JCS_CMYK;
2268       break;
2269     }
2270     case YCbCrColorspace:
2271     case Rec601YCbCrColorspace:
2272     case Rec709YCbCrColorspace:
2273     {
2274       jpeg_info.in_color_space=JCS_YCbCr;
2275       break;
2276     }
2277     case LinearGRAYColorspace:
2278     case GRAYColorspace:
2279     {
2280       if (image_info->type == TrueColorType)
2281         break;
2282       jpeg_info.input_components=1;
2283       jpeg_info.in_color_space=JCS_GRAYSCALE;
2284       break;
2285     }
2286     default:
2287     {
2288       (void) TransformImageColorspace(image,sRGBColorspace,exception);
2289       if (image_info->type == TrueColorType)
2290         break;
2291       if (SetImageGray(image,exception) != MagickFalse)
2292         {
2293           jpeg_info.input_components=1;
2294           jpeg_info.in_color_space=JCS_GRAYSCALE;
2295         }
2296       break;
2297     }
2298   }
2299   jpeg_set_defaults(&jpeg_info);
2300   if (jpeg_info.in_color_space == JCS_CMYK)
2301     jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2302   if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2303     jpeg_info.data_precision=8;
2304   else
2305     jpeg_info.data_precision=BITS_IN_JSAMPLE;
2306   if (image->debug != MagickFalse)
2307     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2308       "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
2309   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2310     {
2311       /*
2312         Set image resolution.
2313       */
2314       jpeg_info.write_JFIF_header=TRUE;
2315       jpeg_info.X_density=(UINT16) image->resolution.x;
2316       jpeg_info.Y_density=(UINT16) image->resolution.y;
2317       /*
2318         Set image resolution units.
2319       */
2320       if (image->units == PixelsPerInchResolution)
2321         jpeg_info.density_unit=(UINT8) 1;
2322       if (image->units == PixelsPerCentimeterResolution)
2323         jpeg_info.density_unit=(UINT8) 2;
2324     }
2325   jpeg_info.dct_method=JDCT_FLOAT;
2326   option=GetImageOption(image_info,"jpeg:dct-method");
2327   if (option != (const char *) NULL)
2328     switch (*option)
2329     {
2330       case 'D':
2331       case 'd':
2332       {
2333         if (LocaleCompare(option,"default") == 0)
2334           jpeg_info.dct_method=JDCT_DEFAULT;
2335         break;
2336       }
2337       case 'F':
2338       case 'f':
2339       {
2340         if (LocaleCompare(option,"fastest") == 0)
2341           jpeg_info.dct_method=JDCT_FASTEST;
2342         if (LocaleCompare(option,"float") == 0)
2343           jpeg_info.dct_method=JDCT_FLOAT;
2344         break;
2345       }
2346       case 'I':
2347       case 'i':
2348       {
2349         if (LocaleCompare(option,"ifast") == 0)
2350           jpeg_info.dct_method=JDCT_IFAST;
2351         if (LocaleCompare(option,"islow") == 0)
2352           jpeg_info.dct_method=JDCT_ISLOW;
2353         break;
2354       }
2355     }
2356   option=GetImageOption(image_info,"jpeg:optimize-coding");
2357   if (option != (const char *) NULL)
2358     jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE :
2359       FALSE;
2360   else
2361     {
2362       MagickSizeType
2363         length;
2364
2365       length=(MagickSizeType) jpeg_info.input_components*image->columns*
2366         image->rows*sizeof(JSAMPLE);
2367       if (length == (MagickSizeType) ((size_t) length))
2368         {
2369           /*
2370             Perform optimization only if available memory resources permit it.
2371           */
2372           status=AcquireMagickResource(MemoryResource,length);
2373           if (status != MagickFalse)
2374             RelinquishMagickResource(MemoryResource,length);
2375           jpeg_info.optimize_coding=status == MagickFalse ? FALSE : TRUE;
2376         }
2377     }
2378 #if defined(C_ARITH_CODING_SUPPORTED)
2379   option=GetImageOption(image_info,"jpeg:arithmetic-coding");
2380   if (IsStringTrue(option) != MagickFalse)
2381     {
2382       jpeg_info.arith_code=TRUE;
2383       jpeg_info.optimize_coding=FALSE; // Not supported.
2384     }
2385 #endif
2386 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2387   if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2388       (image_info->interlace != NoInterlace))
2389     {
2390       if (image->debug != MagickFalse)
2391         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2392           "Interlace: progressive");
2393       jpeg_simple_progression(&jpeg_info);
2394     }
2395   else
2396     if (image->debug != MagickFalse)
2397       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2398         "Interlace: non-progressive");
2399 #else
2400   if (image->debug != MagickFalse)
2401     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2402       "Interlace: nonprogressive");
2403 #endif
2404   quality=92;
2405   if ((image_info->compression != LosslessJPEGCompression) &&
2406       (image->quality <= 100))
2407     {
2408       if (image->quality != UndefinedCompressionQuality)
2409         quality=(int) image->quality;
2410       if (image->debug != MagickFalse)
2411         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2412           (double) image->quality);
2413     }
2414   else
2415     {
2416 #if !defined(C_LOSSLESS_SUPPORTED)
2417       quality=100;
2418       if (image->debug != MagickFalse)
2419         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2420 #else
2421       if (image->quality < 100)
2422         (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2423           "LosslessToLossyJPEGConversion","`%s'",image->filename);
2424       else
2425         {
2426           int
2427             point_transform,
2428             predictor;
2429
2430           predictor=image->quality/100;  /* range 1-7 */
2431           point_transform=image->quality % 20;  /* range 0-15 */
2432           jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2433           if (image->debug != MagickFalse)
2434             {
2435               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2436                 "Compression: lossless");
2437               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2438                 "Predictor: %d",predictor);
2439               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2440                 "Point Transform: %d",point_transform);
2441             }
2442         }
2443 #endif
2444     }
2445   option=GetImageOption(image_info,"jpeg:extent");
2446   if (option != (const char *) NULL)
2447     {
2448       Image
2449         *jpeg_image;
2450
2451       ImageInfo
2452         *extent_info;
2453
2454       extent_info=CloneImageInfo(image_info);
2455       extent_info->blob=NULL;
2456       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2457       if (jpeg_image != (Image *) NULL)
2458         {
2459           MagickSizeType
2460             extent;
2461
2462           size_t
2463             maximum,
2464             minimum;
2465
2466           /*
2467             Search for compression quality that does not exceed image extent.
2468           */
2469           extent_info->quality=0;
2470           extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2471           (void) DeleteImageOption(extent_info,"jpeg:extent");
2472           (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2473           maximum=image_info->quality;
2474           if (maximum < 2)
2475             maximum=101;
2476           for (minimum=2; minimum < maximum; )
2477           {
2478             (void) AcquireUniqueFilename(jpeg_image->filename);
2479             jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2480             status=WriteJPEGImage(extent_info,jpeg_image,exception);
2481             if (GetBlobSize(jpeg_image) <= extent)
2482               minimum=jpeg_image->quality+1;
2483             else
2484               maximum=jpeg_image->quality-1;
2485             (void) RelinquishUniqueFileResource(jpeg_image->filename);
2486           }
2487           quality=(int) minimum-1;
2488           jpeg_image=DestroyImage(jpeg_image);
2489         }
2490       extent_info=DestroyImageInfo(extent_info);
2491     }
2492   jpeg_set_quality(&jpeg_info,quality,TRUE);
2493 #if (JPEG_LIB_VERSION >= 70)
2494   option=GetImageOption(image_info,"quality");
2495   if (option != (const char *) NULL)
2496     {
2497       GeometryInfo
2498         geometry_info;
2499
2500       int
2501         flags;
2502
2503       /*
2504         Set quality scaling for luminance and chrominance separately.
2505       */
2506       flags=ParseGeometry(option,&geometry_info);
2507       if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2508         {
2509           jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2510             (geometry_info.rho+0.5));
2511           jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2512             (geometry_info.sigma+0.5));
2513           jpeg_default_qtables(&jpeg_info,TRUE);
2514         }
2515     }
2516 #endif
2517   colorspace=jpeg_info.in_color_space;
2518   value=GetImageOption(image_info,"jpeg:colorspace");
2519   if (value == (char *) NULL)
2520     value=GetImageProperty(image,"jpeg:colorspace",exception);
2521   if (value != (char *) NULL)
2522     colorspace=StringToInteger(value);
2523   sampling_factor=(const char *) NULL;
2524   if (colorspace == jpeg_info.in_color_space)
2525     {
2526       value=GetImageOption(image_info,"jpeg:sampling-factor");
2527       if (value == (char *) NULL)
2528         value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2529       if (value != (char *) NULL)
2530         {
2531           sampling_factor=value;
2532           if (image->debug != MagickFalse)
2533             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2534               "  Input sampling-factors=%s",sampling_factor);
2535         }
2536     }
2537   value=GetImageOption(image_info,"jpeg:sampling-factor");
2538   if (image_info->sampling_factor != (char *) NULL)
2539     sampling_factor=image_info->sampling_factor;
2540   if (sampling_factor == (const char *) NULL)
2541     {
2542       if (quality >= 90)
2543         for (i=0; i < MAX_COMPONENTS; i++)
2544         {
2545           jpeg_info.comp_info[i].h_samp_factor=1;
2546           jpeg_info.comp_info[i].v_samp_factor=1;
2547         }
2548     }
2549   else
2550     {
2551       char
2552         **factors;
2553
2554       GeometryInfo
2555         geometry_info;
2556
2557       MagickStatusType
2558         flags;
2559
2560       /*
2561         Set sampling factor.
2562       */
2563       i=0;
2564       factors=SamplingFactorToList(sampling_factor);
2565       if (factors != (char **) NULL)
2566         {
2567           for (i=0; i < MAX_COMPONENTS; i++)
2568           {
2569             if (factors[i] == (char *) NULL)
2570               break;
2571             flags=ParseGeometry(factors[i],&geometry_info);
2572             if ((flags & SigmaValue) == 0)
2573               geometry_info.sigma=geometry_info.rho;
2574             jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2575             jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2576             factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2577           }
2578           factors=(char **) RelinquishMagickMemory(factors);
2579         }
2580       for ( ; i < MAX_COMPONENTS; i++)
2581       {
2582         jpeg_info.comp_info[i].h_samp_factor=1;
2583         jpeg_info.comp_info[i].v_samp_factor=1;
2584       }
2585     }
2586   option=GetImageOption(image_info,"jpeg:q-table");
2587   if (option != (const char *) NULL)
2588     {
2589       QuantizationTable
2590         *table;
2591
2592       /*
2593         Custom quantization tables.
2594       */
2595       table=GetQuantizationTable(option,"0",exception);
2596       if (table != (QuantizationTable *) NULL)
2597         {
2598           for (i=0; i < MAX_COMPONENTS; i++)
2599             jpeg_info.comp_info[i].quant_tbl_no=0;
2600           jpeg_add_quant_table(&jpeg_info,0,table->levels,
2601             jpeg_quality_scaling(quality),0);
2602           table=DestroyQuantizationTable(table);
2603         }
2604       table=GetQuantizationTable(option,"1",exception);
2605       if (table != (QuantizationTable *) NULL)
2606         {
2607           for (i=1; i < MAX_COMPONENTS; i++)
2608             jpeg_info.comp_info[i].quant_tbl_no=1;
2609           jpeg_add_quant_table(&jpeg_info,1,table->levels,
2610             jpeg_quality_scaling(quality),0);
2611           table=DestroyQuantizationTable(table);
2612         }
2613       table=GetQuantizationTable(option,"2",exception);
2614       if (table != (QuantizationTable *) NULL)
2615         {
2616           for (i=2; i < MAX_COMPONENTS; i++)
2617             jpeg_info.comp_info[i].quant_tbl_no=2;
2618           jpeg_add_quant_table(&jpeg_info,2,table->levels,
2619             jpeg_quality_scaling(quality),0);
2620           table=DestroyQuantizationTable(table);
2621         }
2622       table=GetQuantizationTable(option,"3",exception);
2623       if (table != (QuantizationTable *) NULL)
2624         {
2625           for (i=3; i < MAX_COMPONENTS; i++)
2626             jpeg_info.comp_info[i].quant_tbl_no=3;
2627           jpeg_add_quant_table(&jpeg_info,3,table->levels,
2628             jpeg_quality_scaling(quality),0);
2629           table=DestroyQuantizationTable(table);
2630         }
2631     }
2632   jpeg_start_compress(&jpeg_info,TRUE);
2633   if (image->debug != MagickFalse)
2634     {
2635       if (image->storage_class == PseudoClass)
2636         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2637           "Storage class: PseudoClass");
2638       else
2639         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2640           "Storage class: DirectClass");
2641       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2642         (double) image->depth);
2643       if (image->colors != 0)
2644         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2645           "Number of colors: %.20g",(double) image->colors);
2646       else
2647         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2648           "Number of colors: unspecified");
2649       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2650         "JPEG data precision: %d",(int) jpeg_info.data_precision);
2651       switch (image->colorspace)
2652       {
2653         case CMYKColorspace:
2654         {
2655           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2656             "Storage class: DirectClass");
2657           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2658             "Colorspace: CMYK");
2659           break;
2660         }
2661         case YCbCrColorspace:
2662         case Rec601YCbCrColorspace:
2663         case Rec709YCbCrColorspace:
2664         {
2665           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2666             "Colorspace: YCbCr");
2667           break;
2668         }
2669         default:
2670           break;
2671       }
2672       switch (image->colorspace)
2673       {
2674         case CMYKColorspace:
2675         {
2676           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2677             "Colorspace: CMYK");
2678           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2679             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2680             jpeg_info.comp_info[0].h_samp_factor,
2681             jpeg_info.comp_info[0].v_samp_factor,
2682             jpeg_info.comp_info[1].h_samp_factor,
2683             jpeg_info.comp_info[1].v_samp_factor,
2684             jpeg_info.comp_info[2].h_samp_factor,
2685             jpeg_info.comp_info[2].v_samp_factor,
2686             jpeg_info.comp_info[3].h_samp_factor,
2687             jpeg_info.comp_info[3].v_samp_factor);
2688           break;
2689         }
2690         case GRAYColorspace:
2691         {
2692           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2693             "Colorspace: GRAY");
2694           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2695             "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2696             jpeg_info.comp_info[0].v_samp_factor);
2697           break;
2698         }
2699         case sRGBColorspace:
2700         case RGBColorspace:
2701         {
2702           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2703             "Image colorspace is RGB");
2704           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2705             "Sampling factors: %dx%d,%dx%d,%dx%d",
2706             jpeg_info.comp_info[0].h_samp_factor,
2707             jpeg_info.comp_info[0].v_samp_factor,
2708             jpeg_info.comp_info[1].h_samp_factor,
2709             jpeg_info.comp_info[1].v_samp_factor,
2710             jpeg_info.comp_info[2].h_samp_factor,
2711             jpeg_info.comp_info[2].v_samp_factor);
2712           break;
2713         }
2714         case YCbCrColorspace:
2715         case Rec601YCbCrColorspace:
2716         case Rec709YCbCrColorspace:
2717         {
2718           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2719             "Colorspace: YCbCr");
2720           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2721             "Sampling factors: %dx%d,%dx%d,%dx%d",
2722             jpeg_info.comp_info[0].h_samp_factor,
2723             jpeg_info.comp_info[0].v_samp_factor,
2724             jpeg_info.comp_info[1].h_samp_factor,
2725             jpeg_info.comp_info[1].v_samp_factor,
2726             jpeg_info.comp_info[2].h_samp_factor,
2727             jpeg_info.comp_info[2].v_samp_factor);
2728           break;
2729         }
2730         default:
2731         {
2732           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2733             image->colorspace);
2734           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2735             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2736             jpeg_info.comp_info[0].h_samp_factor,
2737             jpeg_info.comp_info[0].v_samp_factor,
2738             jpeg_info.comp_info[1].h_samp_factor,
2739             jpeg_info.comp_info[1].v_samp_factor,
2740             jpeg_info.comp_info[2].h_samp_factor,
2741             jpeg_info.comp_info[2].v_samp_factor,
2742             jpeg_info.comp_info[3].h_samp_factor,
2743             jpeg_info.comp_info[3].v_samp_factor);
2744           break;
2745         }
2746       }
2747     }
2748   /*
2749     Write JPEG profiles.
2750   */
2751   value=GetImageProperty(image,"comment",exception);
2752   if (value != (char *) NULL)
2753     for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2754       jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2755         (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2756   if (image->profiles != (void *) NULL)
2757     WriteProfile(&jpeg_info,image,exception);
2758   /*
2759     Convert MIFF to JPEG raster pixels.
2760   */
2761   memory_info=AcquireVirtualMemory((size_t) image->columns,
2762     jpeg_info.input_components*sizeof(*jpeg_pixels));
2763   if (memory_info == (MemoryInfo *) NULL)
2764     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2765   jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2766   if (setjmp(error_manager.error_recovery) != 0)
2767     {
2768       jpeg_destroy_compress(&jpeg_info);
2769       if (memory_info != (MemoryInfo *) NULL)
2770         memory_info=RelinquishVirtualMemory(memory_info);
2771       (void) CloseBlob(image);
2772       return(MagickFalse);
2773     }
2774   scanline[0]=(JSAMPROW) jpeg_pixels;
2775   scale=65535/(unsigned short) GetQuantumRange((size_t)
2776     jpeg_info.data_precision);
2777   if (scale == 0)
2778     scale=1;
2779   if (jpeg_info.data_precision <= 8)
2780     {
2781       if ((jpeg_info.in_color_space == JCS_RGB) ||
2782           (jpeg_info.in_color_space == JCS_YCbCr))
2783         for (y=0; y < (ssize_t) image->rows; y++)
2784         {
2785           register const Quantum
2786             *p;
2787
2788           register ssize_t
2789             x;
2790
2791           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2792           if (p == (const Quantum *) NULL)
2793             break;
2794           q=jpeg_pixels;
2795           for (x=0; x < (ssize_t) image->columns; x++)
2796           {
2797             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2798             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2799             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2800             p+=GetPixelChannels(image);
2801           }
2802           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2803           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2804             image->rows);
2805           if (status == MagickFalse)
2806             break;
2807         }
2808       else
2809         if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2810           for (y=0; y < (ssize_t) image->rows; y++)
2811           {
2812             register const Quantum
2813               *p;
2814
2815             register ssize_t
2816               x;
2817
2818             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2819             if (p == (const Quantum *) NULL)
2820               break;
2821             q=jpeg_pixels;
2822             for (x=0; x < (ssize_t) image->columns; x++)
2823             {
2824               *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2825                 image,p)));
2826               p+=GetPixelChannels(image);
2827             }
2828             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2829             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2830               image->rows);
2831             if (status == MagickFalse)
2832               break;
2833             }
2834         else
2835           for (y=0; y < (ssize_t) image->rows; y++)
2836           {
2837             register const Quantum
2838               *p;
2839
2840             register ssize_t
2841               x;
2842
2843             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2844             if (p == (const Quantum *) NULL)
2845               break;
2846             q=jpeg_pixels;
2847             for (x=0; x < (ssize_t) image->columns; x++)
2848             {
2849               /*
2850                 Convert DirectClass packets to contiguous CMYK scanlines.
2851               */
2852               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2853                 GetPixelCyan(image,p))));
2854               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2855                 GetPixelMagenta(image,p))));
2856               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2857                 GetPixelYellow(image,p))));
2858               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2859                 GetPixelBlack(image,p))));
2860               p+=GetPixelChannels(image);
2861             }
2862             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2863             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2864               image->rows);
2865             if (status == MagickFalse)
2866               break;
2867           }
2868     }
2869   else
2870     if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2871       for (y=0; y < (ssize_t) image->rows; y++)
2872       {
2873         register const Quantum
2874           *p;
2875
2876         register ssize_t
2877           x;
2878
2879         p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2880         if (p == (const Quantum *) NULL)
2881           break;
2882         q=jpeg_pixels;
2883         for (x=0; x < (ssize_t) image->columns; x++)
2884         {
2885           *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2886             p)))/scale);
2887           p+=GetPixelChannels(image);
2888         }
2889         (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2890         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2891           image->rows);
2892         if (status == MagickFalse)
2893           break;
2894       }
2895     else
2896       if ((jpeg_info.in_color_space == JCS_RGB) ||
2897           (jpeg_info.in_color_space == JCS_YCbCr))
2898         for (y=0; y < (ssize_t) image->rows; y++)
2899         {
2900           register const Quantum
2901             *p;
2902
2903           register ssize_t
2904             x;
2905
2906           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2907           if (p == (const Quantum *) NULL)
2908             break;
2909           q=jpeg_pixels;
2910           for (x=0; x < (ssize_t) image->columns; x++)
2911           {
2912             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2913             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2914             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2915             p+=GetPixelChannels(image);
2916           }
2917           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2918           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2919             image->rows);
2920           if (status == MagickFalse)
2921             break;
2922         }
2923       else
2924         for (y=0; y < (ssize_t) image->rows; y++)
2925         {
2926           register const Quantum
2927             *p;
2928
2929           register ssize_t
2930             x;
2931
2932           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2933           if (p == (const Quantum *) NULL)
2934             break;
2935           q=jpeg_pixels;
2936           for (x=0; x < (ssize_t) image->columns; x++)
2937           {
2938             /*
2939               Convert DirectClass packets to contiguous CMYK scanlines.
2940             */
2941             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2942               image,p))/scale);
2943             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2944               image,p))/scale);
2945             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2946               image,p))/scale);
2947             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2948               image,p))/scale);
2949             p+=GetPixelChannels(image);
2950           }
2951           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2952           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2953             image->rows);
2954           if (status == MagickFalse)
2955             break;
2956         }
2957   if (y == (ssize_t) image->rows)
2958     jpeg_finish_compress(&jpeg_info);
2959   /*
2960     Relinquish resources.
2961   */
2962   jpeg_destroy_compress(&jpeg_info);
2963   memory_info=RelinquishVirtualMemory(memory_info);
2964   (void) CloseBlob(image);
2965   return(MagickTrue);
2966 }
2967 #endif