]> granicus.if.org Git - imagemagick/blob - coders/jpeg.c
(no commit message)
[imagemagick] / coders / jpeg.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                        JJJJJ  PPPP   EEEEE   GGGG                           %
7 %                          J    P   P  E      G                               %
8 %                          J    PPPP   EEE    G  GG                           %
9 %                        J J    P      E      G   G                           %
10 %                        JJJ    P      EEEEE   GGG                            %
11 %                                                                             %
12 %                                                                             %
13 %                       Read/Write JPEG Image Format                          %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % This software is based in part on the work of the Independent JPEG Group.
37 % See ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz for copyright and
38 % licensing restrictions.  Blob support contributed by Glenn Randers-Pehrson.
39 %
40 %
41 */
42 \f
43 /*
44   Include declarations.
45 */
46 #include "MagickCore/studio.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/colormap-private.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.h"
55 #include "MagickCore/colorspace.h"
56 #include "MagickCore/colorspace-private.h"
57 #include "MagickCore/constitute.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/magick.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/module.h"
68 #include "MagickCore/monitor.h"
69 #include "MagickCore/monitor-private.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantum-private.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/string-private.h"
80 #include "MagickCore/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  8192
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 != 0)
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   if (IsITUFaxImage(image) != MagickFalse)
1071     {
1072       image->colorspace=LabColorspace;
1073       jpeg_info.out_color_space=JCS_YCbCr;
1074     }
1075   else
1076     if (jpeg_info.out_color_space == JCS_CMYK)
1077       image->colorspace=CMYKColorspace;
1078   /*
1079     Set image resolution.
1080   */
1081   units=0;
1082   if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1) &&
1083       (jpeg_info.Y_density != 1))
1084     {
1085       image->resolution.x=(double) jpeg_info.X_density;
1086       image->resolution.y=(double) jpeg_info.Y_density;
1087       units=(size_t) jpeg_info.density_unit;
1088     }
1089   if (units == 1)
1090     image->units=PixelsPerInchResolution;
1091   if (units == 2)
1092     image->units=PixelsPerCentimeterResolution;
1093   number_pixels=(MagickSizeType) image->columns*image->rows;
1094   option=GetImageOption(image_info,"jpeg:size");
1095   if (option != (const char *) NULL)
1096     {
1097       double
1098         scale_factor;
1099
1100       GeometryInfo
1101         geometry_info;
1102
1103       MagickStatusType
1104         flags;
1105
1106       /*
1107         Scale the image.
1108       */
1109       flags=ParseGeometry(option,&geometry_info);
1110       if ((flags & SigmaValue) == 0)
1111         geometry_info.sigma=geometry_info.rho;
1112       jpeg_calc_output_dimensions(&jpeg_info);
1113       image->magick_columns=jpeg_info.output_width;
1114       image->magick_rows=jpeg_info.output_height;
1115       scale_factor=1.0;
1116       if (geometry_info.rho != 0.0)
1117         scale_factor=jpeg_info.output_width/geometry_info.rho;
1118       if ((geometry_info.sigma != 0.0) &&
1119           (scale_factor > (jpeg_info.output_height/geometry_info.sigma)))
1120         scale_factor=jpeg_info.output_height/geometry_info.sigma;
1121       jpeg_info.scale_num=1U;
1122       jpeg_info.scale_denom=(unsigned int) scale_factor;
1123       jpeg_calc_output_dimensions(&jpeg_info);
1124       if (image->debug != MagickFalse)
1125         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1126           "Scale factor: %.20g",(double) scale_factor);
1127     }
1128   precision=(size_t) jpeg_info.data_precision;
1129 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
1130 #if defined(D_LOSSLESS_SUPPORTED)
1131   image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
1132     JPEGInterlace : NoInterlace;
1133   image->compression=jpeg_info.process == JPROC_LOSSLESS ?
1134     LosslessJPEGCompression : JPEGCompression;
1135   if (jpeg_info.data_precision > 8)
1136     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1137       "12-bit JPEG not supported. Reducing pixel data to 8 bits","`%s'",
1138       image->filename);
1139   if (jpeg_info.data_precision == 16)
1140     jpeg_info.data_precision=12;
1141 #else
1142   image->interlace=jpeg_info.progressive_mode != 0 ? JPEGInterlace :
1143     NoInterlace;
1144   image->compression=JPEGCompression;
1145 #endif
1146 #else
1147   image->compression=JPEGCompression;
1148   image->interlace=JPEGInterlace;
1149 #endif
1150   option=GetImageOption(image_info,"jpeg:colors");
1151   if (option != (const char *) NULL)
1152     {
1153       /*
1154         Let the JPEG library quantize the image.
1155       */
1156       jpeg_info.quantize_colors=MagickTrue;
1157       jpeg_info.desired_number_of_colors=(int) StringToUnsignedLong(option);
1158     }
1159   option=GetImageOption(image_info,"jpeg:block-smoothing");
1160   jpeg_info.do_block_smoothing=IsStringTrue(option);
1161   jpeg_info.dct_method=JDCT_FLOAT;
1162   option=GetImageOption(image_info,"jpeg:dct-method");
1163   if (option != (const char *) NULL)
1164     switch (*option)
1165     {
1166       case 'D':
1167       case 'd':
1168       {
1169         if (LocaleCompare(option,"default") == 0)
1170           jpeg_info.dct_method=JDCT_DEFAULT;
1171         break;
1172       }
1173       case 'F':
1174       case 'f':
1175       {
1176         if (LocaleCompare(option,"fastest") == 0)
1177           jpeg_info.dct_method=JDCT_FASTEST;
1178         if (LocaleCompare(option,"float") == 0)
1179           jpeg_info.dct_method=JDCT_FLOAT;
1180         break;
1181       }
1182       case 'I':
1183       case 'i':
1184       {
1185         if (LocaleCompare(option,"ifast") == 0)
1186           jpeg_info.dct_method=JDCT_IFAST;
1187         if (LocaleCompare(option,"islow") == 0)
1188           jpeg_info.dct_method=JDCT_ISLOW;
1189         break;
1190       }
1191     }
1192   option=GetImageOption(image_info,"jpeg:fancy-upsampling");
1193   jpeg_info.do_fancy_upsampling=IsStringTrue(option);
1194   (void) jpeg_start_decompress(&jpeg_info);
1195   image->columns=jpeg_info.output_width;
1196   image->rows=jpeg_info.output_height;
1197   image->depth=(size_t) jpeg_info.data_precision;
1198   if (jpeg_info.out_color_space == JCS_YCbCr)
1199     image->colorspace=YCbCrColorspace;
1200   if (jpeg_info.out_color_space == JCS_CMYK)
1201     image->colorspace=CMYKColorspace;
1202   option=GetImageOption(image_info,"jpeg:colors");
1203   if (option != (const char *) NULL)
1204     if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
1205          == MagickFalse)
1206       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1207   if ((jpeg_info.output_components == 1) &&
1208       (jpeg_info.quantize_colors == MagickFalse))
1209     {
1210       size_t
1211         colors;
1212
1213       colors=(size_t) GetQuantumRange(image->depth)+1;
1214       if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1215         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1216     }
1217   if (image->debug != MagickFalse)
1218     {
1219       if (image->interlace != NoInterlace)
1220         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1221           "Interlace: progressive");
1222       else
1223         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1224           "Interlace: nonprogressive");
1225       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Data precision: %d",
1226         (int) jpeg_info.data_precision);
1227       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
1228         (int) jpeg_info.output_width,(int) jpeg_info.output_height);
1229     }
1230   JPEGSetImageQuality(&jpeg_info,image);
1231   JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
1232   (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
1233     jpeg_info.out_color_space);
1234   (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
1235   if (image_info->ping != MagickFalse)
1236     {
1237       jpeg_destroy_decompress(&jpeg_info);
1238       (void) CloseBlob(image);
1239       return(GetFirstImageInList(image));
1240     }
1241   jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
1242     jpeg_info.output_components*sizeof(JSAMPLE));
1243   if (jpeg_pixels == (JSAMPLE *) NULL)
1244     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1245   /*
1246     Convert JPEG pixels to pixel packets.
1247   */
1248   if (setjmp(error_manager.error_recovery) != 0)
1249     {
1250       if (jpeg_pixels != (unsigned char *) NULL)
1251         jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1252       jpeg_destroy_decompress(&jpeg_info);
1253       (void) CloseBlob(image);
1254       number_pixels=(MagickSizeType) image->columns*image->rows;
1255       if (number_pixels != 0)
1256         return(GetFirstImageInList(image));
1257       return(DestroyImage(image));
1258     }
1259   if (jpeg_info.quantize_colors != MagickFalse)
1260     {
1261       image->colors=(size_t) jpeg_info.actual_number_of_colors;
1262       if (jpeg_info.out_color_space == JCS_GRAYSCALE)
1263         for (i=0; i < (ssize_t) image->colors; i++)
1264         {
1265           image->colormap[i].red=(double) ScaleCharToQuantum(
1266             jpeg_info.colormap[0][i]);
1267           image->colormap[i].green=image->colormap[i].red;
1268           image->colormap[i].blue=image->colormap[i].red;
1269           image->colormap[i].alpha=OpaqueAlpha;
1270         }
1271       else
1272         for (i=0; i < (ssize_t) image->colors; i++)
1273         {
1274           image->colormap[i].red=(double) ScaleCharToQuantum(
1275             jpeg_info.colormap[0][i]);
1276           image->colormap[i].green=(double) ScaleCharToQuantum(
1277             jpeg_info.colormap[1][i]);
1278           image->colormap[i].blue=(double) ScaleCharToQuantum(
1279             jpeg_info.colormap[2][i]);
1280           image->colormap[i].alpha=OpaqueAlpha;
1281         }
1282     }
1283   scanline[0]=(JSAMPROW) jpeg_pixels;
1284   for (y=0; y < (ssize_t) image->rows; y++)
1285   {
1286     register ssize_t
1287       x;
1288
1289     register Quantum
1290       *restrict q;
1291
1292     if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
1293       {
1294         (void) ThrowMagickException(exception,GetMagickModule(),
1295           CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename);
1296         continue;
1297       }
1298     p=jpeg_pixels;
1299     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1300     if (q == (Quantum *) NULL)
1301       break;
1302     if (jpeg_info.data_precision > 8)
1303       {
1304         if (jpeg_info.output_components == 1)
1305           for (x=0; x < (ssize_t) image->columns; x++)
1306           {
1307             size_t
1308               pixel;
1309
1310             if (precision != 16)
1311               pixel=(size_t) GETJSAMPLE(*p);
1312             else
1313               pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
1314             index=ConstrainColormapIndex(image,pixel,exception);
1315             SetPixelIndex(image,index,q);
1316             SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1317             p++;
1318             q+=GetPixelChannels(image);
1319           }
1320         else
1321           if (image->colorspace != CMYKColorspace)
1322             for (x=0; x < (ssize_t) image->columns; x++)
1323             {
1324               SetPixelRed(image,ScaleShortToQuantum((unsigned char)
1325                 (GETJSAMPLE(*p++) << 4)),q);
1326               SetPixelGreen(image,ScaleShortToQuantum((unsigned char)
1327                 (GETJSAMPLE(*p++) << 4)),q);
1328               SetPixelBlue(image,ScaleShortToQuantum((unsigned char)
1329                 (GETJSAMPLE(*p++) << 4)),q);
1330               SetPixelAlpha(image,OpaqueAlpha,q);
1331               q+=GetPixelChannels(image);
1332             }
1333           else
1334             for (x=0; x < (ssize_t) image->columns; x++)
1335             {
1336               SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
1337                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1338               SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
1339                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1340               SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
1341                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1342               SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
1343                 (unsigned char) (GETJSAMPLE(*p++) << 4)),q);
1344               SetPixelAlpha(image,OpaqueAlpha,q);
1345               q+=GetPixelChannels(image);
1346             }
1347       }
1348     else
1349       if (jpeg_info.output_components == 1)
1350         for (x=0; x < (ssize_t) image->columns; x++)
1351         {
1352           index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
1353           SetPixelIndex(image,index,q);
1354           SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
1355           p++;
1356           q+=GetPixelChannels(image);
1357         }
1358       else
1359         if (image->colorspace != CMYKColorspace)
1360           for (x=0; x < (ssize_t) image->columns; x++)
1361           {
1362             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1363               GETJSAMPLE(*p++)),q);
1364             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1365               GETJSAMPLE(*p++)),q);
1366             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1367               GETJSAMPLE(*p++)),q);
1368             SetPixelAlpha(image,OpaqueAlpha,q);
1369             q+=GetPixelChannels(image);
1370           }
1371         else
1372           for (x=0; x < (ssize_t) image->columns; x++)
1373           {
1374             SetPixelCyan(image,QuantumRange-ScaleCharToQuantum(
1375               (unsigned char) GETJSAMPLE(*p++)),q);
1376             SetPixelMagenta(image,QuantumRange-ScaleCharToQuantum(
1377               (unsigned char) GETJSAMPLE(*p++)),q);
1378             SetPixelYellow(image,QuantumRange-ScaleCharToQuantum(
1379               (unsigned char) GETJSAMPLE(*p++)),q);
1380             SetPixelBlack(image,QuantumRange-ScaleCharToQuantum(
1381               (unsigned char) GETJSAMPLE(*p++)),q);
1382             SetPixelAlpha(image,OpaqueAlpha,q);
1383             q+=GetPixelChannels(image);
1384           }
1385     if (SyncAuthenticPixels(image,exception) == MagickFalse)
1386       break;
1387     status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1388       image->rows);
1389     if (status == MagickFalse)
1390       {
1391         jpeg_abort_decompress(&jpeg_info);
1392         break;
1393       }
1394   }
1395   if (status != MagickFalse)
1396     {
1397       error_manager.finished=MagickTrue;
1398       if (setjmp(error_manager.error_recovery) == 0)
1399         (void) jpeg_finish_decompress(&jpeg_info);
1400     }
1401   /*
1402     Free jpeg resources.
1403   */
1404   jpeg_destroy_decompress(&jpeg_info);
1405   jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
1406   (void) CloseBlob(image);
1407   return(GetFirstImageInList(image));
1408 }
1409 #endif
1410 \f
1411 /*
1412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 %                                                                             %
1414 %                                                                             %
1415 %                                                                             %
1416 %   R e g i s t e r J P E G I m a g e                                         %
1417 %                                                                             %
1418 %                                                                             %
1419 %                                                                             %
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 %
1422 %  RegisterJPEGImage() adds properties for the JPEG image format to
1423 %  the list of supported formats.  The properties include the image format
1424 %  tag, a method to read and/or write the format, whether the format
1425 %  supports the saving of more than one frame to the same file or blob,
1426 %  whether the format supports native in-memory I/O, and a brief
1427 %  description of the format.
1428 %
1429 %  The format of the RegisterJPEGImage method is:
1430 %
1431 %      size_t RegisterJPEGImage(void)
1432 %
1433 */
1434 ModuleExport size_t RegisterJPEGImage(void)
1435 {
1436   char
1437     version[MaxTextExtent];
1438
1439   MagickInfo
1440     *entry;
1441
1442   static const char
1443     description[] = "Joint Photographic Experts Group JFIF format";
1444
1445   *version='\0';
1446 #if defined(JPEG_LIB_VERSION)
1447   (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
1448 #endif
1449   entry=SetMagickInfo("JPEG");
1450   entry->thread_support=NoThreadSupport;
1451 #if defined(MAGICKCORE_JPEG_DELEGATE)
1452   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1453   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1454 #endif
1455   entry->magick=(IsImageFormatHandler *) IsJPEG;
1456   entry->adjoin=MagickFalse;
1457   entry->description=ConstantString(description);
1458   if (*version != '\0')
1459     entry->version=ConstantString(version);
1460   entry->module=ConstantString("JPEG");
1461   (void) RegisterMagickInfo(entry);
1462   entry=SetMagickInfo("JPG");
1463   entry->thread_support=NoThreadSupport;
1464 #if defined(MAGICKCORE_JPEG_DELEGATE)
1465   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1466   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1467 #endif
1468   entry->adjoin=MagickFalse;
1469   entry->description=ConstantString(description);
1470   if (*version != '\0')
1471     entry->version=ConstantString(version);
1472   entry->module=ConstantString("JPEG");
1473   (void) RegisterMagickInfo(entry);
1474   entry=SetMagickInfo("PJPEG");
1475   entry->thread_support=NoThreadSupport;
1476 #if defined(MAGICKCORE_JPEG_DELEGATE)
1477   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
1478   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
1479 #endif
1480   entry->adjoin=MagickFalse;
1481   entry->description=ConstantString(description);
1482   if (*version != '\0')
1483     entry->version=ConstantString(version);
1484   entry->module=ConstantString("JPEG");
1485   (void) RegisterMagickInfo(entry);
1486   return(MagickImageCoderSignature);
1487 }
1488 \f
1489 /*
1490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1491 %                                                                             %
1492 %                                                                             %
1493 %                                                                             %
1494 %   U n r e g i s t e r J P E G I m a g e                                     %
1495 %                                                                             %
1496 %                                                                             %
1497 %                                                                             %
1498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499 %
1500 %  UnregisterJPEGImage() removes format registrations made by the
1501 %  JPEG module from the list of supported formats.
1502 %
1503 %  The format of the UnregisterJPEGImage method is:
1504 %
1505 %      UnregisterJPEGImage(void)
1506 %
1507 */
1508 ModuleExport void UnregisterJPEGImage(void)
1509 {
1510   (void) UnregisterMagickInfo("PJPG");
1511   (void) UnregisterMagickInfo("JPEG");
1512   (void) UnregisterMagickInfo("JPG");
1513 }
1514 \f
1515 #if defined(MAGICKCORE_JPEG_DELEGATE)
1516 /*
1517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518 %                                                                             %
1519 %                                                                             %
1520 %                                                                             %
1521 %  W r i t e J P E G I m a g e                                                %
1522 %                                                                             %
1523 %                                                                             %
1524 %                                                                             %
1525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526 %
1527 %  WriteJPEGImage() writes a JPEG image file and returns it.  It
1528 %  allocates the memory necessary for the new Image structure and returns a
1529 %  pointer to the new image.
1530 %
1531 %  The format of the WriteJPEGImage method is:
1532 %
1533 %      MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1534 %        Image *image,ExceptionInfo *exception)
1535 %
1536 %  A description of each parameter follows:
1537 %
1538 %    o image_info: the image info.
1539 %
1540 %    o jpeg_image:  The image.
1541 %
1542 %    o exception: return any errors or warnings in this structure.
1543 %
1544 */
1545
1546 static QuantizationTable *DestroyQuantizationTable(QuantizationTable *table)
1547 {
1548   assert(table != (QuantizationTable *) NULL);
1549   if (table->slot != (char *) NULL)
1550     table->slot=DestroyString(table->slot);
1551   if (table->description != (char *) NULL)
1552     table->description=DestroyString(table->description);
1553   if (table->levels != (unsigned int *) NULL)
1554     table->levels=(unsigned int *) RelinquishMagickMemory(table->levels);
1555   table=(QuantizationTable *) RelinquishMagickMemory(table);
1556   return(table);
1557 }
1558
1559 static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
1560 {
1561   DestinationManager
1562     *destination;
1563
1564   destination=(DestinationManager *) cinfo->dest;
1565   destination->manager.free_in_buffer=(size_t) WriteBlob(destination->image,
1566     MaxBufferExtent,destination->buffer);
1567   if (destination->manager.free_in_buffer != MaxBufferExtent)
1568     ERREXIT(cinfo,JERR_FILE_WRITE);
1569   destination->manager.next_output_byte=destination->buffer;
1570   return(TRUE);
1571 }
1572
1573 static QuantizationTable *GetQuantizationTable(const char *filename,
1574   const char *slot,ExceptionInfo *exception)
1575 {
1576   char
1577     *p,
1578     *xml;
1579
1580   const char
1581     *attribute,
1582     *content;
1583
1584   double
1585     value;
1586
1587   register ssize_t
1588     i;
1589
1590   ssize_t
1591     j;
1592
1593   QuantizationTable
1594     *table;
1595
1596   size_t
1597     length;
1598
1599   XMLTreeInfo
1600     *description,
1601     *levels,
1602     *quantization_tables,
1603     *table_iterator;
1604
1605   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1606     "Loading quantization tables \"%s\" ...",filename);
1607   table=(QuantizationTable *) NULL;
1608   xml=FileToString(filename,~0,exception);
1609   if (xml == (char *) NULL)
1610     return(table);
1611   quantization_tables=NewXMLTree(xml,exception);
1612   if (quantization_tables == (XMLTreeInfo *) NULL)
1613     {
1614       xml=DestroyString(xml);
1615       return(table);
1616     }
1617   for (table_iterator=GetXMLTreeChild(quantization_tables,"table");
1618        table_iterator != (XMLTreeInfo *) NULL;
1619        table_iterator=GetNextXMLTreeTag(table_iterator))
1620   {
1621     attribute=GetXMLTreeAttribute(table_iterator,"slot");
1622     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1623       break;
1624     attribute=GetXMLTreeAttribute(table_iterator,"alias");
1625     if ((attribute != (char *) NULL) && (LocaleCompare(slot,attribute) == 0))
1626       break;
1627   }
1628   if (table_iterator == (XMLTreeInfo *) NULL)
1629     {
1630       xml=DestroyString(xml);
1631       return(table);
1632     }
1633   description=GetXMLTreeChild(table_iterator,"description");
1634   if (description == (XMLTreeInfo *) NULL)
1635     {
1636       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1637         "XmlMissingElement", "<description>, slot \"%s\"",slot);
1638       quantization_tables=DestroyXMLTree(quantization_tables);
1639       xml=DestroyString(xml);
1640       return(table);
1641     }
1642   levels=GetXMLTreeChild(table_iterator,"levels");
1643   if (levels == (XMLTreeInfo *) NULL)
1644     {
1645       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1646         "XmlMissingElement", "<levels>, slot \"%s\"", slot);
1647       quantization_tables=DestroyXMLTree(quantization_tables);
1648       xml=DestroyString(xml);
1649       return(table);
1650     }
1651   table=(QuantizationTable *) AcquireMagickMemory(sizeof(*table));
1652   if (table == (QuantizationTable *) NULL)
1653     ThrowFatalException(ResourceLimitFatalError,
1654       "UnableToAcquireQuantizationTable");
1655   table->slot=(char *) NULL;
1656   table->description=(char *) NULL;
1657   table->levels=(unsigned int *) NULL;
1658   attribute=GetXMLTreeAttribute(table_iterator,"slot");
1659   if (attribute != (char *) NULL)
1660     table->slot=ConstantString(attribute);
1661   content=GetXMLTreeContent(description);
1662   if (content != (char *) NULL)
1663     table->description=ConstantString(content);
1664   attribute=GetXMLTreeAttribute(levels,"width");
1665   if (attribute == (char *) NULL)
1666     {
1667       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1668         "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
1669       quantization_tables=DestroyXMLTree(quantization_tables);
1670       table=DestroyQuantizationTable(table);
1671       xml=DestroyString(xml);
1672       return(table);
1673     }
1674   table->width=StringToUnsignedLong(attribute);
1675   if (table->width == 0)
1676     {
1677       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1678        "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
1679       quantization_tables=DestroyXMLTree(quantization_tables);
1680       table=DestroyQuantizationTable(table);
1681       xml=DestroyString(xml);
1682       return(table);
1683     }
1684   attribute=GetXMLTreeAttribute(levels,"height");
1685   if (attribute == (char *) NULL)
1686     {
1687       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1688         "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
1689       quantization_tables=DestroyXMLTree(quantization_tables);
1690       table=DestroyQuantizationTable(table);
1691       xml=DestroyString(xml);
1692       return(table);
1693     }
1694   table->height=StringToUnsignedLong(attribute);
1695   if (table->height == 0)
1696     {
1697       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1698         "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
1699       quantization_tables=DestroyXMLTree(quantization_tables);
1700       table=DestroyQuantizationTable(table);
1701       xml=DestroyString(xml);
1702       return(table);
1703     }
1704   attribute=GetXMLTreeAttribute(levels,"divisor");
1705   if (attribute == (char *) NULL)
1706     {
1707       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1708         "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
1709       quantization_tables=DestroyXMLTree(quantization_tables);
1710       table=DestroyQuantizationTable(table);
1711       xml=DestroyString(xml);
1712       return(table);
1713     }
1714   table->divisor=InterpretLocaleValue(attribute,(char **) NULL);
1715   if (table->divisor == 0.0)
1716     {
1717       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1718         "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
1719       quantization_tables=DestroyXMLTree(quantization_tables);
1720       table=DestroyQuantizationTable(table);
1721       xml=DestroyString(xml);
1722       return(table);
1723     }
1724   content=GetXMLTreeContent(levels);
1725   if (content == (char *) NULL)
1726     {
1727       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1728         "XmlMissingContent", "<levels>, table \"%s\"",slot);
1729       quantization_tables=DestroyXMLTree(quantization_tables);
1730       table=DestroyQuantizationTable(table);
1731       xml=DestroyString(xml);
1732       return(table);
1733     }
1734   length=(size_t) table->width*table->height;
1735   if (length < 64)
1736     length=64;
1737   table->levels=(unsigned int *) AcquireQuantumMemory(length,
1738     sizeof(*table->levels));
1739   if (table->levels == (unsigned int *) NULL)
1740     ThrowFatalException(ResourceLimitFatalError,
1741       "UnableToAcquireQuantizationTable");
1742   for (i=0; i < (ssize_t) (table->width*table->height); i++)
1743   {
1744     table->levels[i]=(unsigned int) (InterpretLocaleValue(content,&p)/
1745       table->divisor+0.5);
1746     while (isspace((int) ((unsigned char) *p)) != 0)
1747       p++;
1748     if (*p == ',')
1749       p++;
1750     content=p;
1751   }
1752   value=InterpretLocaleValue(content,&p);
1753   (void) value;
1754   if (p != content)
1755     {
1756       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1757         "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
1758      quantization_tables=DestroyXMLTree(quantization_tables);
1759      table=DestroyQuantizationTable(table);
1760      xml=DestroyString(xml);
1761      return(table);
1762    }
1763   for (j=i; j < 64; j++)
1764     table->levels[j]=table->levels[j-1];
1765   quantization_tables=DestroyXMLTree(quantization_tables);
1766   xml=DestroyString(xml);
1767   return(table);
1768 }
1769
1770 static void InitializeDestination(j_compress_ptr cinfo)
1771 {
1772   DestinationManager
1773     *destination;
1774
1775   destination=(DestinationManager *) cinfo->dest;
1776   destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
1777     ((j_common_ptr) cinfo,JPOOL_IMAGE,MaxBufferExtent*sizeof(JOCTET));
1778   destination->manager.next_output_byte=destination->buffer;
1779   destination->manager.free_in_buffer=MaxBufferExtent;
1780 }
1781
1782 static inline size_t MagickMin(const size_t x,const size_t y)
1783 {
1784   if (x < y)
1785     return(x);
1786   return(y);
1787 }
1788
1789 static void TerminateDestination(j_compress_ptr cinfo)
1790 {
1791   DestinationManager
1792     *destination;
1793
1794   destination=(DestinationManager *) cinfo->dest;
1795   if ((MaxBufferExtent-(int) destination->manager.free_in_buffer) > 0)
1796     {
1797       ssize_t
1798         count;
1799
1800       count=WriteBlob(destination->image,MaxBufferExtent-
1801         destination->manager.free_in_buffer,destination->buffer);
1802       if (count != (ssize_t)
1803           (MaxBufferExtent-destination->manager.free_in_buffer))
1804         ERREXIT(cinfo,JERR_FILE_WRITE);
1805     }
1806 }
1807
1808 static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
1809 {
1810   const char
1811     *name;
1812
1813   const StringInfo
1814     *profile;
1815
1816   MagickBooleanType
1817     iptc;
1818
1819   register ssize_t
1820     i;
1821
1822   size_t
1823     length,
1824     tag_length;
1825
1826   StringInfo
1827     *custom_profile;
1828
1829   /*
1830     Save image profile as a APP marker.
1831   */
1832   iptc=MagickFalse;
1833   custom_profile=AcquireStringInfo(65535L);
1834   ResetImageProfileIterator(image);
1835   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1836   {
1837     register unsigned char
1838       *p;
1839
1840     profile=GetImageProfile(image,name);
1841     p=GetStringInfoDatum(custom_profile);
1842     if (LocaleCompare(name,"EXIF") == 0)
1843       for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
1844       {
1845         length=MagickMin(GetStringInfoLength(profile)-i,65533L);
1846         jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
1847           (unsigned int) length);
1848       }
1849     if (LocaleCompare(name,"ICC") == 0)
1850       {
1851         register unsigned char
1852           *p;
1853
1854         tag_length=14;
1855         p=GetStringInfoDatum(custom_profile);
1856         (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
1857         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
1858         {
1859           length=MagickMin(GetStringInfoLength(profile)-i,65519L);
1860           p[12]=(unsigned char) ((i/65519L)+1);
1861           p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
1862           (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
1863             length);
1864           jpeg_write_marker(jpeg_info,ICC_MARKER,GetStringInfoDatum(
1865             custom_profile),(unsigned int) (length+tag_length));
1866         }
1867       }
1868     if (((LocaleCompare(name,"IPTC") == 0) ||
1869         (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
1870       {
1871         size_t
1872           roundup;
1873
1874         iptc=MagickTrue;
1875         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
1876         {
1877           length=MagickMin(GetStringInfoLength(profile)-i,65500L);
1878           roundup=(size_t) (length & 0x01);
1879           if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
1880             {
1881               (void) memcpy(p,"Photoshop 3.0 ",14);
1882               tag_length=14;
1883             }
1884           else
1885             {
1886               (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
1887               tag_length=26;
1888               p[24]=(unsigned char) (length >> 8);
1889               p[25]=(unsigned char) (length & 0xff);
1890             }
1891           p[13]=0x00;
1892           (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
1893           if (roundup != 0)
1894             p[length+tag_length]='\0';
1895           jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
1896             custom_profile),(unsigned int) (length+tag_length+roundup));
1897         }
1898       }
1899     if (LocaleCompare(name,"XMP") == 0)
1900       {
1901         StringInfo
1902           *xmp_profile;
1903
1904         /*
1905           Add namespace to XMP profile.
1906         */
1907         xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/ ");
1908         ConcatenateStringInfo(xmp_profile,profile);
1909         GetStringInfoDatum(xmp_profile)[28]='\0';
1910         for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1911         {
1912           length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1913           jpeg_write_marker(jpeg_info,XML_MARKER,
1914             GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1915         }
1916         xmp_profile=DestroyStringInfo(xmp_profile);
1917       }
1918     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1919       "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1920     name=GetNextImageProfile(image);
1921   }
1922   custom_profile=DestroyStringInfo(custom_profile);
1923 }
1924
1925 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1926 {
1927   DestinationManager
1928     *destination;
1929
1930   cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1931     ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
1932   destination=(DestinationManager *) cinfo->dest;
1933   destination->manager.init_destination=InitializeDestination;
1934   destination->manager.empty_output_buffer=EmptyOutputBuffer;
1935   destination->manager.term_destination=TerminateDestination;
1936   destination->image=image;
1937 }
1938
1939 static char **SamplingFactorToList(const char *text)
1940 {
1941   char
1942     **textlist;
1943
1944   register char
1945     *q;
1946
1947   register const char
1948     *p;
1949
1950   register ssize_t
1951     i;
1952
1953   size_t
1954     lines;
1955
1956   if (text == (char *) NULL)
1957     return((char **) NULL);
1958   /*
1959     Convert string to an ASCII list.
1960   */
1961   lines=1;
1962   for (p=text; *p != '\0'; p++)
1963     if (*p == ',')
1964       lines++;
1965   textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
1966     sizeof(*textlist));
1967   if (textlist == (char **) NULL)
1968     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1969   p=text;
1970   for (i=0; i < (ssize_t) lines; i++)
1971   {
1972     for (q=(char *) p; *q != '\0'; q++)
1973       if (*q == ',')
1974         break;
1975     textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1976       sizeof(*textlist[i]));
1977     if (textlist[i] == (char *) NULL)
1978       ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
1979     (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
1980     if (*q == '\r')
1981       q++;
1982     p=q+1;
1983   }
1984   textlist[i]=(char *) NULL;
1985   return(textlist);
1986 }
1987
1988 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
1989   Image *image,ExceptionInfo *exception)
1990 {
1991   const char
1992     *option,
1993     *sampling_factor,
1994     *value;
1995
1996   ErrorManager
1997     error_manager;
1998
1999   int
2000     quality;
2001
2002   JSAMPLE
2003     *jpeg_pixels;
2004
2005   JSAMPROW
2006     scanline[1];
2007
2008   MagickBooleanType
2009     status;
2010
2011   register JSAMPLE
2012     *q;
2013
2014   register ssize_t
2015     i;
2016
2017   ssize_t
2018     y;
2019
2020   struct jpeg_compress_struct
2021     jpeg_info;
2022
2023   struct jpeg_error_mgr
2024     jpeg_error;
2025
2026   /*
2027     Open image file.
2028   */
2029   assert(image_info != (const ImageInfo *) NULL);
2030   assert(image_info->signature == MagickSignature);
2031   assert(image != (Image *) NULL);
2032   assert(image->signature == MagickSignature);
2033   if (image->debug != MagickFalse)
2034     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2035   assert(exception != (ExceptionInfo *) NULL);
2036   assert(exception->signature == MagickSignature);
2037   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2038   if (status == MagickFalse)
2039     return(status);
2040   /*
2041     Initialize JPEG parameters.
2042   */
2043   (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2044   (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2045   (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2046   jpeg_info.client_data=(void *) image;
2047   jpeg_info.err=jpeg_std_error(&jpeg_error);
2048   jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2049   jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2050   error_manager.exception=exception;
2051   error_manager.image=image;
2052   jpeg_pixels=(JSAMPLE *) NULL;
2053   if (setjmp(error_manager.error_recovery) != 0)
2054     {
2055       jpeg_destroy_compress(&jpeg_info);
2056       (void) CloseBlob(image);
2057       return(MagickFalse);
2058     }
2059   jpeg_info.client_data=(void *) &error_manager;
2060   jpeg_create_compress(&jpeg_info);
2061   JPEGDestinationManager(&jpeg_info,image);
2062   if ((image->columns != (unsigned int) image->columns) ||
2063       (image->rows != (unsigned int) image->rows))
2064     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2065   jpeg_info.image_width=(unsigned int) image->columns;
2066   jpeg_info.image_height=(unsigned int) image->rows;
2067   jpeg_info.input_components=3;
2068   jpeg_info.data_precision=8;
2069   jpeg_info.in_color_space=JCS_RGB;
2070   switch (image->colorspace)
2071   {
2072     case CMYKColorspace:
2073     {
2074       jpeg_info.input_components=4;
2075       jpeg_info.in_color_space=JCS_CMYK;
2076       break;
2077     }
2078     case YCbCrColorspace:
2079     case Rec601YCbCrColorspace:
2080     case Rec709YCbCrColorspace:
2081     {
2082       jpeg_info.in_color_space=JCS_YCbCr;
2083       break;
2084     }
2085     case GRAYColorspace:
2086     case Rec601LumaColorspace:
2087     case Rec709LumaColorspace:
2088     {
2089       jpeg_info.input_components=1;
2090       jpeg_info.in_color_space=JCS_GRAYSCALE;
2091       break;
2092     }
2093     default:
2094     {
2095       if (IssRGBColorspace(image->colorspace) == MagickFalse)
2096         (void) TransformImageColorspace(image,sRGBColorspace,exception);
2097       break;
2098     }
2099   }
2100   if ((image_info->type != TrueColorType) &&
2101       (IsImageGray(image,exception) != MagickFalse))
2102     {
2103       jpeg_info.input_components=1;
2104       jpeg_info.in_color_space=JCS_GRAYSCALE;
2105     }
2106   jpeg_set_defaults(&jpeg_info);
2107   if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2108     jpeg_info.data_precision=8;
2109   else
2110     if (sizeof(JSAMPLE) > 1)
2111       jpeg_info.data_precision=12;
2112   jpeg_info.density_unit=(UINT8) 1;
2113   if (image->debug != MagickFalse)
2114     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2115       "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2116       floor(image->resolution.y+0.5));
2117   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2118     {
2119       /*
2120         Set image resolution.
2121       */
2122       jpeg_info.write_JFIF_header=MagickTrue;
2123       jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2124       jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2125       if (image->units == PixelsPerInchResolution)
2126         jpeg_info.density_unit=(UINT8) 1;
2127       if (image->units == PixelsPerCentimeterResolution)
2128         jpeg_info.density_unit=(UINT8) 2;
2129     }
2130   jpeg_info.dct_method=JDCT_FLOAT;
2131   option=GetImageOption(image_info,"jpeg:dct-method");
2132   if (option != (const char *) NULL)
2133     switch (*option)
2134     {
2135       case 'D':
2136       case 'd':
2137       {
2138         if (LocaleCompare(option,"default") == 0)
2139           jpeg_info.dct_method=JDCT_DEFAULT;
2140         break;
2141       }
2142       case 'F':
2143       case 'f':
2144       {
2145         if (LocaleCompare(option,"fastest") == 0)
2146           jpeg_info.dct_method=JDCT_FASTEST;
2147         if (LocaleCompare(option,"float") == 0)
2148           jpeg_info.dct_method=JDCT_FLOAT;
2149         break;
2150       }
2151       case 'I':
2152       case 'i':
2153       {
2154         if (LocaleCompare(option,"ifast") == 0)
2155           jpeg_info.dct_method=JDCT_IFAST;
2156         if (LocaleCompare(option,"islow") == 0)
2157           jpeg_info.dct_method=JDCT_ISLOW;
2158         break;
2159       }
2160     }
2161   option=GetImageOption(image_info,"jpeg:optimize-coding");
2162   if (option != (const char *) NULL)
2163     jpeg_info.optimize_coding=IsStringTrue(option);
2164   else
2165     {
2166       MagickSizeType
2167         length;
2168
2169       length=(MagickSizeType) jpeg_info.input_components*image->columns*
2170         image->rows*sizeof(JSAMPLE);
2171       if (length == (MagickSizeType) ((size_t) length))
2172         {
2173           /*
2174             Perform optimization only if available memory resources permit it.
2175           */
2176           status=AcquireMagickResource(MemoryResource,length);
2177           RelinquishMagickResource(MemoryResource,length);
2178           jpeg_info.optimize_coding=status;
2179         }
2180     }
2181 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2182   if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2183       (image_info->interlace != NoInterlace))
2184     {
2185       if (image->debug != MagickFalse)
2186         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187           "Interlace: progressive");
2188       jpeg_simple_progression(&jpeg_info);
2189     }
2190   else
2191     if (image->debug != MagickFalse)
2192       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2193         "Interlace: non-progressive");
2194 #else
2195   if (image->debug != MagickFalse)
2196     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2197       "Interlace: nonprogressive");
2198 #endif
2199   option=GetImageOption(image_info,"jpeg:extent");
2200   if (option != (const char *) NULL)
2201     {
2202       Image
2203         *jpeg_image;
2204
2205       ImageInfo
2206         *jpeg_info;
2207
2208       jpeg_info=CloneImageInfo(image_info);
2209       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2210       if (jpeg_image != (Image *) NULL)
2211         {
2212           MagickSizeType
2213             extent;
2214
2215           size_t
2216             maximum,
2217             minimum;
2218
2219           /*
2220             Search for compression quality that does not exceed image extent.
2221           */
2222           jpeg_info->quality=0;
2223           extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2224           (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2225           (void) AcquireUniqueFilename(jpeg_image->filename);
2226           maximum=101;
2227           for (minimum=0; minimum != maximum; )
2228           {
2229             jpeg_image->quality=minimum+(maximum-minimum)/2;
2230             status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2231             if (GetBlobSize(jpeg_image) <= extent)
2232               minimum=jpeg_image->quality+1;
2233             else
2234               maximum=jpeg_image->quality-1;
2235           }
2236           (void) RelinquishUniqueFileResource(jpeg_image->filename);
2237           image->quality=minimum-1;
2238           jpeg_image=DestroyImage(jpeg_image);
2239         }
2240       jpeg_info=DestroyImageInfo(jpeg_info);
2241     }
2242   quality=92;
2243   if ((image_info->compression != LosslessJPEGCompression) &&
2244       (image->quality <= 100))
2245     {
2246       if (image->quality != UndefinedCompressionQuality)
2247         quality=(int) image->quality;
2248       if (image->debug != MagickFalse)
2249         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2250           (double) image->quality);
2251     }
2252   else
2253     {
2254 #if !defined(C_LOSSLESS_SUPPORTED)
2255       quality=100;
2256       if (image->debug != MagickFalse)
2257         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2258 #else
2259       if (image->quality < 100)
2260         (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2261           "LosslessToLossyJPEGConversion",image->filename);
2262       else
2263         {
2264           int
2265             point_transform,
2266             predictor;
2267
2268           predictor=image->quality/100;  /* range 1-7 */
2269           point_transform=image->quality % 20;  /* range 0-15 */
2270           jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2271           if (image->debug != MagickFalse)
2272             {
2273               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2274                 "Compression: lossless");
2275               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2276                 "Predictor: %d",predictor);
2277               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2278                 "Point Transform: %d",point_transform);
2279             }
2280         }
2281 #endif
2282     }
2283   jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2284   sampling_factor=(const char *) NULL;
2285   value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2286   if (value != (char *) NULL)
2287     {
2288       sampling_factor=value;
2289       if (image->debug != MagickFalse)
2290         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2291           "  Input sampling-factors=%s",sampling_factor);
2292     }
2293   if (image_info->sampling_factor != (char *) NULL)
2294     sampling_factor=image_info->sampling_factor;
2295   if (sampling_factor == (const char *) NULL)
2296     {
2297       if (image->quality >= 90)
2298         for (i=0; i < MAX_COMPONENTS; i++)
2299         {
2300           jpeg_info.comp_info[i].h_samp_factor=1;
2301           jpeg_info.comp_info[i].v_samp_factor=1;
2302         }
2303     }
2304   else
2305     {
2306       char
2307         **factors;
2308
2309       GeometryInfo
2310         geometry_info;
2311
2312       MagickStatusType
2313         flags;
2314
2315       /*
2316         Set sampling factor.
2317       */
2318       i=0;
2319       factors=SamplingFactorToList(sampling_factor);
2320       if (factors != (char **) NULL)
2321         {
2322           for (i=0; i < MAX_COMPONENTS; i++)
2323           {
2324             if (factors[i] == (char *) NULL)
2325               break;
2326             flags=ParseGeometry(factors[i],&geometry_info);
2327             if ((flags & SigmaValue) == 0)
2328               geometry_info.sigma=geometry_info.rho;
2329             jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2330             jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2331             factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2332           }
2333           factors=(char **) RelinquishMagickMemory(factors);
2334         }
2335       for ( ; i < MAX_COMPONENTS; i++)
2336       {
2337         jpeg_info.comp_info[i].h_samp_factor=1;
2338         jpeg_info.comp_info[i].v_samp_factor=1;
2339       }
2340     }
2341   if (jpeg_info.input_components == 1)
2342     for (i=0; i < MAX_COMPONENTS; i++)
2343     {
2344       jpeg_info.comp_info[i].h_samp_factor=1;
2345       jpeg_info.comp_info[i].v_samp_factor=1;
2346     }
2347   option=GetImageOption(image_info,"jpeg:q-table");
2348   if (option != (const char *) NULL)
2349     {
2350       QuantizationTable
2351         *table;
2352
2353       /*
2354         Custom quantization tables.
2355       */
2356       table=GetQuantizationTable(option,"0",exception);
2357       if (table != (QuantizationTable *) NULL)
2358         {
2359           jpeg_add_quant_table(&jpeg_info,0,table->levels,jpeg_quality_scaling(
2360             quality),0);
2361           table=DestroyQuantizationTable(table);
2362         }
2363       table=GetQuantizationTable(option,"1",exception);
2364       if (table != (QuantizationTable *) NULL)
2365         {
2366           jpeg_add_quant_table(&jpeg_info,1,table->levels,jpeg_quality_scaling(
2367             quality),0);
2368           table=DestroyQuantizationTable(table);
2369         }
2370       table=GetQuantizationTable(option,"2",exception);
2371       if (table != (QuantizationTable *) NULL)
2372         {
2373           jpeg_add_quant_table(&jpeg_info,2,table->levels,jpeg_quality_scaling(
2374             quality),0);
2375           table=DestroyQuantizationTable(table);
2376         }
2377       table=GetQuantizationTable(option,"3",exception);
2378       if (table != (QuantizationTable *) NULL)
2379         {
2380           jpeg_add_quant_table(&jpeg_info,3,table->levels,jpeg_quality_scaling(
2381             quality),0);
2382           table=DestroyQuantizationTable(table);
2383         }
2384     }
2385   jpeg_start_compress(&jpeg_info,MagickTrue);
2386   if (image->debug != MagickFalse)
2387     {
2388       if (image->storage_class == PseudoClass)
2389         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2390           "Storage class: PseudoClass");
2391       else
2392         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2393           "Storage class: DirectClass");
2394       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2395         (double) image->depth);
2396       if (image->colors != 0)
2397         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2398           "Number of colors: %.20g",(double) image->colors);
2399       else
2400         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2401           "Number of colors: unspecified");
2402       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2403         "JPEG data precision: %d",(int) jpeg_info.data_precision);
2404       switch (image->colorspace)
2405       {
2406         case CMYKColorspace:
2407         {
2408           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2409             "Storage class: DirectClass");
2410           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2411             "Colorspace: CMYK");
2412           break;
2413         }
2414         case YCbCrColorspace:
2415         case Rec601YCbCrColorspace:
2416         case Rec709YCbCrColorspace:
2417         {
2418           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2419             "Colorspace: YCbCr");
2420           break;
2421         }
2422         default:
2423           break;
2424       }
2425       switch (image->colorspace)
2426       {
2427         case CMYKColorspace:
2428         {
2429           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2430             "Colorspace: CMYK");
2431           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2432             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2433             jpeg_info.comp_info[0].h_samp_factor,
2434             jpeg_info.comp_info[0].v_samp_factor,
2435             jpeg_info.comp_info[1].h_samp_factor,
2436             jpeg_info.comp_info[1].v_samp_factor,
2437             jpeg_info.comp_info[2].h_samp_factor,
2438             jpeg_info.comp_info[2].v_samp_factor,
2439             jpeg_info.comp_info[3].h_samp_factor,
2440             jpeg_info.comp_info[3].v_samp_factor);
2441           break;
2442         }
2443         case GRAYColorspace:
2444         case Rec601LumaColorspace:
2445         case Rec709LumaColorspace:
2446         {
2447           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2448             "Colorspace: GRAY");
2449           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2450             "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2451             jpeg_info.comp_info[0].v_samp_factor);
2452           break;
2453         }
2454         case RGBColorspace:
2455         {
2456           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2457             "Image colorspace is RGB");
2458           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2459             "Sampling factors: %dx%d,%dx%d,%dx%d",
2460             jpeg_info.comp_info[0].h_samp_factor,
2461             jpeg_info.comp_info[0].v_samp_factor,
2462             jpeg_info.comp_info[1].h_samp_factor,
2463             jpeg_info.comp_info[1].v_samp_factor,
2464             jpeg_info.comp_info[2].h_samp_factor,
2465             jpeg_info.comp_info[2].v_samp_factor);
2466           break;
2467         }
2468         case YCbCrColorspace:
2469         case Rec601YCbCrColorspace:
2470         case Rec709YCbCrColorspace:
2471         {
2472           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2473             "Colorspace: YCbCr");
2474           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2475             "Sampling factors: %dx%d,%dx%d,%dx%d",
2476             jpeg_info.comp_info[0].h_samp_factor,
2477             jpeg_info.comp_info[0].v_samp_factor,
2478             jpeg_info.comp_info[1].h_samp_factor,
2479             jpeg_info.comp_info[1].v_samp_factor,
2480             jpeg_info.comp_info[2].h_samp_factor,
2481             jpeg_info.comp_info[2].v_samp_factor);
2482           break;
2483         }
2484         default:
2485         {
2486           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2487             image->colorspace);
2488           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2489             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2490             jpeg_info.comp_info[0].h_samp_factor,
2491             jpeg_info.comp_info[0].v_samp_factor,
2492             jpeg_info.comp_info[1].h_samp_factor,
2493             jpeg_info.comp_info[1].v_samp_factor,
2494             jpeg_info.comp_info[2].h_samp_factor,
2495             jpeg_info.comp_info[2].v_samp_factor,
2496             jpeg_info.comp_info[3].h_samp_factor,
2497             jpeg_info.comp_info[3].v_samp_factor);
2498           break;
2499         }
2500       }
2501     }
2502   /*
2503     Write JPEG profiles.
2504   */
2505   value=GetImageProperty(image,"comment",exception);
2506   if (value != (char *) NULL)
2507     for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2508       jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2509         (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2510   if (image->profiles != (void *) NULL)
2511     WriteProfile(&jpeg_info,image);
2512   /*
2513     Convert MIFF to JPEG raster pixels.
2514   */
2515   jpeg_pixels=(JSAMPLE *) AcquireQuantumMemory((size_t) image->columns,
2516     jpeg_info.input_components*sizeof(*jpeg_pixels));
2517   if (jpeg_pixels == (JSAMPLE *) NULL)
2518     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2519   if (setjmp(error_manager.error_recovery) != 0)
2520     {
2521       jpeg_destroy_compress(&jpeg_info);
2522       if (jpeg_pixels != (unsigned char *) NULL)
2523         jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2524       (void) CloseBlob(image);
2525       return(MagickFalse);
2526     }
2527   scanline[0]=(JSAMPROW) jpeg_pixels;
2528   if (jpeg_info.data_precision <= 8)
2529     {
2530       if ((jpeg_info.in_color_space == JCS_RGB) ||
2531           (jpeg_info.in_color_space == JCS_YCbCr))
2532         for (y=0; y < (ssize_t) image->rows; y++)
2533         {
2534           register const Quantum
2535             *p;
2536
2537           register ssize_t
2538             x;
2539
2540           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2541           if (p == (const Quantum *) NULL)
2542             break;
2543           q=jpeg_pixels;
2544           for (x=0; x < (ssize_t) image->columns; x++)
2545           {
2546             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2547             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2548             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2549             p+=GetPixelChannels(image);
2550           }
2551           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2552           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2553             image->rows);
2554           if (status == MagickFalse)
2555             break;
2556         }
2557       else
2558         if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2559           for (y=0; y < (ssize_t) image->rows; y++)
2560           {
2561             register const Quantum
2562               *p;
2563
2564             register ssize_t
2565               x;
2566
2567             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2568             if (p == (const Quantum *) NULL)
2569               break;
2570             q=jpeg_pixels;
2571             for (x=0; x < (ssize_t) image->columns; x++)
2572             {
2573               *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelIntensity(image,p));
2574               p+=GetPixelChannels(image);
2575             }
2576             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2577             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2578               image->rows);
2579             if (status == MagickFalse)
2580               break;
2581           }
2582         else
2583           for (y=0; y < (ssize_t) image->rows; y++)
2584           {
2585             register const Quantum
2586               *p;
2587
2588             register ssize_t
2589               x;
2590
2591             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2592             if (p == (const Quantum *) NULL)
2593               break;
2594             q=jpeg_pixels;
2595             for (x=0; x < (ssize_t) image->columns; x++)
2596             {
2597               /*
2598                 Convert DirectClass packets to contiguous CMYK scanlines.
2599               */
2600               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2601                 GetPixelRed(image,p))));
2602               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2603                 GetPixelGreen(image,p))));
2604               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2605                 GetPixelBlue(image,p))));
2606               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2607                 GetPixelBlack(image,p))));
2608               p+=GetPixelChannels(image);
2609             }
2610             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2611             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2612               image->rows);
2613             if (status == MagickFalse)
2614               break;
2615           }
2616     }
2617   else
2618     if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2619       for (y=0; y < (ssize_t) image->rows; y++)
2620       {
2621         register const Quantum
2622           *p;
2623
2624         register ssize_t
2625           x;
2626
2627         p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2628         if (p == (const Quantum *) NULL)
2629           break;
2630         q=jpeg_pixels;
2631         for (x=0; x < (ssize_t) image->columns; x++)
2632         {
2633           *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelIntensity(image,p)) >> 4);
2634           p+=GetPixelChannels(image);
2635         }
2636         (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2637         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2638           image->rows);
2639         if (status == MagickFalse)
2640           break;
2641       }
2642     else
2643       if ((jpeg_info.in_color_space == JCS_RGB) ||
2644           (jpeg_info.in_color_space == JCS_YCbCr))
2645         for (y=0; y < (ssize_t) image->rows; y++)
2646         {
2647           register const Quantum
2648             *p;
2649
2650           register ssize_t
2651             x;
2652
2653           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2654           if (p == (const Quantum *) NULL)
2655             break;
2656           q=jpeg_pixels;
2657           for (x=0; x < (ssize_t) image->columns; x++)
2658           {
2659             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p)) >> 4);
2660             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p)) >> 4);
2661             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p)) >> 4);
2662             p+=GetPixelChannels(image);
2663           }
2664           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2665           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2666             image->rows);
2667           if (status == MagickFalse)
2668             break;
2669         }
2670       else
2671         for (y=0; y < (ssize_t) image->rows; y++)
2672         {
2673           register const Quantum
2674             *p;
2675
2676           register ssize_t
2677             x;
2678
2679           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2680           if (p == (const Quantum *) NULL)
2681             break;
2682           q=jpeg_pixels;
2683           for (x=0; x < (ssize_t) image->columns; x++)
2684           {
2685             /*
2686               Convert DirectClass packets to contiguous CMYK scanlines.
2687             */
2688             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2689               GetPixelRed(image,p)) >> 4));
2690             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2691               GetPixelGreen(image,p)) >> 4));
2692             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2693               GetPixelBlue(image,p)) >> 4));
2694             *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
2695               GetPixelBlack(image,p)) >> 4));
2696             p+=GetPixelChannels(image);
2697           }
2698           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2699           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2700             image->rows);
2701           if (status == MagickFalse)
2702             break;
2703         }
2704   if (y == (ssize_t) image->rows)
2705     jpeg_finish_compress(&jpeg_info);
2706   /*
2707     Relinquish resources.
2708   */
2709   jpeg_destroy_compress(&jpeg_info);
2710   jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
2711   (void) CloseBlob(image);
2712   return(MagickTrue);
2713 }
2714 #endif