]> granicus.if.org Git - imagemagick/blobdiff - coders/jpeg.c
Fixed memory leak reported in #456.
[imagemagick] / coders / jpeg.c
index b445ff45221a50ae3a4864568a9423744db3320c..3a82319da2c3038526a6b4df516892df74a2816d 100644 (file)
@@ -23,7 +23,7 @@
 %  You may not use this file except in compliance with the License.  You may  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    http://www.imagemagick.org/script/license.php                            %
+%    https://www.imagemagick.org/script/license.php                           %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
@@ -95,8 +95,7 @@
 #include "jpeglib.h"
 #include "jerror.h"
 #endif
-
-
+\f
 /*
   Define declarations.
 */
 #define IPTC_MARKER  (JPEG_APP0+13)
 #define XML_MARKER  (JPEG_APP0+1)
 #define MaxBufferExtent  16384
-
-
+\f
 /*
   Typedef declarations.
 */
@@ -173,8 +171,7 @@ typedef struct _QuantizationTable
   unsigned int
     *levels;
 } QuantizationTable;
-
-
+\f
 /*
   Forward declarations.
 */
@@ -182,8 +179,7 @@ typedef struct _QuantizationTable
 static MagickBooleanType
   WriteJPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
 #endif
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -217,8 +213,7 @@ static MagickBooleanType IsJPEG(const unsigned char *magick,const size_t length)
     return(MagickTrue);
   return(MagickFalse);
 }
-
-
+\f
 #if defined(MAGICKCORE_JPEG_DELEGATE)
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -364,10 +359,9 @@ static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,int level)
         Process warning message.
       */
       (jpeg_info->err->format_message)(jpeg_info,message);
