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