From: Dimitri Schoolwerth Date: Wed, 17 Aug 2011 21:01:09 +0000 (+0000) Subject: Improved BMP decoding. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/d06c3098ab6add89fbee763416d5e5546c66fe23 Improved BMP decoding. The BMP decoder did not handle images that are not stored upside down but straight up (in which case the height is negative). Also with RLE4 or RLE8 compressed images the 'end of scanline' RLE marker was not handled correctly. Fixed the issues and added a unit test for them. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68766 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index 631130805c..f3c7f8c040 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -533,6 +533,14 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, wxON_BLOCK_EXIT1(&BMPPalette::Free, cmap); + bool isUpsideDown = true; + + if (height < 0) + { + isUpsideDown = false; + height = -height; + } + // destroy existing here instead of: image->Destroy(); image->Create(width, height); @@ -702,9 +710,10 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, // this case (see #10915) bool hasValidAlpha = false; - /* BMPs are stored upside down */ - for ( int line = (height - 1); line >= 0; line-- ) + for ( int row = 0; row < height; row++ ) { + int line = isUpsideDown ? height - 1 - row : row; + int linepos = 0; for ( int column = 0; column < width ; ) { @@ -734,21 +743,24 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, { if ( aByte == 0 ) { - if ( column > 0 ) - column = width; + // end of scanline marker + column = width; + row--; } else if ( aByte == 1 ) { + // end of RLE data marker, stop decoding column = width; - line = -1; + row = height; } else if ( aByte == 2 ) { + // delta marker, move in image aByte = stream.GetC(); column += aByte; linepos = column * bpp / 4; aByte = stream.GetC(); - line -= aByte; // upside down + row += aByte; // upside down } else { @@ -817,20 +829,24 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, { if ( aByte == 0 ) { - /* column = width; */ + // end of scanline marker + column = width; + row--; } else if ( aByte == 1 ) { + // end of RLE data marker, stop decoding column = width; - line = -1; + row = height; } else if ( aByte == 2 ) { + // delta marker, move in image aByte = stream.GetC(); column += aByte; linepos = column * bpp / 8; aByte = stream.GetC(); - line += aByte; + row -= aByte; } else { diff --git a/tests/image/horse_grey.bmp b/tests/image/horse_grey.bmp new file mode 100644 index 0000000000..b99ffd63ba Binary files /dev/null and b/tests/image/horse_grey.bmp differ diff --git a/tests/image/horse_grey_flipped.bmp b/tests/image/horse_grey_flipped.bmp new file mode 100644 index 0000000000..7cd67f3cb3 Binary files /dev/null and b/tests/image/horse_grey_flipped.bmp differ diff --git a/tests/image/horse_rle4.bmp b/tests/image/horse_rle4.bmp new file mode 100644 index 0000000000..bdc43a1f36 Binary files /dev/null and b/tests/image/horse_rle4.bmp differ diff --git a/tests/image/horse_rle4_flipped.bmp b/tests/image/horse_rle4_flipped.bmp new file mode 100644 index 0000000000..6f23188428 Binary files /dev/null and b/tests/image/horse_rle4_flipped.bmp differ diff --git a/tests/image/horse_rle8.bmp b/tests/image/horse_rle8.bmp new file mode 100644 index 0000000000..31dfc87571 Binary files /dev/null and b/tests/image/horse_rle8.bmp differ diff --git a/tests/image/horse_rle8_flipped.bmp b/tests/image/horse_rle8_flipped.bmp new file mode 100644 index 0000000000..bd16370397 Binary files /dev/null and b/tests/image/horse_rle8_flipped.bmp differ diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 6b98ad4f3c..ae63591d8e 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -77,6 +77,7 @@ private: CPPUNIT_TEST( ReadCorruptedTGA ); CPPUNIT_TEST( GIFComment ); CPPUNIT_TEST( DibPadding ); + CPPUNIT_TEST( BMPFlippingAndRLECompression ); CPPUNIT_TEST_SUITE_END(); void LoadFromSocketStream(); @@ -90,6 +91,7 @@ private: void ReadCorruptedTGA(); void GIFComment(); void DibPadding(); + void BMPFlippingAndRLECompression(); DECLARE_NO_COPY_CLASS(ImageTestCase) }; @@ -1262,6 +1264,26 @@ void ImageTestCase::DibPadding() CPPUNIT_ASSERT( image.SaveFile(memOut, wxBITMAP_TYPE_ICO) ); } +static void CompareBMPImage(const wxString& file1, const wxString& file2) +{ + wxImage image1(file1); + CPPUNIT_ASSERT( image1.IsOk() ); + + wxImage image2(file2); + CPPUNIT_ASSERT( image2.IsOk() ); + + CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_BMP), image1, 0, &image2); +} + +void ImageTestCase::BMPFlippingAndRLECompression() +{ + CompareBMPImage("image/horse_grey.bmp", "image/horse_grey_flipped.bmp"); + + CompareBMPImage("image/horse_rle8.bmp", "image/horse_grey.bmp"); + CompareBMPImage("image/horse_rle8.bmp", "image/horse_rle8_flipped.bmp"); + + CompareBMPImage("image/horse_rle4.bmp", "image/horse_rle4_flipped.bmp"); +} #endif //wxUSE_IMAGE