-      if (jpeg_info->err->num_warnings++ > JPEGExcessiveWarnings)
-        JPEGErrorHandler(jpeg_info);
-      ThrowBinaryException(CorruptImageWarning,(char *) message,
-        image->filename);
+      if (jpeg_info->err->num_warnings++ < JPEGExcessiveWarnings)
+        ThrowBinaryException(CorruptImageWarning,(char *) message,
+          image->filename);
     }
   else
     if ((image->debug != MagickFalse) &&
@@ -536,7 +530,7 @@ static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
 static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
 {
   char
-    magick[MaxTextExtent];
+    magick[MagickPathExtent];
 
   ErrorManager
     *error_manager;
@@ -642,7 +636,7 @@ static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
 static boolean ReadProfile(j_decompress_ptr jpeg_info)
 {
   char
-    name[MaxTextExtent];
+    name[MagickPathExtent];
 
   const StringInfo
     *previous_profile;
@@ -683,7 +677,7 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
     return(TRUE);
   length-=2;
   marker=jpeg_info->unread_marker-JPEG_APP0;
-  (void) FormatLocaleString(name,MaxTextExtent,"APP%d",marker);
+  (void) FormatLocaleString(name,MagickPathExtent,"APP%d",marker);
   error_manager=(ErrorManager *) jpeg_info->client_data;
   exception=error_manager->exception;
   image=error_manager->image;
@@ -703,7 +697,7 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
     {
       p=GetStringInfoDatum(profile);
       if ((length > 4) && (LocaleNCompare((char *) p,"exif",4) == 0))
-        (void) CopyMagickString(name,"exif",MaxTextExtent);
+        (void) CopyMagickString(name,"exif",MagickPathExtent);
       if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
         {
           ssize_t
@@ -721,21 +715,21 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
           }
           if (j < (ssize_t) GetStringInfoLength(profile))
             (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
-          (void) CopyMagickString(name,"xmp",MaxTextExtent);
+          (void) CopyMagickString(name,"xmp",MagickPathExtent);
         }
     }
   previous_profile=GetImageProfile(image,name);
   if (previous_profile != (const StringInfo *) NULL)
     {
       size_t
-        length;
+        profile_length;
 
-      length=GetStringInfoLength(profile);
+      profile_length=GetStringInfoLength(profile);
       SetStringInfoLength(profile,GetStringInfoLength(profile)+
         GetStringInfoLength(previous_profile));
       (void) memmove(GetStringInfoDatum(profile)+
         GetStringInfoLength(previous_profile),GetStringInfoDatum(profile),
-        length);
+        profile_length);
       (void) memcpy(GetStringInfoDatum(profile),
         GetStringInfoDatum(previous_profile),
         GetStringInfoLength(previous_profile));
@@ -798,7 +792,7 @@ static void JPEGSourceManager(j_decompress_ptr cinfo,Image *image)
 }
 
 static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
-  Image *image, ExceptionInfo *exception)
+  Image *image)
 {
   image->quality=UndefinedCompressionQuality;
 #if defined(D_PROGRESSIVE_SUPPORTED)
@@ -935,14 +929,14 @@ static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
 static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info,  Image *image,ExceptionInfo *exception)
 {
   char
-    sampling_factor[MaxTextExtent];
+    sampling_factor[MagickPathExtent];
 
   switch (jpeg_info->out_color_space)
   {
     case JCS_CMYK:
     {
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: CMYK");
-      (void) FormatLocaleString(sampling_factor,MaxTextExtent,
+      (void) FormatLocaleString(sampling_factor,MagickPathExtent,
         "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
         jpeg_info->comp_info[0].v_samp_factor,
         jpeg_info->comp_info[1].h_samp_factor,
@@ -957,7 +951,7 @@ static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info,
     {
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
         "Colorspace: GRAYSCALE");
-      (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
+      (void) FormatLocaleString(sampling_factor,MagickPathExtent,"%dx%d",
         jpeg_info->comp_info[0].h_samp_factor,
         jpeg_info->comp_info[0].v_samp_factor);
       break;
@@ -965,7 +959,7 @@ static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info,
     case JCS_RGB:
     {
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: RGB");
-      (void) FormatLocaleString(sampling_factor,MaxTextExtent,
+      (void) FormatLocaleString(sampling_factor,MagickPathExtent,
         "%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
         jpeg_info->comp_info[0].v_samp_factor,
         jpeg_info->comp_info[1].h_samp_factor,
@@ -978,7 +972,7 @@ static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info,
     {
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colorspace: %d",
         jpeg_info->out_color_space);
-      (void) FormatLocaleString(sampling_factor,MaxTextExtent,
+      (void) FormatLocaleString(sampling_factor,MagickPathExtent,
         "%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info->comp_info[0].h_samp_factor,
         jpeg_info->comp_info[0].v_samp_factor,
         jpeg_info->comp_info[1].h_samp_factor,
@@ -1000,7 +994,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   ExceptionInfo *exception)
 {
   char
-    value[MaxTextExtent];
+    value[MagickPathExtent];
 
   const char
     *option;
@@ -1052,12 +1046,12 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
     Open image file.
   */
   assert(image_info != (const ImageInfo *) NULL);
-  assert(image_info->signature == MagickSignature);
+  assert(image_info->signature == MagickCoreSignature);
   if (image_info->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
       image_info->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   debug=IsEventLogging();
   (void) debug;
   image=AcquireImage(image_info,exception);
@@ -1266,8 +1260,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
     if (AcquireImageColormap(image,StringToUnsignedLong(option),exception)
          == MagickFalse)
       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-  if ((jpeg_info.output_components == 1) &&
-      (jpeg_info.quantize_colors == MagickFalse))
+  if ((jpeg_info.output_components == 1) && (jpeg_info.quantize_colors == 0))
     {
       size_t
         colors;
@@ -1289,9 +1282,9 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %dx%d",
         (int) jpeg_info.output_width,(int) jpeg_info.output_height);
     }
-  JPEGSetImageQuality(&jpeg_info,image,exception);
+  JPEGSetImageQuality(&jpeg_info,image);
   JPEGSetImageSamplingFactor(&jpeg_info,image,exception);
-  (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+  (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
     jpeg_info.out_color_space);
   (void) SetImageProperty(image,"jpeg:colorspace",value,exception);
   if (image_info->ping != MagickFalse)
@@ -1302,7 +1295,16 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
     }
   status=SetImageExtent(image,image->columns,image->rows,exception);
   if (status == MagickFalse)
-    return(DestroyImageList(image));
+    {
+      jpeg_destroy_decompress(&jpeg_info);
+      return(DestroyImageList(image));
+    }
+  if ((jpeg_info.output_components != 1) &&
+      (jpeg_info.output_components != 3) && (jpeg_info.output_components != 4))
+    {
+      jpeg_destroy_decompress(&jpeg_info);
+      ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
+    }
   memory_info=AcquireVirtualMemory((size_t) image->columns,
     jpeg_info.output_components*sizeof(*jpeg_pixels));
   if (memory_info == (MemoryInfo *) NULL)
@@ -1325,7 +1327,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
         return(GetFirstImageInList(image));
       return(DestroyImage(image));
     }
-  if (jpeg_info.quantize_colors != MagickFalse)
+  if (jpeg_info.quantize_colors != 0)
     {
       image->colors=(size_t) jpeg_info.actual_number_of_colors;
       if (jpeg_info.out_color_space == JCS_GRAYSCALE)
@@ -1335,7 +1337,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
             jpeg_info.colormap[0][i]);
           image->colormap[i].green=image->colormap[i].red;
           image->colormap[i].blue=image->colormap[i].red;
-          image->colormap[i].alpha=OpaqueAlpha;
+          image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
         }
       else
         for (i=0; i < (ssize_t) image->colors; i++)
@@ -1346,7 +1348,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
             jpeg_info.colormap[1][i]);
           image->colormap[i].blue=(double) ScaleCharToQuantum(
             jpeg_info.colormap[2][i]);
-          image->colormap[i].alpha=OpaqueAlpha;
+          image->colormap[i].alpha=(MagickRealType) OpaqueAlpha;
         }
     }
   scanline[0]=(JSAMPROW) jpeg_pixels;
@@ -1356,7 +1358,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
       x;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
       {
@@ -1373,17 +1375,18 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
         unsigned short
           scale;
 
-        scale=65535U/GetQuantumRange(jpeg_info.data_precision);
+        scale=65535/(unsigned short) GetQuantumRange((size_t)
+          jpeg_info.data_precision);
         if (jpeg_info.output_components == 1)
           for (x=0; x < (ssize_t) image->columns; x++)
           {
-            size_t
+            ssize_t
               pixel;
 
-            pixel=(size_t) (scale*GETJSAMPLE(*p));
-            index=ConstrainColormapIndex(image,pixel,exception);
+            pixel=(ssize_t) (scale*GETJSAMPLE(*p));
+            index=(Quantum) ConstrainColormapIndex(image,pixel,exception);
             SetPixelIndex(image,index,q);
-            SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
+            SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
             p++;
             q+=GetPixelChannels(image);
           }
@@ -1391,26 +1394,26 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
           if (image->colorspace != CMYKColorspace)
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              SetPixelRed(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
-                q);
-              SetPixelGreen(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
-                q);
-              SetPixelBlue(image,ScaleShortToQuantum(scale*GETJSAMPLE(*p++)),
-                q);
+              SetPixelRed(image,ScaleShortToQuantum(
+                (unsigned short) (scale*GETJSAMPLE(*p++))),q);
+              SetPixelGreen(image,ScaleShortToQuantum(
+                (unsigned short) (scale*GETJSAMPLE(*p++))),q);
+              SetPixelBlue(image,ScaleShortToQuantum(
+                (unsigned short) (scale*GETJSAMPLE(*p++))),q);
               SetPixelAlpha(image,OpaqueAlpha,q);
               q+=GetPixelChannels(image);
             }
           else
             for (x=0; x < (ssize_t) image->columns; x++)
             {
-              SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(scale*
-                GETJSAMPLE(*p++)),q);
-              SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(scale*
-                GETJSAMPLE(*p++)),q);
-              SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(scale*
-                GETJSAMPLE(*p++)),q);
-              SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(scale*
-                GETJSAMPLE(*p++)),q);
+              SetPixelCyan(image,QuantumRange-ScaleShortToQuantum(
+                (unsigned short) (scale*GETJSAMPLE(*p++))),q);
+              SetPixelMagenta(image,QuantumRange-ScaleShortToQuantum(
+                (unsigned short) (scale*GETJSAMPLE(*p++))),q);
+              SetPixelYellow(image,QuantumRange-ScaleShortToQuantum(
+                (unsigned short) (scale*GETJSAMPLE(*p++))),q);
+              SetPixelBlack(image,QuantumRange-ScaleShortToQuantum(
+                (unsigned short) (scale*GETJSAMPLE(*p++))),q);
               SetPixelAlpha(image,OpaqueAlpha,q);
               q+=GetPixelChannels(image);
             }
@@ -1419,9 +1422,10 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
       if (jpeg_info.output_components == 1)
         for (x=0; x < (ssize_t) image->columns; x++)
         {
-          index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p),exception);
+          index=(Quantum) ConstrainColormapIndex(image,(ssize_t) GETJSAMPLE(*p),
+            exception);
           SetPixelIndex(image,index,q);
-          SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
+          SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
           p++;
           q+=GetPixelChannels(image);
         }
