]> granicus.if.org Git - imagemagick/commitdiff
Added support for RGB555, RGB565, ARGB4444 and ARGB1555 to the BMP encoder (Fixes...
authorDirk Lemstra <dirk@git.imagemagick.org>
Sat, 14 Jan 2017 18:37:55 +0000 (19:37 +0100)
committerDirk Lemstra <dirk@git.imagemagick.org>
Sat, 14 Jan 2017 18:37:55 +0000 (19:37 +0100)
ChangeLog
coders/bmp.c

index 5923556f932cf828c33c0da84742f3cac558aa71..eea73c0c38062b03f6c363d209eb5d68dedbec98 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-01-14  7.0.4-4 Dirk Lemstra <dirk@lem.....org>
+  * Added support for RGB555, RGB565, ARGB4444 and ARGB1555 to the
+    BMP encoder (reference
+    https://github.com/ImageMagick/ImageMagick/issues/344).
+
 2017-01-10  7.0.4-4 Cristy  <quetzlzacatenango@image...>
   * Recognize XML policy closing tags (reference
     https://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=31182).
index b5ca143af57dbec89b5226f5a32fcc7e09da415f..f6d5aeff67a5889b2f86c15a089e572cc53bd8cf 100644 (file)
 #define LCS_GM_ABS_COLORIMETRIC  8  /* Absolute */
 #endif
 \f
+/*
+  Enumerated declaractions.
+*/
+typedef enum
+{
+  UndefinedSubtype,
+  RGB555,
+  RGB565,
+  ARGB4444,
+  ARGB1555
+} BMPSubtype;
+
 /*
   Typedef declarations.
 */
@@ -1512,6 +1524,9 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
   BMPInfo
     bmp_info;
 
+  BMPSubtype
+    bmp_subtype;
+
   const char
     *option;
 
@@ -1597,6 +1612,11 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
       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)
@@ -1638,15 +1658,65 @@ 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 != 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,"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)
           {
-            option=GetImageOption(image_info,"bmp3:alpha");
-            if (IsStringTrue(option))
-              bmp_info.bits_per_pixel=32;
+            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);
@@ -1848,6 +1918,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:
       {
         /*
@@ -2029,10 +2164,10 @@ static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
         /*
           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));