]> granicus.if.org Git - imagemagick/blobdiff - coders/bmp.c
...
[imagemagick] / coders / bmp.c
index 7bfd065b80a5c4bcfacdcedcc23d6217dd2ce169..ab5818379d1497d8a4a389aa338b9e7ed026b2b9 100644 (file)
 %                               December 2001                                 %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2018 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  %
 %  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,          %
@@ -75,7 +75,7 @@
 #define BI_JPEG  4
 #undef BI_PNG
 #define BI_PNG  5
-#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
 #undef BI_RGB
 #define BI_RGB  0
 #undef BI_RLE8
 #define LCS_GM_ABS_COLORIMETRIC  8  /* Absolute */
 #endif
 \f
+/*
+  Enumerated declaractions.
+*/
+typedef enum
+{
+  UndefinedSubtype,
+  RGB555,
+  RGB565,
+  ARGB4444,
+  ARGB1555
+} BMPSubtype;
+
 /*
   Typedef declarations.
 */
@@ -137,7 +149,7 @@ typedef struct _BMPInfo
     alpha_mask,
     colors_important;
 
-  int
+  long
     colorspace;
 
   PrimaryInfo
@@ -169,8 +181,8 @@ static MagickBooleanType
 %
 %  The format of the DecodeImage method is:
 %
-%      MagickBooleanType DecodeImage(Image *image,
-%        const size_t compression,unsigned char *pixels)
+%      MagickBooleanType DecodeImage(Image *image,const size_t compression,
+%        unsigned char *pixels,const size_t number_pixels)
 %
 %  A description of each parameter follows:
 %
@@ -184,33 +196,14 @@ static MagickBooleanType
 %    o pixels:  The address of a byte (8 bits) array of pixel data created by
 %      the decoding process.
 %
+%    o number_pixels:  The number of pixels.
+%
 */
-
-static inline ssize_t MagickAbsoluteValue(const ssize_t x)
-{
-  if (x < 0)
-    return(-x);
-  return(x);
-}
-
-static inline size_t MagickMax(const size_t x,const size_t y)
-{
-  if (x > y)
-    return(x);
-  return(y);
-}
-
-static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
-{
-  if (x < y)
-    return(x);
-  return(y);
-}
-
 static MagickBooleanType DecodeImage(Image *image,const size_t compression,
-  unsigned char *pixels)
+  unsigned char *pixels,const size_t number_pixels)
 {
   int
+    byte,
     count;
 
   register ssize_t
@@ -224,34 +217,35 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
   ssize_t
     y;
 
-  unsigned char
-    byte;
-
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(pixels != (unsigned char *) NULL);
-  (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows*
-    sizeof(*pixels));
+  (void) memset(pixels,0,number_pixels*sizeof(*pixels));
   byte=0;
   x=0;
   p=pixels;
-  q=pixels+(size_t) image->columns*image->rows;
+  q=pixels+number_pixels;
   for (y=0; y < (ssize_t) image->rows; )
   {
-    if ((p < pixels) || (p >= q))
+    MagickBooleanType
+      status;
+
+    if ((p < pixels) || (p > q))
       break;
     count=ReadBlobByte(image);
     if (count == EOF)
       break;
-    if (count != 0)
+    if (count > 0)
       {
         /*
           Encoded mode.
         */
         count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
-        byte=(unsigned char) ReadBlobByte(image);
+        byte=ReadBlobByte(image);
+        if (byte == EOF)
+          break;
         if (compression == BI_RLE8)
           {
             for (i=0; i < (ssize_t) count; i++)
@@ -271,6 +265,8 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
           Escape mode.
         */
         count=ReadBlobByte(image);
+        if (count == EOF)
+          break;
         if (count == 0x01)
           return(MagickTrue);
         switch (count)
@@ -303,12 +299,21 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
             count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
             if (compression == BI_RLE8)
               for (i=0; i < (ssize_t) count; i++)
-                *p++=(unsigned char) ReadBlobByte(image);
+              {
+                byte=ReadBlobByte(image);
+                if (byte == EOF)
+                  break;
+                *p++=(unsigned char) byte;
+              }
             else
               for (i=0; i < (ssize_t) count; i++)
               {
                 if ((i & 0x01) == 0)
-                  byte=(unsigned char) ReadBlobByte(image);
+                  {
+                    byte=ReadBlobByte(image);
+                    if (byte == EOF)
+                      break;
+                  }
                 *p++=(unsigned char)
                   ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
               }
@@ -319,21 +324,25 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
             if (compression == BI_RLE8)
               {
                 if ((count & 0x01) != 0)
-                  (void) ReadBlobByte(image);
+                  if (ReadBlobByte(image) == EOF)
+                    break;
               }
             else
               if (((count & 0x03) == 1) || ((count & 0x03) == 2))
-                (void) ReadBlobByte(image);
+                if (ReadBlobByte(image) == EOF)
+                  break;
             break;
           }
         }
       }
-    if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
+    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
+      image->rows);
+    if (status == MagickFalse)
       break;
   }
   (void) ReadBlobByte(image);  /* end of line */
   (void) ReadBlobByte(image);