@@ -1477,8 +1481,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   return(GetFirstImageInList(image));
 }
 #endif
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -1504,85 +1507,92 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
 */
 ModuleExport size_t RegisterJPEGImage(void)
 {
+#define JPEGDescription "Joint Photographic Experts Group JFIF format"
+
   char
-    version[MaxTextExtent];
+    version[MagickPathExtent];
 
   MagickInfo
     *entry;
 
-  static const char
-    description[] = "Joint Photographic Experts Group JFIF format";
-
   *version='\0';
 #if defined(JPEG_LIB_VERSION)
-  (void) FormatLocaleString(version,MaxTextExtent,"%d",JPEG_LIB_VERSION);
+  (void) FormatLocaleString(version,MagickPathExtent,"%d",JPEG_LIB_VERSION);
 #endif
-  entry=SetMagickInfo("JPE");
-#if JPEG_LIB_VERSION < 80
-  entry->thread_support=NoThreadSupport;
+  entry=AcquireMagickInfo("JPEG","JPE",JPEGDescription);
+#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
+  entry->flags^=CoderDecoderThreadSupportFlag;
 #endif
 #if defined(MAGICKCORE_JPEG_DELEGATE)
   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
 #endif
   entry->magick=(IsImageFormatHandler *) IsJPEG;
-  entry->adjoin=MagickFalse;
-  entry->description=ConstantString(description);
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags^=CoderUseExtensionFlag;
   if (*version != '\0')
     entry->version=ConstantString(version);
   entry->mime_type=ConstantString("image/jpeg");
-  entry->module=ConstantString("JPEG");
   (void) RegisterMagickInfo(entry);
-  entry=SetMagickInfo("JPEG");
-#if JPEG_LIB_VERSION < 80
-  entry->thread_support=NoThreadSupport;
+  entry=AcquireMagickInfo("JPEG","JPEG",JPEGDescription);
+#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
+  entry->flags^=CoderDecoderThreadSupportFlag;
 #endif
 #if defined(MAGICKCORE_JPEG_DELEGATE)
   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
 #endif
   entry->magick=(IsImageFormatHandler *) IsJPEG;
-  entry->adjoin=MagickFalse;
-  entry->description=ConstantString(description);
+  entry->flags^=CoderAdjoinFlag;
   if (*version != '\0')
     entry->version=ConstantString(version);
   entry->mime_type=ConstantString("image/jpeg");
-  entry->module=ConstantString("JPEG");
   (void) RegisterMagickInfo(entry);
-  entry=SetMagickInfo("JPG");
-#if JPEG_LIB_VERSION < 80
-  entry->thread_support=NoThreadSupport;
+  entry=AcquireMagickInfo("JPEG","JPG",JPEGDescription);
+#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
+  entry->flags^=CoderDecoderThreadSupportFlag;
 #endif
 #if defined(MAGICKCORE_JPEG_DELEGATE)
   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
 #endif
-  entry->adjoin=MagickFalse;
-  entry->description=ConstantString(description);
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags^=CoderUseExtensionFlag;
   if (*version != '\0')
     entry->version=ConstantString(version);
   entry->mime_type=ConstantString("image/jpeg");
-  entry->module=ConstantString("JPEG");
   (void) RegisterMagickInfo(entry);
-  entry=SetMagickInfo("PJPEG");
-#if JPEG_LIB_VERSION < 80
-  entry->thread_support=NoThreadSupport;
+  entry=AcquireMagickInfo("JPEG","JPS",JPEGDescription);
+#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
+  entry->flags^=CoderDecoderThreadSupportFlag;
 #endif
 #if defined(MAGICKCORE_JPEG_DELEGATE)
   entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
   entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
 #endif
-  entry->adjoin=MagickFalse;
-  entry->description=ConstantString(description);
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags^=CoderUseExtensionFlag;
+  if (*version != '\0')
+    entry->version=ConstantString(version);
+  entry->mime_type=ConstantString("image/jpeg");
+  (void) RegisterMagickInfo(entry);
+  entry=AcquireMagickInfo("JPEG","PJPEG",JPEGDescription);
+#if (JPEG_LIB_VERSION < 80) && !defined(LIBJPEG_TURBO_VERSION)
+  entry->flags^=CoderDecoderThreadSupportFlag;
+#endif
+#if defined(MAGICKCORE_JPEG_DELEGATE)
+  entry->decoder=(DecodeImageHandler *) ReadJPEGImage;
+  entry->encoder=(EncodeImageHandler *) WriteJPEGImage;
+#endif
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags^=CoderUseExtensionFlag;
   if (*version != '\0')
     entry->version=ConstantString(version);
   entry->mime_type=ConstantString("image/jpeg");
-  entry->module=ConstantString("JPEG");
   (void) RegisterMagickInfo(entry);
   return(MagickImageCoderSignature);
 }
