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