-  return(MagickTrue);
+  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
 }
 \f
 /*
@@ -391,7 +400,7 @@ static size_t EncodeImage(Image *image,const size_t bytes_per_line,
     Runlength encode pixels.
   */
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(pixels != (const unsigned char *) NULL);
@@ -531,12 +540,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
   size_t
     bit,
-    blue,
     bytes_per_line,
-    green,
-    length,
-    opacity,
-    red;
+    length;
 
   ssize_t
     count,
@@ -546,16 +551,22 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     magick[12],
     *pixels;
 
+  unsigned int
+    blue,
+    green,
+    offset_bits,
+    red;
+
   /*
     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);
   image=AcquireImage(image_info,exception);
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   if (status == MagickFalse)
@@ -566,10 +577,13 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
   /*
     Determine if this a BMP file.
   */
-  (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
+  (void) memset(&bmp_info,0,sizeof(bmp_info));
   bmp_info.ba_offset=0;
   start_position=0;
+  offset_bits=0;
   count=ReadBlob(image,2,magick);
+  if (count != 2)
+    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   do
   {
     PixelInfo
@@ -578,15 +592,10 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     PixelPacket
       shift;
 
-    size_t
-      profile_data,
-      profile_size;
-
     /*
       Verify BMP identifier.
     */
-    if (bmp_info.ba_offset == 0)
-      start_position=TellBlob(image)-2;
+    start_position=TellBlob(image)-2;
     bmp_info.ba_offset=0;
     while (LocaleNCompare((char *) magick,"BA",2) == 0)
     {
@@ -600,7 +609,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     if (image->debug != MagickFalse)
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Magick: %c%c",
         magick[0],magick[1]);
-    if ((count == 0) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
+    if ((count != 2) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
         (LocaleNCompare((char *) magick,"CI",2) != 0)))
       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
     bmp_info.file_size=ReadBlobLSBLong(image);
@@ -615,7 +624,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           OS/2 BMP image file.
         */
-        (void) CopyMagickString(image->magick,"BMP2",MaxTextExtent);
+        (void) CopyMagickString(image->magick,"BMP2",MagickPathExtent);
         bmp_info.width=(ssize_t) ((short) ReadBlobLSBShort(image));
         bmp_info.height=(ssize_t) ((short) ReadBlobLSBShort(image));
         bmp_info.planes=ReadBlobLSBShort(image);
@@ -642,8 +651,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         */
         if (bmp_info.size < 40)
           ThrowReaderException(CorruptImageError,"NonOS2HeaderSizeError");
-        bmp_info.width=(ssize_t) ((int) ReadBlobLSBLong(image));
-        bmp_info.height=(ssize_t) ((int) ReadBlobLSBLong(image));
+        bmp_info.width=(ssize_t) ReadBlobLSBSignedLong(image);
+        bmp_info.height=(ssize_t) ReadBlobLSBSignedLong(image);
         bmp_info.planes=ReadBlobLSBShort(image);
         bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
         bmp_info.compression=ReadBlobLSBLong(image);
@@ -651,9 +660,9 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         bmp_info.x_pixels=ReadBlobLSBLong(image);
         bmp_info.y_pixels=ReadBlobLSBLong(image);
         bmp_info.number_colors=ReadBlobLSBLong(image);
+        if (bmp_info.number_colors > GetBlobSize(image))
+          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
         bmp_info.colors_important=ReadBlobLSBLong(image);
-        profile_data=0;
-        profile_size=0;
         if (image->debug != MagickFalse)
           {
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -663,7 +672,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
               bmp_info.height);
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "  Bits per pixel: %.20g",(double) bmp_info.bits_per_pixel);
-            switch ((int) bmp_info.compression)
+            switch (bmp_info.compression)
             {
               case BI_RGB:
               {
@@ -715,15 +724,14 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         bmp_info.blue_mask=ReadBlobLSBLong(image);
         if (bmp_info.size > 40)
           {
-
             double
-              sum;
+              gamma;
 
             /*
               Read color management information.
             */
             bmp_info.alpha_mask=ReadBlobLSBLong(image);
-            bmp_info.colorspace=(int) ReadBlobLSBLong(image);
+            bmp_info.colorspace=ReadBlobLSBSignedLong(image);
             /*
               Decode 2^30 fixed point formatted CIE primaries.
             */
@@ -738,24 +746,27 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             bmp_info.blue_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
             bmp_info.blue_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
 
-            sum=bmp_info.red_primary.x+bmp_info.red_primary.y+
+            gamma=bmp_info.red_primary.x+bmp_info.red_primary.y+
               bmp_info.red_primary.z;
-            bmp_info.red_primary.x/=sum;
-            bmp_info.red_primary.y/=sum;
+            gamma=PerceptibleReciprocal(gamma);
+            bmp_info.red_primary.x*=gamma;
+            bmp_info.red_primary.y*=gamma;
             image->chromaticity.red_primary.x=bmp_info.red_primary.x;
             image->chromaticity.red_primary.y=bmp_info.red_primary.y;
 
-            sum=bmp_info.green_primary.x+bmp_info.green_primary.y+
+            gamma=bmp_info.green_primary.x+bmp_info.green_primary.y+
               bmp_info.green_primary.z;
-            bmp_info.green_primary.x/=sum;
-            bmp_info.green_primary.y/=sum;
+            gamma=PerceptibleReciprocal(gamma);
+            bmp_info.green_primary.x*=gamma;
+            bmp_info.green_primary.y*=gamma;
             image->chromaticity.green_primary.x=bmp_info.green_primary.x;
             image->chromaticity.green_primary.y=bmp_info.green_primary.y;
 
-            sum=bmp_info.blue_primary.x+bmp_info.blue_primary.y+
+            gamma=bmp_info.blue_primary.x+bmp_info.blue_primary.y+
               bmp_info.blue_primary.z;
-            bmp_info.blue_primary.x/=sum;
-            bmp_info.blue_primary.y/=sum;
+            gamma=PerceptibleReciprocal(gamma);
+            bmp_info.blue_primary.x*=gamma;
+            bmp_info.blue_primary.y*=gamma;
             image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;
             image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;
 
@@ -772,7 +783,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
               bmp_info.gamma_scale.z)/3.0;
           }
         else
-          (void) CopyMagickString(image->magick,"BMP3",MaxTextExtent);
+          (void) CopyMagickString(image->magick,"BMP3",MagickPathExtent);
 
         if (bmp_info.size > 108)
           {
@@ -806,10 +817,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 break;
               }
             }
-            profile_data=ReadBlobLSBLong(image);
-            profile_size=ReadBlobLSBLong(image);
-            (void) profile_data;
-            (void) profile_size;
+            (void) ReadBlobLSBLong(image);  /* Profile data */
+            (void) ReadBlobLSBLong(image);  /* Profile size */
             (void) ReadBlobLSBLong(image);  /* Reserved byte */
           }
       }
