diff --git a/build/cmake/tests/gui/CMakeLists.txt b/build/cmake/tests/gui/CMakeLists.txt index 72217949b6..9ef1076103 100644 --- a/build/cmake/tests/gui/CMakeLists.txt +++ b/build/cmake/tests/gui/CMakeLists.txt @@ -148,6 +148,7 @@ set(TEST_GUI_DATA horse.tif horse.xpm image/bitfields.bmp + image/bitfields-alpha.bmp image/8bpp-colorsused-large.bmp image/8bpp-colorsused-negative.bmp image/rle4-delta-320x240.bmp diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index 382103c523..f46ba6b284 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -510,7 +510,7 @@ struct BMPDesc wxScopedArray paletteData; - int rmask, gmask, bmask, amask; + int rmask, gmask, bmask; }; // Read the data in BMP format into the given image. @@ -620,6 +620,18 @@ bool LoadBMPData(wxImage * image, const BMPDesc& desc, gmask = desc.gmask; bmask = desc.bmask; + // Mimic Windows behaviour: alpha is applied only in 32bpp + // and if the colour masks are the same as for BI_RGB. + // Any alpha mask in the header is ignored. + if ( bpp == 32 && + rmask == 0x00FF0000 && + gmask == 0x0000FF00 && + bmask == 0x000000FF ) + { + amask = 0xFF000000; + ashift = 24; + } + // find shift amount (Least significant bit of mask) for (bit = bpp-1; bit>=0; bit--) { @@ -1207,15 +1219,18 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, if ( desc.comp == BI_BITFIELDS ) { // Read the mask values from the header. - if ( !stream.ReadAll(dbuf, 4 * 4) ) + if ( !stream.ReadAll(dbuf, 4 * 3) ) return false; - hdrBytesRead += 4 * 4; + hdrBytesRead += 4 * 3; desc.rmask = wxINT32_SWAP_ON_BE(dbuf[0]); desc.gmask = wxINT32_SWAP_ON_BE(dbuf[1]); desc.bmask = wxINT32_SWAP_ON_BE(dbuf[2]); - desc.amask = wxINT32_SWAP_ON_BE(dbuf[3]); + + // There will also be an alpha mask if (and only if) the header is + // V4 or V5, so we mustn't try to read it if we don't have one of + // those. But it's not used anywhere in any case. } // Now that we've read everything we needed from the header, advance @@ -1231,6 +1246,10 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, // bytes preceding it: "BM" signature and 3 other DWORDs. wxFileOffset bytesRead = 14 + hdrSize; + // We might have read colour masks. + if ( desc.comp == BI_BITFIELDS ) + bytesRead += 12; + // We must have a palette for 1bpp, 4bpp and 8bpp bitmaps. if (desc.ncolors == 0 && desc.bpp < 16) desc.ncolors = 1 << desc.bpp; diff --git a/src/msw/dib.cpp b/src/msw/dib.cpp index 2b390c3779..3c8cda7263 100644 --- a/src/msw/dib.cpp +++ b/src/msw/dib.cpp @@ -416,7 +416,9 @@ HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, const void *bits switch ( pbmih->biCompression ) { case BI_BITFIELDS: - numColors = 3; + // with a classic BITMAPINFOHEADER, there are 3 colour-mask DWORDs + // after the header. Otherwise the masks are part of the header + numColors = pbmih->biSize == sizeof(BITMAPINFOHEADER) ? 3 : 0; break; case BI_RGB: @@ -436,7 +438,10 @@ HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, const void *bits numColors = 0; } - bits = reinterpret_cast(pbmih + 1) + numColors * sizeof(RGBQUAD); + // pbmih->biSize might not be the same as sizeof(BITMAPINFOHEADER) + // (such as in the case of a BITMAPV4HEADER or BITMAPV5HEADER); + // we need to advance by the number of bytes actually present + bits = reinterpret_cast(pbmih) + pbmih->biSize + numColors * sizeof(RGBQUAD); } HBITMAP hbmp = ::CreateDIBitmap diff --git a/tests/Makefile.in b/tests/Makefile.in index c1aaca8f35..1adca31cda 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -582,7 +582,7 @@ data-image-sample: data-images: @mkdir -p image - @for f in bitfields.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.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; do \ + @for f in bitfields.bmp bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.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; do \ if test ! -f image/$$f -a ! -d image/$$f ; \ then x=yep ; \ else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \ diff --git a/tests/image/bitfields-alpha.bmp b/tests/image/bitfields-alpha.bmp new file mode 100644 index 0000000000..b4ad4e4928 Binary files /dev/null and b/tests/image/bitfields-alpha.bmp differ diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 4db1d30da2..bc72474000 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1331,12 +1331,20 @@ static wxImage ImageFromBMPFile(const wxString& filename) // wxDIB::ConvertToBitmap() about it because we need to test its // code path where bits==nullptr, so we just have to fail the test const BITMAPINFO* pbmi = reinterpret_cast(&buf[0]); - wxUint32 nColors = pbmi->bmiHeader.biClrUsed - ? pbmi->bmiHeader.biClrUsed - : (pbmi->bmiHeader.biBitCount <= 8 - ? 1 << pbmi->bmiHeader.biBitCount - : 0); - wxUint32 cbColorTable = nColors * sizeof(RGBQUAD); + wxUint32 numColors = 0; + if ( pbmi->bmiHeader.biCompression == BI_BITFIELDS ) + { + if ( pbmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) ) + numColors = 3; + } + else + { + if ( pbmi->bmiHeader.biClrUsed ) + numColors = pbmi->bmiHeader.biClrUsed; + else if ( pbmi->bmiHeader.biBitCount <= 8 ) + numColors = 1 << pbmi->bmiHeader.biBitCount; + } + wxUint32 cbColorTable = numColors * sizeof(RGBQUAD); size_t ofstComputed = hdrLen + pbmi->bmiHeader.biSize + cbColorTable; REQUIRE(ofstComputed == ofstDeclared); @@ -1350,7 +1358,7 @@ static wxImage ImageFromBMPFile(const wxString& filename) // Compare the results of loading a BMP via wxBMPHandler // and via Windows' own conversion (CreateDIBitmap()) -static void CompareBMPImageLoad(const wxString& filename) +static void CompareBMPImageLoad(const wxString& filename, int properties = 0) { wxImage image1 = ImageFromBMPFile(filename); REQUIRE( image1.IsOk() ); @@ -1359,11 +1367,17 @@ static void CompareBMPImageLoad(const wxString& filename) REQUIRE( image2.IsOk() ); INFO("Comparing loading methods for " << filename); - CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_BMP), image1, 0, &image2); + CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_BMP), + image1, properties, &image2); } TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BMPLoadMethod", "[image][bmp]") { + CompareBMPImageLoad("image/bitfields.bmp"); + // We would check the alpha on this one, but at the moment it fails + // because of the way CompareImage() saves and reloads images, + // which for BMPs does not preserve the alpha channel + CompareBMPImageLoad("image/bitfields-alpha.bmp"/*, wxIMAGE_HAVE_ALPHA*/); CompareBMPImageLoad("image/horse_grey.bmp"); CompareBMPImageLoad("image/horse_rle8.bmp"); CompareBMPImageLoad("image/horse_rle4.bmp"); diff --git a/tests/makefile.gcc b/tests/makefile.gcc index b72eb94599..138bf16b3b 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -552,7 +552,7 @@ data-image-sample: data-images: if not exist image mkdir image - for %%f in (bitfields.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.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) 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 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) do if not exist image\%%f copy .\image\%%f image fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr diff --git a/tests/makefile.vc b/tests/makefile.vc index 73f03802d7..3d76c9ebbb 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -845,7 +845,7 @@ data-image-sample: data-images: if not exist image mkdir image - for %f in (bitfields.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.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) 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 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) do if not exist image\%f copy .\image\%f image fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr diff --git a/tests/test.bkl b/tests/test.bkl index 5bd7328665..0b8e222333 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -354,6 +354,7 @@ image bitfields.bmp + bitfields-alpha.bmp 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp rle4-delta-320x240.bmp