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