@@ -833,10 +842,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
       ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
     if (bmp_info.bits_per_pixel < 16 &&
         bmp_info.number_colors > (1U << bmp_info.bits_per_pixel))
-      {
-        ThrowReaderException(CorruptImageError,
-            "UnrecognizedNumberOfColors");
-      }
+      ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
     if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
       ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
     if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
@@ -846,8 +852,12 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     switch (bmp_info.compression)
     {
       case BI_RGB:
+        image->compression=NoCompression;
+        break;
       case BI_RLE8:
       case BI_RLE4:
+        image->compression=RLECompression;
+        break;
       case BI_BITFIELDS:
         break;
       case BI_JPEG:
@@ -861,8 +871,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     image->rows=(size_t) MagickAbsoluteValue(bmp_info.height);
     image->depth=bmp_info.bits_per_pixel <= 8 ? bmp_info.bits_per_pixel : 8;
     image->alpha_trait=((bmp_info.alpha_mask != 0) &&
-      (bmp_info.compression == BI_BITFIELDS)) ||
-      (bmp_info.bits_per_pixel == 32) ? BlendPixelTrait : UndefinedPixelTrait;
+      (bmp_info.compression == BI_BITFIELDS)) ? BlendPixelTrait :
+      UndefinedPixelTrait;
     if (bmp_info.bits_per_pixel < 16)
       {
         size_t
@@ -874,6 +884,15 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         if (image->colors == 0)
           image->colors=one << bmp_info.bits_per_pixel;
       }
+    image->resolution.x=(double) bmp_info.x_pixels/100.0;
+    image->resolution.y=(double) bmp_info.y_pixels/100.0;
+    image->units=PixelsPerCentimeterResolution;
+    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
+      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
+        break;
+    status=SetImageExtent(image,image->columns,image->rows,exception);
+    if (status == MagickFalse)
+      return(DestroyImageList(image));
     if (image->storage_class == PseudoClass)
       {
         unsigned char
@@ -900,10 +919,17 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
           packet_size=4;
         offset=SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);
         if (offset < 0)
-          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+          {
+            bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
+            ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+          }
         count=ReadBlob(image,packet_size*image->colors,bmp_colormap);
         if (count != (ssize_t) (packet_size*image->colors))
-          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
+          {
+            bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
+            ThrowReaderException(CorruptImageError,
+              "InsufficientImageDataInFile");
+          }
         p=bmp_colormap;
         for (i=0; i < (ssize_t) image->colors; i++)
         {
@@ -915,15 +941,12 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         }
         bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
       }
-    image->resolution.x=(double) bmp_info.x_pixels/100.0;
-    image->resolution.y=(double) bmp_info.y_pixels/100.0;
-    image->units=PixelsPerCentimeterResolution;
-    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
-      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
-        break;
     /*
       Read image data.
     */
+    if (bmp_info.offset_bits == offset_bits)
+      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+    offset_bits=bmp_info.offset_bits;
     offset=SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);
     if (offset < 0)
       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
