]> 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(TRUE);
599   length-=4;
600   if (length <= 7)
601     return(TRUE);
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             if (profile != (StringInfo *) NULL)
1975               ConcatenateStringInfo(xmp_profile,profile);
1976             GetStringInfoDatum(xmp_profile)[28]='\0';
1977             for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
1978             {
1979               length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
1980               jpeg_write_marker(jpeg_info,XML_MARKER,
1981                 GetStringInfoDatum(xmp_profile)+i,(unsigned int) length);
1982             }
1983             xmp_profile=DestroyStringInfo(xmp_profile);
1984           }
1985       }
1986     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1987       "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
1988     name=GetNextImageProfile(image);
1989   }
1990   custom_profile=DestroyStringInfo(custom_profile);
1991 }
1992
1993 static void JPEGDestinationManager(j_compress_ptr cinfo,Image * image)
1994 {
1995   DestinationManager
1996     *destination;
1997
1998   cinfo->dest=(struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
1999     ((j_common_ptr) cinfo,JPOOL_IMAGE,sizeof(DestinationManager));
2000   destination=(DestinationManager *) cinfo->dest;
2001   destination->manager.init_destination=InitializeDestination;
2002   destination->manager.empty_output_buffer=EmptyOutputBuffer;
2003   destination->manager.term_destination=TerminateDestination;
2004   destination->image=image;
2005 }
2006
2007 static char **SamplingFactorToList(const char *text)
2008 {
2009   char
2010     **textlist;
2011
2012   register char
2013     *q;
2014
2015   register const char
2016     *p;
2017
2018   register ssize_t
2019     i;
2020
2021   size_t
2022     lines;
2023
2024   if (text == (char *) NULL)
2025     return((char **) NULL);
2026   /*
2027     Convert string to an ASCII list.
2028   */
2029   lines=1;
2030   for (p=text; *p != '\0'; p++)
2031     if (*p == ',')
2032       lines++;
2033   textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
2034     sizeof(*textlist));
2035   if (textlist == (char **) NULL)
2036     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2037   p=text;
2038   for (i=0; i < (ssize_t) lines; i++)
2039   {
2040     for (q=(char *) p; *q != '\0'; q++)
2041       if (*q == ',')
2042         break;
2043     textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
2044       sizeof(*textlist[i]));
2045     if (textlist[i] == (char *) NULL)
2046       ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
2047     (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
2048     if (*q == '\r')
2049       q++;
2050     p=q+1;
2051   }
2052   textlist[i]=(char *) NULL;
2053   return(textlist);
2054 }
2055
2056 static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
2057   Image *image,ExceptionInfo *exception)
2058 {
2059   const char
2060     *option,
2061     *sampling_factor,
2062     *value;
2063
2064   ErrorManager
2065     error_manager;
2066
2067   int
2068     colorspace,
2069     quality;
2070
2071   JSAMPLE
2072     *volatile jpeg_pixels;
2073
2074   JSAMPROW
2075     scanline[1];
2076
2077   MagickBooleanType
2078     status;
2079
2080   MemoryInfo
2081     *memory_info;
2082
2083   register JSAMPLE
2084     *q;
2085
2086   register ssize_t
2087     i;
2088
2089   ssize_t
2090     y;
2091
2092   struct jpeg_compress_struct
2093     jpeg_info;
2094
2095   struct jpeg_error_mgr
2096     jpeg_error;
2097
2098   unsigned short
2099     scale;
2100
2101   /*
2102     Open image file.
2103   */
2104   assert(image_info != (const ImageInfo *) NULL);
2105   assert(image_info->signature == MagickSignature);
2106   assert(image != (Image *) NULL);
2107   assert(image->signature == MagickSignature);
2108   if (image->debug != MagickFalse)
2109     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2110   assert(exception != (ExceptionInfo *) NULL);
2111   assert(exception->signature == MagickSignature);
2112   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2113   if (status == MagickFalse)
2114     return(status);
2115   /*
2116     Initialize JPEG parameters.
2117   */
2118   (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
2119   (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
2120   (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
2121   jpeg_info.client_data=(void *) image;
2122   jpeg_info.err=jpeg_std_error(&jpeg_error);
2123   jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
2124   jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
2125   error_manager.exception=exception;
2126   error_manager.image=image;
2127   memory_info=(MemoryInfo *) NULL;
2128   if (setjmp(error_manager.error_recovery) != 0)
2129     {
2130       jpeg_destroy_compress(&jpeg_info);
2131       (void) CloseBlob(image);
2132       return(MagickFalse);
2133     }
2134   jpeg_info.client_data=(void *) &error_manager;
2135   jpeg_create_compress(&jpeg_info);
2136   JPEGDestinationManager(&jpeg_info,image);
2137   if ((image->columns != (unsigned int) image->columns) ||
2138       (image->rows != (unsigned int) image->rows))
2139     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2140   jpeg_info.image_width=(unsigned int) image->columns;
2141   jpeg_info.image_height=(unsigned int) image->rows;
2142   jpeg_info.input_components=3;
2143   jpeg_info.data_precision=8;
2144   jpeg_info.in_color_space=JCS_RGB;
2145   switch (image->colorspace)
2146   {
2147     case CMYKColorspace:
2148     {
2149       jpeg_info.input_components=4;
2150       jpeg_info.in_color_space=JCS_CMYK;
2151       break;
2152     }
2153     case YCbCrColorspace:
2154     case Rec601YCbCrColorspace:
2155     case Rec709YCbCrColorspace:
2156     {
2157       jpeg_info.in_color_space=JCS_YCbCr;
2158       break;
2159     }
2160     case GRAYColorspace:
2161     {
2162       if (image_info->type == TrueColorType)
2163         break;
2164       jpeg_info.input_components=1;
2165       jpeg_info.in_color_space=JCS_GRAYSCALE;
2166       break;
2167     }
2168     default:
2169     {
2170       (void) TransformImageColorspace(image,sRGBColorspace,exception);
2171       if (image_info->type == TrueColorType)
2172         break;
2173       if (IsImageGray(image,exception) != MagickFalse)
2174         {
2175           jpeg_info.input_components=1;
2176           jpeg_info.in_color_space=JCS_GRAYSCALE;
2177         }
2178       break;
2179     }
2180   }
2181   jpeg_set_defaults(&jpeg_info);
2182   if (jpeg_info.in_color_space == JCS_CMYK)
2183     jpeg_set_colorspace(&jpeg_info,JCS_YCCK);
2184   if ((jpeg_info.data_precision != 12) && (image->depth <= 8))
2185     jpeg_info.data_precision=8;
2186   else
2187     jpeg_info.data_precision=BITS_IN_JSAMPLE;
2188   jpeg_info.density_unit=(UINT8) 1;
2189   if (image->debug != MagickFalse)
2190     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2191       "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
2192       floor(image->resolution.y+0.5));
2193   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
2194     {
2195       /*
2196         Set image resolution.
2197       */
2198       jpeg_info.write_JFIF_header=TRUE;
2199       jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
2200       jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
2201       /*
2202         Set image resolution units.
2203       */
2204       jpeg_info.density_unit=(UINT8) 0;
2205       if (image->units == PixelsPerInchResolution)
2206         jpeg_info.density_unit=(UINT8) 1;
2207       if (image->units == PixelsPerCentimeterResolution)
2208         jpeg_info.density_unit=(UINT8) 2;
2209     }
2210   jpeg_info.dct_method=JDCT_FLOAT;
2211   option=GetImageOption(image_info,"jpeg:dct-method");
2212   if (option != (const char *) NULL)
2213     switch (*option)
2214     {
2215       case 'D':
2216       case 'd':
2217       {
2218         if (LocaleCompare(option,"default") == 0)
2219           jpeg_info.dct_method=JDCT_DEFAULT;
2220         break;
2221       }
2222       case 'F':
2223       case 'f':
2224       {
2225         if (LocaleCompare(option,"fastest") == 0)
2226           jpeg_info.dct_method=JDCT_FASTEST;
2227         if (LocaleCompare(option,"float") == 0)
2228           jpeg_info.dct_method=JDCT_FLOAT;
2229         break;
2230       }
2231       case 'I':
2232       case 'i':
2233       {
2234         if (LocaleCompare(option,"ifast") == 0)
2235           jpeg_info.dct_method=JDCT_IFAST;
2236         if (LocaleCompare(option,"islow") == 0)
2237           jpeg_info.dct_method=JDCT_ISLOW;
2238         break;
2239       }
2240     }
2241   option=GetImageOption(image_info,"jpeg:optimize-coding");
2242   if (option != (const char *) NULL)
2243     jpeg_info.optimize_coding=IsStringTrue(option) != MagickFalse ? TRUE : FALSE;
2244   else
2245     {
2246       MagickSizeType
2247         length;
2248
2249       length=(MagickSizeType) jpeg_info.input_components*image->columns*
2250         image->rows*sizeof(JSAMPLE);
2251       if (length == (MagickSizeType) ((size_t) length))
2252         {
2253           /*
2254             Perform optimization only if available memory resources permit it.
2255           */
2256           status=AcquireMagickResource(MemoryResource,length);
2257           RelinquishMagickResource(MemoryResource,length);
2258           jpeg_info.optimize_coding=status;
2259         }
2260     }
2261 #if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
2262   if ((LocaleCompare(image_info->magick,"PJPEG") == 0) ||
2263       (image_info->interlace != NoInterlace))
2264     {
2265       if (image->debug != MagickFalse)
2266         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2267           "Interlace: progressive");
2268       jpeg_simple_progression(&jpeg_info);
2269     }
2270   else
2271     if (image->debug != MagickFalse)
2272       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2273         "Interlace: non-progressive");
2274 #else
2275   if (image->debug != MagickFalse)
2276     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2277       "Interlace: nonprogressive");
2278 #endif
2279   quality=92;
2280   if ((image_info->compression != LosslessJPEGCompression) &&
2281       (image->quality <= 100))
2282     {
2283       if (image->quality != UndefinedCompressionQuality)
2284         quality=(int) image->quality;
2285       if (image->debug != MagickFalse)
2286         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
2287           (double) image->quality);
2288     }
2289   else
2290     {
2291 #if !defined(C_LOSSLESS_SUPPORTED)
2292       quality=100;
2293       if (image->debug != MagickFalse)
2294         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: 100");
2295 #else
2296       if (image->quality < 100)
2297         (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
2298           "LosslessToLossyJPEGConversion",image->filename);
2299       else
2300         {
2301           int
2302             point_transform,
2303             predictor;
2304
2305           predictor=image->quality/100;  /* range 1-7 */
2306           point_transform=image->quality % 20;  /* range 0-15 */
2307           jpeg_simple_lossless(&jpeg_info,predictor,point_transform);
2308           if (image->debug != MagickFalse)
2309             {
2310               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2311                 "Compression: lossless");
2312               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2313                 "Predictor: %d",predictor);
2314               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2315                 "Point Transform: %d",point_transform);
2316             }
2317         }
2318 #endif
2319     }
2320   option=GetImageOption(image_info,"jpeg:extent");
2321   if (option != (const char *) NULL)
2322     {
2323       Image
2324         *jpeg_image;
2325
2326       ImageInfo
2327         *jpeg_info;
2328
2329       jpeg_info=CloneImageInfo(image_info);
2330       jpeg_info->blob=NULL;
2331       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
2332       if (jpeg_image != (Image *) NULL)
2333         {
2334           MagickSizeType
2335             extent;
2336
2337           size_t
2338             maximum,
2339             minimum;
2340
2341           /*
2342             Search for compression quality that does not exceed image extent.
2343           */
2344           jpeg_info->quality=0;
2345           extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
2346           (void) DeleteImageOption(jpeg_info,"jpeg:extent");
2347           (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
2348           maximum=101;
2349           for (minimum=2; minimum < maximum; )
2350           {
2351             (void) AcquireUniqueFilename(jpeg_image->filename);
2352             jpeg_image->quality=minimum+(maximum-minimum+1)/2;
2353             status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
2354             if (GetBlobSize(jpeg_image) <= extent)
2355               minimum=jpeg_image->quality+1;
2356             else
2357               maximum=jpeg_image->quality-1;
2358             (void) RelinquishUniqueFileResource(jpeg_image->filename);
2359           }
2360           quality=minimum-1;
2361           jpeg_image=DestroyImage(jpeg_image);
2362         }
2363       jpeg_info=DestroyImageInfo(jpeg_info);
2364     }
2365   jpeg_set_quality(&jpeg_info,quality,MagickTrue);
2366 #if (JPEG_LIB_VERSION >= 70)
2367   option=GetImageOption(image_info,"quality");
2368   if (option != (const char *) NULL)
2369     {
2370       GeometryInfo
2371         geometry_info;
2372
2373       int
2374         flags;
2375
2376       /*
2377         Set quality scaling for luminance and chrominance separately.
2378       */
2379       flags=ParseGeometry(option,&geometry_info);
2380       if (((flags & RhoValue) != 0) && ((flags & SigmaValue) != 0))
2381         {
2382           jpeg_info.q_scale_factor[0]=jpeg_quality_scaling((int)
2383             (geometry_info.rho+0.5));
2384           jpeg_info.q_scale_factor[1]=jpeg_quality_scaling((int)
2385             (geometry_info.sigma+0.5));
2386           jpeg_default_qtables(&jpeg_info,MagickTrue);
2387         }
2388     }
2389 #endif
2390   colorspace=jpeg_info.in_color_space;
2391   value=GetImageOption(image_info,"jpeg:colorspace");
2392   if (value == (char *) NULL)
2393     value=GetImageProperty(image,"jpeg:colorspace",exception);
2394   if (value != (char *) NULL)
2395     colorspace=StringToInteger(value);
2396   sampling_factor=(const char *) NULL;
2397   if (colorspace == jpeg_info.in_color_space)
2398     {
2399       value=GetImageOption(image_info,"jpeg:sampling-factor");
2400       if (value == (char *) NULL)
2401         value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2402       if (value != (char *) NULL)
2403         {
2404           sampling_factor=value;
2405           if (image->debug != MagickFalse)
2406             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2407               "  Input sampling-factors=%s",sampling_factor);
2408         }
2409     }
2410   value=GetImageOption(image_info,"jpeg:sampling-factor");
2411   if (image_info->sampling_factor != (char *) NULL)
2412     sampling_factor=image_info->sampling_factor;
2413   if (sampling_factor == (const char *) NULL)
2414     {
2415       if (image->quality >= 90)
2416         for (i=0; i < MAX_COMPONENTS; i++)
2417         {
2418           jpeg_info.comp_info[i].h_samp_factor=1;
2419           jpeg_info.comp_info[i].v_samp_factor=1;
2420         }
2421     }
2422   else
2423     {
2424       char
2425         **factors;
2426
2427       GeometryInfo
2428         geometry_info;
2429
2430       MagickStatusType
2431         flags;
2432
2433       /*
2434         Set sampling factor.
2435       */
2436       i=0;
2437       factors=SamplingFactorToList(sampling_factor);
2438       if (factors != (char **) NULL)
2439         {
2440           for (i=0; i < MAX_COMPONENTS; i++)
2441           {
2442             if (factors[i] == (char *) NULL)
2443               break;
2444             flags=ParseGeometry(factors[i],&geometry_info);
2445             if ((flags & SigmaValue) == 0)
2446               geometry_info.sigma=geometry_info.rho;
2447             jpeg_info.comp_info[i].h_samp_factor=(int) geometry_info.rho;
2448             jpeg_info.comp_info[i].v_samp_factor=(int) geometry_info.sigma;
2449             factors[i]=(char *) RelinquishMagickMemory(factors[i]);
2450           }
2451           factors=(char **) RelinquishMagickMemory(factors);
2452         }
2453       for ( ; i < MAX_COMPONENTS; i++)
2454       {
2455         jpeg_info.comp_info[i].h_samp_factor=1;
2456         jpeg_info.comp_info[i].v_samp_factor=1;
2457       }
2458     }
2459   option=GetImageOption(image_info,"jpeg:q-table");
2460   if (option != (const char *) NULL)
2461     {
2462       QuantizationTable
2463         *table;
2464
2465       /*
2466         Custom quantization tables.
2467       */
2468       table=GetQuantizationTable(option,"0",exception);
2469       if (table != (QuantizationTable *) NULL)
2470         {
2471           for (i=0; i < MAX_COMPONENTS; i++)
2472             jpeg_info.comp_info[i].quant_tbl_no=0;
2473           jpeg_add_quant_table(&jpeg_info,0,table->levels,
2474             jpeg_quality_scaling(quality),0);
2475           table=DestroyQuantizationTable(table);
2476         }
2477       table=GetQuantizationTable(option,"1",exception);
2478       if (table != (QuantizationTable *) NULL)
2479         {
2480           for (i=1; i < MAX_COMPONENTS; i++)
2481             jpeg_info.comp_info[i].quant_tbl_no=1;
2482           jpeg_add_quant_table(&jpeg_info,1,table->levels,
2483             jpeg_quality_scaling(quality),0);
2484           table=DestroyQuantizationTable(table);
2485         }
2486       table=GetQuantizationTable(option,"2",exception);
2487       if (table != (QuantizationTable *) NULL)
2488         {
2489           for (i=2; i < MAX_COMPONENTS; i++)
2490             jpeg_info.comp_info[i].quant_tbl_no=2;
2491           jpeg_add_quant_table(&jpeg_info,2,table->levels,
2492             jpeg_quality_scaling(quality),0);
2493           table=DestroyQuantizationTable(table);
2494         }
2495       table=GetQuantizationTable(option,"3",exception);
2496       if (table != (QuantizationTable *) NULL)
2497         {
2498           for (i=3; i < MAX_COMPONENTS; i++)
2499             jpeg_info.comp_info[i].quant_tbl_no=3;
2500           jpeg_add_quant_table(&jpeg_info,3,table->levels,
2501             jpeg_quality_scaling(quality),0);
2502           table=DestroyQuantizationTable(table);
2503         }
2504     }
2505   jpeg_start_compress(&jpeg_info,MagickTrue);
2506   if (image->debug != MagickFalse)
2507     {
2508       if (image->storage_class == PseudoClass)
2509         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2510           "Storage class: PseudoClass");
2511       else
2512         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2513           "Storage class: DirectClass");
2514       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
2515         (double) image->depth);
2516       if (image->colors != 0)
2517         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2518           "Number of colors: %.20g",(double) image->colors);
2519       else
2520         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2521           "Number of colors: unspecified");
2522       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2523         "JPEG data precision: %d",(int) jpeg_info.data_precision);
2524       switch (image->colorspace)
2525       {
2526         case CMYKColorspace:
2527         {
2528           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2529             "Storage class: DirectClass");
2530           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2531             "Colorspace: CMYK");
2532           break;
2533         }
2534         case YCbCrColorspace:
2535         case Rec601YCbCrColorspace:
2536         case Rec709YCbCrColorspace:
2537         {
2538           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2539             "Colorspace: YCbCr");
2540           break;
2541         }
2542         default:
2543           break;
2544       }
2545       switch (image->colorspace)
2546       {
2547         case CMYKColorspace:
2548         {
2549           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2550             "Colorspace: CMYK");
2551           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2552             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2553             jpeg_info.comp_info[0].h_samp_factor,
2554             jpeg_info.comp_info[0].v_samp_factor,
2555             jpeg_info.comp_info[1].h_samp_factor,
2556             jpeg_info.comp_info[1].v_samp_factor,
2557             jpeg_info.comp_info[2].h_samp_factor,
2558             jpeg_info.comp_info[2].v_samp_factor,
2559             jpeg_info.comp_info[3].h_samp_factor,
2560             jpeg_info.comp_info[3].v_samp_factor);
2561           break;
2562         }
2563         case GRAYColorspace:
2564         {
2565           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2566             "Colorspace: GRAY");
2567           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2568             "Sampling factors: %dx%d",jpeg_info.comp_info[0].h_samp_factor,
2569             jpeg_info.comp_info[0].v_samp_factor);
2570           break;
2571         }
2572         case sRGBColorspace:
2573         case RGBColorspace:
2574         {
2575           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2576             "Image colorspace is RGB");
2577           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2578             "Sampling factors: %dx%d,%dx%d,%dx%d",
2579             jpeg_info.comp_info[0].h_samp_factor,
2580             jpeg_info.comp_info[0].v_samp_factor,
2581             jpeg_info.comp_info[1].h_samp_factor,
2582             jpeg_info.comp_info[1].v_samp_factor,
2583             jpeg_info.comp_info[2].h_samp_factor,
2584             jpeg_info.comp_info[2].v_samp_factor);
2585           break;
2586         }
2587         case YCbCrColorspace:
2588         case Rec601YCbCrColorspace:
2589         case Rec709YCbCrColorspace:
2590         {
2591           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2592             "Colorspace: YCbCr");
2593           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2594             "Sampling factors: %dx%d,%dx%d,%dx%d",
2595             jpeg_info.comp_info[0].h_samp_factor,
2596             jpeg_info.comp_info[0].v_samp_factor,
2597             jpeg_info.comp_info[1].h_samp_factor,
2598             jpeg_info.comp_info[1].v_samp_factor,
2599             jpeg_info.comp_info[2].h_samp_factor,
2600             jpeg_info.comp_info[2].v_samp_factor);
2601           break;
2602         }
2603         default:
2604         {
2605           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
2606             image->colorspace);
2607           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2608             "Sampling factors: %dx%d,%dx%d,%dx%d,%dx%d",
2609             jpeg_info.comp_info[0].h_samp_factor,
2610             jpeg_info.comp_info[0].v_samp_factor,
2611             jpeg_info.comp_info[1].h_samp_factor,
2612             jpeg_info.comp_info[1].v_samp_factor,
2613             jpeg_info.comp_info[2].h_samp_factor,
2614             jpeg_info.comp_info[2].v_samp_factor,
2615             jpeg_info.comp_info[3].h_samp_factor,
2616             jpeg_info.comp_info[3].v_samp_factor);
2617           break;
2618         }
2619       }
2620     }
2621   /*
2622     Write JPEG profiles.
2623   */
2624   value=GetImageProperty(image,"comment",exception);
2625   if (value != (char *) NULL)
2626     for (i=0; i < (ssize_t) strlen(value); i+=65533L)
2627       jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
2628         (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
2629   if (image->profiles != (void *) NULL)
2630     WriteProfile(&jpeg_info,image);
2631   /*
2632     Convert MIFF to JPEG raster pixels.
2633   */
2634   memory_info=AcquireVirtualMemory((size_t) image->columns,
2635     jpeg_info.input_components*sizeof(*jpeg_pixels));
2636   if (memory_info == (MemoryInfo *) NULL)
2637     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2638   jpeg_pixels=(JSAMPLE *) GetVirtualMemoryBlob(memory_info);
2639   if (setjmp(error_manager.error_recovery) != 0)
2640     {
2641       jpeg_destroy_compress(&jpeg_info);
2642       if (memory_info != (MemoryInfo *) NULL)
2643         memory_info=RelinquishVirtualMemory(memory_info);
2644       (void) CloseBlob(image);
2645       return(MagickFalse);
2646     }
2647   scanline[0]=(JSAMPROW) jpeg_pixels;
2648   scale=65535U/GetQuantumRange(jpeg_info.data_precision);
2649   if (scale == 0)
2650     scale=1; 
2651   if (jpeg_info.data_precision <= 8)
2652     {
2653       if ((jpeg_info.in_color_space == JCS_RGB) ||
2654           (jpeg_info.in_color_space == JCS_YCbCr))
2655         for (y=0; y < (ssize_t) image->rows; y++)
2656         {
2657           register const Quantum
2658             *p;
2659
2660           register ssize_t
2661             x;
2662
2663           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2664           if (p == (const Quantum *) NULL)
2665             break;
2666           q=jpeg_pixels;
2667           for (x=0; x < (ssize_t) image->columns; x++)
2668           {
2669             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelRed(image,p));
2670             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelGreen(image,p));
2671             *q++=(JSAMPLE) ScaleQuantumToChar(GetPixelBlue(image,p));
2672             p+=GetPixelChannels(image);
2673           }
2674           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2675           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2676             image->rows);
2677           if (status == MagickFalse)
2678             break;
2679         }
2680       else
2681         if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2682           for (y=0; y < (ssize_t) image->rows; y++)
2683           {
2684             register const Quantum
2685               *p;
2686
2687             register ssize_t
2688               x;
2689
2690             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2691             if (p == (const Quantum *) NULL)
2692               break;
2693             q=jpeg_pixels;
2694             for (x=0; x < (ssize_t) image->columns; x++)
2695             {
2696               *q++=(JSAMPLE) ScaleQuantumToChar(ClampToQuantum(GetPixelLuma(
2697                 image,p)));
2698               p+=GetPixelChannels(image);
2699             }
2700             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2701             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2702               image->rows);
2703             if (status == MagickFalse)
2704               break;
2705             }
2706         else
2707           for (y=0; y < (ssize_t) image->rows; y++)
2708           {
2709             register const Quantum
2710               *p;
2711
2712             register ssize_t
2713               x;
2714
2715             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2716             if (p == (const Quantum *) NULL)
2717               break;
2718             q=jpeg_pixels;
2719             for (x=0; x < (ssize_t) image->columns; x++)
2720             {
2721               /*
2722                 Convert DirectClass packets to contiguous CMYK scanlines.
2723               */
2724               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2725                 GetPixelCyan(image,p))));
2726               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2727                 GetPixelMagenta(image,p))));
2728               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2729                 GetPixelYellow(image,p))));
2730               *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
2731                 GetPixelBlack(image,p))));
2732               p+=GetPixelChannels(image);
2733             }
2734             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2735             status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2736               image->rows);
2737             if (status == MagickFalse)
2738               break;
2739           }
2740     }
2741   else
2742     if (jpeg_info.in_color_space == JCS_GRAYSCALE)
2743       for (y=0; y < (ssize_t) image->rows; y++)
2744       {
2745         register const Quantum
2746           *p;
2747
2748         register ssize_t
2749           x;
2750
2751         p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2752         if (p == (const Quantum *) NULL)
2753           break;
2754         q=jpeg_pixels;
2755         for (x=0; x < (ssize_t) image->columns; x++)
2756         {
2757           *q++=(JSAMPLE) (ScaleQuantumToShort(ClampToQuantum(GetPixelLuma(image,
2758             p)))/scale);
2759           p+=GetPixelChannels(image);
2760         }
2761         (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2762         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2763           image->rows);
2764         if (status == MagickFalse)
2765           break;
2766       }
2767     else
2768       if ((jpeg_info.in_color_space == JCS_RGB) ||
2769           (jpeg_info.in_color_space == JCS_YCbCr))
2770         for (y=0; y < (ssize_t) image->rows; y++)
2771         {
2772           register const Quantum
2773             *p;
2774
2775           register ssize_t
2776             x;
2777
2778           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2779           if (p == (const Quantum *) NULL)
2780             break;
2781           q=jpeg_pixels;
2782           for (x=0; x < (ssize_t) image->columns; x++)
2783           {
2784             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelRed(image,p))/scale);
2785             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelGreen(image,p))/scale);
2786             *q++=(JSAMPLE) (ScaleQuantumToShort(GetPixelBlue(image,p))/scale);
2787             p+=GetPixelChannels(image);
2788           }
2789           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2790           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2791             image->rows);
2792           if (status == MagickFalse)
2793             break;
2794         }
2795       else
2796         for (y=0; y < (ssize_t) image->rows; y++)
2797         {
2798           register const Quantum
2799             *p;
2800
2801           register ssize_t
2802             x;
2803
2804           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2805           if (p == (const Quantum *) NULL)
2806             break;
2807           q=jpeg_pixels;
2808           for (x=0; x < (ssize_t) image->columns; x++)
2809           {
2810             /*
2811               Convert DirectClass packets to contiguous CMYK scanlines.
2812             */
2813             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelRed(
2814               image,p))/scale);
2815             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelGreen(
2816               image,p))/scale);
2817             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlue(
2818               image,p))/scale);
2819             *q++=(JSAMPLE) (ScaleQuantumToShort(QuantumRange-GetPixelBlack(
2820               image,p))/scale);
2821             p+=GetPixelChannels(image);
2822           }
2823           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
2824           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2825             image->rows);
2826           if (status == MagickFalse)
2827             break;
2828         }
2829   if (y == (ssize_t) image->rows)
2830     jpeg_finish_compress(&jpeg_info);
2831   /*
2832     Relinquish resources.
2833   */
2834   jpeg_destroy_compress(&jpeg_info);
2835   memory_info=RelinquishVirtualMemory(memory_info);
2836   (void) CloseBlob(image);
2837   return(MagickTrue);
2838 }
2839 #endif