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