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