From: Dirk Lemstra Date: Sat, 14 Jan 2017 18:37:55 +0000 (+0100) Subject: Added support for RGB555, RGB565, ARGB4444 and ARGB1555 to the BMP encoder (Fixes... X-Git-Tag: 7.0.4-4~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a12953ccebf65858e65ec59f07e80ef4d9284d51;p=imagemagick Added support for RGB555, RGB565, ARGB4444 and ARGB1555 to the BMP encoder (Fixes #344) --- diff --git a/ChangeLog b/ChangeLog index 5923556f9..eea73c0c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-01-14 7.0.4-4 Dirk Lemstra + * 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 * Recognize XML policy closing tags (reference https://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=31182). diff --git a/coders/bmp.c b/coders/bmp.c index b5ca143af..f6d5aeff6 100644 --- a/coders/bmp.c +++ b/coders/bmp.c @@ -106,6 +106,18 @@ #define LCS_GM_ABS_COLORIMETRIC 8 /* Absolute */ #endif +/* + 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));