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