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