-
-
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -1605,12 +1615,12 @@ ModuleExport size_t RegisterJPEGImage(void)
 ModuleExport void UnregisterJPEGImage(void)
 {
   (void) UnregisterMagickInfo("PJPG");
-  (void) UnregisterMagickInfo("JPEG");
+  (void) UnregisterMagickInfo("JPS");
   (void) UnregisterMagickInfo("JPG");
+  (void) UnregisterMagickInfo("JPEG");
   (void) UnregisterMagickInfo("JPE");
 }
-
-
+\f
 #if defined(MAGICKCORE_JPEG_DELEGATE)
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1733,7 +1743,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (description == (XMLTreeInfo *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlMissingElement", "<description>, slot \"%s\"",slot);
+        "XmlMissingElement","<description>, slot \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       xml=DestroyString(xml);
       return(table);
@@ -1742,7 +1752,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (levels == (XMLTreeInfo *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlMissingElement", "<levels>, slot \"%s\"", slot);
+        "XmlMissingElement","<levels>, slot \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       xml=DestroyString(xml);
       return(table);
@@ -1764,7 +1774,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (attribute == (char *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlMissingAttribute", "<levels width>, slot \"%s\"",slot);
+        "XmlMissingAttribute","<levels width>, slot \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       table=DestroyQuantizationTable(table);
       xml=DestroyString(xml);
@@ -1774,7 +1784,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (table->width == 0)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-       "XmlInvalidAttribute", "<levels width>, table \"%s\"",slot);
+       "XmlInvalidAttribute","<levels width>, table \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       table=DestroyQuantizationTable(table);
       xml=DestroyString(xml);
@@ -1784,7 +1794,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (attribute == (char *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlMissingAttribute", "<levels height>, table \"%s\"",slot);
+        "XmlMissingAttribute","<levels height>, table \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       table=DestroyQuantizationTable(table);
       xml=DestroyString(xml);
@@ -1794,7 +1804,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (table->height == 0)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlInvalidAttribute", "<levels height>, table \"%s\"",slot);
+        "XmlInvalidAttribute","<levels height>, table \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       table=DestroyQuantizationTable(table);
       xml=DestroyString(xml);
@@ -1804,7 +1814,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (attribute == (char *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlMissingAttribute", "<levels divisor>, table \"%s\"",slot);
+        "XmlMissingAttribute","<levels divisor>, table \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       table=DestroyQuantizationTable(table);
       xml=DestroyString(xml);
@@ -1814,7 +1824,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (table->divisor == 0.0)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlInvalidAttribute", "<levels divisor>, table \"%s\"",slot);
+        "XmlInvalidAttribute","<levels divisor>, table \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       table=DestroyQuantizationTable(table);
       xml=DestroyString(xml);
@@ -1824,7 +1834,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (content == (char *) NULL)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlMissingContent", "<levels>, table \"%s\"",slot);
+        "XmlMissingContent","<levels>, table \"%s\"",slot);
       quantization_tables=DestroyXMLTree(quantization_tables);
       table=DestroyQuantizationTable(table);
       xml=DestroyString(xml);