@@ -931,14 +954,16 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
       bmp_info.bits_per_pixel<<=1;
     bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
     length=(size_t) bytes_per_line*image->rows;
-    pixel_info=AcquireVirtualMemory((size_t) image->rows,
-      MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
-    if (pixel_info == (MemoryInfo *) NULL)
-      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
+    if (((MagickSizeType) length/8) > GetBlobSize(image))
+      ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
     if ((bmp_info.compression == BI_RGB) ||
         (bmp_info.compression == BI_BITFIELDS))
       {
+        pixel_info=AcquireVirtualMemory(image->rows,
+          MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
+        if (pixel_info == (MemoryInfo *) NULL)
+          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+        pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
         if (image->debug != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
             "  Reading pixels (%.20g bytes)",(double) length);
@@ -955,7 +980,13 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Convert run-length encoded raster pixels.
         */
-        status=DecodeImage(image,bmp_info.compression,pixels);
+        pixel_info=AcquireVirtualMemory(image->rows,
+          MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
+        if (pixel_info == (MemoryInfo *) NULL)
+          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+        pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
+        status=DecodeImage(image,bmp_info.compression,pixels,
+          image->columns*image->rows);
         if (status == MagickFalse)
           {
             pixel_info=RelinquishVirtualMemory(pixel_info);
@@ -968,7 +999,33 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     */
     if (bmp_info.compression == BI_RGB)
       {
-        bmp_info.alpha_mask=image->alpha_trait == BlendPixelTrait ?
+        /*
+          We should ignore the alpha value in BMP3 files but there have been
+          reports about 32 bit files with alpha. We do a quick check to see if
+          the alpha channel contains a value that is not zero (default value).
+          If we find a non zero value we asume the program that wrote the file
+          wants to use the alpha channel.
+        */
+        if ((image->alpha_trait == UndefinedPixelTrait) && (bmp_info.size == 40) &&
+            (bmp_info.bits_per_pixel == 32))
+          {
+            bytes_per_line=4*(image->columns);
+            for (y=(ssize_t) image->rows-1; y >= 0; y--)
+            {
+              p=pixels+(image->rows-y-1)*bytes_per_line;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                if (*(p+3) != 0)
+                  {
+                    image->alpha_trait=BlendPixelTrait;
+                    y=-1;
+                    break;
+                  }
+                p+=4;
+              }
+            }
+          }
+        bmp_info.alpha_mask=image->alpha_trait != UndefinedPixelTrait ?
           0xff000000U : 0U;
         bmp_info.red_mask=0x00ff0000U;
         bmp_info.green_mask=0x0000ff00U;
@@ -983,43 +1040,75 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             bmp_info.blue_mask=0x0000001fU;
           }
       }
+    (void) memset(&shift,0,sizeof(shift));
+    (void) memset(&quantum_bits,0,sizeof(quantum_bits));
     if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
       {
-        register size_t
+        register unsigned int
           sample;
 
         /*
           Get shift and quantum bits info from bitfield masks.
         */
-        (void) ResetMagickMemory(&shift,0,sizeof(shift));
-        (void) ResetMagickMemory(&quantum_bits,0,sizeof(quantum_bits));
         if (bmp_info.red_mask != 0)
           while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)
+          {
             shift.red++;
+            if (shift.red >= 32U)
+              break;
+          }
         if (bmp_info.green_mask != 0)
           while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)
+          {
             shift.green++;
+            if (shift.green >= 32U)
+              break;
+          }
         if (bmp_info.blue_mask != 0)
           while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)
+          {
             shift.blue++;
+            if (shift.blue >= 32U)
+              break;
+          }
         if (bmp_info.alpha_mask != 0)
           while (((bmp_info.alpha_mask << shift.alpha) & 0x80000000UL) == 0)
+          {
             shift.alpha++;
+            if (shift.alpha >= 32U)
+              break;
+          }
         sample=shift.red;
         while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
+        {
           sample++;
+          if (sample >= 32U)
+            break;
+        }
         quantum_bits.red=(MagickRealType) (sample-shift.red);
         sample=shift.green;
         while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
+        {
           sample++;
+          if (sample >= 32U)
+            break;
+        }
         quantum_bits.green=(MagickRealType) (sample-shift.green);
         sample=shift.blue;
         while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
+        {
           sample++;
+          if (sample >= 32U)
+            break;
+        }
         quantum_bits.blue=(MagickRealType) (sample-shift.blue);
         sample=shift.alpha;
         while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
+        {
           sample++;
+          if (sample >= 32U)
+            break;
+        }
         quantum_bits.alpha=(MagickRealType) (sample-shift.alpha);
       }
     switch (bmp_info.bits_per_pixel)
@@ -1081,21 +1170,26 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             break;
           for (x=0; x < ((ssize_t) image->columns-1); x+=2)
           {
-            index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
+            ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0x0f),&index,
+              exception);
             SetPixelIndex(image,index,q);
             q+=GetPixelChannels(image);
