Up-scale BMP color components using Windows-compatible method

This allows tests to compare against native behavior under Windows
This commit is contained in:
Paul Cornett
2025-02-22 13:01:52 -08:00
parent b8199fa9ce
commit 45a7efd642
8 changed files with 44 additions and 42 deletions
+1
View File
@@ -156,6 +156,7 @@ set(TEST_GUI_DATA
image/32bpp_rgb_a0.ico
image/badrle4.bmp
image/rgb16-3103.bmp
image/rgb32-7187.bmp
image/rle4-delta-320x240.bmp
image/rle8-delta-320x240-expected.bmp
image/rle8-delta-320x240.bmp
+37 -34
View File
@@ -513,6 +513,19 @@ struct BMPDesc
int rmask, gmask, bmask;
};
// This seems to be the method Windows uses for up-scaling color components.
// It works well with 4 bits or more, not so well with less. But using it
// allows tests to compare against native behavior under Windows.
inline wxUint8 UpscaleTo8Bits(wxUint8 x, unsigned nbits)
{
if (nbits < 8)
{
x <<= (8 - nbits);
x |= x >> nbits;
}
return x;
}
// Read the data in BMP format into the given image.
//
// The stream must be positioned at the start of the bitmap data
@@ -528,6 +541,7 @@ bool LoadBMPData(wxImage * image, const BMPDesc& desc,
wxUint32 rmask = 0, gmask = 0, bmask = 0, amask = 0;
unsigned rshift = 0, gshift = 0, bshift = 0, ashift = 0;
unsigned rbits = 0, gbits = 0, bbits = 0;
BMPPalette cmapMono[2];
BMPPalette* cmap = nullptr;
@@ -607,8 +621,6 @@ bool LoadBMPData(wxImage * image, const BMPDesc& desc,
{
if ( desc.comp == BI_BITFIELDS )
{
int bit;
rmask = desc.rmask;
gmask = desc.gmask;
bmask = desc.bmask;
@@ -624,28 +636,14 @@ bool LoadBMPData(wxImage * image, const BMPDesc& desc,
amask = 0xFF000000;
ashift = 24;
}
// find shift amount (Least significant bit of mask)
for (bit = bpp-1; bit>=0; bit--)
{
if (bmask & (1 << bit))
bshift = bit;
if (gmask & (1 << bit))
gshift = bit;
if (rmask & (1 << bit))
rshift = bit;
}
}
else if ( bpp == 16 )
{
rmask = 0x7C00;
gmask = 0x03E0;
bmask = 0x001F;
rshift = 10;
gshift = 5;
bshift = 0;
}
else if ( bpp == 32 )
else // bpp == 32
{
rmask = 0x00FF0000;
gmask = 0x0000FF00;
@@ -653,10 +651,23 @@ bool LoadBMPData(wxImage * image, const BMPDesc& desc,
amask = 0xFF000000;
ashift = 24;
rshift = 16;
gshift = 8;
bshift = 0;
}
// Determine shift counts and move masks to low byte,
// discarding lowest bits of any mask with more than 8 bits
for (; rmask && ((rmask & 1) == 0 || rmask > 0xff); rmask >>= 1)
rshift++;
for (; gmask && ((gmask & 1) == 0 || gmask > 0xff); gmask >>= 1)
gshift++;
for (; bmask && ((bmask & 1) == 0 || bmask > 0xff); bmask >>= 1)
bshift++;
// Count mask bits
for (; rmask; rmask >>= 1)
rbits++;
for (; gmask; gmask >>= 1)
gbits++;
for (; bmask; bmask >>= 1)
bbits++;
}
// RLE-compressed bitmaps do not necessarily specify every pixel explicitly,
@@ -918,20 +929,15 @@ bool LoadBMPData(wxImage * image, const BMPDesc& desc,
}
else if ( bpp == 16 )
{
unsigned char temp;
wxUint16 aWord;
if ( !stream.ReadAll(&aWord, 2) )
return false;
wxUINT16_SWAP_ON_BE_IN_PLACE(aWord);
linepos += 2;
// scale color components to 8 bits
temp = rmask ? (aWord & rmask) * 255 / rmask : 0;
ptr[poffset] = temp;
temp = gmask ? (aWord & gmask) * 255 / gmask : 0;
ptr[poffset + 1] = temp;
temp = bmask ? (aWord & bmask) * 255 / bmask : 0;
ptr[poffset + 2] = temp;
ptr[poffset ] = UpscaleTo8Bits(aWord >> rshift, rbits);
ptr[poffset + 1] = UpscaleTo8Bits(aWord >> gshift, gbits);
ptr[poffset + 2] = UpscaleTo8Bits(aWord >> bshift, bbits);
column++;
}
else
@@ -943,12 +949,9 @@ bool LoadBMPData(wxImage * image, const BMPDesc& desc,
wxUINT32_SWAP_ON_BE_IN_PLACE(aDword);
linepos += 4;
temp = (unsigned char)((aDword & rmask) >> rshift);
ptr[poffset] = temp;
temp = (unsigned char)((aDword & gmask) >> gshift);
ptr[poffset + 1] = temp;
temp = (unsigned char)((aDword & bmask) >> bshift);
ptr[poffset + 2] = temp;
ptr[poffset ] = UpscaleTo8Bits(aDword >> rshift, rbits);
ptr[poffset + 1] = UpscaleTo8Bits(aDword >> gshift, gbits);
ptr[poffset + 2] = UpscaleTo8Bits(aDword >> bshift, bbits);
if ( alpha )
{
temp = (unsigned char)((aDword & amask) >> ashift);
+1 -1
View File
@@ -599,7 +599,7 @@ data-image-sample:
data-images:
@mkdir -p image
@for f in bitfields.bmp bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp 32bpp_rgb.bmp 32bpp_rgb.ico 32bpp_rgb_a0.ico badrle4.bmp rgb16-3103.bmp rle4-delta-320x240.bmp rle8-delta-320x240.bmp rle8-delta-320x240-expected.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png width-times-height-overflow.bmp width_height_32_bit_overflow.pgm bad_truncated.gif; do \
@for f in bitfields.bmp bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp 32bpp_rgb.bmp 32bpp_rgb.ico 32bpp_rgb_a0.ico badrle4.bmp rgb16-3103.bmp rgb32-7187.bmp rle4-delta-320x240.bmp rle8-delta-320x240.bmp rle8-delta-320x240-expected.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png width-times-height-overflow.bmp width_height_32_bit_overflow.pgm bad_truncated.gif; do \
if test ! -f image/$$f -a ! -d image/$$f ; \
then x=yep ; \
else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \
+2 -5
View File
@@ -1409,6 +1409,8 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BMPLoadMethod", "[image][bmp]")
CompareBMPImageLoad("image/horse_grey.bmp");
CompareBMPImageLoad("image/horse_rle8.bmp");
CompareBMPImageLoad("image/horse_rle4.bmp");
CompareBMPImageLoad("image/rgb16-3103.bmp");
CompareBMPImageLoad("image/rgb32-7187.bmp");
CompareBMPImageLoad("image/rle8-delta-320x240.bmp",
wxIMAGE_HAVE_DELTA_RLE_BITMAP);
CompareBMPImageLoad("image/rle4-delta-320x240.bmp",
@@ -1647,11 +1649,6 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BMP", "[image][bmp]")
REQUIRE(image.LoadFile("image/32bpp_rgb_a0.ico", wxBITMAP_TYPE_ICO));
REQUIRE_FALSE(image.GetAlpha());
}
SECTION("bitfields")
{
REQUIRE(image.LoadFile("image/rgb16-3103.bmp", wxBITMAP_TYPE_BMP));
REQUIRE(image.GetData()[0] == 0xff);
}
}
TEST_CASE_METHOD(ImageHandlersInit, "wxImage::Paste", "[image][paste]")
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

+1 -1
View File
@@ -574,7 +574,7 @@ data-image-sample:
data-images:
if not exist image mkdir image
for %%f in (bitfields.bmp bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp 32bpp_rgb.bmp 32bpp_rgb.ico 32bpp_rgb_a0.ico badrle4.bmp rgb16-3103.bmp rle4-delta-320x240.bmp rle8-delta-320x240.bmp rle8-delta-320x240-expected.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png width-times-height-overflow.bmp width_height_32_bit_overflow.pgm bad_truncated.gif) do if not exist image\%%f copy .\image\%%f image
for %%f in (bitfields.bmp bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp 32bpp_rgb.bmp 32bpp_rgb.ico 32bpp_rgb_a0.ico badrle4.bmp rgb16-3103.bmp rgb32-7187.bmp rle4-delta-320x240.bmp rle8-delta-320x240.bmp rle8-delta-320x240-expected.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png width-times-height-overflow.bmp width_height_32_bit_overflow.pgm bad_truncated.gif) do if not exist image\%%f copy .\image\%%f image
en_GB:
if not exist $(OBJS)\intl\en_GB mkdir $(OBJS)\intl\en_GB
+1 -1
View File
@@ -875,7 +875,7 @@ data-image-sample:
data-images:
if not exist image mkdir image
for %f in (bitfields.bmp bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp 32bpp_rgb.bmp 32bpp_rgb.ico 32bpp_rgb_a0.ico badrle4.bmp rgb16-3103.bmp rle4-delta-320x240.bmp rle8-delta-320x240.bmp rle8-delta-320x240-expected.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png width-times-height-overflow.bmp width_height_32_bit_overflow.pgm bad_truncated.gif) do if not exist image\%f copy .\image\%f image
for %f in (bitfields.bmp bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp 32bpp_rgb.bmp 32bpp_rgb.ico 32bpp_rgb_a0.ico badrle4.bmp rgb16-3103.bmp rgb32-7187.bmp rle4-delta-320x240.bmp rle8-delta-320x240.bmp rle8-delta-320x240-expected.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png width-times-height-overflow.bmp width_height_32_bit_overflow.pgm bad_truncated.gif) do if not exist image\%f copy .\image\%f image
en_GB:
if not exist $(OBJS)\intl\en_GB mkdir $(OBJS)\intl\en_GB
+1
View File
@@ -384,6 +384,7 @@
32bpp_rgb_a0.ico
badrle4.bmp
rgb16-3103.bmp
rgb32-7187.bmp
rle4-delta-320x240.bmp
rle8-delta-320x240.bmp
rle8-delta-320x240-expected.bmp