@@ -1853,7 +1863,7 @@ static QuantizationTable *GetQuantizationTable(const char *filename,
   if (p != content)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
-        "XmlInvalidContent", "<level> too many values, table \"%s\"",slot);
+        "XmlInvalidContent","<level> too many values, table \"%s\"",slot);
      quantization_tables=DestroyXMLTree(quantization_tables);
      table=DestroyQuantizationTable(table);
      xml=DestroyString(xml);
@@ -1878,13 +1888,6 @@ static void InitializeDestination(j_compress_ptr cinfo)
   destination->manager.free_in_buffer=MaxBufferExtent;
 }
 
-static inline size_t MagickMin(const size_t x,const size_t y)
-{
-  if (x < y)
-    return(x);
-  return(y);
-}
-
 static void TerminateDestination(j_compress_ptr cinfo)
 {
   DestinationManager
@@ -1904,7 +1907,8 @@ static void TerminateDestination(j_compress_ptr cinfo)
     }
 }
 
-static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
+static void WriteProfile(j_compress_ptr jpeg_info,Image *image,
+  ExceptionInfo *exception)
 {
   const char
     *name;
@@ -1933,16 +1937,18 @@ static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
   ResetImageProfileIterator(image);
   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
   {
-    register unsigned char
-      *p;
-
     profile=GetImageProfile(image,name);
-    p=GetStringInfoDatum(custom_profile);
     if (LocaleCompare(name,"EXIF") == 0)
-      for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65533L)
       {
-        length=MagickMin(GetStringInfoLength(profile)-i,65533L);
-        jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile)+i,
+        length=GetStringInfoLength(profile);
+        if (length > 65533L)
+          {
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              CoderWarning,"ExifProfileSizeExceedsLimit","`%s'",
+              image->filename);
+            length=65533L;
+          }
+        jpeg_write_marker(jpeg_info,XML_MARKER,GetStringInfoDatum(profile),
           (unsigned int) length);
       }
     if (LocaleCompare(name,"ICC") == 0)
