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