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