]> granicus.if.org Git - imagemagick/blobdiff - coders/jpeg.c
(no commit message)
[imagemagick] / coders / jpeg.c
index c0b0e635feca5846fd59be25ee23adb9691a2104..6af6d2af9f6f3baeccf099f9c1835c34641fe970 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -50,6 +50,7 @@
 #include "magick/color.h"
 #include "magick/colormap-private.h"
 #include "magick/color-private.h"
+#include "magick/colormap.h"
 #include "magick/colorspace.h"
 #include "magick/constitute.h"
 #include "magick/exception.h"
@@ -61,6 +62,7 @@
 #include "magick/log.h"
 #include "magick/magick.h"
 #include "magick/memory_.h"
+#include "magick/module.h"
 #include "magick/monitor.h"
 #include "magick/monitor-private.h"
 #include "magick/option.h"
 #include "magick/splay-tree.h"
 #include "magick/static.h"
 #include "magick/string_.h"
-#include "magick/module.h"
+#include "magick/string-private.h"
 #include "magick/utility.h"
 #include <setjmp.h>
 #if defined(MAGICKCORE_JPEG_DELEGATE)
 #define JPEG_INTERNAL_OPTIONS
 #if defined(__MINGW32__)
 # define XMD_H 1  /* Avoid conflicting typedef for INT32 */
+typedef unsigned char boolean;
 #endif
 #undef HAVE_STDLIB_H
 #include "jpeglib.h"
@@ -272,6 +275,26 @@ static void InitializeSource(j_decompress_ptr cinfo)
   source->start_of_blob=TRUE;
 }
 
+static MagickBooleanType IsITUFaxImage(const Image *image)
+{
+  const StringInfo
+    *profile;
+
+  const unsigned char
+    *datum;
+
+  profile=GetImageProfile(image,"8bim");
+  if (profile == (const StringInfo *) NULL)
+    return(MagickFalse);
+  if (GetStringInfoLength(profile) < 5)
+    return(MagickFalse);
+  datum=GetStringInfoDatum(profile);
+  if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
+      (datum[3] == 0x41) && (datum[4] == 0x58))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
 static void JPEGErrorHandler(j_common_ptr jpeg_info)
 {
   ErrorManager
@@ -296,7 +319,7 @@ static boolean ReadComment(j_decompress_ptr jpeg_info)
   register char
     *p;
 
-  register long
+  register ssize_t
     i;
 
   size_t
@@ -307,7 +330,7 @@ static boolean ReadComment(j_decompress_ptr jpeg_info)
   */
   error_manager=(ErrorManager *) jpeg_info->client_data;
   image=error_manager->image;
-  length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
+  length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
   length+=GetCharacter(jpeg_info);
   length-=2;
   if (length <= 0)
@@ -322,7 +345,7 @@ static boolean ReadComment(j_decompress_ptr jpeg_info)
   /*
     Read comment.
   */
-  i=(long) length-1;
+  i=(ssize_t) length-1;
   for (p=comment; i-- >= 0; p++)
     *p=(char) GetCharacter(jpeg_info);
   *p='\0';
@@ -345,7 +368,7 @@ static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
   MagickBooleanType
     status;
 
-  register long
+  register ssize_t
     i;
 
   register unsigned char
@@ -361,7 +384,7 @@ static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
   /*
     Read color profile.
   */
-  length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
+  length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
   length+=(size_t) GetCharacter(jpeg_info);
   length-=2;
   if (length <= 14)
@@ -377,7 +400,7 @@ static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
       /*
         Not a ICC profile, return.
       */
-      for (i=0; i < (long) (length-12); i++)
+      for (i=0; i < (ssize_t) (length-12); i++)
         (void) GetCharacter(jpeg_info);
       return(MagickTrue);
     }
@@ -391,7 +414,7 @@ static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   p=GetStringInfoDatum(profile);
-  for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
+  for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
     *p++=(unsigned char) GetCharacter(jpeg_info);
   icc_profile=(StringInfo *) GetImageProfile(image,"icc");
   if (icc_profile != (StringInfo *) NULL)
@@ -409,7 +432,7 @@ static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
     }
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-      "Profile: ICC, %lu bytes",(unsigned long) length);
+      "Profile: ICC, %.20g bytes",(double) length);
   return(MagickTrue);
 }
 
@@ -427,7 +450,7 @@ static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
   MagickBooleanType
     status;
 
-  register long
+  register ssize_t
     i;
 
   register unsigned char
@@ -443,7 +466,7 @@ static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
   /*
     Determine length of binary data stored here.
   */
-  length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
+  length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
   length+=(size_t) GetCharacter(jpeg_info);
   length-=2;
   if (length <= 14)
@@ -466,7 +489,7 @@ static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
       /*
         Not a IPTC profile, return.
       */
