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