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