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