-      for (i=0; i < (long) length; i++)
+      for (i=0; i < (ssize_t) length; i++)
         (void) GetCharacter(jpeg_info);
       return(MagickTrue);
     }
@@ -487,7 +510,7 @@ static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   p=GetStringInfoDatum(profile);
-  for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
+  for (i=0;  i < (ssize_t) GetStringInfoLength(profile); i++)
     *p++=(unsigned char) GetCharacter(jpeg_info);
   iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
   if (iptc_profile != (StringInfo *) NULL)
@@ -497,7 +520,10 @@ static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
     }
   else
     {
-      status=SetImageProfile(image,"8bim",profile);
+      if (strcmp((char *) GetStringInfoDatum(profile),"8BIM") != 0)
+        status=SetImageProfile(image,"iptc",profile);
+      else
+        status=SetImageProfile(image,"8BIM",profile);
       profile=DestroyStringInfo(profile);
       if (status == MagickFalse)
         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
@@ -505,7 +531,7 @@ static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
     }
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-      "Profile: iptc, %lu bytes",(unsigned long) length);
+      "Profile: iptc, %.20g bytes",(double) length);
   return(MagickTrue);
 }
 
@@ -526,7 +552,7 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
   MagickBooleanType
     status;
 
-  register long
+  register ssize_t
     i;
 
   register unsigned char
@@ -541,7 +567,7 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
   /*
     Read generic profile.
   */
-  length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
+  length=(size_t) ((size_t) GetCharacter(jpeg_info) << 8);
   length+=(size_t) GetCharacter(jpeg_info);
   if (length <= 2)
     return(MagickTrue);
@@ -555,7 +581,7 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
   p=GetStringInfoDatum(profile);
-  for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
+  for (i=(ssize_t) GetStringInfoLength(profile)-1; i >= 0; i--)
     *p++=(unsigned char) GetCharacter(jpeg_info);
   if (marker == 1)
     {
@@ -564,20 +590,20 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
         (void) CopyMagickString(name,"exif",MaxTextExtent);
       if ((length > 5) && (LocaleNCompare((char *) p,"http:",5) == 0))
         {
-          long
+          ssize_t
             j;
 
           /*
             Extract namespace from XMP profile.
           */
           p=GetStringInfoDatum(profile);
-          for (j=0; j < (long) GetStringInfoLength(profile); j++)
+          for (j=0; j < (ssize_t) GetStringInfoLength(profile); j++)
           {
             if (*p == '\0')
               break;
             p++;
           }
-          if (j < (long) GetStringInfoLength(profile))
+          if (j < (ssize_t) GetStringInfoLength(profile))
             (void) DestroyStringInfo(SplitStringInfo(profile,(size_t) (j+1)));
           (void) CopyMagickString(name,"xmp",MaxTextExtent);
         }
@@ -589,7 +615,7 @@ static boolean ReadProfile(j_decompress_ptr jpeg_info)
       image->filename);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-      "Profile: %s, %lu bytes",name,(unsigned long) length);
+      "Profile: %s, %.20g bytes",name,(double) length);
   return(MagickTrue);
 }
 
@@ -606,8 +632,8 @@ static void SkipInputData(j_decompress_ptr cinfo,long number_bytes)
     number_bytes-=(long) source->manager.bytes_in_buffer;
     (void) FillInputBuffer(cinfo);
   }
-  source->manager.next_input_byte+=(size_t) number_bytes;
-  source->manager.bytes_in_buffer-=(size_t) number_bytes;
+  source->manager.next_input_byte+=number_bytes;
+  source->manager.bytes_in_buffer-=number_bytes;
 }
 
 static void TerminateSource(j_decompress_ptr cinfo)
