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