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