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