-            index=ConstrainColormapIndex(image,*p & 0x0f,exception);
+            ValidateColormapValue(image,(ssize_t) (*p & 0x0f),&index,exception);
             SetPixelIndex(image,index,q);
             q+=GetPixelChannels(image);
             p++;
           }
           if ((image->columns % 2) != 0)
             {
-              index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
+              ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0xf),&index,
+                exception);
               SetPixelIndex(image,index,q);
               q+=GetPixelChannels(image);
               p++;
+              x++;
             }
+          if (x < (ssize_t) image->columns)
+            break;
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
             break;
           if (image->previous == (Image *) NULL)
@@ -1125,7 +1219,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             break;
           for (x=(ssize_t) image->columns; x != 0; --x)
           {
-            index=ConstrainColormapIndex(image,*p++,exception);
+            ValidateColormapValue(image,(ssize_t) *p++,&index,exception);
             SetPixelIndex(image,index,q);
             q+=GetPixelChannels(image);
           }
@@ -1145,14 +1239,15 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
       }
       case 16:
       {
-        size_t
+        unsigned int
+          alpha,
           pixel;
 
         /*
           Convert bitfield encoded 16-bit PseudoColor scanline.
         */
-        if (bmp_info.compression != BI_RGB &&
-            bmp_info.compression != BI_BITFIELDS)
+        if ((bmp_info.compression != BI_RGB) &&
+            (bmp_info.compression != BI_BITFIELDS))
           {
             pixel_info=RelinquishVirtualMemory(pixel_info);
             ThrowReaderException(CorruptImageError,
@@ -1168,7 +1263,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
           {
-            pixel=(size_t) (*p++);
+            pixel=(unsigned int) (*p++);
             pixel|=(*p++) << 8;
             red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
             if (quantum_bits.red == 5)
@@ -1187,16 +1282,18 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
               blue|=((blue & 0xe000) >> 5);
             if (quantum_bits.blue <= 8)
               blue|=((blue & 0xff00) >> 8);
-            opacity=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
-            if (quantum_bits.alpha <= 8)
-              opacity|=((opacity & 0xff00) >> 8);
             SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
             SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
             SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
             SetPixelAlpha(image,OpaqueAlpha,q);
-            if (image->alpha_trait == BlendPixelTrait)
-              SetPixelAlpha(image,ScaleShortToQuantum((unsigned short) opacity),
-                q);
+            if (image->alpha_trait != UndefinedPixelTrait)
+              {
+                alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
+                if (quantum_bits.alpha <= 8)
+                  alpha|=((alpha & 0xff00) >> 8);
+                SetPixelAlpha(image,ScaleShortToQuantum(
+                  (unsigned short) alpha),q);
+              }
             q+=GetPixelChannels(image);
           }
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -1260,7 +1357,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         bytes_per_line=4*(image->columns);
         for (y=(ssize_t) image->rows-1; y >= 0; y--)
         {
-          size_t
+          unsigned int
+            alpha,
             pixel;
 
           p=pixels+(image->rows-y-1)*bytes_per_line;
@@ -1269,10 +1367,10 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             break;
           for (x=0; x < (ssize_t) image->columns; x++)
           {
-            pixel=(size_t) (*p++);
-            pixel|=((size_t) *p++ << 8);
-            pixel|=((size_t) *p++ << 16);
-            pixel|=((size_t) *p++ << 24);
+            pixel=(unsigned int) (*p++);
+            pixel|=((unsigned int) *p++ << 8);
+            pixel|=((unsigned int) *p++ << 16);
+            pixel|=((unsigned int) *p++ << 24);
             red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
             if (quantum_bits.red == 8)
               red|=(red >> 8);
@@ -1282,16 +1380,18 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
             if (quantum_bits.blue == 8)
               blue|=(blue >> 8);
-            opacity=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
-            if (quantum_bits.alpha == 8)
-              opacity|=(opacity >> 8);
             SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
             SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
             SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
             SetPixelAlpha(image,OpaqueAlpha,q);
-            if (image->alpha_trait == BlendPixelTrait)
-              SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
-                opacity),q);
+            if (image->alpha_trait != UndefinedPixelTrait)
+              {
+                alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
+                if (quantum_bits.alpha == 8)
+                  alpha|=(alpha >> 8);
+                SetPixelAlpha(image,ScaleShortToQuantum(
+                  (unsigned short) alpha),q);
+              }
             q+=GetPixelChannels(image);
           }
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
@@ -1314,6 +1414,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
       }
     }
     pixel_info=RelinquishVirtualMemory(pixel_info);
+    if (y > 0)
+      break;
     if (EOFBlob(image) != MagickFalse)
       {
         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
@@ -1332,7 +1434,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         if (flipped_image != (Image *) NULL)
           {
             DuplicateBlob(flipped_image,image);
-            image=DestroyImage(image);
+            ReplaceImageInList(&image, flipped_image);
             image=flipped_image;
           }
       }