@@ -1968,10 +1974,14 @@ static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
     if (((LocaleCompare(name,"IPTC") == 0) ||
         (LocaleCompare(name,"8BIM") == 0)) && (iptc == MagickFalse))
       {
+        register unsigned char
+          *p;
+
         size_t
           roundup;
 
         iptc=MagickTrue;
+        p=GetStringInfoDatum(custom_profile);
         for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
         {
           length=MagickMin(GetStringInfoLength(profile)-i,65500L);
@@ -2054,38 +2064,34 @@ static char **SamplingFactorToList(const char *text)
   register ssize_t
     i;
 
-  size_t
-    lines;
-
   if (text == (char *) NULL)
     return((char **) NULL);
   /*
     Convert string to an ASCII list.
   */
-  lines=1;
-  for (p=text; *p != '\0'; p++)
-    if (*p == ',')
-      lines++;
-  textlist=(char **) AcquireQuantumMemory((size_t) lines+MaxTextExtent,
+  textlist=(char **) AcquireQuantumMemory((size_t) MAX_COMPONENTS,
     sizeof(*textlist));
   if (textlist == (char **) NULL)
     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
   p=text;
-  for (i=0; i < (ssize_t) lines; i++)
+  for (i=0; i < (ssize_t) MAX_COMPONENTS; i++)
   {
     for (q=(char *) p; *q != '\0'; q++)
       if (*q == ',')
         break;
-    textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
+    textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MagickPathExtent,
       sizeof(*textlist[i]));
     if (textlist[i] == (char *) NULL)
       ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
     (void) CopyMagickString(textlist[i],p,(size_t) (q-p+1));
     if (*q == '\r')
       q++;
+    if (*q == '\0')
+      break;
     p=q+1;
   }
-  textlist[i]=(char *) NULL;
+  for (i++; i < (ssize_t) MAX_COMPONENTS; i++)
+    textlist[i]=ConstantString("1x1");
   return(textlist);
 }
 
@@ -2100,6 +2106,9 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
   ErrorManager
     error_manager;
 
+  Image
+    *volatile volatile_image;
+
   int
     colorspace,
     quality;
@@ -2138,13 +2147,16 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
     Open image file.
   */
   assert(image_info != (const ImageInfo *) NULL);
-  assert(image_info->signature == MagickSignature);
+  assert(image_info->signature == MagickCoreSignature);
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
+  if ((LocaleCompare(image_info->magick,"JPS") == 0) &&
+      (image->next != (Image *) NULL))
+    image=AppendImages(image,MagickFalse,exception);
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   if (status == MagickFalse)
     return(status);
@@ -2154,17 +2166,18 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
   (void) ResetMagickMemory(&error_manager,0,sizeof(error_manager));
   (void) ResetMagickMemory(&jpeg_info,0,sizeof(jpeg_info));
   (void) ResetMagickMemory(&jpeg_error,0,sizeof(jpeg_error));
-  jpeg_info.client_data=(void *) image;
+  volatile_image=image;
+  jpeg_info.client_data=(void *) volatile_image;
   jpeg_info.err=jpeg_std_error(&jpeg_error);
   jpeg_info.err->emit_message=(void (*)(j_common_ptr,int)) JPEGWarningHandler;
   jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
   error_manager.exception=exception;
-  error_manager.image=image;
+  error_manager.image=volatile_image;
   memory_info=(MemoryInfo *) NULL;
   if (setjmp(error_manager.error_recovery) != 0)
     {
       jpeg_destroy_compress(&jpeg_info);
-      (void) CloseBlob(image);
+      (void) CloseBlob(volatile_image);
       return(MagickFalse);
     }
   jpeg_info.client_data=(void *) &error_manager;
@@ -2206,7 +2219,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
       (void) TransformImageColorspace(image,sRGBColorspace,exception);
       if (image_info->type == TrueColorType)
         break;
-      if (IsImageGray(image,exception) != MagickFalse)
+      if (SetImageGray(image,exception) != MagickFalse)
         {
           jpeg_info.input_components=1;
           jpeg_info.in_color_space=JCS_GRAYSCALE;
@@ -2221,23 +2234,20 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
     jpeg_info.data_precision=8;
   else
     jpeg_info.data_precision=BITS_IN_JSAMPLE;
-  jpeg_info.density_unit=1;
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-      "Image resolution: %.20g,%.20g",floor(image->resolution.x+0.5),
-      floor(image->resolution.y+0.5));
+      "Image resolution: %.20g,%.20g",image->resolution.x,image->resolution.y);
   if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
     {
       /*
         Set image resolution.
       */
       jpeg_info.write_JFIF_header=TRUE;
-      jpeg_info.X_density=(UINT16) floor(image->resolution.x+0.5);
-      jpeg_info.Y_density=(UINT16) floor(image->resolution.y+0.5);
+      jpeg_info.X_density=(UINT16) image->resolution.x;
+      jpeg_info.Y_density=(UINT16) image->resolution.y;
       /*
         Set image resolution units.
       */
-      jpeg_info.density_unit=(UINT8) 0;
       if (image->units == PixelsPerInchResolution)
         jpeg_info.density_unit=(UINT8) 1;
       if (image->units == PixelsPerCentimeterResolution)
@@ -2332,7 +2342,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
 #else
       if (image->quality < 100)
         (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
-          "LosslessToLossyJPEGConversion",image->filename);
+          "LosslessToLossyJPEGConversion","`%s'",image->filename);
       else
         {
           int
@@ -2361,10 +2371,10 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
         *jpeg_image;
 
       ImageInfo
-        *jpeg_info;
+        *extent_info;
 
-      jpeg_info=CloneImageInfo(image_info);
-      jpeg_info->blob=NULL;
+      extent_info=CloneImageInfo(image_info);
+      extent_info->blob=NULL;
       jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
       if (jpeg_image != (Image *) NULL)
         {
@@ -2378,26 +2388,28 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
           /*
             Search for compression quality that does not exceed image extent.
           */
-          jpeg_info->quality=0;
+          extent_info->quality=0;
           extent=(MagickSizeType) SiPrefixToDoubleInterval(option,100.0);
-          (void) DeleteImageOption(jpeg_info,"jpeg:extent");
+          (void) DeleteImageOption(extent_info,"jpeg:extent");
           (void) DeleteImageArtifact(jpeg_image,"jpeg:extent");
-          maximum=101;
+          maximum=image_info->quality;
+          if (maximum < 2)
+            maximum=101;
           for (minimum=2; minimum < maximum; )
           {
             (void) AcquireUniqueFilename(jpeg_image->filename);
             jpeg_image->quality=minimum+(maximum-minimum+1)/2;
-            status=WriteJPEGImage(jpeg_info,jpeg_image,exception);
+            status=WriteJPEGImage(extent_info,jpeg_image,exception);
             if (GetBlobSize(jpeg_image) <= extent)
               minimum=jpeg_image->quality+1;
             else
               maximum=jpeg_image->quality-1;
             (void) RelinquishUniqueFileResource(jpeg_image->filename);
           }
-          quality=minimum-1;
+          quality=(int) minimum-1;
           jpeg_image=DestroyImage(jpeg_image);
         }
-      jpeg_info=DestroyImageInfo(jpeg_info);
+      extent_info=DestroyImageInfo(extent_info);
     }
   jpeg_set_quality(&jpeg_info,quality,TRUE);
 #if (JPEG_LIB_VERSION >= 70)
