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