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