@@ -650,12 +676,12 @@ static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
   else
 #endif
   {
-    long
+    ssize_t
       j,
       qvalue,
       sum;
 
-    register long
+    register ssize_t
       i;
 
     /*
@@ -671,7 +697,7 @@ static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
      if ((jpeg_info->quant_tbl_ptrs[0] != NULL) &&
          (jpeg_info->quant_tbl_ptrs[1] != NULL))
        {
-         long
+         ssize_t
            hash[101] =
            {
              1020, 1015,  932,  848,  780,  735,  702,  679,  660,  645,
@@ -702,7 +728,7 @@ static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
                128,     0
            };
 
-         qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
+         qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
            jpeg_info->quant_tbl_ptrs[0]->quantval[53]+
            jpeg_info->quant_tbl_ptrs[1]->quantval[0]+
            jpeg_info->quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
@@ -710,24 +736,19 @@ static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
          {
            if ((qvalue < hash[i]) && (sum < sums[i]))
              continue;
-           if ((qvalue <= hash[i]) && (sum <= sums[i]))
-             image->quality=(unsigned long) i+1;
+           if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
+             image->quality=(size_t) i+1;
            if (image->debug != MagickFalse)
-             {
-               if (image->quality != UndefinedCompressionQuality)
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                   "Quality: %ld",image->quality);
-               else
-                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                   "Quality: %ld (approximate)",i+1);
-             }
+             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+               "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
+               (sum <= sums[i]) ? "exact" : "approximate");
            break;
          }
        }
      else
        if (jpeg_info->quant_tbl_ptrs[0] != NULL)
          {
-           long
+           ssize_t
              hash[101] =
              {
                510,  505,  422,  380,  355,  338,  326,  318,  311,  305,
@@ -758,22 +779,18 @@ static void JPEGSetImageQuality(struct jpeg_decompress_struct *jpeg_info,
                   64,     0
              };
 
-           qvalue=(long) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
+           qvalue=(ssize_t) (jpeg_info->quant_tbl_ptrs[0]->quantval[2]+
              jpeg_info->quant_tbl_ptrs[0]->quantval[53]);
            for (i=0; i < 100; i++)
            {
              if ((qvalue < hash[i]) && (sum < sums[i]))
                continue;
-             image->quality=(unsigned long) i+1;
+             if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
+               image->quality=(size_t) i+1;
              if (image->debug != MagickFalse)
-               {
-                 if ((qvalue > hash[i]) || (sum > sums[i]))
-                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                     "Quality: %ld (approximate)",i+1);
-                 else
-                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                     "Quality: %ld",i+1);
-               }
+               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                 "Quality: %.20g (%s)",(double) i+1,(qvalue <= hash[i]) &&
+                 (sum <= sums[i]) ? "exact" : "approximate");
              break;
            }
          }
@@ -799,7 +816,7 @@ static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info,
         jpeg_info->comp_info[2].v_samp_factor,
         jpeg_info->comp_info[3].h_samp_factor,
         jpeg_info->comp_info[3].v_samp_factor);
-        break;
+      break;
     }
     case JCS_GRAYSCALE:
     {
@@ -839,8 +856,8 @@ static void JPEGSetImageSamplingFactor(struct jpeg_decompress_struct *jpeg_info,
     }
   }
   (void) SetImageProperty(image,"jpeg:sampling-factor",sampling_factor);
-  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-    "Sampling Factors: %s",sampling_factor);
+  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Sampling Factors: %s",
+    sampling_factor);
 }
 
 static Image *ReadJPEGImage(const ImageInfo *image_info,
@@ -855,13 +872,13 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   ErrorManager
     error_manager;
 
-  IndexPacket
-    jindex;
-
   Image
     *image;
 
-  long
+  IndexPacket
+    index;
+
+  ssize_t
     y;
 
   JSAMPLE
@@ -877,7 +894,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   MagickSizeType
     number_pixels;
 
-  register long
+  register ssize_t
     i;
 
   struct jpeg_decompress_struct
@@ -889,7 +906,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   register JSAMPLE
     *p;
 
-  unsigned long
+  size_t
     precision,
     units;
 
@@ -940,11 +957,19 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   for (i=1; i < 16; i++)
     if ((i != 2) && (i != 13) && (i != 14))
       jpeg_set_marker_processor(&jpeg_info,(int) (JPEG_APP0+i),ReadProfile);
-  i=jpeg_read_header(&jpeg_info,MagickTrue);
+  i=(ssize_t) jpeg_read_header(&jpeg_info,MagickTrue);
   if ((image_info->colorspace == YCbCrColorspace) ||
       (image_info->colorspace == Rec601YCbCrColorspace) ||
       (image_info->colorspace == Rec709YCbCrColorspace))
     jpeg_info.out_color_space=JCS_YCbCr;
+  if (IsITUFaxImage(image) != MagickFalse)
+    {
+      image->colorspace=LabColorspace;
+      jpeg_info.out_color_space=JCS_YCbCr;
+    }
+  else
+    if (jpeg_info.out_color_space == JCS_CMYK)
+      image->colorspace=CMYKColorspace;
   /*
     Set image resolution.
   */
@@ -954,7 +979,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
     {
       image->x_resolution=(double) jpeg_info.X_density;
       image->y_resolution=(double) jpeg_info.Y_density;
-      units=(unsigned long) jpeg_info.density_unit;
+      units=(size_t) jpeg_info.density_unit;
     }
   if (units == 1)
     image->units=PixelsPerInchResolution;
@@ -970,7 +995,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
       GeometryInfo
         geometry_info;
 
-      int
+      MagickStatusType
         flags;
 
       /*
@@ -992,10 +1017,10 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
       jpeg_info.scale_denom=(unsigned int) scale_factor;
       jpeg_calc_output_dimensions(&jpeg_info);
       if (image->debug != MagickFalse)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Scale factor: %ld",
-          (long) scale_factor);
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "Scale factor: %.20g",(double) scale_factor);
     }
-  precision=(unsigned long) jpeg_info.data_precision;
+  precision=(size_t) jpeg_info.data_precision;
 #if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
 #if defined(D_LOSSLESS_SUPPORTED)
   image->interlace=jpeg_info.process == JPROC_PROGRESSIVE ?
@@ -1032,6 +1057,36 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
       if (IsMagickTrue(option) != MagickFalse)
         jpeg_info.do_block_smoothing=MagickTrue;
     }
+  option=GetImageOption(image_info,"jpeg:dct-method");
+  if (option != (const char *) NULL)
+    switch (*option)
+    {
+      case 'D':
+      case 'd':
+      {
+        if (LocaleCompare(option,"default") == 0)
+          jpeg_info.dct_method=JDCT_DEFAULT;
+        break;
+      }
+      case 'F':
+      case 'f':
+      {
+        if (LocaleCompare(option,"fastest") == 0)
+          jpeg_info.dct_method=JDCT_FASTEST;
+        if (LocaleCompare(option,"float") == 0)
+          jpeg_info.dct_method=JDCT_FLOAT;
+        break;
+      }
+      case 'I':
+      case 'i':
+      {
+        if (LocaleCompare(option,"ifast") == 0)
+          jpeg_info.dct_method=JDCT_IFAST;
+        if (LocaleCompare(option,"islow") == 0)
+          jpeg_info.dct_method=JDCT_ISLOW;
+        break;
+      }
+    }
   option=GetImageOption(image_info,"jpeg:fancy-upsampling");
   if (option != (const char *) NULL)
     {
@@ -1042,7 +1097,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   (void) jpeg_start_decompress(&jpeg_info);
   image->columns=jpeg_info.output_width;
   image->rows=jpeg_info.output_height;
-  image->depth=(unsigned long) jpeg_info.data_precision;
+  image->depth=(size_t) jpeg_info.data_precision;
   if (jpeg_info.out_color_space == JCS_YCbCr)
     image->colorspace=YCbCrColorspace;
   if (jpeg_info.out_color_space == JCS_CMYK)
@@ -1053,10 +1108,10 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
   if ((jpeg_info.output_components == 1) &&
       (jpeg_info.quantize_colors == MagickFalse))
     {
-      unsigned long
+      size_t
         colors;
 
-      colors=(unsigned long) GetQuantumRange(image->depth)+1;
+      colors=(size_t) GetQuantumRange(image->depth)+1;
       if (AcquireImageColormap(image,colors) == MagickFalse)
         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
     }
@@ -1075,7 +1130,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
     }
   JPEGSetImageQuality(&jpeg_info,image);
   JPEGSetImageSamplingFactor(&jpeg_info,image);
-  (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
+  (void) FormatMagickString(value,MaxTextExtent,"%.20g",(double)
     jpeg_info.out_color_space);
   (void) SetImageProperty(image,"jpeg:colorspace",value);
   if (image_info->ping != MagickFalse)
@@ -1104,9 +1159,9 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
     }
   if (jpeg_info.quantize_colors != MagickFalse)
     {
-      image->colors=(unsigned long) jpeg_info.actual_number_of_colors;
+      image->colors=(size_t) jpeg_info.actual_number_of_colors;
       if (jpeg_info.out_color_space == JCS_GRAYSCALE)
-        for (i=0; i < (long) image->colors; i++)
+        for (i=0; i < (ssize_t) image->colors; i++)
         {
           image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
           image->colormap[i].green=image->colormap[i].red;
@@ -1114,7 +1169,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
           image->colormap[i].opacity=OpaqueOpacity;
         }
       else
-        for (i=0; i < (long) image->colors; i++)
+        for (i=0; i < (ssize_t) image->colors; i++)
         {
           image->colormap[i].red=ScaleCharToQuantum(jpeg_info.colormap[0][i]);
           image->colormap[i].green=ScaleCharToQuantum(jpeg_info.colormap[1][i]);
@@ -1123,16 +1178,16 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
         }
     }
   scanline[0]=(JSAMPROW) jpeg_pixels;
-  for (y=0; y < (long) image->rows; y++)
+  for (y=0; y < (ssize_t) image->rows; y++)
   {
     register IndexPacket
-      *__restrict indexes;
+      *restrict indexes;
 
-    register long
+    register ssize_t
       x;
 
     register PixelPacket
-      *__restrict q;
+      *restrict q;
 
     if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
       {
@@ -1148,23 +1203,23 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
     if (jpeg_info.data_precision > 8)
       {
         if (jpeg_info.output_components == 1)
-          for (x=0; x < (long) image->columns; x++)
+          for (x=0; x < (ssize_t) image->columns; x++)
           {
-            unsigned long
+            size_t
               pixel;
 
             if (precision != 16)
-              pixel=(unsigned long) GETJSAMPLE(*p);
+              pixel=(size_t) GETJSAMPLE(*p);
             else
-              pixel=(unsigned long) ((GETJSAMPLE(*p) ^ 0x80) << 4);
-            jindex=ConstrainColormapIndex(image,pixel);
-            indexes[x]=jindex;
-            *q++=image->colormap[(int) jindex];
+              pixel=(size_t) ((GETJSAMPLE(*p) ^ 0x80) << 4);
+            index=ConstrainColormapIndex(image,pixel);
+            indexes[x]=index;
+            *q++=image->colormap[(int) index];
             p++;
           }
         else
           if (image->colorspace != CMYKColorspace)
-            for (x=0; x < (long) image->columns; x++)
+            for (x=0; x < (ssize_t) image->columns; x++)
             {
               q->red=ScaleShortToQuantum((unsigned char)
                 (GETJSAMPLE(*p++) << 4));
@@ -1172,11 +1227,11 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
                 (GETJSAMPLE(*p++) << 4));
               q->blue=ScaleShortToQuantum((unsigned char)
                 (GETJSAMPLE(*p++) << 4));
-              q->opacity=OpaqueOpacity;
+              SetOpacityPixelComponent(q,OpaqueOpacity);
               q++;
             }
           else
-            for (x=0; x < (long) image->columns; x++)
+            for (x=0; x < (ssize_t) image->columns; x++)
             {
               q->red=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
                 (GETJSAMPLE(*p++) << 4));
@@ -1184,7 +1239,7 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
                 (unsigned char) (GETJSAMPLE(*p++) << 4));
               q->blue=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
                 (GETJSAMPLE(*p++) << 4));
-              q->opacity=OpaqueOpacity;
+              SetOpacityPixelComponent(q,OpaqueOpacity);
               indexes[x]=(IndexPacket) QuantumRange-ScaleShortToQuantum(
                 (unsigned char) (GETJSAMPLE(*p++) << 4));
               q++;
@@ -1192,25 +1247,25 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
       }
     else
       if (jpeg_info.output_components == 1)
-        for (x=0; x < (long) image->columns; x++)
+        for (x=0; x < (ssize_t) image->columns; x++)
         {
-          jindex=ConstrainColormapIndex(image,(unsigned long) GETJSAMPLE(*p));
-          indexes[x]=(IndexPacket) jindex;
-          *q++=image->colormap[(int) jindex];
+          index=ConstrainColormapIndex(image,(size_t) GETJSAMPLE(*p));
+          indexes[x]=(IndexPacket) index;
+          *q++=image->colormap[(int) index];
           p++;
         }
       else
         if (image->colorspace != CMYKColorspace)
-          for (x=0; x < (long) image->columns; x++)
+          for (x=0; x < (ssize_t) image->columns; x++)
           {
             q->red=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
             q->green=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
             q->blue=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
-            q->opacity=OpaqueOpacity;
+            SetOpacityPixelComponent(q,OpaqueOpacity);
             q++;
           }
         else
-          for (x=0; x < (long) image->columns; x++)
+          for (x=0; x < (ssize_t) image->columns; x++)
           {
             q->red=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
               GETJSAMPLE(*p++));
@@ -1218,14 +1273,14 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
               GETJSAMPLE(*p++));
             q->blue=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
               GETJSAMPLE(*p++));
-            q->opacity=OpaqueOpacity;
+            SetOpacityPixelComponent(q,OpaqueOpacity);
             indexes[x]=(IndexPacket) QuantumRange-ScaleCharToQuantum(
               (unsigned char) GETJSAMPLE(*p++));
             q++;
           }
     if (SyncAuthenticPixels(image,exception) == MagickFalse)
       break;
-    if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
+    if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
       break;
   }
   /*
@@ -1259,10 +1314,10 @@ static Image *ReadJPEGImage(const ImageInfo *image_info,
 %
 %  The format of the RegisterJPEGImage method is:
 %
-%      unsigned long RegisterJPEGImage(void)
+%      size_t RegisterJPEGImage(void)
 %
 */
-ModuleExport unsigned long RegisterJPEGImage(void)
+ModuleExport size_t RegisterJPEGImage(void)
 {
   char
     version[MaxTextExtent];
@@ -1435,7 +1490,7 @@ static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
   MagickBooleanType
     iptc;
 
-  register long
+  register ssize_t
     i;
 
   size_t
@@ -1444,7 +1499,7 @@ static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
   StringInfo
     *custom_profile;
 
-  unsigned long
+  size_t
     tag_length;
 
   /*
@@ -1455,9 +1510,13 @@ 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 < (long) GetStringInfoLength(profile); i+=65533L)
+      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,
@@ -1471,10 +1530,9 @@ static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
         tag_length=14;
         p=GetStringInfoDatum(custom_profile);
         (void) CopyMagickMemory(p,ICC_PROFILE,tag_length);
-        for (i=0; i < (long) GetStringInfoLength(profile); i+=65519L)
+        for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65519L)
         {
           length=MagickMin(GetStringInfoLength(profile)-i,65519L);
-          p=GetStringInfoDatum(custom_profile);
           p[12]=(unsigned char) ((i/65519L)+1);
           p[13]=(unsigned char) (GetStringInfoLength(profile)/65519L+1);
           (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
@@ -1486,33 +1544,28 @@ 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;
-
-        unsigned long
+        size_t
           roundup;
 
         iptc=MagickTrue;
-        p=GetStringInfoDatum(custom_profile);
-        if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
-          {
-            (void) CopyMagickMemory(p,"Photoshop 3.0\0",14);
-            tag_length=14;
-          }
-        else
-          {
-            (void) CopyMagickMemory(p,"Photoshop 3.0\08BIM\04\04\0\0\0\0",24);
-            p[13]=0x00;
-            p[24]=(unsigned char) (GetStringInfoLength(profile) >> 8);
-            p[25]=(unsigned char) (GetStringInfoLength(profile) & 0xff);
-            tag_length=26;
-          }
-        for (i=0; i < (long) GetStringInfoLength(profile); i+=65500L)
+        for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=65500L)
         {
           length=MagickMin(GetStringInfoLength(profile)-i,65500L);
-          roundup=(unsigned long) (length & 0x01);
-          (void) CopyMagickMemory(p+tag_length,GetStringInfoDatum(profile)+i,
-            length);
+          roundup=(size_t) (length & 0x01);
+          if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
+            {
+              (void) memcpy(p,"Photoshop 3.0 ",14);
+              tag_length=14;
+            }
+          else
+            {
+              (void) CopyMagickMemory(p,"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
+              tag_length=26;
+              p[24]=(unsigned char) (length >> 8);
+              p[25]=(unsigned char) (length & 0xff);
+            }
+          p[13]=0x00;
+          (void) memcpy(p+tag_length,GetStringInfoDatum(profile)+i,length);
           if (roundup != 0)
             p[length+tag_length]='\0';
           jpeg_write_marker(jpeg_info,IPTC_MARKER,GetStringInfoDatum(
@@ -1530,7 +1583,7 @@ static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
         xmp_profile=StringToStringInfo("http://ns.adobe.com/xap/1.0/");
         ConcatenateStringInfo(xmp_profile,profile);
         GetStringInfoDatum(xmp_profile)[28]='\0';
-        for (i=0; i < (long) GetStringInfoLength(xmp_profile); i+=65533L)
+        for (i=0; i < (ssize_t) GetStringInfoLength(xmp_profile); i+=65533L)
         {
           length=MagickMin(GetStringInfoLength(xmp_profile)-i,65533L);
           jpeg_write_marker(jpeg_info,XML_MARKER,
@@ -1538,8 +1591,8 @@ static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
         }
         xmp_profile=DestroyStringInfo(xmp_profile);
       }
-    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s profile: %lu bytes",
-      name,(unsigned long) GetStringInfoLength(profile));
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+      "%s profile: %.20g bytes",name,(double) GetStringInfoLength(profile));
     name=GetNextImageProfile(image);
   }
   custom_profile=DestroyStringInfo(custom_profile);
@@ -1570,10 +1623,10 @@ static char **SamplingFactorToList(const char *text)
   register const char
     *p;
 
-  register long
+  register ssize_t
     i;
 
-  unsigned long
+  size_t
     lines;
 
   if (text == (char *) NULL)
@@ -1590,7 +1643,7 @@ static char **SamplingFactorToList(const char *text)
   if (textlist == (char **) NULL)
     ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
   p=text;
-  for (i=0; i < (long) lines; i++)
+  for (i=0; i < (ssize_t) lines; i++)
   {
     for (q=(char *) p; *q != '\0'; q++)
       if (*q == ',')
@@ -1625,7 +1678,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
   JSAMPROW
     scanline[1];
 
-  long
+  ssize_t
     y;
 
   MagickBooleanType
@@ -1634,7 +1687,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
   register JSAMPLE
     *q;
 
-  register long
+  register ssize_t
     i;
 
   struct jpeg_compress_struct
@@ -1707,7 +1760,11 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
       break;
     }
     default:
+    {
+      if (image->colorspace != RGBColorspace)
+        (void) TransformImageColorspace(image,RGBColorspace);
       break;
+    }
   }
   if ((image_info->type != TrueColorType) &&
       (IsGrayImage(image,&image->exception) != MagickFalse))
@@ -1724,16 +1781,16 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
   jpeg_info.density_unit=(UINT8) 1;
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-      "Image resolution: %ld,%ld",(long) (image->x_resolution+0.5),
-      (long) (image->y_resolution+0.5));
+      "Image resolution: %.20g,%.20g",floor(image->x_resolution+0.5),
+      floor(image->y_resolution+0.5));
   if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
     {
       /*
         Set image resolution.
       */
       jpeg_info.write_JFIF_header=MagickTrue;
-      jpeg_info.X_density=(UINT16) image->x_resolution;
-      jpeg_info.Y_density=(UINT16) image->y_resolution;
+      jpeg_info.X_density=(UINT16) floor(image->x_resolution+0.5);
+      jpeg_info.Y_density=(UINT16) floor(image->y_resolution+0.5);
       if (image->units == PixelsPerInchResolution)
         jpeg_info.density_unit=(UINT8) 1;
       if (image->units == PixelsPerCentimeterResolution)
@@ -1812,6 +1869,49 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "Interlace: nonprogressive");
 #endif
+  option=GetImageOption(image_info,"jpeg:extent");
+  if (option != (const char *) NULL)
+    {
+      Image
+        *jpeg_image;
+
+      ImageInfo
+        *jpeg_info;
+
+      jpeg_info=CloneImageInfo(image_info);
+      jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
+      if (jpeg_image != (Image *) NULL)
+        {
+          MagickSizeType
+            extent;
+
+          size_t
+            maximum,
+            minimum;
+
+          /*
+            Search for compression quality that does not exceed image extent.
+          */
+          jpeg_info->quality=0;
+          extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
+          (void) DeleteImageOption(jpeg_info,"jpeg:extent");
+          (void) AcquireUniqueFilename(jpeg_image->filename);
+          maximum=101;
+          for (minimum=0; minimum != maximum; )
+          {
+            jpeg_image->quality=minimum+(maximum-minimum)/2;
+            status=WriteJPEGImage(jpeg_info,jpeg_image);
+            if (GetBlobSize(jpeg_image) <= extent)
+              minimum=jpeg_image->quality+1;
+            else
+              maximum=jpeg_image->quality-1;
+          }
+          (void) RelinquishUniqueFileResource(jpeg_image->filename);
+          image->quality=minimum-1;
+          jpeg_image=DestroyImage(jpeg_image);
+        }
+      jpeg_info=DestroyImageInfo(jpeg_info);
+    }
   if ((image_info->compression != LosslessJPEGCompression) &&
       (image->quality <= 100))
     {
@@ -1820,8 +1920,8 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
       else
         jpeg_set_quality(&jpeg_info,(int) image->quality,MagickTrue);
       if (image->debug != MagickFalse)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %lu",
-          image->quality);
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Quality: %.20g",
+          (double) image->quality);
     }
   else
     {
@@ -1926,11 +2026,11 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
       else
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "Storage class: DirectClass");
-      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %lu",
-        image->depth);
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Depth: %.20g",
+        (double) image->depth);
       if (image->colors != 0)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "Number of colors: %lu",image->colors);
