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