]> granicus.if.org Git - imagemagick/blobdiff - coders/bmp.c
(no commit message)
[imagemagick] / coders / bmp.c
index d86f0b7bfbcf78dacef63faa2edb97489a6af888..217863fff29b77c0da5aa8fb691f562b4180d5c3 100644 (file)
 %             Read/Write Microsoft Windows Bitmap Image Format                %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                            Glenn Randers-Pehrson                            %
 %                               December 2001                                 %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2015 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  %
@@ -59,6 +59,7 @@
 #include "MagickCore/memory_.h"
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/profile.h"
 #include "MagickCore/quantum-private.h"
@@ -74,7 +75,7 @@
 #define BI_JPEG  4
 #undef BI_PNG
 #define BI_PNG  5
-#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
 #undef BI_RGB
 #define BI_RGB  0
 #undef BI_RLE8
@@ -184,28 +185,6 @@ static MagickBooleanType
 %      the decoding process.
 %
 */
-
-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)
 {
@@ -239,7 +218,10 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
   q=pixels+(size_t) image->columns*image->rows;
   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)
@@ -249,16 +231,16 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
         /*
           Encoded mode.
         */
-        count=MagickMin(count,(int) (q-p));
+        count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
         byte=(unsigned char) ReadBlobByte(image);
         if (compression == BI_RLE8)
           {
-            for (i=0; i < count; i++)
+            for (i=0; i < (ssize_t) count; i++)
               *p++=(unsigned char) byte;
           }
         else
           {
-            for (i=0; i < count; i++)
+            for (i=0; i < (ssize_t) count; i++)
               *p++=(unsigned char)
                 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
           }
@@ -270,6 +252,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)
@@ -299,12 +283,12 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
             /*
               Absolute mode.
             */
-            count=MagickMin(count,(int) (q-p));
+            count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
             if (compression == BI_RLE8)
-              for (i=0; i < count; i++)
+              for (i=0; i < (ssize_t) count; i++)
                 *p++=(unsigned char) ReadBlobByte(image);
             else
-              for (i=0; i < count; i++)
+              for (i=0; i < (ssize_t) count; i++)
               {
                 if ((i & 0x01) == 0)
                   byte=(unsigned char) ReadBlobByte(image);
@@ -327,12 +311,14 @@ static MagickBooleanType DecodeImage(Image *image,const size_t compression,
           }
         }
       }
-    if (SetImageProgress(image,LoadImageTag,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
 /*
@@ -512,6 +498,9 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     offset,
     start_position;
 
+  MemoryInfo
+    *pixel_info;
+
   Quantum
     index;
 
@@ -531,7 +520,6 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     bytes_per_line,
     green,
     length,
-    opacity,
     red;
 
   ssize_t
@@ -566,6 +554,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
   bmp_info.ba_offset=0;
   start_position=0;
   count=ReadBlob(image,2,magick);
+  if (count != 2)
+    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   do
   {
     PixelInfo
@@ -596,7 +586,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);
@@ -611,8 +601,9 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           OS/2 BMP image file.
         */
-        bmp_info.width=(short) ReadBlobLSBShort(image);
-        bmp_info.height=(short) ReadBlobLSBShort(image);
+        (void) CopyMagickString(image->magick,"BMP2",MaxTextExtent);
+        bmp_info.width=(ssize_t) ((short) ReadBlobLSBShort(image));
+        bmp_info.height=(ssize_t) ((short) ReadBlobLSBShort(image));
         bmp_info.planes=ReadBlobLSBShort(image);
         bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
         bmp_info.x_pixels=0;
@@ -637,8 +628,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         */
         if (bmp_info.size < 40)
           ThrowReaderException(CorruptImageError,"NonOS2HeaderSizeError");
-        bmp_info.width=(int) ReadBlobLSBLong(image);
-        bmp_info.height=(int) ReadBlobLSBLong(image);
+        bmp_info.width=(ssize_t) ((int) ReadBlobLSBLong(image));
+        bmp_info.height=(ssize_t) ((int) ReadBlobLSBLong(image));
         bmp_info.planes=ReadBlobLSBShort(image);
         bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
         bmp_info.compression=ReadBlobLSBLong(image);
@@ -766,6 +757,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             image->gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
               bmp_info.gamma_scale.z)/3.0;
           }
+        else
+          (void) CopyMagickString(image->magick,"BMP3",MaxTextExtent);
 
         if (bmp_info.size > 108)
           {
@@ -826,10 +819,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))
@@ -853,8 +843,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     image->columns=(size_t) MagickAbsoluteValue(bmp_info.width);
     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) ? BlendPixelTrait :