@@ -1358,7 +1460,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         AcquireNextImage(image_info,image,exception);
         if (GetNextImageInList(image) == (Image *) NULL)
           {
-            image=DestroyImageList(image);
+            status=MagickFalse;
             return((Image *) NULL);
           }
         image=SyncNextImageInList(image);
@@ -1369,6 +1471,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
       }
   } while (IsBMP(magick,2) != MagickFalse);
   (void) CloseBlob(image);
+  if (status == MagickFalse)
+    return(DestroyImageList(image));
   return(GetFirstImageInList(image));
 }
 \f
@@ -1400,30 +1504,26 @@ ModuleExport size_t RegisterBMPImage(void)
   MagickInfo
     *entry;
 
-  entry=SetMagickInfo("BMP");
+  entry=AcquireMagickInfo("BMP","BMP","Microsoft Windows bitmap image");
   entry->decoder=(DecodeImageHandler *) ReadBMPImage;
   entry->encoder=(EncodeImageHandler *) WriteBMPImage;
   entry->magick=(IsImageFormatHandler *) IsBMP;
-  entry->description=ConstantString("Microsoft Windows bitmap image");
-  entry->module=ConstantString("BMP");
-  entry->adjoin=MagickFalse;
-  entry->seekable_stream=MagickTrue;
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   (void) RegisterMagickInfo(entry);
-  entry=SetMagickInfo("BMP2");
+  entry=AcquireMagickInfo("BMP","BMP2","Microsoft Windows bitmap image (V2)");
+  entry->decoder=(DecodeImageHandler *) ReadBMPImage;
   entry->encoder=(EncodeImageHandler *) WriteBMPImage;
   entry->magick=(IsImageFormatHandler *) IsBMP;
-  entry->description=ConstantString("Microsoft Windows bitmap image (V2)");
-  entry->module=ConstantString("BMP");
-  entry->adjoin=MagickFalse;
-  entry->seekable_stream=MagickTrue;
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   (void) RegisterMagickInfo(entry);
-  entry=SetMagickInfo("BMP3");
+  entry=AcquireMagickInfo("BMP","BMP3","Microsoft Windows bitmap image (V3)");
+  entry->decoder=(DecodeImageHandler *) ReadBMPImage;
   entry->encoder=(EncodeImageHandler *) WriteBMPImage;
   entry->magick=(IsImageFormatHandler *) IsBMP;
-  entry->description=ConstantString("Microsoft Windows bitmap image (V3)");
-  entry->module=ConstantString("BMP");
-  entry->adjoin=MagickFalse;
-  entry->seekable_stream=MagickTrue;
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   (void) RegisterMagickInfo(entry);
   return(MagickImageCoderSignature);
 }
@@ -1488,9 +1588,12 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
 {
   BMPInfo
     bmp_info;
-  const char
-    *value;
 
+  BMPSubtype
+    bmp_subtype;
+
+  const char
+    *option;
 
   const StringInfo
     *profile;
@@ -1517,6 +1620,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
 
   size_t
     bytes_per_line,
+    imageListLength,
     type;
 
   ssize_t
@@ -1530,13 +1634,13 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
     Open output 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);
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   if (status == MagickFalse)
     return(status);
@@ -1546,35 +1650,38 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
   else
     if (LocaleCompare(image_info->magick,"BMP3") == 0)
       type=3;
-
-  value=GetImageOption(image_info,"bmp:format");
-
-  if (value != (char *) NULL)
+  option=GetImageOption(image_info,"bmp:format");
+  if (option != (char *) NULL)
     {
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "  Format=%s",value);
-
-      if (LocaleCompare(value,"bmp2") == 0)
+          "  Format=%s",option);
+      if (LocaleCompare(option,"bmp2") == 0)
         type=2;
-      if (LocaleCompare(value,"bmp3") == 0)
+      if (LocaleCompare(option,"bmp3") == 0)
         type=3;
-      if (LocaleCompare(value,"bmp4") == 0)
+      if (LocaleCompare(option,"bmp4") == 0)
         type=4;
     }
-
   scene=0;