+          "Number of colors: %.20g",(double) image->colors);
       else
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "Number of colors: unspecified");
@@ -2039,7 +2139,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
   */
   value=GetImageProperty(image,"comment");
   if (value != (char *) NULL)
-    for (i=0; i < (long) strlen(value); i+=65533L)
+    for (i=0; i < (ssize_t) strlen(value); i+=65533L)
       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)
@@ -2060,60 +2160,58 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
       return(MagickFalse);
     }
   scanline[0]=(JSAMPROW) jpeg_pixels;
-  if (jpeg_info.data_precision > 8)
+  if (jpeg_info.data_precision <= 8)
     {
-      if (jpeg_info.in_color_space == JCS_GRAYSCALE)
-        for (y=0; y < (long) image->rows; y++)
+      if ((jpeg_info.in_color_space == JCS_RGB) ||
+          (jpeg_info.in_color_space == JCS_YCbCr))
+        for (y=0; y < (ssize_t) image->rows; y++)
         {
           register const PixelPacket
             *p;
 
-          register long
+          register ssize_t
             x;
 
           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
           if (p == (const PixelPacket *) NULL)
             break;
           q=jpeg_pixels;
-          for (x=0; x < (long) image->columns; x++)
+          for (x=0; x < (ssize_t) image->columns; x++)
           {
-            *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
-              4);
+            *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
+            *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
+            *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
             p++;
           }
           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
-          if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
+          if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
             break;
         }
       else
