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