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