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