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