]> 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 MagickBooleanType 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,image->filename);
301   else
302     (void) ThrowMagickException(&image->exception,GetMagickModule(),
303       CorruptImageError,(char *) message,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);
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   if ((image_info->colors > 8) && (image_info->colors <= 256))
1124     {
1125       /*
1126         Let the JPEG library quantize for us.
1127       */
1128       jpeg_info.quantize_colors=MagickTrue;
1129       jpeg_info.desired_number_of_colors=(int) image_info->colors;
1130     }
1131   option=GetImageOption(image_info,"jpeg:block-smoothing");
1132   if (option != (const char *) NULL)
1133     {
1134       jpeg_info.do_block_smoothing=MagickFalse;
1135       if (IsMagickTrue(option) != MagickFalse)
1136         jpeg_info.do_block_smoothing=MagickTrue;
1137     }
1138   option=GetImageOption(image_info,"jpeg:dct-method");
1139   if (option != (const char *) NULL)
1140     switch (*option)
1141     {
1142       case 'D':
1143       case 'd':
1144       {
1145         if (LocaleCompare(option,"default") == 0)
1146           jpeg_info.dct_method=JDCT_DEFAULT;
1147         break;
1148       }
1149       case 'F':
1150       case 'f':
1151       {
1152         if (LocaleCompare(option,"fastest") == 0)
1153           jpeg_info.dct_method=JDCT_FASTEST;
1154         if (LocaleCompare(option,"float") == 0)
1155           jpeg_info.dct_method=JDCT_FLOAT;
1156         break;
1157       }
1158       case 'I':
1159       case 'i':
1160       {
1161         if (LocaleCompare(option,"ifast") == 0)
1162           jpeg_info.dct_method=JDCT_IFAST;
1163         if (LocaleCompare(option,"islow") == 0)
1164           jpeg_info.dct_method=JDCT_ISLOW;
1165         break;
1166       }
1167     }
1168   option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1169   if (option != (const char *) NULL)
1170     {
1171       jpeg_info.do_fancy_upsampling=MagickFalse;
1172       if (IsMagickTrue(option) != MagickFalse)
1173         jpeg_info.do_fancy_upsampling=MagickTrue;
1174     }
1175   (void) jpeg_start_decompress(&jpeg_info);
1176   image->columns=jpeg_info.output_width;
1177   image->rows=jpeg_info.output_height;
1178   image->depth=(size_t) jpeg_info.data_precision;
1179   if (jpeg_info.out_color_space == JCS_YCbCr)
1180     image->colorspace=YCbCrColorspace;
1181   if (jpeg_info.out_color_space == JCS_CMYK)
1182     image->colorspace=CMYKColorspace;
1183   if ((image_info->colors != 0) && (image_info->colors <= 256))
1184     if (AcquireImageColormap(image,image_info->colors,exception) == MagickFalse)
1185       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1186   if ((jpeg_info.output_components == 1) &&
1187       (jpeg_info.quantize_colors == MagickFalse))
1188     {
1189       size_t
1190         colors;
1191
1192       colors=(size_t) GetQuantumRange(image->depth)+1;
1193       if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1194         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1195     }
1196   if (image->debug != MagickFalse)
1197     {
1198       if (image->interlace != NoInterlace)
1199         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1200           "Interlace: progressive");
1201       else
1202         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1203           "Interlace: nonprogressive");
1204       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1205         (int) jpeg_info.data_precision);
1206       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1207         (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1208     }
1209   JPEGSetImageQuality(&jpeg_info,image);
1210   JPEGSetImageSamplingFactor(&jpeg_info,image);
1211   (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1212     jpeg_info.out_color_space);
1213   (void) SetImageProperty(image,"jpeg:colorspace",value);
1214   if (image_info->ping != MagickFalse)
1215     {
1216       jpeg_destroy_decompress(&jpeg_info);
1217       (void) CloseBlob(image);
1218       return(GetFirstImageInList(image));
1219     }
1220   jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1221     jpeg_info.output_components*sizeof(JSAMPLE));
1222   if (jpeg_pixels == (JSAMPLE *) NULL)
1223     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1224   /*
1225     Convert JPEG pixels to pixel packets.
1226   */
1227   if (setjmp(error_manager.error_recovery) != 0)
1228     {
1229       if (jpeg_pixels != (unsigned char *) NULL)
1230         jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1231       jpeg_destroy_decompress(&jpeg_info);
1232       (void) CloseBlob(image);
1233       number_pixels=(MagickSizeType) image->columns*image->rows;
1234       if (number_pixels != 0)
1235         return(GetFirstImageInList(image));
1236       return(DestroyImage(image));
1237     }
1238   if (jpeg_info.quantize_colors != MagickFalse)
1239     {
1240       image->colors=(size_t) jpeg_info.actual_number_of_colors;
1241       if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1242         for (i=0; i < (ssize_t) image->colors; i++)
1243         {
1244           image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1245           image->colormap[i].green=image->colormap[i].red;
1246           image->colormap[i].blue=image->colormap[i].red;
1247           image->colormap[i].alpha=OpaqueAlpha;
1248         }
1249       else
1250         for (i=0; i < (ssize_t) image->colors; i++)
1251         {
1252           image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
1253           image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
1254           image->colormap[i].blue=ScaleCharToQuantum(jpeg_info.colormap[2][i]);
1255           image->colormap[i].alpha=OpaqueAlpha;
1256         }
1257     }
1258   scanline[0]=(JSAMPROW) jpeg_pixels;
1259   for (y=0; y < (ssize_t) image->rows; y++)
1260   {
1261     register ssize_t
1262       x;
1263
1264     register Quantum
1265       *restrict q;
1266
1267     if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1268       {
1269         (void) ThrowMagickException(exception,GetMagickModule(),
1270           CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1271         continue;
1272       }
1273     p=jpeg_pixels;
1274     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1275     if (q == (Quantum *) NULL)
1276       break;
1277     if (jpeg_info.data_precision > 8)
1278       {
1279         if (jpeg_info.output_components == 1)
1280           for (x=0; x < (ssize_t) image->columns; x++)
1281           {
1282             size_t
1283               pixel;
1284
1285             if (precision != 16)
1286               pixel=(size_t) GETJSAMPLE(*p);
1287             else
1288               pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1289             index=ConstrainColormapIndex(image,pixel);
1290             SetPixelIndex(image,index,q);
1291             SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1292             p++;
1293             q+=GetPixelChannels(image);
1294           }
1295         else
1296           if (image->colorspace != CMYKColorspace)
1297             for (x=0; x < (ssize_t) image->columns; x++)
1298             {
1299               SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1300                 (GETJSAMPLE(*p++) << 4)),q);
1301               SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1302                 (GETJSAMPLE(*p++) << 4)),q);
1303               SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1304                 (GETJSAMPLE(*p++) << 4)),q);
1305               SetPixelAlpha(image,OpaqueAlpha,q);
1306               q+=GetPixelChannels(image);
1307             }
1308           else
1309             for (x=0; x < (ssize_t) image->columns; x++)
1310             {
1311               SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1312                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1313               SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1314                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1315               SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1316                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1317               SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1318                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1319               SetPixelAlpha(image,OpaqueAlpha,q);
1320               q+=GetPixelChannels(image);
1321             }
1322       }
1323     else
1324       if (jpeg_info.output_components == 1)
1325         for (x=0; x < (ssize_t) image->columns; x++)
1326         {
1327           index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
1328           SetPixelIndex(image,index,q);
1329           SetPixelPacket(image,image->colormap+(ssize_t) index,q);
1330           p++;
1331           q+=GetPixelChannels(image);
1332         }
1333       else
1334         if (image->colorspace != CMYKColorspace)
1335           for (x=0; x < (ssize_t) image->columns; x++)
1336           {
1337             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1338               GETJSAMPLE(*p++)),q);
1339             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1340               GETJSAMPLE(*p++)),q);
1341             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1342               GETJSAMPLE(*p++)),q);
1343             SetPixelAlpha(image,OpaqueAlpha,q);
1344             q+=GetPixelChannels(image);
1345           }
1346         else
1347           for (x=0; x < (ssize_t) image->columns; x++)
1348           {
1349             SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1350               (unsigned char) GETJSAMPLE(*p++)),q);
1351             SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1352               (unsigned char) GETJSAMPLE(*p++)),q);
1353             SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1354               (unsigned char) GETJSAMPLE(*p++)),q);
1355             SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1356               (unsigned char) GETJSAMPLE(*p++)),q);
1357             SetPixelAlpha(image,OpaqueAlpha,q);
1358             q+=GetPixelChannels(image);
1359           }
1360     if (SyncAuthenticPixels(image,exception) == MagickFalse)
1361       break;
1362     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1363       image->rows);
1364     if (status == MagickFalse)
1365       {
1366         jpeg_abort_decompress(&jpeg_info);
1367         break;
1368       }
1369   }
1370   if (status != MagickFalse)
1371     {
1372       error_manager.finished=MagickTrue;
1373       if (setjmp(error_manager.error_recovery) == 0)
1374         (void) jpeg_finish_decompress(&jpeg_info);
1375     }
1376   /*
1377     Free jpeg resources.
1378   */
1379   jpeg_destroy_decompress(&jpeg_info);
1380   jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1381   (void) CloseBlob(image);
1382   return(GetFirstImageInList(image));
1383 }
1384 #endif
1385 \f
1386 /*
1387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388 %                                                                             %
1389 %                                                                             %
1390 %                                                                             %
1391 %   R e g i s t e r J P E G I m a g e                                         %
1392 %                                                                             %
1393 %                                                                             %
1394 %                                                                             %
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 %
1397 %  RegisterJPEGImage() adds properties for the JPEG image format to
1398 %  the list of supported formats.  The properties include the image format
1399 %  tag, a method to read and/or write the format, whether the format
1400 %  supports the saving of more than one frame to the same file or blob,
1401 %  whether the format supports native in-memory I/O, and a brief
1402 %  description of the format.
1403 %
1404 %  The format of the RegisterJPEGImage method is:
1405 %
1406 %      size_t RegisterJPEGImage(void)
1407 %
1408 */
1409 ModuleExport size_t RegisterJPEGImage(void)
1410 {
1411   char
1412     version[MaxTextExtent];
1413
1414   MagickInfo
1415     *entry;
1416
1417   static const char
1418     description[] = "Joint Photographic Experts Group JFIF format";
1419
1420   *version='\0';
1421 #if defined(JPEG_LIB_VERSION)
1422   (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1423 #endif
1424   entry=SetMagickInfo("JPEG");
1425   entry->thread_support=NoThreadSupport;
1426 #if defined(MAGICKCORE_JPEG_DELEGATE)
1427   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1428   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1429 #endif
1430   entry->magick=(IsImageFormatHandler *) IsJPEG;
1431   entry->adjoin=MagickFalse;
1432   entry->description=ConstantString(description);
1433   if (*version != '\0')
1434     entry->version=ConstantString(version);
1435   entry->module=ConstantString("JPEG");
1436   (void) RegisterMagickInfo(entry);
1437   entry=SetMagickInfo("JPG");
1438   entry->thread_support=NoThreadSupport;
1439 #if defined(MAGICKCORE_JPEG_DELEGATE)
1440   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1441   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1442 #endif
1443   entry->adjoin=MagickFalse;
1444   entry->description=ConstantString(description);
1445   if (*version != '\0')
1446     entry->version=ConstantString(version);
1447   entry->module=ConstantString("JPEG");
1448   (void) RegisterMagickInfo(entry);
1449   entry=SetMagickInfo("PJPEG");
1450   entry->thread_support=NoThreadSupport;
1451 #if defined(MAGICKCORE_JPEG_DELEGATE)
1452   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1453   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1454 #endif
1455   entry->adjoin=MagickFalse;
1456   entry->description=ConstantString(description);
1457   if (*version != '\0')
1458     entry->version=ConstantString(version);
1459   entry->module=ConstantString("JPEG");
1460   (void) RegisterMagickInfo(entry);
1461   return(MagickImageCoderSignature);
1462 }
1463 \f
1464 /*
1465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466 %                                                                             %
1467 %                                                                             %
1468 %                                                                             %
1469 %   U n r e g i s t e r J P E G I m a g e                                     %
1470 %                                                                             %
1471 %                                                                             %
1472 %                                                                             %
1473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474 %
1475 %  UnregisterJPEGImage() removes format registrations made by the
1476 %  JPEG module from the list of supported formats.
1477 %
1478 %  The format of the UnregisterJPEGImage method is:
1479 %
1480 %      UnregisterJPEGImage(void)
1481 %
1482 */
1483 ModuleExport void UnregisterJPEGImage(void)
1484 {
1485   (void) UnregisterMagickInfo("PJPG");
1486   (void) UnregisterMagickInfo("JPEG");
1487   (void) UnregisterMagickInfo("JPG");
1488 }
1489 \f
1490 #if defined(MAGICKCORE_JPEG_DELEGATE)
1491 /*
1492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1493 %                                                                             %
1494 %                                                                             %
1495 %                                                                             %
1496 %  W r i t e J P E G I m a g e                                                %
1497 %                                                                             %
1498 %                                                                             %
1499 %                                                                             %
1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1501 %
1502 %  WriteJPEGImage() writes a JPEG image file and returns it.  It
1503 %  allocates the memory necessary for the new Image structure and returns a
1504 %  pointer to the new image.
1505 %
1506 %  The format of the WriteJPEGImage method is:
1507 %
1508 %      MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1509 %        Image *image,ExceptionInfo *exception)
1510 %
1511 %  A description of each parameter follows:
1512 %
1513 %    o image_info: the image info.
1514 %
1515 %    o jpeg_image:  The image.
1516 %
1517 %    o exception: return any errors or warnings in this structure.
1518 %
1519 */
1520
1521 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1522 {
1523   DestinationManager
1524     *destination;
1525
1526   destination=(DestinationManager *) cinfo->dest;
1527   destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1528     MaxBufferExtent,destination->buffer);
1529   if (destination->manager.free_in_buffer != MaxBufferExtent)
1530     ERREXIT(cinfo,JERR_FILE_WRITE);
1531   destination->manager.next_output_byte=destination->buffer;
1532   return(TRUE);
1533 }
1534
1535 static void InitializeDestination(j_compress_ptr cinfo)
1536 {
1537   DestinationManager
1538     *destination;
1539
1540   destination=(DestinationManager *) cinfo->dest;
1541   destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1542     ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1543   destination->manager.next_output_byte=destination->buffer;
1544   destination->manager.free_in_buffer=MaxBufferExtent;
1545 }
1546
1547 static inline size_t MagickMin(const size_t x,const size_t y)
1548 {
1549   if (x < y)
1550     return(x);
1551   return(y);
1552 }
1553
1554 static void TerminateDestination(j_compress_ptr cinfo)
1555 {
1556   DestinationManager
1557     *destination;
1558
1559   destination=(DestinationManager *) cinfo->dest;
1560   if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1561     {
1562       ssize_t
1563         count;
1564
1565       count=WriteBlob(destination->image,MaxBufferExtent-
1566         destination->manager.free_in_buffer,destination->buffer);
1567       if (count != (ssize_t)
1568           (MaxBufferExtent-destination->manager.free_in_buffer))
1569         ERREXIT(cinfo,JERR_FILE_WRITE);
1570     }
1571 }
1572
1573 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1574 {
1575   const char
1576     *name;
1577
1578   const StringInfo
1579     *profile;
1580
1581   MagickBooleanType
1582     iptc;
1583
1584   register ssize_t
1585     i;
1586
1587   size_t
1588     length,
1589     tag_length;
1590
1591   StringInfo
1592     *custom_profile;
1593
1594   /*
1595     Save image profile as a APP marker.
1596   */
1597   iptc=MagickFalse;
1598   custom_profile=AcquireStringInfo(65535L);
1599   ResetImageProfileIterator(image);
1600   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1601   {
1602     register unsigned char
1603       *p;
1604
1605     profile=GetImageProfile(image,name);
1606     p=GetStringInfoDatum(custom_profile);
1607     if (LocaleCompare(name,"EXIF") == 0)
1608       for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1609       {
1610         length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1611         jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1612           (unsigned int) length);
1613       }
1614     if (LocaleCompare(name,"ICC") == 0)
1615       {
1616         register unsigned char
1617           *p;
1618
1619         tag_length=14;
1620         p=GetStringInfoDatum(custom_profile);
1621         (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1622         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1623         {
1624           length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1625           p[12]=(unsigned char) ((i/65519L)+1);
1626           p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1627           (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1628             length);
1629           jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1630             custom_profile),(unsigned int) (length+tag_length));
1631         }
1632       }
1633     if (((LocaleCompare(name,"IPTC") == 0) ||
1634         (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1635       {
1636         size_t
1637           roundup;
1638
1639         iptc=MagickTrue;
1640         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1641         {
1642           length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1643           roundup=(size_t) (length & 0x01);
1644           if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1645             {
1646               (void) memcpy(p,"Photoshop 3.0 ",14);
1647               tag_length=14;
1648             }
1649           else
1650             {
1651               (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1652               tag_length=26;
1653               p[24]=(unsigned char) (length >> 8);
1654               p[25]=(unsigned char) (length & 0xff);
1655             }
1656           p[13]=0x00;
1657           (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1658           if (roundup != 0)
1659             p[length+tag_length]='\0';
1660           jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1661             custom_profile),(unsigned int) (length+tag_length+roundup));
1662         }
1663       }
1664     if (LocaleCompare(name,"XMP") == 0)
1665       {
1666         StringInfo
1667           *xmp_profile;
1668
1669         /*
1670           Add namespace to XMP profile.
1671         */
1672         xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
1673         ConcatenateStringInfo(xmp_profile,profile);
1674         GetStringInfoDatum(xmp_profile)[28]='\0';
1675         for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1676         {
1677           length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1678           jpeg_write_marker(jpeg_info,XML_MARKER,
1679             GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1680         }
1681         xmp_profile=DestroyStringInfo(xmp_profile);
1682       }
1683     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1684       "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1685     name=GetNextImageProfile(image);
1686   }
1687   custom_profile=DestroyStringInfo(custom_profile);
1688 }
1689
1690 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1691 {
1692   DestinationManager
1693     *destination;
1694
1695   cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1696     ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1697   destination=(DestinationManager *) cinfo->dest;
1698   destination->manager.init_destination=InitializeDestination;
1699   destination->manager.empty_output_buffer=EmptyOutputBuffer;
1700   destination->manager.term_destination=TerminateDestination;
1701   destination->image=image;
1702 }
1703
1704 static char **SamplingFactorToList(const char *text)
1705 {
1706   char
1707     **textlist;
1708
1709   register char
1710     *q;
1711
1712   register const char
1713     *p;
1714
1715   register ssize_t
1716     i;
1717
1718   size_t
1719     lines;
1720
1721   if (text == (char *) NULL)
1722     return((char **) NULL);
1723   /*
1724     Convert string to an ASCII list.
1725   */
1726   lines=1;
1727   for (p=text; *p != '\0'; p++)
1728     if (*p == ',')
1729       lines++;
1730   textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1731     sizeof(*textlist));
1732   if (textlist == (char **) NULL)
1733     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1734   p=text;
1735   for (i=0; i < (ssize_t) lines; i++)
1736   {
1737     for (q=(char *) p; *q != '\0'; q++)
1738       if (*q == ',')
1739         break;
1740     textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1741       sizeof(*textlist[i]));
1742     if (textlist[i] == (char *) NULL)
1743       ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1744     (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1745     if (*q == '\r')
1746       q++;
1747     p=q+1;
1748   }
1749   textlist[i]=(char *) NULL;
1750   return(textlist);
1751 }
1752
1753 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1754   Image *image,ExceptionInfo *exception)
1755 {
1756   const char
1757     *option,
1758     *sampling_factor,
1759     *value;
1760
1761   ErrorManager
1762     error_manager;
1763
1764   JSAMPLE
1765     *jpeg_pixels;
1766
1767   JSAMPROW
1768     scanline[1];
1769
1770   MagickBooleanType
1771     status;
1772
1773   register JSAMPLE
1774     *q;
1775
1776   register ssize_t
1777     i;
1778
1779   ssize_t
1780     y;
1781
1782   struct jpeg_compress_struct
1783     jpeg_info;
1784
1785   struct jpeg_error_mgr
1786     jpeg_error;
1787
1788   /*
1789     Open image file.
1790   */
1791   assert(image_info != (const ImageInfo *) NULL);
1792   assert(image_info->signature == MagickSignature);
1793   assert(image != (Image *) NULL);
1794   assert(image->signature == MagickSignature);
1795   if (image->debug != MagickFalse)
1796     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1797   assert(exception != (ExceptionInfo *) NULL);
1798   assert(exception->signature == MagickSignature);
1799   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1800   if (status == MagickFalse)
1801     return(status);
1802   /*
1803     Initialize JPEG parameters.
1804   */
1805   (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
1806   (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
1807   (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
1808   jpeg_info.client_data=(void *) image;
1809   jpeg_info.err=jpeg_std_error(&jpeg_error);
1810   jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
1811   jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
1812   error_manager.exception=exception;
1813   error_manager.image=image;
1814   jpeg_pixels=(JSAMPLE *) NULL;
1815   if (setjmp(error_manager.error_recovery) != 0)
1816     {
1817       jpeg_destroy_compress(&jpeg_info);
1818       (void) CloseBlob(image);
1819       return(MagickFalse);
1820     }
1821   jpeg_info.client_data=(void *) &error_manager;
1822   jpeg_create_compress(&jpeg_info);
1823   JPEGDestinationManager(&jpeg_info,image);
1824   if ((image->columns != (unsigned int) image->columns) ||
1825       (image->rows != (unsigned int) image->rows))
1826     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1827   jpeg_info.image_width=(unsigned int) image->columns;
1828   jpeg_info.image_height=(unsigned int) image->rows;
1829   jpeg_info.input_components=3;
1830   jpeg_info.data_precision=8;
1831   jpeg_info.in_color_space=JCS_RGB;
1832   switch (image->colorspace)
1833   {
1834     case CMYKColorspace:
1835     {
1836       jpeg_info.input_components=4;
1837       jpeg_info.in_color_space=JCS_CMYK;
1838       break;
1839     }
1840     case YCbCrColorspace:
1841     case Rec601YCbCrColorspace:
1842     case Rec709YCbCrColorspace:
1843     {
1844       jpeg_info.in_color_space=JCS_YCbCr;
1845       break;
1846     }
1847     case GRAYColorspace:
1848     case Rec601LumaColorspace:
1849     case Rec709LumaColorspace:
1850     {
1851       jpeg_info.input_components=1;
1852       jpeg_info.in_color_space=JCS_GRAYSCALE;
1853       break;
1854     }
1855     default:
1856     {
1857       if (IsRGBColorspace(image->colorspace) == MagickFalse)
1858         (void) TransformImageColorspace(image,RGBColorspace);
1859       break;
1860     }
1861   }
1862   if ((image_info->type != TrueColorType) &&
1863       (IsImageGray(image,exception) != MagickFalse))
1864     {
1865       jpeg_info.input_components=1;
1866       jpeg_info.in_color_space=JCS_GRAYSCALE;
1867     }
1868   jpeg_set_defaults(&jpeg_info);
1869   if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
1870     jpeg_info.data_precision=8;
1871   else
1872     if (sizeof(JSAMPLE) > 1)
1873       jpeg_info.data_precision=12;
1874   jpeg_info.density_unit=(UINT8) 1;
1875   if (image->debug != MagickFalse)
1876     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1877       "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
1878       floor(image->y_resolution+0.5));
1879   if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
1880     {
1881       /*
1882         Set image resolution.
1883       */
1884       jpeg_info.write_JFIF_header=MagickTrue;
1885       jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
1886       jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
1887       if (image->units == PixelsPerInchResolution)
1888         jpeg_info.density_unit=(UINT8) 1;
1889       if (image->units == PixelsPerCentimeterResolution)
1890         jpeg_info.density_unit=(UINT8) 2;
1891     }
1892   option=GetImageOption(image_info,"jpeg:dct-method");
1893   if (option != (const char *) NULL)
1894     switch (*option)
1895     {
1896       case 'D':
1897       case 'd':
1898       {
1899         if (LocaleCompare(option,"default") == 0)
1900           jpeg_info.dct_method=JDCT_DEFAULT;
1901         break;
1902       }
1903       case 'F':
1904       case 'f':
1905       {
1906         if (LocaleCompare(option,"fastest") == 0)
1907           jpeg_info.dct_method=JDCT_FASTEST;
1908         if (LocaleCompare(option,"float") == 0)
1909           jpeg_info.dct_method=JDCT_FLOAT;
1910         break;
1911       }
1912       case 'I':
1913       case 'i':
1914       {
1915         if (LocaleCompare(option,"ifast") == 0)
1916           jpeg_info.dct_method=JDCT_IFAST;
1917         if (LocaleCompare(option,"islow") == 0)
1918           jpeg_info.dct_method=JDCT_ISLOW;
1919         break;
1920       }
1921     }
1922   option=GetImageOption(image_info,"jpeg:optimize-coding");
1923   if (option != (const char *) NULL)
1924     {
1925       jpeg_info.optimize_coding=MagickFalse;
1926       if (IsMagickTrue(option) != MagickFalse)
1927         jpeg_info.optimize_coding=MagickTrue;
1928     }
1929   else
1930     {
1931       MagickSizeType
1932         length;
1933
1934       length=(MagickSizeType) jpeg_info.input_components*image->columns*
1935         image->rows*sizeof(JSAMPLE);
1936       if (length == (MagickSizeType) ((size_t) length))
1937         {
1938           /*
1939             Perform optimization only if available memory resources permit it.
1940           */
1941           status=AcquireMagickResource(MemoryResource,length);
1942           if (status != MagickFalse)
1943             jpeg_info.optimize_coding=MagickTrue;
1944           RelinquishMagickResource(MemoryResource,length);
1945         }
1946     }
1947 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
1948   if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
1949       (image_info->interlace != NoInterlace))
1950     {
1951       if (image->debug != MagickFalse)
1952         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1953           "Interlace: progressive");
1954       jpeg_simple_progression(&jpeg_info);
1955     }
1956   else
1957     if (image->debug != MagickFalse)
1958       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1959         "Interlace: non-progressive");
1960 #else
1961   if (image->debug != MagickFalse)
1962     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1963       "Interlace: nonprogressive");
1964 #endif
1965   option=GetImageOption(image_info,"jpeg:extent");
1966   if (option != (const char *) NULL)
1967     {
1968       Image
1969         *jpeg_image;
1970
1971       ImageInfo
1972         *jpeg_info;
1973
1974       jpeg_info=CloneImageInfo(image_info);
1975       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
1976       if (jpeg_image != (Image *) NULL)
1977         {
1978           MagickSizeType
1979             extent;
1980
1981           size_t
1982             maximum,
1983             minimum;
1984
1985           /*
1986             Search for compression quality that does not exceed image extent.
1987           */
1988           jpeg_info->quality=0;
1989           extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
1990           (void) DeleteImageOption(jpeg_info,"jpeg:extent");
1991           (void) AcquireUniqueFilename(jpeg_image->filename);
1992           maximum=101;
1993           for (minimum=0; minimum != maximum; )
1994           {
1995             jpeg_image->quality=minimum+(maximum-minimum)/2;
1996             status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
1997             if (GetBlobSize(jpeg_image) <= extent)
1998               minimum=jpeg_image->quality+1;
1999             else
2000               maximum=jpeg_image->quality-1;
2001           }
2002           (void) RelinquishUniqueFileResource(jpeg_image->filename);
2003           image->quality=minimum-1;
2004           jpeg_image=DestroyImage(jpeg_image);
2005         }
2006       jpeg_info=DestroyImageInfo(jpeg_info);
2007     }
2008   if ((image_info->compression != LosslessJPEGCompression) &&
2009       (image->quality <= 100))
2010     {
2011       if (image->quality == UndefinedCompressionQuality)
2012         jpeg_set_quality(&jpeg_info,92,MagickTrue);
2013       else
2014         jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
2015       if (image->debug != MagickFalse)
2016         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2017           (double) image->quality);
2018     }
2019   else
2020     {
2021 #if !defined(C_LOSSLESS_SUPPORTED)
2022       jpeg_set_quality(&jpeg_info,100,MagickTrue);
2023       if (image->debug != MagickFalse)
2024         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2025 #else
2026       if (image->quality < 100)
2027         (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2028           "LosslessToLossyJPEGConversion",image->filename);
2029       else
2030         {
2031           int
2032             point_transform,
2033             predictor;
2034
2035           predictor=image->quality/100;  /* range 1-7 */
2036           point_transform=image->quality % 20;  /* range 0-15 */
2037           jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2038           if (image->debug != MagickFalse)
2039             {
2040               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2041                 "Compression: lossless");
2042               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2043                 "Predictor: %d",predictor);
2044               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2045                 "Point Transform: %d",point_transform);
2046             }
2047         }
2048 #endif
2049     }
2050   sampling_factor=(const char *) NULL;
2051   value=GetImageProperty(image,"jpeg:sampling-factor");
2052   if (value != (char *) NULL)
2053     {
2054       sampling_factor=value;
2055       if (image->debug != MagickFalse)
2056         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2057           "  Input sampling-factors=%s",sampling_factor);
2058     }
2059   if (image_info->sampling_factor != (char *) NULL)
2060     sampling_factor=image_info->sampling_factor;
2061   if (sampling_factor == (const char *) NULL)
2062     {
2063       if (image->quality >= 90)
2064         for (i=0; i < MAX_COMPONENTS; i++)
2065         {
2066           jpeg_info.comp_info[i].h_samp_factor=1;
2067           jpeg_info.comp_info[i].v_samp_factor=1;
2068         }
2069     }
2070   else
2071     {
2072       char
2073         **factors;
2074
2075       GeometryInfo
2076         geometry_info;
2077
2078       MagickStatusType
2079         flags;
2080
2081       /*
2082         Set sampling factor.
2083       */
2084       i=0;
2085       factors=SamplingFactorToList(sampling_factor);
2086       if (factors != (char **) NULL)
2087         {
2088           for (i=0; i < MAX_COMPONENTS; i++)
2089           {
2090             if (factors[i] == (char *) NULL)
2091               break;
2092             flags=ParseGeometry(factors[i],&geometry_info);
2093             if ((flags & SigmaValue) == 0)
2094               geometry_info.sigma=geometry_info.rho;
2095             jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2096             jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2097             factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2098           }
2099           factors=(char **) RelinquishMagickMemory(factors);
2100         }
2101       for ( ; i < MAX_COMPONENTS; i++)
2102       {
2103         jpeg_info.comp_info[i].h_samp_factor=1;
2104         jpeg_info.comp_info[i].v_samp_factor=1;
2105       }
2106     }
2107   if (jpeg_info.input_components == 1)
2108     for (i=0; i < MAX_COMPONENTS; i++)
2109     {
2110       jpeg_info.comp_info[i].h_samp_factor=1;
2111       jpeg_info.comp_info[i].v_samp_factor=1;
2112     }
2113   jpeg_start_compress(&jpeg_info,MagickTrue);
2114   if (image->debug != MagickFalse)
2115     {
2116       if (image->storage_class == PseudoClass)
2117         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2118           "Storage class: PseudoClass");
2119       else
2120         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2121           "Storage class: DirectClass");
2122       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2123         (double) image->depth);
2124       if (image->colors != 0)
2125         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2126           "Number of colors: %.20g",(double) image->colors);
2127       else
2128         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2129           "Number of colors: unspecified");
2130       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2131         "JPEG data precision: %d",(int) jpeg_info.data_precision);
2132       switch (image->colorspace)
2133       {
2134         case CMYKColorspace:
2135         {
2136           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2137             "Storage class: DirectClass");
2138           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2139             "Colorspace: CMYK");
2140           break;
2141         }
2142         case YCbCrColorspace:
2143         case Rec601YCbCrColorspace:
2144         case Rec709YCbCrColorspace:
2145         {
2146           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2147             "Colorspace: YCbCr");
2148           break;
2149         }
2150         default:
2151           break;
2152       }
2153       switch (image->colorspace)
2154       {
2155         case CMYKColorspace:
2156         {
2157           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2158             "Colorspace: CMYK");
2159           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2160             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2161             jpeg_info.comp_info[0].h_samp_factor,
2162             jpeg_info.comp_info[0].v_samp_factor,
2163             jpeg_info.comp_info[1].h_samp_factor,
2164             jpeg_info.comp_info[1].v_samp_factor,
2165             jpeg_info.comp_info[2].h_samp_factor,
2166             jpeg_info.comp_info[2].v_samp_factor,
2167             jpeg_info.comp_info[3].h_samp_factor,
2168             jpeg_info.comp_info[3].v_samp_factor);
2169           break;
2170         }
2171         case GRAYColorspace:
2172         case Rec601LumaColorspace:
2173         case Rec709LumaColorspace:
2174         {
2175           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2176             "Colorspace: GRAY");
2177           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2178             "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2179             jpeg_info.comp_info[0].v_samp_factor);
2180           break;
2181         }
2182         case RGBColorspace:
2183         {
2184           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2185             "Image colorspace is RGB");
2186           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187             "Sampling factors: %dx%d,%dx%d,%dx%d",
2188             jpeg_info.comp_info[0].h_samp_factor,
2189             jpeg_info.comp_info[0].v_samp_factor,
2190             jpeg_info.comp_info[1].h_samp_factor,
2191             jpeg_info.comp_info[1].v_samp_factor,
2192             jpeg_info.comp_info[2].h_samp_factor,
2193             jpeg_info.comp_info[2].v_samp_factor);
2194           break;
2195         }
2196         case YCbCrColorspace:
2197         case Rec601YCbCrColorspace:
2198         case Rec709YCbCrColorspace:
2199         {
2200           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2201             "Colorspace: YCbCr");
2202           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2203             "Sampling factors: %dx%d,%dx%d,%dx%d",
2204             jpeg_info.comp_info[0].h_samp_factor,
2205             jpeg_info.comp_info[0].v_samp_factor,
2206             jpeg_info.comp_info[1].h_samp_factor,
2207             jpeg_info.comp_info[1].v_samp_factor,
2208             jpeg_info.comp_info[2].h_samp_factor,
2209             jpeg_info.comp_info[2].v_samp_factor);
2210           break;
2211         }
2212         default:
2213         {
2214           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2215             image->colorspace);
2216           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2217             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2218             jpeg_info.comp_info[0].h_samp_factor,
2219             jpeg_info.comp_info[0].v_samp_factor,
2220             jpeg_info.comp_info[1].h_samp_factor,
2221             jpeg_info.comp_info[1].v_samp_factor,
2222             jpeg_info.comp_info[2].h_samp_factor,
2223             jpeg_info.comp_info[2].v_samp_factor,
2224             jpeg_info.comp_info[3].h_samp_factor,
2225             jpeg_info.comp_info[3].v_samp_factor);
2226           break;
2227         }
2228       }
2229     }
2230   /*
2231     Write JPEG profiles.
2232   */
2233   value=GetImageProperty(image,"comment");
2234   if (value != (char *) NULL)
2235     for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2236       jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2237         (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2238   if (image->profiles != (void *) NULL)
2239     WriteProfile(&jpeg_info,image);
2240   /*
2241     Convert MIFF to JPEG raster pixels.
2242   */
2243   jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2244     jpeg_info.input_components*sizeof(*jpeg_pixels));
2245   if (jpeg_pixels == (JSAMPLE *) NULL)
2246     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2247   if (setjmp(error_manager.error_recovery) != 0)
2248     {
2249       jpeg_destroy_compress(&jpeg_info);
2250       if (jpeg_pixels != (unsigned char *) NULL)
2251         jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2252       (void) CloseBlob(image);
2253       return(MagickFalse);
2254     }
2255   scanline[0]=(JSAMPROW) jpeg_pixels;
2256   if (jpeg_info.data_precision <= 8)
2257     {
2258       if ((jpeg_info.in_color_space == JCS_RGB) ||
2259           (jpeg_info.in_color_space == JCS_YCbCr))
2260         for (y=0; y < (ssize_t) image->rows; y++)
2261         {
2262           register const Quantum
2263             *p;
2264
2265           register ssize_t
2266             x;
2267
2268           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2269           if (p == (const Quantum *) NULL)
2270             break;
2271           q=jpeg_pixels;
2272           for (x=0; x < (ssize_t) image->columns; x++)
2273           {
2274             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2275             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2276             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2277             p+=GetPixelChannels(image);
2278           }
2279           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2280           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2281             image->rows);
2282           if (status == MagickFalse)
2283             break;
2284         }
2285       else
2286         if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2287           for (y=0; y < (ssize_t) image->rows; y++)
2288           {
2289             register const Quantum
2290               *p;
2291
2292             register ssize_t
2293               x;
2294
2295             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2296             if (p == (const Quantum *) NULL)
2297               break;
2298             q=jpeg_pixels;
2299             for (x=0; x < (ssize_t) image->columns; x++)
2300             {
2301               *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2302               p+=GetPixelChannels(image);
2303             }
2304             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2305             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2306               image->rows);
2307             if (status == MagickFalse)
2308               break;
2309           }
2310         else
2311           for (y=0; y < (ssize_t) image->rows; y++)
2312           {
2313             register const Quantum
2314               *p;
2315
2316             register ssize_t
2317               x;
2318
2319             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2320             if (p == (const Quantum *) NULL)
2321               break;
2322             q=jpeg_pixels;
2323             for (x=0; x < (ssize_t) image->columns; x++)
2324             {
2325               /*
2326                 Convert DirectClass packets to contiguous CMYK scanlines.
2327               */
2328               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2329                 GetPixelRed(image,p))));
2330               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2331                 GetPixelGreen(image,p))));
2332               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2333                 GetPixelBlue(image,p))));
2334               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2335                 GetPixelBlack(image,p))));
2336               p+=GetPixelChannels(image);
2337             }
2338             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2339             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2340               image->rows);
2341             if (status == MagickFalse)
2342               break;
2343           }
2344     }
2345   else
2346     if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2347       for (y=0; y < (ssize_t) image->rows; y++)
2348       {
2349         register const Quantum
2350           *p;
2351
2352         register ssize_t
2353           x;
2354
2355         p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2356         if (p == (const Quantum *) NULL)
2357           break;
2358         q=jpeg_pixels;
2359         for (x=0; x < (ssize_t) image->columns; x++)
2360         {
2361           *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >>
2362             4);
2363           p+=GetPixelChannels(image);
2364         }
2365         (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2366         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2367           image->rows);
2368         if (status == MagickFalse)
2369           break;
2370       }
2371     else
2372       if ((jpeg_info.in_color_space == JCS_RGB) ||
2373           (jpeg_info.in_color_space == JCS_YCbCr))
2374         for (y=0; y < (ssize_t) image->rows; y++)
2375         {
2376           register const Quantum
2377             *p;
2378
2379           register ssize_t
2380             x;
2381
2382           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2383           if (p == (const Quantum *) NULL)
2384             break;
2385           q=jpeg_pixels;
2386           for (x=0; x < (ssize_t) image->columns; x++)
2387           {
2388             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2389             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2390             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2391             p+=GetPixelChannels(image);
2392           }
2393           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2394           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2395             image->rows);
2396           if (status == MagickFalse)
2397             break;
2398         }
2399       else
2400         for (y=0; y < (ssize_t) image->rows; y++)
2401         {
2402           register const Quantum
2403             *p;
2404
2405           register ssize_t
2406             x;
2407
2408           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2409           if (p == (const Quantum *) NULL)
2410             break;
2411           q=jpeg_pixels;
2412           for (x=0; x < (ssize_t) image->columns; x++)
2413           {
2414             /*
2415               Convert DirectClass packets to contiguous CMYK scanlines.
2416             */
2417             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2418               GetPixelRed(image,p)) >> 4));
2419             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2420               GetPixelGreen(image,p)) >> 4));
2421             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2422               GetPixelBlue(image,p)) >> 4));
2423             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2424               GetPixelBlack(image,p)) >> 4));
2425             p+=GetPixelChannels(image);
2426           }
2427           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2428           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2429             image->rows);
2430           if (status == MagickFalse)
2431             break;
2432         }
2433   if (y == (ssize_t) image->rows)
2434     jpeg_finish_compress(&jpeg_info);
2435   /*
2436     Relinquish resources.
2437   */
2438   jpeg_destroy_compress(&jpeg_info);
2439   jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2440   (void) CloseBlob(image);
2441   return(MagickTrue);
2442 }
2443 #endif