-        if ((jpeg_info.in_color_space == JCS_RGB) ||
-            (jpeg_info.in_color_space == JCS_YCbCr))
-          for (y=0; y < (long) image->rows; y++)
+        if (jpeg_info.in_color_space == JCS_GRAYSCALE)
+          for (y=0; y < (ssize_t) image->rows; y++)
           {
             register const PixelPacket
               *p;
 
-            register long
+            register ssize_t
               x;
 
             p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
             if (p == (const PixelPacket *) NULL)
               break;
             q=jpeg_pixels;
-            for (x=0; x < (long) image->columns; x++)
+            for (x=0; x < (ssize_t) image->columns; x++)
             {
-              *q++=(JSAMPLE) (ScaleQuantumToShort(p->red) >> 4);
-              *q++=(JSAMPLE) (ScaleQuantumToShort(p->green) >> 4);
-              *q++=(JSAMPLE) (ScaleQuantumToShort(p->blue) >> 4);
+              *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
               p++;
             }
             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
-            status=SetImageProgress(image,SaveImageTag,y,image->rows);
-            if (status == MagickFalse)
+            if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
               break;
           }
         else
-          for (y=0; y < (long) image->rows; y++)
+          for (y=0; y < (ssize_t) image->rows; y++)
           {
             register const IndexPacket
               *indexes;
@@ -2121,7 +2219,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
             register const PixelPacket
               *p;
 
-            register long
+            register ssize_t
               x;
 
             p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
@@ -2129,74 +2227,83 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
               break;
             q=jpeg_pixels;
             indexes=GetVirtualIndexQueue(image);
-            for (x=0; x < (long) image->columns; x++)
+            for (x=0; x < (ssize_t) image->columns; x++)
             {
               /*
                 Convert DirectClass packets to contiguous CMYK scanlines.
               */
-              *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->red) >> 4));
-              *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->green) >> 4));
-              *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->blue) >> 4));
-              *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
+              *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
+                GetRedPixelComponent(p))));
+              *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
+                GetGreenPixelComponent(p))));
+              *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
+                GetBluePixelComponent(p))));
+              *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
+                indexes[x])));
               p++;
             }
             (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
-            status=SetImageProgress(image,SaveImageTag,y,image->rows);
-            if (status == MagickFalse)
+            if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
               break;
           }
     }
   else
     if (jpeg_info.in_color_space == JCS_GRAYSCALE)
