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