+  imageListLength=GetImageListLength(image);
   do
   {
     /*
       Initialize BMP raster file header.
     */
-    (void) TransformImageColorspace(image,sRGBColorspace,exception);
-    (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
+    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+      (void) TransformImageColorspace(image,sRGBColorspace,exception);
+    (void) memset(&bmp_info,0,sizeof(bmp_info));
     bmp_info.file_size=14+12;
     if (type > 2)
       bmp_info.file_size+=28;
     bmp_info.offset_bits=bmp_info.file_size;
     bmp_info.compression=BI_RGB;
+    bmp_info.red_mask=0x00ff0000U;
+    bmp_info.green_mask=0x0000ff00U;
+    bmp_info.blue_mask=0x000000ffU;
+    bmp_info.alpha_mask=0xff000000U;
+    bmp_subtype=UndefinedSubtype;
     if ((image->storage_class == PseudoClass) && (image->colors > 256))
       (void) SetImageStorageClass(image,DirectClass,exception);
     if (image->storage_class != DirectClass)
@@ -1594,7 +1701,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
         if (image_info->compression == RLECompression)
           bmp_info.bits_per_pixel=8;
         bmp_info.number_colors=1U << bmp_info.bits_per_pixel;
-        if (image->alpha_trait == BlendPixelTrait)
+        if (image->alpha_trait != UndefinedPixelTrait)
           (void) SetImageStorageClass(image,DirectClass,exception);
         else
           if ((size_t) bmp_info.number_colors < image->colors)
@@ -1616,10 +1723,66 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
           Full color BMP raster.
         */
         bmp_info.number_colors=0;
-        bmp_info.bits_per_pixel=(unsigned short)
-          ((type > 3) && (image->alpha_trait == BlendPixelTrait) ? 32 : 24);
-        bmp_info.compression=(unsigned int) ((type > 3) &&
-          (image->alpha_trait == BlendPixelTrait) ?  BI_BITFIELDS : BI_RGB);
+        option=GetImageOption(image_info,"bmp:subtype");
+        if (option != (const char *) NULL)
+        {
+          if (image->alpha_trait != UndefinedPixelTrait)
+            {
+              if (LocaleNCompare(option,"ARGB4444",8) == 0)
+                {
+                  bmp_subtype=ARGB4444;
+                  bmp_info.red_mask=0x00000f00U;
+                  bmp_info.green_mask=0x000000f0U;
+                  bmp_info.blue_mask=0x0000000fU;
+                  bmp_info.alpha_mask=0x0000f000U;
+                }
+              else if (LocaleNCompare(option,"ARGB1555",8) == 0)
+                {
+                  bmp_subtype=ARGB1555;
+                  bmp_info.red_mask=0x00007c00U;
+                  bmp_info.green_mask=0x000003e0U;
+                  bmp_info.blue_mask=0x0000001fU;
+                  bmp_info.alpha_mask=0x00008000U;
+                }
+            }
+          else
+          {
+            if (LocaleNCompare(option,"RGB555",6) == 0)
+              {
+                bmp_subtype=RGB555;
+                bmp_info.red_mask=0x00007c00U;
+                bmp_info.green_mask=0x000003e0U;
+                bmp_info.blue_mask=0x0000001fU;
+                bmp_info.alpha_mask=0U;
+              }
+            else if (LocaleNCompare(option,"RGB565",6) == 0)
+              {
+                bmp_subtype=RGB565;
+                bmp_info.red_mask=0x0000f800U;
+                bmp_info.green_mask=0x000007e0U;
+                bmp_info.blue_mask=0x0000001fU;
+                bmp_info.alpha_mask=0U;
+              }
+          }
+        }
+        if (bmp_subtype != UndefinedSubtype)
+          {
+            bmp_info.bits_per_pixel=16;
+            bmp_info.compression=BI_BITFIELDS;
+          }
+        else
+          {
+            bmp_info.bits_per_pixel=(unsigned short) ((type > 3) &&
+               (image->alpha_trait != UndefinedPixelTrait) ? 32 : 24);
+            bmp_info.compression=(unsigned int) ((type > 3) &&
+              (image->alpha_trait != UndefinedPixelTrait) ? BI_BITFIELDS : BI_RGB);
+            if ((type == 3) && (image->alpha_trait != UndefinedPixelTrait))
+              {
+                option=GetImageOption(image_info,"bmp3:alpha");
+                if (IsStringTrue(option))
+                  bmp_info.bits_per_pixel=32;
+              }
+          }
       }
     bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
     bmp_info.ba_offset=0;
@@ -1630,7 +1793,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
     if (type == 2)
       bmp_info.size=12;
     else
-      if ((type == 3) || ((image->alpha_trait != BlendPixelTrait) &&
+      if ((type == 3) || ((image->alpha_trait == UndefinedPixelTrait) &&
           (have_color_info == MagickFalse)))
         {
           type=3;
@@ -1652,6 +1815,9 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
           bmp_info.file_size+=extra_size;
           bmp_info.offset_bits+=extra_size;
         }
+    if (((ssize_t) image->columns != (ssize_t) ((signed int) image->columns)) ||
+        ((ssize_t) image->rows != (ssize_t) ((signed int) image->rows)))
+      ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
     bmp_info.width=(ssize_t) image->columns;
     bmp_info.height=(ssize_t) image->rows;
     bmp_info.planes=1;
@@ -1679,12 +1845,12 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
     /*
       Convert MIFF to BMP raster pixels.
     */
-    pixel_info=AcquireVirtualMemory((size_t) bmp_info.image_size,
-      sizeof(*pixels));
+    pixel_info=AcquireVirtualMemory(image->rows,
+      MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
     if (pixel_info == (MemoryInfo *) NULL)
       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
     pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
-    (void) ResetMagickMemory(pixels,0,(size_t) bmp_info.image_size);
+    (void) memset(pixels,0,(size_t) bmp_info.image_size);
     switch (bmp_info.bits_per_pixel)
     {
       case 1:
@@ -1740,7 +1906,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
       }
       case 4:
       {
-        size_t
+        unsigned int
           byte,
           nibble;
 
@@ -1761,7 +1927,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
           for (x=0; x < (ssize_t) image->columns; x++)
           {
             byte<<=4;
-            byte|=((size_t) GetPixelIndex(image,p) & 0x0f);
+            byte|=((unsigned int) GetPixelIndex(image,p) & 0x0f);
             nibble++;
             if (nibble == 2)
               {
@@ -1817,6 +1983,71 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
         }
         break;
       }
+      case 16:
+      {
+        /*
+          Convert DirectClass packet to BMP BGR888.
+        */
+        for (y=0; y < (ssize_t) image->rows; y++)
+        {
+          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+          if (p == (const Quantum *) NULL)
+            break;
+          q=pixels+(image->rows-y-1)*bytes_per_line;
+          for (x=0; x < (ssize_t) image->columns; x++)
+          {
+            unsigned short
+              pixel;
+
+            pixel=0;
+            if (bmp_subtype == ARGB4444)
+              {
+                pixel=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelAlpha(image,p),15) << 12);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelRed(image,p),15) << 8);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelGreen(image,p),15) << 4);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelBlue(image,p),15));
+              }
+            else if (bmp_subtype == RGB565)
+              {
+                pixel=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelRed(image,p),31) << 11);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelGreen(image,p),63) << 5);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelBlue(image,p),31));
+              }
+            else
+              {
+                if (bmp_subtype == ARGB1555)
+                  pixel=(unsigned short) (ScaleQuantumToAny(
+                    GetPixelAlpha(image,p),1) << 15);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelRed(image,p),31) << 10);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelGreen(image,p),31) << 5);
+                pixel|=(unsigned short) (ScaleQuantumToAny(
+                  GetPixelBlue(image,p),31));
+              }
+            *((unsigned short *) q)=pixel;
+            q+=2;
+            p+=GetPixelChannels(image);
+          }
+          for (x=2L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)
+            *q++=0x00;
+          if (image->previous == (Image *) NULL)
+            {
+              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
+                image->rows);
+              if (status == MagickFalse)
+                break;
+            }
+        }
+        break;
+      }
       case 24:
       {
         /*
@@ -1918,7 +2149,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
             "   Storage class=PseudoClass");
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "   Image depth=%.20g",(double) image->depth);
-        if (image->alpha_trait == BlendPixelTrait)
+        if (image->alpha_trait != UndefinedPixelTrait)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
             "   Matte=True");
         else
@@ -1970,8 +2201,8 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
           Write 12-byte version 2 bitmap header.
         */
         (void) WriteBlobLSBLong(image,bmp_info.size);
-        (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.width);
-        (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.height);
+        (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.width);
+        (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.height);
         (void) WriteBlobLSBShort(image,bmp_info.planes);
         (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
       }
@@ -1981,8 +2212,8 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
           Write 40-byte version 3+ bitmap header.
         */
         (void) WriteBlobLSBLong(image,bmp_info.size);
-        (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.width);
-        (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.height);
+        (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.width);
+        (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.height);
         (void) WriteBlobLSBShort(image,bmp_info.planes);
         (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
         (void) WriteBlobLSBLong(image,bmp_info.compression);
@@ -1992,16 +2223,16 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
         (void) WriteBlobLSBLong(image,bmp_info.number_colors);
         (void) WriteBlobLSBLong(image,bmp_info.colors_important);
       }
-    if ((type > 3) && ((image->alpha_trait == BlendPixelTrait) ||
+    if ((type > 3) && ((image->alpha_trait != UndefinedPixelTrait) ||
         (have_color_info != MagickFalse)))
       {
         /*
           Write the rest of the 108-byte BMP Version 4 header.
         */
-        (void) WriteBlobLSBLong(image,0x00ff0000U);  /* Red mask */
-        (void) WriteBlobLSBLong(image,0x0000ff00U);  /* Green mask */
-        (void) WriteBlobLSBLong(image,0x000000ffU);  /* Blue mask */
-        (void) WriteBlobLSBLong(image,0xff000000U);  /* Alpha mask */
+        (void) WriteBlobLSBLong(image,bmp_info.red_mask);
+        (void) WriteBlobLSBLong(image,bmp_info.green_mask);
+        (void) WriteBlobLSBLong(image,bmp_info.blue_mask);
+        (void) WriteBlobLSBLong(image,bmp_info.alpha_mask);
         (void) WriteBlobLSBLong(image,0x73524742U);  /* sRGB */
         (void) WriteBlobLSBLong(image,(unsigned int)
           (image->chromaticity.red_primary.x*0x40000000));
@@ -2118,8 +2349,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
     if (GetNextImageInList(image) == (Image *) NULL)
       break;
     image=SyncNextImageInList(image);
-    status=SetImageProgress(image,SaveImagesTag,scene++,
-      GetImageListLength(image));
+    status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
     if (status == MagickFalse)
       break;
   } while (image_info->adjoin != MagickFalse);