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
This commit is contained in:
Dimitri Schoolwerth
2011-08-17 21:01:09 +00:00
parent ee19ab6d80
commit d06c3098ab
8 changed files with 47 additions and 9 deletions

View File

@@ -533,6 +533,14 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
wxON_BLOCK_EXIT1(&BMPPalette::Free, cmap); wxON_BLOCK_EXIT1(&BMPPalette::Free, cmap);
bool isUpsideDown = true;
if (height < 0)
{
isUpsideDown = false;
height = -height;
}
// destroy existing here instead of: // destroy existing here instead of:
image->Destroy(); image->Destroy();
image->Create(width, height); image->Create(width, height);
@@ -702,9 +710,10 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
// this case (see #10915) // this case (see #10915)
bool hasValidAlpha = false; bool hasValidAlpha = false;
/* BMPs are stored upside down */ for ( int row = 0; row < height; row++ )
for ( int line = (height - 1); line >= 0; line-- )
{ {
int line = isUpsideDown ? height - 1 - row : row;
int linepos = 0; int linepos = 0;
for ( int column = 0; column < width ; ) for ( int column = 0; column < width ; )
{ {
@@ -734,21 +743,24 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
{ {
if ( aByte == 0 ) if ( aByte == 0 )
{ {
if ( column > 0 ) // end of scanline marker
column = width; column = width;
row--;
} }
else if ( aByte == 1 ) else if ( aByte == 1 )
{ {
// end of RLE data marker, stop decoding
column = width; column = width;
line = -1; row = height;
} }
else if ( aByte == 2 ) else if ( aByte == 2 )
{ {
// delta marker, move in image
aByte = stream.GetC(); aByte = stream.GetC();
column += aByte; column += aByte;
linepos = column * bpp / 4; linepos = column * bpp / 4;
aByte = stream.GetC(); aByte = stream.GetC();
line -= aByte; // upside down row += aByte; // upside down
} }
else else
{ {
@@ -817,20 +829,24 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
{ {
if ( aByte == 0 ) if ( aByte == 0 )
{ {
/* column = width; */ // end of scanline marker
column = width;
row--;
} }
else if ( aByte == 1 ) else if ( aByte == 1 )
{ {
// end of RLE data marker, stop decoding
column = width; column = width;
line = -1; row = height;
} }
else if ( aByte == 2 ) else if ( aByte == 2 )
{ {
// delta marker, move in image
aByte = stream.GetC(); aByte = stream.GetC();
column += aByte; column += aByte;
linepos = column * bpp / 8; linepos = column * bpp / 8;
aByte = stream.GetC(); aByte = stream.GetC();
line += aByte; row -= aByte;
} }
else else
{ {

BIN
tests/image/horse_grey.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
tests/image/horse_rle4.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
tests/image/horse_rle8.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -77,6 +77,7 @@ private:
CPPUNIT_TEST( ReadCorruptedTGA ); CPPUNIT_TEST( ReadCorruptedTGA );
CPPUNIT_TEST( GIFComment ); CPPUNIT_TEST( GIFComment );
CPPUNIT_TEST( DibPadding ); CPPUNIT_TEST( DibPadding );
CPPUNIT_TEST( BMPFlippingAndRLECompression );
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
void LoadFromSocketStream(); void LoadFromSocketStream();
@@ -90,6 +91,7 @@ private:
void ReadCorruptedTGA(); void ReadCorruptedTGA();
void GIFComment(); void GIFComment();
void DibPadding(); void DibPadding();
void BMPFlippingAndRLECompression();
DECLARE_NO_COPY_CLASS(ImageTestCase) DECLARE_NO_COPY_CLASS(ImageTestCase)
}; };
@@ -1262,6 +1264,26 @@ void ImageTestCase::DibPadding()
CPPUNIT_ASSERT( image.SaveFile(memOut, wxBITMAP_TYPE_ICO) ); 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 #endif //wxUSE_IMAGE