+    image->alpha_trait=((bmp_info.alpha_mask != 0) &&
+      (bmp_info.compression == BI_BITFIELDS)) ? BlendPixelTrait :
       UndefinedPixelTrait;
     if (bmp_info.bits_per_pixel < 16)
       {
@@ -900,9 +890,9 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         p=bmp_colormap;
         for (i=0; i < (ssize_t) image->colors; i++)
         {
-          image->colormap[i].blue=ScaleCharToQuantum(*p++);
-          image->colormap[i].green=ScaleCharToQuantum(*p++);
-          image->colormap[i].red=ScaleCharToQuantum(*p++);
+          image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(*p++);
+          image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(*p++);
+          image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(*p++);
           if (packet_size == 4)
             p++;
         }
@@ -914,6 +904,9 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     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));
     /*
       Read image data.
     */
@@ -924,10 +917,11 @@ 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;
-    pixels=(unsigned char *) AcquireQuantumMemory((size_t) image->rows,
+    pixel_info=AcquireVirtualMemory((size_t) image->rows,
       MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
-    if (pixels == (unsigned char *) NULL)
+    if (pixel_info == (MemoryInfo *) NULL)
       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
     if ((bmp_info.compression == BI_RGB) ||
         (bmp_info.compression == BI_BITFIELDS))
       {
@@ -937,7 +931,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         count=ReadBlob(image,length,pixels);
         if (count != (ssize_t) length)
           {
-            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+            pixel_info=RelinquishVirtualMemory(pixel_info);
             ThrowReaderException(CorruptImageError,
               "InsufficientImageDataInFile");
           }
@@ -950,7 +944,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         status=DecodeImage(image,bmp_info.compression,pixels);
         if (status == MagickFalse)
           {
-            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+            pixel_info=RelinquishVirtualMemory(pixel_info);
             ThrowReaderException(CorruptImageError,
               "UnableToRunlengthDecodeImage");
           }
@@ -960,8 +954,34 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
     */
     if (bmp_info.compression == BI_RGB)
       {
-        bmp_info.alpha_mask=image->alpha_trait == BlendPixelTrait ?
-          0xff000000L : 0L;
+        /*
+          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;
         bmp_info.blue_mask=0x000000ffU;
@@ -975,6 +995,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             bmp_info.blue_mask=0x0000001fU;
           }
       }
+    (void) ResetMagickMemory(&shift,0,sizeof(shift));
+    (void) ResetMagickMemory(&quantum_bits,0,sizeof(quantum_bits));
     if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
       {
         register size_t
@@ -983,8 +1005,6 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           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++;
@@ -1000,19 +1020,19 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         sample=shift.red;
         while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
           sample++;
-        quantum_bits.red=(Quantum) (sample-shift.red);
+        quantum_bits.red=(MagickRealType) (sample-shift.red);
         sample=shift.green;
         while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
           sample++;
-        quantum_bits.green=(Quantum) (sample-shift.green);
+        quantum_bits.green=(MagickRealType) (sample-shift.green);
         sample=shift.blue;
         while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
           sample++;
-        quantum_bits.blue=(Quantum) (sample-shift.blue);
+        quantum_bits.blue=(MagickRealType) (sample-shift.blue);
         sample=shift.alpha;
         while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
           sample++;
-        quantum_bits.alpha=(Quantum) (sample-shift.alpha);
+        quantum_bits.alpha=(MagickRealType) (sample-shift.alpha);
       }
     switch (bmp_info.bits_per_pixel)
     {
@@ -1051,8 +1071,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             break;
           if (image->previous == (Image *) NULL)
             {
-              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
+              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
+                (image->rows-y),image->rows);
               if (status == MagickFalse)
                 break;
             }
@@ -1073,27 +1093,35 @@ 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);
+            if (IsValidColormapIndex(image,(*p >> 4) & 0x0f,&index,exception)
+                == MagickFalse)
+              break;
             SetPixelIndex(image,index,q);
             q+=GetPixelChannels(image);
-            index=ConstrainColormapIndex(image,*p & 0x0f,exception);
+            if (IsValidColormapIndex(image,*p & 0x0f,&index,exception) ==
+                MagickFalse)
+              break;
             SetPixelIndex(image,index,q);
             q+=GetPixelChannels(image);
             p++;
           }
           if ((image->columns % 2) != 0)
             {
-              index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
+              if (IsValidColormapIndex(image,(*p >> 4) & 0xf,&index,exception)
+                  == MagickFalse)
+                break;
               SetPixelIndex(image,index,q);
               q+=GetPixelChannels(image);
               p++;
             }
+          if (x < image->columns)
+            break;
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
             break;
           if (image->previous == (Image *) NULL)
             {
-              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
+              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
+                (image->rows-y),image->rows);
               if (status == MagickFalse)
                 break;
             }
@@ -1117,17 +1145,21 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
             break;
           for (x=(ssize_t) image->columns; x != 0; --x)
           {
-            index=ConstrainColormapIndex(image,*p++,exception);
+            if (IsValidColormapIndex(image,*p++,&index,exception) ==
+                MagickFalse)
+              break;
             SetPixelIndex(image,index,q);
             q+=GetPixelChannels(image);
           }
+          if (x > 0)
+            break;
           if (SyncAuthenticPixels(image,exception) == MagickFalse)
             break;
           offset=(MagickOffsetType) (image->rows-y-1);
           if (image->previous == (Image *) NULL)
             {
-              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
+              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
+                (image->rows-y),image->rows);
               if (status == MagickFalse)
                 break;
             }
@@ -1138,6 +1170,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
       case 16:
       {
         size_t
+          alpha,
           pixel;
 
         /*
@@ -1146,7 +1179,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         if (bmp_info.compression != BI_RGB &&
             bmp_info.compression != BI_BITFIELDS)
           {
-            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+            pixel_info=RelinquishVirtualMemory(pixel_info);
             ThrowReaderException(CorruptImageError,
               "UnrecognizedImageCompression");
           }
@@ -1179,16 +1212,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)
@@ -1196,8 +1231,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
           offset=(MagickOffsetType) (image->rows-y-1);
           if (image->previous == (Image *) NULL)
             {
-              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
+              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
+                (image->rows-y),image->rows);
               if (status == MagickFalse)
                 break;
             }
@@ -1229,8 +1264,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
           offset=(MagickOffsetType) (image->rows-y-1);
           if (image->previous == (Image *) NULL)
             {
-              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
+              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
+                (image->rows-y),image->rows);
               if (status == MagickFalse)
                 break;
             }
@@ -1245,7 +1280,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         if ((bmp_info.compression != BI_RGB) &&
             (bmp_info.compression != BI_BITFIELDS))
           {
-            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+            pixel_info=RelinquishVirtualMemory(pixel_info);
             ThrowReaderException(CorruptImageError,
               "UnrecognizedImageCompression");
           }
@@ -1253,6 +1288,7 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
         for (y=(ssize_t) image->rows-1; y >= 0; y--)
         {
           size_t
+            alpha,
             pixel;
 
           p=pixels+(image->rows-y-1)*bytes_per_line;
@@ -1262,9 +1298,9 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
           for (x=0; x < (ssize_t) image->columns; x++)
           {
             pixel=(size_t) (*p++);
-            pixel|=(*p++ << 8);
-            pixel|=(*p++ << 16);
-            pixel|=(*p++ << 24);
+            pixel|=((size_t) *p++ << 8);
+            pixel|=((size_t) *p++ << 16);
+            pixel|=((size_t) *p++ << 24);
             red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
             if (quantum_bits.red == 8)
               red|=(red >> 8);
@@ -1274,16 +1310,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)
@@ -1291,8 +1329,8 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
           offset=(MagickOffsetType) (image->rows-y-1);
           if (image->previous == (Image *) NULL)
             {
-              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
-                image->rows);
+              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
+                (image->rows-y),image->rows);
               if (status == MagickFalse)
                 break;
             }
@@ -1301,11 +1339,13 @@ static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
       }
       default:
       {
-        pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+        pixel_info=RelinquishVirtualMemory(pixel_info);
         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
       }
     }
-    pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+    pixel_info=RelinquishVirtualMemory(pixel_info);
+    if (y > 0)
+      break;
     if (EOFBlob(image) != MagickFalse)
       {
         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
@@ -1398,24 +1438,24 @@ ModuleExport size_t RegisterBMPImage(void)
   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|=CoderSeekableStreamFlag;
   (void) RegisterMagickInfo(entry);
   entry=SetMagickInfo("BMP2");
   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|=CoderSeekableStreamFlag;
   (void) RegisterMagickInfo(entry);
   entry=SetMagickInfo("BMP3");
   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|=CoderSeekableStreamFlag;
   (void) RegisterMagickInfo(entry);
   return(MagickImageCoderSignature);
 }
@@ -1480,6 +1520,9 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
 {
   BMPInfo
     bmp_info;
+  const char
+    *value;
+
 
   const StringInfo
     *profile;
@@ -1491,6 +1534,9 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
   MagickOffsetType
     scene;
 
+  MemoryInfo
+    *pixel_info;
+
   register const Quantum
     *p;
 
@@ -1532,14 +1578,29 @@ 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)
+    {
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "  Format=%s",value);
+
+      if (LocaleCompare(value,"bmp2") == 0)
+        type=2;
+      if (LocaleCompare(value,"bmp3") == 0)
+        type=3;
+      if (LocaleCompare(value,"bmp4") == 0)
+        type=4;
+    }
+
   scene=0;
   do
   {
     /*
       Initialize BMP raster file header.
     */
-    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
-      (void) TransformImageColorspace(image,sRGBColorspace,exception);
+    (void) TransformImageColorspace(image,sRGBColorspace,exception);
     (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
     bmp_info.file_size=14+12;
     if (type > 2)
@@ -1565,7 +1626,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)
@@ -1588,9 +1649,9 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
         */
         bmp_info.number_colors=0;
         bmp_info.bits_per_pixel=(unsigned short)
-          ((type > 3) && (image->alpha_trait == BlendPixelTrait) ? 32 : 24);
+          ((type > 3) && (image->alpha_trait != UndefinedPixelTrait) ? 32 : 24);
         bmp_info.compression=(unsigned int) ((type > 3) &&
-          (image->alpha_trait == BlendPixelTrait) ?  BI_BITFIELDS : BI_RGB);
+          (image->alpha_trait != UndefinedPixelTrait) ?  BI_BITFIELDS : BI_RGB);
       }
     bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
     bmp_info.ba_offset=0;
@@ -1601,7 +1662,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;
@@ -1650,10 +1711,11 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
     /*
       Convert MIFF to BMP raster pixels.
     */
-    pixels=(unsigned char *) AcquireQuantumMemory((size_t) bmp_info.image_size,
+    pixel_info=AcquireVirtualMemory((size_t) bmp_info.image_size,
       sizeof(*pixels));
-    if (pixels == (unsigned char *) NULL)
+    if (pixel_info == (MemoryInfo *) NULL)
       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
     (void) ResetMagickMemory(pixels,0,(size_t) bmp_info.image_size);
     switch (bmp_info.bits_per_pixel)
     {
@@ -1712,7 +1774,9 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
       {
         size_t
           byte,
-          nibble,
+          nibble;
+
+        ssize_t
           offset;
 
         /*
@@ -1848,27 +1912,26 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
     if ((type > 2) && (bmp_info.bits_per_pixel == 8))
       if (image_info->compression != NoCompression)
         {
-          size_t
-            length;
+          MemoryInfo
+            *rle_info;
 
           /*
             Convert run-length encoded raster pixels.
           */
-          length=(size_t) (2*(bytes_per_line+2)*(image->rows+2)+2);
-          bmp_data=(unsigned char *) NULL;
-          if (~length >= bytes_per_line)
-            bmp_data=(unsigned char *) AcquireQuantumMemory(length+
-              bytes_per_line,sizeof(*bmp_data));
-          if (bmp_data == (unsigned char *) NULL)
+          rle_info=AcquireVirtualMemory((size_t) (2*(bytes_per_line+2)+2),
+            (image->rows+2)*sizeof(*pixels));
+          if (rle_info == (MemoryInfo *) NULL)
             {
-              pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+              pixel_info=RelinquishVirtualMemory(pixel_info);
               ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
             }
+          bmp_data=(unsigned char *) GetVirtualMemoryBlob(rle_info);
           bmp_info.file_size-=bmp_info.image_size;
           bmp_info.image_size=(unsigned int) EncodeImage(image,bytes_per_line,
             pixels,bmp_data);
           bmp_info.file_size+=bmp_info.image_size;
-          pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+          pixel_info=RelinquishVirtualMemory(pixel_info);
+          pixel_info=rle_info;
           pixels=bmp_data;
           bmp_info.compression=BI_RLE8;
         }
@@ -1887,7 +1950,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
@@ -1961,7 +2024,7 @@ 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)))
       {
         /*
@@ -2057,9 +2120,9 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
         q=bmp_colormap;
         for (i=0; i < (ssize_t) MagickMin((ssize_t) image->colors,(ssize_t) bmp_info.number_colors); i++)
         {
-          *q++=ScaleQuantumToChar(image->colormap[i].blue);
-          *q++=ScaleQuantumToChar(image->colormap[i].green);
-          *q++=ScaleQuantumToChar(image->colormap[i].red);
+          *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
+          *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
+          *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
           if (type > 2)
             *q++=(unsigned char) 0x0;
         }
@@ -2083,7 +2146,7 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
         "  Pixels:  %u bytes",bmp_info.image_size);
     (void) WriteBlob(image,(size_t) bmp_info.image_size,pixels);
-    pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+    pixel_info=RelinquishVirtualMemory(pixel_info);
     if (GetNextImageInList(image) == (Image *) NULL)
       break;
     image=SyncNextImageInList(image);