]> git.saurik.com Git - wxWidgets.git/commitdiff
Improved BMP decoding.
authorDimitri Schoolwerth <dimitri.schoolwerth@gmail.com>
Wed, 17 Aug 2011 21:01:09 +0000 (21:01 +0000)
committerDimitri Schoolwerth <dimitri.schoolwerth@gmail.com>
Wed, 17 Aug 2011 21:01:09 +0000 (21:01 +0000)
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

src/common/imagbmp.cpp
tests/image/horse_grey.bmp [new file with mode: 0644]
tests/image/horse_grey_flipped.bmp [new file with mode: 0644]
tests/image/horse_rle4.bmp [new file with mode: 0644]
tests/image/horse_rle4_flipped.bmp [new file with mode: 0644]
tests/image/horse_rle8.bmp [new file with mode: 0644]
tests/image/horse_rle8_flipped.bmp [new file with mode: 0644]
tests/image/image.cpp

index 631130805c99d5b3246c31845a847888811f7513..f3c7f8c0407e52159932787bdc8a69a2972227e0 100644 (file)
@@ -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 (file)
index 0000000..b99ffd6
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 (file)
index 0000000..7cd67f3
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 (file)
index 0000000..bdc43a1
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 (file)
index 0000000..6f23188
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 (file)
index 0000000..31dfc87
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 (file)
index 0000000..bd16370
Binary files /dev/null and b/tests/image/horse_rle8_flipped.bmp differ
index 6b98ad4f3ce9a73ccecb7846ad62830b0d839942..ae63591d8e5a9441485956fc9ef790b0aba160b0 100644 (file)
@@ -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