-      for (y=0; y < (long) image->rows; y++)
+      for (y=0; y < (ssize_t) image->rows; y++)
       {
         register const PixelPacket
           *p;
 
-        register long
+        register ssize_t
           x;
 
         p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
         if (p == (const PixelPacket *) NULL)
           break;
         q=jpeg_pixels;
-        for (x=0; x < (long) image->columns; x++)
+        for (x=0; x < (ssize_t) image->columns; x++)
         {
-          *q++=(JSAMPLE) ScaleQuantumToChar(PixelIntensityToQuantum(p));
+          *q++=(JSAMPLE) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) >>
+            4);
           p++;
         }
         (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
-        if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
+        if (SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
           break;
       }
     else
       if ((jpeg_info.in_color_space == JCS_RGB) ||
           (jpeg_info.in_color_space == JCS_YCbCr))
-        for (y=0; y < (long) image->rows; y++)
+        for (y=0; y < (ssize_t) image->rows; y++)
         {
           register const PixelPacket
             *p;
 
-          register long
+          register ssize_t
             x;
 
           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
           if (p == (const PixelPacket *) NULL)
             break;
           q=jpeg_pixels;
-          for (x=0; x < (long) image->columns; x++)
+          for (x=0; x < (ssize_t) image->columns; x++)
           {
-            *q++=(JSAMPLE) ScaleQuantumToChar(p->red);
-            *q++=(JSAMPLE) ScaleQuantumToChar(p->green);
-            *q++=(JSAMPLE) ScaleQuantumToChar(p->blue);
+            *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >>
+              4);
+            *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >>
+              4);
+            *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >>
+              4);
             p++;
           }
           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
