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