]> granicus.if.org Git - imagemagick/blob - coders/jpeg.c
(no commit message)
[imagemagick] / coders / jpeg.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                        JJJJJ  PPPP   EEEEE   GGGG                           %
7 %                          J    P   P  E      G                               %
8 %                          J    PPPP   EEE    G  GG                           %
9 %                        J J    P      E      G   G                           %
10 %                        JJJ    P      EEEEE   GGG                            %
11 %                                                                             %
12 %                                                                             %
13 %                       Read/Write JPEG Image Format                          %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions.  Blob support contributed by Glenn Randers-Pehrson.
39 %
40 %
41 */
42
43
44 /*
45   Include declarations.
46 */
47 #include "MagickCore/studio.h"
48 #include "MagickCore/artifact.h"
49 #include "MagickCore/attribute.h"
50 #include "MagickCore/blob.h"
51 #include "MagickCore/blob-private.h"
52 #include "MagickCore/cache.h"
53 #include "MagickCore/color.h"
54 #include "MagickCore/colormap-private.h"
55 #include "MagickCore/color-private.h"
56 #include "MagickCore/colormap.h"
57 #include "MagickCore/colorspace.h"
58 #include "MagickCore/colorspace-private.h"
59 #include "MagickCore/constitute.h"
60 #include "MagickCore/exception.h"
61 #include "MagickCore/exception-private.h"
62 #include "MagickCore/geometry.h"
63 #include "MagickCore/image.h"
64 #include "MagickCore/image-private.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/magick.h"
68 #include "MagickCore/memory_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/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     units;
1026
1027   ssize_t
1028     y;
1029
1030   /*
1031     Open image file.
1032   */
1033   assert(image_info != (const ImageInfo *) NULL);
1034   assert(image_info->signature == MagickSignature);
1035   if (image_info->debug != MagickFalse)
1036     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1037       image_info->filename);
1038   assert(exception != (ExceptionInfo *) NULL);
1039   assert(exception->signature == MagickSignature);
1040   debug=IsEventLogging();
1041   (void) debug;
1042   image=AcquireImage(image_info,exception);
1043   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1044   if (status == MagickFalse)
1045     {
1046       image=DestroyImageList(image);
1047       return((Image *) NULL);
1048     }
1049   /*
1050     Initialize JPEG parameters.
1051   */
1052   (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1053   (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1054   (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1055   jpeg_info.err=jpeg_std_error(&jpeg_error);
1056   jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1057   jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1058   memory_info=(MemoryInfo *) NULL;
1059   error_manager.exception=exception;
1060   error_manager.image=image;
1061   if (setjmp(error_manager.error_recovery) != 0)
1062     {
1063       jpeg_destroy_decompress(&jpeg_info);
1064       if (error_manager.profile != (StringInfo *) NULL)
1065         error_manager.profile=DestroyStringInfo(error_manager.profile);
1066       (void) CloseBlob(image);
1067       number_pixels=(MagickSizeType) image->columns*image->rows;
1068       if (number_pixels != 0)
1069         return(GetFirstImageInList(image));
1070       return(DestroyImage(image));
1071     }
1072   jpeg_info.client_data=(void *) &error_manager;
1073   jpeg_create_decompress(&jpeg_info);
1074   JPEGSourceManager(&jpeg_info,image);
1075   jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
1076   jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
1077   jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
1078   for (i=1; i < 16; i++)
1079     if ((i != 2) && (i != 13) && (i != 14))
1080       jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
1081   i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
1082   if ((image_info->colorspace == YCbCrColorspace) ||
1083       (image_info->colorspace == Rec601YCbCrColorspace) ||
1084       (image_info->colorspace == Rec709YCbCrColorspace))
1085     jpeg_info.out_color_space=JCS_YCbCr;
1086   /*
1087     Set image resolution.
1088   */
1089   units=0;
1090   if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1091       (jpeg_info.Y_density != 1))
1092     {
1093       image->resolution.x=(double) jpeg_info.X_density;
1094       image->resolution.y=(double) jpeg_info.Y_density;
1095       units=(size_t) jpeg_info.density_unit;
1096     }
1097   if (units == 1)
1098     image->units=PixelsPerInchResolution;
1099   if (units == 2)
1100     image->units=PixelsPerCentimeterResolution;
1101   number_pixels=(MagickSizeType) image->columns*image->rows;
1102   option=GetImageOption(image_info,"jpeg:size");
1103   if (option != (const char *) NULL)
1104     {
1105       double
1106         scale_factor;
1107
1108       GeometryInfo
1109         geometry_info;
1110
1111       MagickStatusType
1112         flags;
1113
1114       /*
1115         Scale the image.
1116       */
1117       flags=ParseGeometry(option,&geometry_info);
1118       if ((flags & SigmaValue) == 0)
1119         geometry_info.sigma=geometry_info.rho;
1120       jpeg_calc_output_dimensions(&jpeg_info);
1121       image->magick_columns=jpeg_info.output_width;
1122       image->magick_rows=jpeg_info.output_height;
1123       scale_factor=1.0;
1124       if (geometry_info.rho != 0.0)
1125         scale_factor=jpeg_info.output_width/geometry_info.rho;
1126       if ((geometry_info.sigma != 0.0) &&
1127           (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1128         scale_factor=jpeg_info.output_height/geometry_info.sigma;
1129       jpeg_info.scale_num=1U;
1130       jpeg_info.scale_denom=(unsigned int) scale_factor;
1131       jpeg_calc_output_dimensions(&jpeg_info);
1132       if (image->debug != MagickFalse)
1133         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1134           "Scale factor: %.20g",(double) scale_factor);
1135     }
1136 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1137 #if defined(D_LOSSLESS_SUPPORTED)
1138   image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1139     JPEGInterlace : NoInterlace;
1140   image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1141     LosslessJPEGCompression : JPEGCompression;
1142   if (jpeg_info.data_precision > 8)
1143     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1144       "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1145       image->filename);
1146   if (jpeg_info.data_precision == 16)
1147     jpeg_info.data_precision=12;
1148 #else
1149   image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1150     NoInterlace;
1151   image->compression=JPEGCompression;
1152 #endif
1153 #else
1154   image->compression=JPEGCompression;
1155   image->interlace=JPEGInterlace;
1156 #endif
1157   option=GetImageOption(image_info,"jpeg:colors");
1158   if (option != (const char *) NULL)
1159     {
1160       /*
1161         Let the JPEG library quantize the image.
1162       */
1163       jpeg_info.quantize_colors=MagickTrue;
1164       jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1165     }
1166   option=GetImageOption(image_info,"jpeg:block-smoothing");
1167   if (option != (const char *) NULL)
1168     jpeg_info.do_block_smoothing=IsStringTrue(option);
1169   jpeg_info.dct_method=JDCT_FLOAT;
1170   option=GetImageOption(image_info,"jpeg:dct-method");
1171   if (option != (const char *) NULL)
1172     switch (*option)
1173     {
1174       case 'D':
1175       case 'd':
1176       {
1177         if (LocaleCompare(option,"default") == 0)
1178           jpeg_info.dct_method=JDCT_DEFAULT;
1179         break;
1180       }
1181       case 'F':
1182       case 'f':
1183       {
1184         if (LocaleCompare(option,"fastest") == 0)
1185           jpeg_info.dct_method=JDCT_FASTEST;
1186         if (LocaleCompare(option,"float") == 0)
1187           jpeg_info.dct_method=JDCT_FLOAT;
1188         break;
1189       }
1190       case 'I':
1191       case 'i':
1192       {
1193         if (LocaleCompare(option,"ifast") == 0)
1194           jpeg_info.dct_method=JDCT_IFAST;
1195         if (LocaleCompare(option,"islow") == 0)
1196           jpeg_info.dct_method=JDCT_ISLOW;
1197         break;
1198       }
1199     }
1200   option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1201   if (option != (const char *) NULL)
1202     jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1203   (void) jpeg_start_decompress(&jpeg_info);
1204   image->columns=jpeg_info.output_width;
1205   image->rows=jpeg_info.output_height;
1206   image->depth=(size_t) jpeg_info.data_precision;
1207   switch (jpeg_info.out_color_space)
1208   {
1209     case JCS_RGB:
1210     default:
1211     {
1212       (void) SetImageColorspace(image,sRGBColorspace,exception);
1213       break;
1214     }
1215     case JCS_GRAYSCALE:
1216     {
1217       (void) SetImageColorspace(image,GRAYColorspace,exception);
1218       break;
1219     }
1220     case JCS_YCbCr:
1221     {
1222       (void) SetImageColorspace(image,YCbCrColorspace,exception);
1223       break;
1224     }
1225     case JCS_CMYK:
1226     {
1227       (void) SetImageColorspace(image,CMYKColorspace,exception);
1228       break;
1229     }
1230   }
1231   if (IsITUFaxImage(image) != MagickFalse)
1232     {
1233       (void) SetImageColorspace(image,LabColorspace,exception);
1234       jpeg_info.out_color_space=JCS_YCbCr;
1235     }
1236   option=GetImageOption(image_info,"jpeg:colors");
1237   if (option != (const char *) NULL)
1238     if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1239          == MagickFalse)
1240       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1241   if ((jpeg_info.output_components == 1) &&
1242       (jpeg_info.quantize_colors == MagickFalse))
1243     {
1244       size_t
1245         colors;
1246
1247       colors=(size_t) GetQuantumRange(image->depth)+1;
1248       if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1249         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1250     }
1251   if (image->debug != MagickFalse)
1252     {
1253       if (image->interlace != NoInterlace)
1254         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1255           "Interlace: progressive");
1256       else
1257         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1258           "Interlace: nonprogressive");
1259       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1260         (int) jpeg_info.data_precision);
1261       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1262         (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1263     }
1264   JPEGSetImageQuality(&jpeg_info,image,exception);
1265   JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1266   (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1267     jpeg_info.out_color_space);
1268   (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1269   if (image_info->ping != MagickFalse)
1270     {
1271       jpeg_destroy_decompress(&jpeg_info);
1272       (void) CloseBlob(image);
1273       return(GetFirstImageInList(image));
1274     }
1275   memory_info=AcquireVirtualMemory((size_t) image->columns,
1276     jpeg_info.output_components*sizeof(*jpeg_pixels));
1277   if (memory_info == (MemoryInfo *) NULL)
1278     {
1279       jpeg_destroy_decompress(&jpeg_info);
1280       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1281     }
1282   jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
1283   /*
1284     Convert JPEG pixels to pixel packets.
1285   */
1286   if (setjmp(error_manager.error_recovery) != 0)
1287     {
1288       if (memory_info != (MemoryInfo *) NULL)
1289         memory_info=RelinquishVirtualMemory(memory_info);
1290       jpeg_destroy_decompress(&jpeg_info);
1291       (void) CloseBlob(image);
1292       number_pixels=(MagickSizeType) image->columns*image->rows;
1293       if (number_pixels != 0)
1294         return(GetFirstImageInList(image));
1295       return(DestroyImage(image));
1296     }
1297   if (jpeg_info.quantize_colors != MagickFalse)
1298     {
1299       image->colors=(size_t) jpeg_info.actual_number_of_colors;
1300       if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1301         for (i=0; i < (ssize_t) image->colors; i++)
1302         {
1303           image->colormap[i].red=(double) ScaleCharToQuantum(
1304             jpeg_info.colormap[0][i]);
1305           image->colormap[i].green=image->colormap[i].red;
1306           image->colormap[i].blue=image->colormap[i].red;
1307           image->colormap[i].alpha=OpaqueAlpha;
1308         }
1309       else
1310         for (i=0; i < (ssize_t) image->colors; i++)
1311         {
1312           image->colormap[i].red=(double) ScaleCharToQuantum(
1313             jpeg_info.colormap[0][i]);
1314           image->colormap[i].green=(double) ScaleCharToQuantum(
1315             jpeg_info.colormap[1][i]);
1316           image->colormap[i].blue=(double) ScaleCharToQuantum(
1317             jpeg_info.colormap[2][i]);
1318           image->colormap[i].alpha=OpaqueAlpha;
1319         }
1320     }
1321   scanline[0]=(JSAMPROW) jpeg_pixels;
1322   for (y=0; y < (ssize_t) image->rows; y++)
1323   {
1324     register ssize_t
1325       x;
1326
1327     register Quantum
1328       *restrict q;
1329
1330     if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1331       {
1332         (void) ThrowMagickException(exception,GetMagickModule(),
1333           CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1334         continue;
1335       }
1336     p=jpeg_pixels;
1337     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1338     if (q == (Quantum *) NULL)
1339       break;
1340     if (jpeg_info.data_precision > 8)
1341       {
1342         unsigned short
1343           scale;
1344
1345         scale=65535U/GetQuantumRange(jpeg_info.data_precision);
1346         if (jpeg_info.output_components == 1)
1347           for (x=0; x < (ssize_t) image->columns; x++)
1348           {
1349             size_t
1350               pixel;
1351
1352             pixel=(size_t) (scale*GETJSAMPLE(*p));
1353             index=ConstrainColormapIndex(image,pixel,exception);
1354             SetPixelIndex(image,index,q);
1355             SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1356             p++;
1357             q+=GetPixelChannels(image);
1358           }
1359         else
1360           if (image->colorspace != CMYKColorspace)
1361             for (x=0; x < (ssize_t) image->columns; x++)
1362             {
1363               SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1364               SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1365               SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1366               SetPixelAlpha(image,OpaqueAlpha,q);
1367               q+=GetPixelChannels(image);
1368             }
1369           else
1370             for (x=0; x < (ssize_t) image->columns; x++)
1371             {
1372               SetPixelCyan(image,QuantumRange-
1373                 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1374               SetPixelMagenta(image,QuantumRange-
1375                 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1376               SetPixelYellow(image,QuantumRange-
1377                 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1378               SetPixelBlack(image,QuantumRange-
1379                 ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),q);
1380               SetPixelAlpha(image,OpaqueAlpha,q);
1381               q+=GetPixelChannels(image);
1382             }
1383       }
1384     else
1385       if (jpeg_info.output_components == 1)
1386         for (x=0; x < (ssize_t) image->columns; x++)
1387         {
1388           index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1389           SetPixelIndex(image,index,q);
1390           SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1391           p++;
1392           q+=GetPixelChannels(image);
1393         }
1394       else
1395         if (image->colorspace != CMYKColorspace)
1396           for (x=0; x < (ssize_t) image->columns; x++)
1397           {
1398             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1399               GETJSAMPLE(*p++)),q);
1400             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1401               GETJSAMPLE(*p++)),q);
1402             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1403               GETJSAMPLE(*p++)),q);
1404             SetPixelAlpha(image,OpaqueAlpha,q);
1405             q+=GetPixelChannels(image);
1406           }
1407         else
1408           for (x=0; x < (ssize_t) image->columns; x++)
1409           {
1410             SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1411               (unsigned char) GETJSAMPLE(*p++)),q);
1412             SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1413               (unsigned char) GETJSAMPLE(*p++)),q);
1414             SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1415               (unsigned char) GETJSAMPLE(*p++)),q);
1416             SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1417               (unsigned char) GETJSAMPLE(*p++)),q);
1418             SetPixelAlpha(image,OpaqueAlpha,q);
1419             q+=GetPixelChannels(image);
1420           }
1421     if (SyncAuthenticPixels(image,exception) == MagickFalse)
1422       break;
1423     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1424       image->rows);
1425     if (status == MagickFalse)
1426       {
1427         jpeg_abort_decompress(&jpeg_info);
1428         break;
1429       }
1430   }
1431   if (status != MagickFalse)
1432     {
1433       error_manager.finished=MagickTrue;
1434       if (setjmp(error_manager.error_recovery) == 0)
1435         (void) jpeg_finish_decompress(&jpeg_info);
1436     }
1437   /*
1438     Free jpeg resources.
1439   */
1440   jpeg_destroy_decompress(&jpeg_info);
1441   memory_info=RelinquishVirtualMemory(memory_info);
1442   (void) CloseBlob(image);
1443   return(GetFirstImageInList(image));
1444 }
1445 #endif
1446
1447
1448 /*
1449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1450 %                                                                             %
1451 %                                                                             %
1452 %                                                                             %
1453 %   R e g i s t e r J P E G I m a g e                                         %
1454 %                                                                             %
1455 %                                                                             %
1456 %                                                                             %
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458 %
1459 %  RegisterJPEGImage() adds properties for the JPEG image format to
1460 %  the list of supported formats.  The properties include the image format
1461 %  tag, a method to read and/or write the format, whether the format
1462 %  supports the saving of more than one frame to the same file or blob,
1463 %  whether the format supports native in-memory I/O, and a brief
1464 %  description of the format.
1465 %
1466 %  The format of the RegisterJPEGImage method is:
1467 %
1468 %      size_t RegisterJPEGImage(void)
1469 %
1470 */
1471 ModuleExport size_t RegisterJPEGImage(void)
1472 {
1473   char
1474     version[MaxTextExtent];
1475
1476   MagickInfo
1477     *entry;
1478
1479   static const char
1480     description[] = "Joint Photographic Experts Group JFIF format";
1481
1482   *version='\0';
1483 #if defined(JPEG_LIB_VERSION)
1484   (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1485 #endif
1486   entry=SetMagickInfo("JPEG");
1487   entry->thread_support=NoThreadSupport;
1488 #if defined(MAGICKCORE_JPEG_DELEGATE)
1489   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1490   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1491 #endif
1492   entry->magick=(IsImageFormatHandler *) IsJPEG;
1493   entry->adjoin=MagickFalse;
1494   entry->description=ConstantString(description);
1495   if (*version != '\0')
1496     entry->version=ConstantString(version);
1497   entry->mime_type=ConstantString("image/jpeg");
1498   entry->module=ConstantString("JPEG");
1499   (void) RegisterMagickInfo(entry);
1500   entry=SetMagickInfo("JPG");
1501   entry->thread_support=NoThreadSupport;
1502 #if defined(MAGICKCORE_JPEG_DELEGATE)
1503   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1504   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1505 #endif
1506   entry->adjoin=MagickFalse;
1507   entry->description=ConstantString(description);
1508   if (*version != '\0')
1509     entry->version=ConstantString(version);
1510   entry->mime_type=ConstantString("image/jpeg");
1511   entry->module=ConstantString("JPEG");
1512   (void) RegisterMagickInfo(entry);
1513   entry=SetMagickInfo("PJPEG");
1514   entry->thread_support=NoThreadSupport;
1515 #if defined(MAGICKCORE_JPEG_DELEGATE)
1516   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1517   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1518 #endif
1519   entry->adjoin=MagickFalse;
1520   entry->description=ConstantString(description);
1521   if (*version != '\0')
1522     entry->version=ConstantString(version);
1523   entry->mime_type=ConstantString("image/jpeg");
1524   entry->module=ConstantString("JPEG");
1525   (void) RegisterMagickInfo(entry);
1526   return(MagickImageCoderSignature);
1527 }
1528
1529
1530 /*
1531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532 %                                                                             %
1533 %                                                                             %
1534 %                                                                             %
1535 %   U n r e g i s t e r J P E G I m a g e                                     %
1536 %                                                                             %
1537 %                                                                             %
1538 %                                                                             %
1539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540 %
1541 %  UnregisterJPEGImage() removes format registrations made by the
1542 %  JPEG module from the list of supported formats.
1543 %
1544 %  The format of the UnregisterJPEGImage method is:
1545 %
1546 %      UnregisterJPEGImage(void)
1547 %
1548 */
1549 ModuleExport void UnregisterJPEGImage(void)
1550 {
1551   (void) UnregisterMagickInfo("PJPG");
1552   (void) UnregisterMagickInfo("JPEG");
1553   (void) UnregisterMagickInfo("JPG");
1554 }
1555
1556
1557 #if defined(MAGICKCORE_JPEG_DELEGATE)
1558 /*
1559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560 %                                                                             %
1561 %                                                                             %
1562 %                                                                             %
1563 %  W r i t e J P E G I m a g e                                                %
1564 %                                                                             %
1565 %                                                                             %
1566 %                                                                             %
1567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568 %
1569 %  WriteJPEGImage() writes a JPEG image file and returns it.  It
1570 %  allocates the memory necessary for the new Image structure and returns a
1571 %  pointer to the new image.
1572 %
1573 %  The format of the WriteJPEGImage method is:
1574 %
1575 %      MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1576 %        Image *image,ExceptionInfo *exception)
1577 %
1578 %  A description of each parameter follows:
1579 %
1580 %    o image_info: the image info.
1581 %
1582 %    o jpeg_image:  The image.
1583 %
1584 %    o exception: return any errors or warnings in this structure.
1585 %
1586 */
1587
1588 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1589 {
1590   assert(table != (QuantizationTable *) NULL);
1591   if (table->slot != (char *) NULL)
1592     table->slot=DestroyString(table->slot);
1593   if (table->description != (char *) NULL)
1594     table->description=DestroyString(table->description);
1595   if (table->levels != (unsigned int *) NULL)
1596     table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1597   table=(QuantizationTable *) RelinquishMagickMemory(table);
1598   return(table);
1599 }
1600
1601 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1602 {
1603   DestinationManager
1604     *destination;
1605
1606   destination=(DestinationManager *) cinfo->dest;
1607   destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1608     MaxBufferExtent,destination->buffer);
1609   if (destination->manager.free_in_buffer != MaxBufferExtent)
1610     ERREXIT(cinfo,JERR_FILE_WRITE);
1611   destination->manager.next_output_byte=destination->buffer;
1612   return(TRUE);
1613 }
1614
1615 static QuantizationTable *GetQuantizationTable(const char *filename,
1616   const char *slot,ExceptionInfo *exception)
1617 {
1618   char
1619     *p,
1620     *xml;
1621
1622   const char
1623     *attribute,
1624     *content;
1625
1626   double
1627     value;
1628
1629   register ssize_t
1630     i;
1631
1632   ssize_t
1633     j;
1634
1635   QuantizationTable
1636     *table;
1637
1638   size_t
1639     length;
1640
1641   XMLTreeInfo
1642     *description,
1643     *levels,
1644     *quantization_tables,
1645     *table_iterator;
1646
1647   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1648     "Loading quantization tables \"%s\" ...",filename);
1649   table=(QuantizationTable *) NULL;
1650   xml=FileToString(filename,~0UL,exception);
1651   if (xml == (char *) NULL)
1652     return(table);
1653   quantization_tables=NewXMLTree(xml,exception);
1654   if (quantization_tables == (XMLTreeInfo *) NULL)
1655     {
1656       xml=DestroyString(xml);
1657       return(table);
1658     }
1659   for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1660        table_iterator != (XMLTreeInfo *) NULL;
1661        table_iterator=GetNextXMLTreeTag(table_iterator))
1662   {
1663     attribute=GetXMLTreeAttribute(table_iterator,"slot");
1664     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1665       break;
1666     attribute=GetXMLTreeAttribute(table_iterator,"alias");
1667     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1668       break;
1669   }
1670   if (table_iterator == (XMLTreeInfo *) NULL)
1671     {
1672       xml=DestroyString(xml);
1673       return(table);
1674     }
1675   description=GetXMLTreeChild(table_iterator,"description");
1676   if (description == (XMLTreeInfo *) NULL)
1677     {
1678       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1679         "XmlMissingElement", "<description>, slot \"%s\"",slot);
1680       quantization_tables=DestroyXMLTree(quantization_tables);
1681       xml=DestroyString(xml);
1682       return(table);
1683     }
1684   levels=GetXMLTreeChild(table_iterator,"levels");
1685   if (levels == (XMLTreeInfo *) NULL)
1686     {
1687       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1688         "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1689       quantization_tables=DestroyXMLTree(quantization_tables);
1690       xml=DestroyString(xml);
1691       return(table);
1692     }
1693   table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1694   if (table == (QuantizationTable *) NULL)
1695     ThrowFatalException(ResourceLimitFatalError,
1696       "UnableToAcquireQuantizationTable");
1697   table->slot=(char *) NULL;
1698   table->description=(char *) NULL;
1699   table->levels=(unsigned int *) NULL;
1700   attribute=GetXMLTreeAttribute(table_iterator,"slot");
1701   if (attribute != (char *) NULL)
1702     table->slot=ConstantString(attribute);
1703   content=GetXMLTreeContent(description);
1704   if (content != (char *) NULL)
1705     table->description=ConstantString(content);
1706   attribute=GetXMLTreeAttribute(levels,"width");
1707   if (attribute == (char *) NULL)
1708     {
1709       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1710         "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1711       quantization_tables=DestroyXMLTree(quantization_tables);
1712       table=DestroyQuantizationTable(table);
1713       xml=DestroyString(xml);
1714       return(table);
1715     }
1716   table->width=StringToUnsignedLong(attribute);
1717   if (table->width == 0)
1718     {
1719       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1720        "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1721       quantization_tables=DestroyXMLTree(quantization_tables);
1722       table=DestroyQuantizationTable(table);
1723       xml=DestroyString(xml);
1724       return(table);
1725     }
1726   attribute=GetXMLTreeAttribute(levels,"height");
1727   if (attribute == (char *) NULL)
1728     {
1729       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1730         "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1731       quantization_tables=DestroyXMLTree(quantization_tables);
1732       table=DestroyQuantizationTable(table);
1733       xml=DestroyString(xml);
1734       return(table);
1735     }
1736   table->height=StringToUnsignedLong(attribute);
1737   if (table->height == 0)
1738     {
1739       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1740         "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1741       quantization_tables=DestroyXMLTree(quantization_tables);
1742       table=DestroyQuantizationTable(table);
1743       xml=DestroyString(xml);
1744       return(table);
1745     }
1746   attribute=GetXMLTreeAttribute(levels,"divisor");
1747   if (attribute == (char *) NULL)
1748     {
1749       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1750         "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1751       quantization_tables=DestroyXMLTree(quantization_tables);
1752       table=DestroyQuantizationTable(table);
1753       xml=DestroyString(xml);
1754       return(table);
1755     }
1756   table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1757   if (table->divisor == 0.0)
1758     {
1759       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1760         "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1761       quantization_tables=DestroyXMLTree(quantization_tables);
1762       table=DestroyQuantizationTable(table);
1763       xml=DestroyString(xml);
1764       return(table);
1765     }
1766   content=GetXMLTreeContent(levels);
1767   if (content == (char *) NULL)
1768     {
1769       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1770         "XmlMissingContent", "<levels>, table \"%s\"",slot);
1771       quantization_tables=DestroyXMLTree(quantization_tables);
1772       table=DestroyQuantizationTable(table);
1773       xml=DestroyString(xml);
1774       return(table);
1775     }
1776   length=(size_t) table->width*table->height;
1777   if (length < 64)
1778     length=64;
1779   table->levels=(unsigned int *) AcquireQuantumMemory(length,
1780     sizeof(*table->levels));
1781   if (table->levels == (unsigned int *) NULL)
1782     ThrowFatalException(ResourceLimitFatalError,
1783       "UnableToAcquireQuantizationTable");
1784   for (i=0; i < (ssize_t) (table->width*table->height); i++)
1785   {
1786     table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1787       table->divisor+0.5);
1788     while (isspace((int) ((unsigned char) *p)) != 0)
1789       p++;
1790     if (*p == ',')
1791       p++;
1792     content=p;
1793   }
1794   value=InterpretLocaleValue(content,&p);
1795   (void) value;
1796   if (p != content)
1797     {
1798       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1799         "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1800      quantization_tables=DestroyXMLTree(quantization_tables);
1801      table=DestroyQuantizationTable(table);
1802      xml=DestroyString(xml);
1803      return(table);
1804    }
1805   for (j=i; j < 64; j++)
1806     table->levels[j]=table->levels[j-1];
1807   quantization_tables=DestroyXMLTree(quantization_tables);
1808   xml=DestroyString(xml);
1809   return(table);
1810 }
1811
1812 static void InitializeDestination(j_compress_ptr cinfo)
1813 {
1814   DestinationManager
1815     *destination;
1816
1817   destination=(DestinationManager *) cinfo->dest;
1818   destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1819     ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1820   destination->manager.next_output_byte=destination->buffer;
1821   destination->manager.free_in_buffer=MaxBufferExtent;
1822 }
1823
1824 static inline size_t MagickMin(const size_t x,const size_t y)
1825 {
1826   if (x < y)
1827     return(x);
1828   return(y);
1829 }
1830
1831 static void TerminateDestination(j_compress_ptr cinfo)
1832 {
1833   DestinationManager
1834     *destination;
1835
1836   destination=(DestinationManager *) cinfo->dest;
1837   if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1838     {
1839       ssize_t
1840         count;
1841
1842       count=WriteBlob(destination->image,MaxBufferExtent-
1843         destination->manager.free_in_buffer,destination->buffer);
1844       if (count != (ssize_t)
1845           (MaxBufferExtent-destination->manager.free_in_buffer))
1846         ERREXIT(cinfo,JERR_FILE_WRITE);
1847     }
1848 }
1849
1850 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1851 {
1852   const char
1853     *name;
1854
1855   const StringInfo
1856     *profile;
1857
1858   MagickBooleanType
1859     iptc;
1860
1861   register ssize_t
1862     i;
1863
1864   size_t
1865     length,
1866     tag_length;
1867
1868   StringInfo
1869     *custom_profile;
1870
1871   /*
1872     Save image profile as a APP marker.
1873   */
1874   iptc=MagickFalse;
1875   custom_profile=AcquireStringInfo(65535L);
1876   ResetImageProfileIterator(image);
1877   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1878   {
1879     register unsigned char
1880       *p;
1881
1882     profile=GetImageProfile(image,name);
1883     p=GetStringInfoDatum(custom_profile);
1884     if (LocaleCompare(name,"EXIF") == 0)
1885       for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1886       {
1887         length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1888         jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1889           (unsigned int) length);
1890       }
1891     if (LocaleCompare(name,"ICC") == 0)
1892       {
1893         register unsigned char
1894           *p;
1895
1896         tag_length=strlen(ICC_PROFILE);
1897         p=GetStringInfoDatum(custom_profile);
1898         (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1899         p[tag_length]='\0';
1900         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1901         {
1902           length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1903           p[12]=(unsigned char) ((i/65519L)+1);
1904           p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1905           (void) CopyMagickMemory(p+tag_length+3,GetStringInfoDatum(profile)+i,
1906             length);
1907           jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1908             custom_profile),(unsigned int) (length+tag_length+3));
1909         }
1910       }
1911     if (((LocaleCompare(name,"IPTC") == 0) ||
1912         (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1913       {
1914         size_t
1915           roundup;
1916
1917         iptc=MagickTrue;
1918         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1919         {
1920           length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1921           roundup=(size_t) (length & 0x01);
1922           if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1923             {
1924               (void) memcpy(p,"Photoshop 3.0 ",14);
1925               tag_length=14;
1926             }
1927           else
1928             {
1929               (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1930               tag_length=26;
1931               p[24]=(unsigned char) (length >> 8);
1932               p[25]=(unsigned char) (length & 0xff);
1933             }
1934           p[13]=0x00;
1935           (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1936           if (roundup != 0)
1937             p[length+tag_length]='\0';
1938           jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1939             custom_profile),(unsigned int) (length+tag_length+roundup));
1940         }
1941       }
1942     if (LocaleCompare(name,"XMP") == 0)
1943       {
1944         StringInfo
1945           *xmp_profile;
1946
1947         /*
1948           Add namespace to XMP profile.
1949         */
1950         xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1951         ConcatenateStringInfo(xmp_profile,profile);
1952         GetStringInfoDatum(xmp_profile)[28]='\0';
1953         for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1954         {
1955           length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1956           jpeg_write_marker(jpeg_info,XML_MARKER,
1957             GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1958         }
1959         xmp_profile=DestroyStringInfo(xmp_profile);
1960       }
1961     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1962       "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1963     name=GetNextImageProfile(image);
1964   }
1965   custom_profile=DestroyStringInfo(custom_profile);
1966 }
1967
1968 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1969 {
1970   DestinationManager
1971     *destination;
1972
1973   cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1974     ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1975   destination=(DestinationManager *) cinfo->dest;
1976   destination->manager.init_destination=InitializeDestination;
1977   destination->manager.empty_output_buffer=EmptyOutputBuffer;
1978   destination->manager.term_destination=TerminateDestination;
1979   destination->image=image;
1980 }
1981
1982 static char **SamplingFactorToList(const char *text)
1983 {
1984   char
1985     **textlist;
1986
1987   register char
1988     *q;
1989
1990   register const char
1991     *p;
1992
1993   register ssize_t
1994     i;
1995
1996   size_t
1997     lines;
1998
1999   if (text == (char *) NULL)
2000     return((char **) NULL);
2001   /*
2002     Convert string to an ASCII list.
2003   */
2004   lines=1;
2005   for (p=text; *p != '\0'; p++)
2006     if (*p == ',')
2007       lines++;
2008   textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2009     sizeof(*textlist));
2010   if (textlist == (char **) NULL)
2011     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2012   p=text;
2013   for (i=0; i < (ssize_t) lines; i++)
2014   {
2015     for (q=(char *) p; *q != '\0'; q++)
2016       if (*q == ',')
2017         break;
2018     textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2019       sizeof(*textlist[i]));
2020     if (textlist[i] == (char *) NULL)
2021       ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2022     (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2023     if (*q == '\r')
2024       q++;
2025     p=q+1;
2026   }
2027   textlist[i]=(char *) NULL;
2028   return(textlist);
2029 }
2030
2031 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2032   Image *image,ExceptionInfo *exception)
2033 {
2034   const char
2035     *option,
2036     *sampling_factor,
2037     *value;
2038
2039   ErrorManager
2040     error_manager;
2041
2042   int
2043     colorspace,
2044     quality;
2045
2046   JSAMPLE
2047     *volatile jpeg_pixels;
2048
2049   JSAMPROW
2050     scanline[1];
2051
2052   MagickBooleanType
2053     status;
2054
2055   MemoryInfo
2056     *memory_info;
2057
2058   register JSAMPLE
2059     *q;
2060
2061   register ssize_t
2062     i;
2063
2064   ssize_t
2065     y;
2066
2067   struct jpeg_compress_struct
2068     jpeg_info;
2069
2070   struct jpeg_error_mgr
2071     jpeg_error;
2072
2073   unsigned short
2074     scale;
2075
2076   /*
2077     Open image file.
2078   */
2079   assert(image_info != (const ImageInfo *) NULL);
2080   assert(image_info->signature == MagickSignature);
2081   assert(image != (Image *) NULL);
2082   assert(image->signature == MagickSignature);
2083   if (image->debug != MagickFalse)
2084     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2085   assert(exception != (ExceptionInfo *) NULL);
2086   assert(exception->signature == MagickSignature);
2087   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2088   if (status == MagickFalse)
2089     return(status);
2090   /*
2091     Initialize JPEG parameters.
2092   */
2093   (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2094   (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2095   (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2096   jpeg_info.client_data=(void *) image;
2097   jpeg_info.err=jpeg_std_error(&jpeg_error);
2098   jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2099   jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2100   error_manager.exception=exception;
2101   error_manager.image=image;
2102   memory_info=(MemoryInfo *) NULL;
2103   if (setjmp(error_manager.error_recovery) != 0)
2104     {
2105       jpeg_destroy_compress(&jpeg_info);
2106       (void) CloseBlob(image);
2107       return(MagickFalse);
2108     }
2109   jpeg_info.client_data=(void *) &error_manager;
2110   jpeg_create_compress(&jpeg_info);
2111   JPEGDestinationManager(&jpeg_info,image);
2112   if ((image->columns != (unsigned int) image->columns) ||
2113       (image->rows != (unsigned int) image->rows))
2114     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2115   jpeg_info.image_width=(unsigned int) image->columns;
2116   jpeg_info.image_height=(unsigned int) image->rows;
2117   jpeg_info.input_components=3;
2118   jpeg_info.data_precision=8;
2119   jpeg_info.in_color_space=JCS_RGB;
2120   switch (image->colorspace)
2121   {
2122     case CMYKColorspace:
2123     {
2124       jpeg_info.input_components=4;
2125       jpeg_info.in_color_space=JCS_CMYK;
2126       break;
2127     }
2128     case YCbCrColorspace:
2129     case Rec601YCbCrColorspace:
2130     case Rec709YCbCrColorspace:
2131     {
2132       jpeg_info.in_color_space=JCS_YCbCr;
2133       break;
2134     }
2135     case GRAYColorspace:
2136     {
2137       jpeg_info.input_components=1;
2138       jpeg_info.in_color_space=JCS_GRAYSCALE;
2139       break;
2140     }
2141     default:
2142     {
2143       if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
2144         (void) TransformImageColorspace(image,sRGBColorspace,exception);
2145       break;
2146     }
2147   }
2148   if ((image_info->type != TrueColorType) &&
2149       (IsImageGray(image,exception) != MagickFalse))
2150     {
2151       jpeg_info.input_components=1;
2152       jpeg_info.in_color_space=JCS_GRAYSCALE;
2153     }
2154   jpeg_set_defaults(&jpeg_info);
2155   if (jpeg_info.in_color_space == JCS_CMYK)
2156     jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2157   if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2158     jpeg_info.data_precision=8;
2159   else
2160     jpeg_info.data_precision=BITS_IN_JSAMPLE;
2161   jpeg_info.density_unit=(UINT8) 1;
2162   if (image->debug != MagickFalse)
2163     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2164       "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2165       floor(image->resolution.y+0.5));
2166   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2167     {
2168       /*
2169         Set image resolution.
2170       */
2171       jpeg_info.write_JFIF_header=MagickTrue;
2172       jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2173       jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2174       /*
2175         Set image resolution units.
2176       */
2177       jpeg_info.density_unit=(UINT8) 0;
2178       if (image->units == PixelsPerInchResolution)
2179         jpeg_info.density_unit=(UINT8) 1;
2180       if (image->units == PixelsPerCentimeterResolution)
2181         jpeg_info.density_unit=(UINT8) 2;
2182     }
2183   jpeg_info.dct_method=JDCT_FLOAT;
2184   option=GetImageOption(image_info,"jpeg:dct-method");
2185   if (option != (const char *) NULL)
2186     switch (*option)
2187     {
2188       case 'D':
2189       case 'd':
2190       {
2191         if (LocaleCompare(option,"default") == 0)
2192           jpeg_info.dct_method=JDCT_DEFAULT;
2193         break;
2194       }
2195       case 'F':
2196       case 'f':
2197       {
2198         if (LocaleCompare(option,"fastest") == 0)
2199           jpeg_info.dct_method=JDCT_FASTEST;
2200         if (LocaleCompare(option,"float") == 0)
2201           jpeg_info.dct_method=JDCT_FLOAT;
2202         break;
2203       }
2204       case 'I':
2205       case 'i':
2206       {
2207         if (LocaleCompare(option,"ifast") == 0)
2208           jpeg_info.dct_method=JDCT_IFAST;
2209         if (LocaleCompare(option,"islow") == 0)
2210           jpeg_info.dct_method=JDCT_ISLOW;
2211         break;
2212       }
2213     }
2214   option=GetImageOption(image_info,"jpeg:optimize-coding");
2215   if (option != (const char *) NULL)
2216     jpeg_info.optimize_coding=IsStringTrue(option);
2217   else
2218     {
2219       MagickSizeType
2220         length;
2221
2222       length=(MagickSizeType) jpeg_info.input_components*image->columns*
2223         image->rows*sizeof(JSAMPLE);
2224       if (length == (MagickSizeType) ((size_t) length))
2225         {
2226           /*
2227             Perform optimization only if available memory resources permit it.
2228           */
2229           status=AcquireMagickResource(MemoryResource,length);
2230           RelinquishMagickResource(MemoryResource,length);
2231           jpeg_info.optimize_coding=status;
2232         }
2233     }
2234 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2235   if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2236       (image_info->interlace != NoInterlace))
2237     {
2238       if (image->debug != MagickFalse)
2239         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2240           "Interlace: progressive");
2241       jpeg_simple_progression(&jpeg_info);
2242     }
2243   else
2244     if (image->debug != MagickFalse)
2245       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2246         "Interlace: non-progressive");
2247 #else
2248   if (image->debug != MagickFalse)
2249     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2250       "Interlace: nonprogressive");
2251 #endif
2252   quality=92;
2253   option=GetImageOption(image_info,"jpeg:extent");
2254   if (option != (const char *) NULL)
2255     {
2256       Image
2257         *jpeg_image;
2258
2259       ImageInfo
2260         *jpeg_info;
2261
2262       jpeg_info=CloneImageInfo(image_info);
2263       jpeg_info->blob=NULL;
2264       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2265       if (jpeg_image != (Image *) NULL)
2266         {
2267           MagickSizeType
2268             extent;
2269
2270           size_t
2271             maximum,
2272             minimum;
2273
2274           /*
2275             Search for compression quality that does not exceed image extent.
2276           */
2277           jpeg_info->quality=0;
2278           extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2279           (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2280           (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2281           (void) AcquireUniqueFilename(jpeg_image->filename);
2282           maximum=101;
2283           for (minimum=2; minimum < maximum; )
2284           {
2285             jpeg_info->quality=minimum+(maximum-minimum+1)/2;
2286             status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2287             if (GetBlobSize(jpeg_image) <= extent)
2288               minimum=jpeg_info->quality+1;
2289             else
2290               maximum=jpeg_info->quality-1;
2291           }
2292           (void) RelinquishUniqueFileResource(jpeg_image->filename);
2293           quality=minimum-1;
2294           jpeg_image=DestroyImage(jpeg_image);
2295         }
2296       jpeg_info=DestroyImageInfo(jpeg_info);
2297     }
2298   if ((image_info->compression != LosslessJPEGCompression) &&
2299       (image->quality <= 100))
2300     {
2301       if (image->quality != UndefinedCompressionQuality)
2302         quality=(int) image->quality;
2303       if (image->debug != MagickFalse)
2304         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2305           (double) image->quality);
2306     }
2307   else
2308     {
2309 #if !defined(C_LOSSLESS_SUPPORTED)
2310       quality=100;
2311       if (image->debug != MagickFalse)
2312         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2313 #else
2314       if (image->quality < 100)
2315         (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2316           "LosslessToLossyJPEGConversion",image->filename);
2317       else
2318         {
2319           int
2320             point_transform,
2321             predictor;
2322
2323           predictor=image->quality/100;  /* range 1-7 */
2324           point_transform=image->quality % 20;  /* range 0-15 */
2325           jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2326           if (image->debug != MagickFalse)
2327             {
2328               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2329                 "Compression: lossless");
2330               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2331                 "Predictor: %d",predictor);
2332               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2333                 "Point Transform: %d",point_transform);
2334             }
2335         }
2336 #endif
2337     }
2338   jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2339 #if (JPEG_LIB_VERSION >= 70)
2340   option=GetImageOption(image_info,"quality");
2341   if (option != (const char *) NULL)
2342     {
2343       GeometryInfo
2344         geometry_info;
2345
2346       int
2347         flags;
2348
2349       /*
2350         Set quality scaling for luminance and chrominance separately.
2351       */
2352       flags=ParseGeometry(option,&geometry_info);
2353       if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2354         {
2355           jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2356             (geometry_info.rho+0.5));
2357           jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2358             (geometry_info.sigma+0.5));
2359           jpeg_default_qtables(&jpeg_info,MagickTrue);
2360         }
2361     }
2362 #endif
2363   colorspace=jpeg_info.in_color_space;
2364   value=GetImageOption(image_info,"jpeg:colorspace");
2365   if (value == (char *) NULL)
2366     value=GetImageProperty(image,"jpeg:colorspace",exception);
2367   if (value != (char *) NULL)
2368     colorspace=StringToInteger(value);
2369   sampling_factor=(const char *) NULL;
2370   if (colorspace == jpeg_info.in_color_space)
2371     {
2372       value=GetImageOption(image_info,"jpeg:sampling-factor");
2373       if (value == (char *) NULL)
2374         value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2375       if (value != (char *) NULL)
2376         {
2377           sampling_factor=value;
2378           if (image->debug != MagickFalse)
2379             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2380               "  Input sampling-factors=%s",sampling_factor);
2381         }
2382     }
2383   value=GetImageOption(image_info,"jpeg:sampling-factor");
2384   if (image_info->sampling_factor != (char *) NULL)
2385     sampling_factor=image_info->sampling_factor;
2386   if (sampling_factor == (const char *) NULL)
2387     {
2388       if (image->quality >= 90)
2389         for (i=0; i < MAX_COMPONENTS; i++)
2390         {
2391           jpeg_info.comp_info[i].h_samp_factor=1;
2392           jpeg_info.comp_info[i].v_samp_factor=1;
2393         }
2394     }
2395   else
2396     {
2397       char
2398         **factors;
2399
2400       GeometryInfo
2401         geometry_info;
2402
2403       MagickStatusType
2404         flags;
2405
2406       /*
2407         Set sampling factor.
2408       */
2409       i=0;
2410       factors=SamplingFactorToList(sampling_factor);
2411       if (factors != (char **) NULL)
2412         {
2413           for (i=0; i < MAX_COMPONENTS; i++)
2414           {
2415             if (factors[i] == (char *) NULL)
2416               break;
2417             flags=ParseGeometry(factors[i],&geometry_info);
2418             if ((flags & SigmaValue) == 0)
2419               geometry_info.sigma=geometry_info.rho;
2420             jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2421             jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2422             factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2423           }
2424           factors=(char **) RelinquishMagickMemory(factors);
2425         }
2426       for ( ; i < MAX_COMPONENTS; i++)
2427       {
2428         jpeg_info.comp_info[i].h_samp_factor=1;
2429         jpeg_info.comp_info[i].v_samp_factor=1;
2430       }
2431     }
2432   option=GetImageOption(image_info,"jpeg:q-table");
2433   if (option != (const char *) NULL)
2434     {
2435       QuantizationTable
2436         *table;
2437
2438       /*
2439         Custom quantization tables.
2440       */
2441       table=GetQuantizationTable(option,"0",exception);
2442       if (table != (QuantizationTable *) NULL)
2443         {
2444           for (i=0; i < MAX_COMPONENTS; i++)
2445             jpeg_info.comp_info[i].quant_tbl_no=0;
2446           jpeg_add_quant_table(&jpeg_info,0,table->levels,
2447             jpeg_quality_scaling(quality),0);
2448           table=DestroyQuantizationTable(table);
2449         }
2450       table=GetQuantizationTable(option,"1",exception);
2451       if (table != (QuantizationTable *) NULL)
2452         {
2453           for (i=1; i < MAX_COMPONENTS; i++)
2454             jpeg_info.comp_info[i].quant_tbl_no=1;
2455           jpeg_add_quant_table(&jpeg_info,1,table->levels,
2456             jpeg_quality_scaling(quality),0);
2457           table=DestroyQuantizationTable(table);
2458         }
2459       table=GetQuantizationTable(option,"2",exception);
2460       if (table != (QuantizationTable *) NULL)
2461         {
2462           for (i=2; i < MAX_COMPONENTS; i++)
2463             jpeg_info.comp_info[i].quant_tbl_no=2;
2464           jpeg_add_quant_table(&jpeg_info,2,table->levels,
2465             jpeg_quality_scaling(quality),0);
2466           table=DestroyQuantizationTable(table);
2467         }
2468       table=GetQuantizationTable(option,"3",exception);
2469       if (table != (QuantizationTable *) NULL)
2470         {
2471           for (i=3; i < MAX_COMPONENTS; i++)
2472             jpeg_info.comp_info[i].quant_tbl_no=3;
2473           jpeg_add_quant_table(&jpeg_info,3,table->levels,
2474             jpeg_quality_scaling(quality),0);
2475           table=DestroyQuantizationTable(table);
2476         }
2477     }
2478   jpeg_start_compress(&jpeg_info,MagickTrue);
2479   if (image->debug != MagickFalse)
2480     {
2481       if (image->storage_class == PseudoClass)
2482         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2483           "Storage class: PseudoClass");
2484       else
2485         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2486           "Storage class: DirectClass");
2487       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2488         (double) image->depth);
2489       if (image->colors != 0)
2490         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2491           "Number of colors: %.20g",(double) image->colors);
2492       else
2493         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2494           "Number of colors: unspecified");
2495       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496         "JPEG data precision: %d",(int) jpeg_info.data_precision);
2497       switch (image->colorspace)
2498       {
2499         case CMYKColorspace:
2500         {
2501           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2502             "Storage class: DirectClass");
2503           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2504             "Colorspace: CMYK");
2505           break;
2506         }
2507         case YCbCrColorspace:
2508         case Rec601YCbCrColorspace:
2509         case Rec709YCbCrColorspace:
2510         {
2511           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2512             "Colorspace: YCbCr");
2513           break;
2514         }
2515         default:
2516           break;
2517       }
2518       switch (image->colorspace)
2519       {
2520         case CMYKColorspace:
2521         {
2522           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2523             "Colorspace: CMYK");
2524           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2525             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2526             jpeg_info.comp_info[0].h_samp_factor,
2527             jpeg_info.comp_info[0].v_samp_factor,
2528             jpeg_info.comp_info[1].h_samp_factor,
2529             jpeg_info.comp_info[1].v_samp_factor,
2530             jpeg_info.comp_info[2].h_samp_factor,
2531             jpeg_info.comp_info[2].v_samp_factor,
2532             jpeg_info.comp_info[3].h_samp_factor,
2533             jpeg_info.comp_info[3].v_samp_factor);
2534           break;
2535         }
2536         case GRAYColorspace:
2537         {
2538           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2539             "Colorspace: GRAY");
2540           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2541             "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2542             jpeg_info.comp_info[0].v_samp_factor);
2543           break;
2544         }
2545         case sRGBColorspace:
2546         case RGBColorspace:
2547         {
2548           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2549             "Image colorspace is RGB");
2550           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2551             "Sampling factors: %dx%d,%dx%d,%dx%d",
2552             jpeg_info.comp_info[0].h_samp_factor,
2553             jpeg_info.comp_info[0].v_samp_factor,
2554             jpeg_info.comp_info[1].h_samp_factor,
2555             jpeg_info.comp_info[1].v_samp_factor,
2556             jpeg_info.comp_info[2].h_samp_factor,
2557             jpeg_info.comp_info[2].v_samp_factor);
2558           break;
2559         }
2560         case YCbCrColorspace:
2561         case Rec601YCbCrColorspace:
2562         case Rec709YCbCrColorspace:
2563         {
2564           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2565             "Colorspace: YCbCr");
2566           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2567             "Sampling factors: %dx%d,%dx%d,%dx%d",
2568             jpeg_info.comp_info[0].h_samp_factor,
2569             jpeg_info.comp_info[0].v_samp_factor,
2570             jpeg_info.comp_info[1].h_samp_factor,
2571             jpeg_info.comp_info[1].v_samp_factor,
2572             jpeg_info.comp_info[2].h_samp_factor,
2573             jpeg_info.comp_info[2].v_samp_factor);
2574           break;
2575         }
2576         default:
2577         {
2578           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2579             image->colorspace);
2580           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2581             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2582             jpeg_info.comp_info[0].h_samp_factor,
2583             jpeg_info.comp_info[0].v_samp_factor,
2584             jpeg_info.comp_info[1].h_samp_factor,
2585             jpeg_info.comp_info[1].v_samp_factor,
2586             jpeg_info.comp_info[2].h_samp_factor,
2587             jpeg_info.comp_info[2].v_samp_factor,
2588             jpeg_info.comp_info[3].h_samp_factor,
2589             jpeg_info.comp_info[3].v_samp_factor);
2590           break;
2591         }
2592       }
2593     }
2594   /*
2595     Write JPEG profiles.
2596   */
2597   value=GetImageProperty(image,"comment",exception);
2598   if (value != (char *) NULL)
2599     for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2600       jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2601         (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2602   if (image->profiles != (void *) NULL)
2603     WriteProfile(&jpeg_info,image);
2604   /*
2605     Convert MIFF to JPEG raster pixels.
2606   */
2607   memory_info=AcquireVirtualMemory((size_t) image->columns,
2608     jpeg_info.input_components*sizeof(*jpeg_pixels));
2609   if (memory_info == (MemoryInfo *) NULL)
2610     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2611   jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2612   if (setjmp(error_manager.error_recovery) != 0)
2613     {
2614       jpeg_destroy_compress(&jpeg_info);
2615       if (memory_info != (MemoryInfo *) NULL)
2616         memory_info=RelinquishVirtualMemory(memory_info);
2617       (void) CloseBlob(image);
2618       return(MagickFalse);
2619     }
2620   scanline[0]=(JSAMPROW) jpeg_pixels;
2621   scale=65535U/GetQuantumRange(jpeg_info.data_precision);
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)))/scale);
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))/scale);
2756             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2757             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
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) (ScaleQuantumToShort(QuantumRange-
2785               GetPixelRed(image,p))/scale);
2786             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-
2787               GetPixelGreen(image,p))/scale);
2788             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-
2789               GetPixelBlue(image,p))/scale);
2790             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-
2791               GetPixelBlack(image,p))/scale);
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