-          if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
+          status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
+                image->rows);
+          if (status == MagickFalse)
             break;
         }
       else
-        for (y=0; y < (long) image->rows; y++)
+        for (y=0; y < (ssize_t) image->rows; y++)
         {
           register const IndexPacket
             *indexes;
@@ -2204,7 +2311,7 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
           register const PixelPacket
             *p;
 
-          register long
+          register ssize_t
             x;
 
           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
@@ -2212,26 +2319,27 @@ static MagickBooleanType WriteJPEGImage(const ImageInfo *image_info,
             break;
           q=jpeg_pixels;
           indexes=GetVirtualIndexQueue(image);
-          for (x=0; x < (long) image->columns; x++)
+          for (x=0; x < (ssize_t) image->columns; x++)
           {
             /*
               Convert DirectClass packets to contiguous CMYK scanlines.
             */
-            *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
-              p->red)));
-            *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
-              p->green)));
-            *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
-              p->blue)));
-            *q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
-              indexes[x])));
+            *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
+              GetRedPixelComponent(p)) >> 4));
+            *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
+              GetGreenPixelComponent(p)) >> 4));
+            *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(
+              GetBluePixelComponent(p)) >> 4));
+            *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
             p++;
           }
           (void) jpeg_write_scanlines(&jpeg_info,scanline,1);
-          if (SetImageProgress(image,SaveImageTag,y,image->rows) == MagickFalse)
+          status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
+                image->rows);
+          if (status == MagickFalse)
             break;
         }
-  if (y == (long) image->rows)
+  if (y == (ssize_t) image->rows)
     jpeg_finish_compress(&jpeg_info);
   /*
     Relinquish resources.