@@ -2449,7 +2461,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
     sampling_factor=image_info->sampling_factor;
   if (sampling_factor == (const char *) NULL)
     {
-      if (image->quality >= 90)
+      if (quality >= 90)
         for (i=0; i < MAX_COMPONENTS; i++)
         {
           jpeg_info.comp_info[i].h_samp_factor=1;
@@ -2664,7 +2676,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
       jpeg_write_marker(&jpeg_info,JPEG_COM,(unsigned char *) value+i,
         (unsigned int) MagickMin((size_t) strlen(value+i),65533L));
   if (image->profiles != (void *) NULL)
-    WriteProfile(&jpeg_info,image);
+    WriteProfile(&jpeg_info,image,exception);
   /*
     Convert MIFF to JPEG raster pixels.
   */
@@ -2682,9 +2694,10 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
       return(MagickFalse);
     }
   scanline[0]=(JSAMPROW) jpeg_pixels;
-  scale=65535U/GetQuantumRange(jpeg_info.data_precision);
+  scale=65535/(unsigned short) GetQuantumRange((size_t)
+    jpeg_info.data_precision);
   if (scale == 0)
-    scale=1; 
+    scale=1;
   if (jpeg_info.data_precision <= 8)
     {
       if ((jpeg_info.in_color_space == JCS_RGB) ||