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