From 0985996d019d5a1b73ba1bf501cac72dbe82dbf6 Mon Sep 17 00:00:00 2001 From: David Costanzo Date: Wed, 17 Nov 2021 20:38:43 -0800 Subject: [PATCH] Fix loading of RLE bitmaps in wxBMPHandler - Fix handling of delta encoding that change vertical position - Fix handling of end-of-line encodings that are given mid-line - Removed unnecessary computation for linepos Add regression tests for the bitmaps using RLE and loading which previously didn't work correctly. Closes https://github.com/wxWidgets/wxWidgets/pull/2590 Closes #19318. --- build/cmake/tests/gui/CMakeLists.txt | 3 ++ src/common/imagbmp.cpp | 42 +++++++++++++------- tests/Makefile.in | 2 +- tests/image/image.cpp | 5 +++ tests/image/rle4-delta-320x240.bmp | Bin 0 -> 3686 bytes tests/image/rle8-delta-320x240-expected.bmp | Bin 0 -> 77962 bytes tests/image/rle8-delta-320x240.bmp | Bin 0 -> 4646 bytes tests/makefile.gcc | 2 +- tests/makefile.vc | 2 +- tests/test.bkl | 3 ++ 10 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 tests/image/rle4-delta-320x240.bmp create mode 100644 tests/image/rle8-delta-320x240-expected.bmp create mode 100644 tests/image/rle8-delta-320x240.bmp diff --git a/build/cmake/tests/gui/CMakeLists.txt b/build/cmake/tests/gui/CMakeLists.txt index d581676179..e2a988ece1 100644 --- a/build/cmake/tests/gui/CMakeLists.txt +++ b/build/cmake/tests/gui/CMakeLists.txt @@ -146,6 +146,9 @@ set(TEST_GUI_DATA horse.xpm image/8bpp-colorsused-large.bmp image/8bpp-colorsused-negative.bmp + image/rle4-delta-320x240.bmp + image/rle8-delta-320x240-expected.bmp + image/rle8-delta-320x240.bmp image/horse_grey.bmp image/horse_grey_flipped.bmp image/horse_rle4.bmp diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index ba10eb0664..1cd654f960 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -772,11 +772,15 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, if ( first == 0 ) { + // This is an escape sequence with special meaning. if ( aByte == 0 ) { // end of scanline marker - column = width; - row--; + // This is ignored if the end-of-line was + // implicitly assumed when column==width, + // in which case column is now 0. + if (column != 0) + column = width; } else if ( aByte == 1 ) { @@ -787,18 +791,23 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, else if ( aByte == 2 ) { // delta marker, move in image + + // process column offset aByte = stream.GetC(); if ( !stream.IsOk() ) return false; column += aByte; - linepos = column * bpp / 4; + + // process row offset aByte = stream.GetC(); if ( !stream.IsOk() ) return false; - row += aByte; // upside down + row += aByte; + line = isUpsideDown ? height - 1 - row : row; } else { + // absolute mode (pixels not runs) int absolute = aByte; wxUint8 nibble[2] ; int readBytes = 0 ; @@ -817,8 +826,6 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, ptr[poffset + 1] = cmap[nibble[k%2]].g; ptr[poffset + 2] = cmap[nibble[k%2]].b; column++; - if ( k % 2 ) - linepos++; } if ( readBytes & 0x01 ) { @@ -840,8 +847,6 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, ptr[poffset + 1] = cmap[nibble[l%2]].g; ptr[poffset + 2] = cmap[nibble[l%2]].b; column++; - if ( l % 2 ) - linepos++; } } } @@ -874,8 +879,11 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, if ( aByte == 0 ) { // end of scanline marker - column = width; - row--; + // This is ignored if the end-of-line was + // implicitly assumed when column==width, + // in which case column is now 0. + if (column != 0) + column = width; } else if ( aByte == 1 ) { @@ -886,22 +894,26 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, else if ( aByte == 2 ) { // delta marker, move in image + + // process column offset aByte = stream.GetC(); if ( !stream.IsOk() ) return false; column += aByte; - linepos = column * bpp / 8; + + // process row offset aByte = stream.GetC(); if ( !stream.IsOk() ) return false; - row -= aByte; + row += aByte; + line = isUpsideDown ? height - 1 - row : row; } else { + // absolute mode (pixels not runs) int absolute = aByte; for (int k = 0; k < absolute; k++) { - linepos++; aByte = stream.GetC(); if ( !stream.IsOk() ) return false; @@ -920,13 +932,13 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, } else { + // encoded mode (repeat aByte first times) for ( int l = 0; l < first && column < width; l++ ) { ptr[poffset ] = cmap[aByte].r; ptr[poffset + 1] = cmap[aByte].g; ptr[poffset + 2] = cmap[aByte].b; column++; - linepos++; } } } @@ -994,7 +1006,7 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, column++; } } - while ( (linepos < linesize) && (comp != 1) && (comp != 2) ) + while ( (linepos < linesize) && (comp != BI_RLE8) && (comp != BI_RLE4) ) { ++linepos; if ( !stream.ReadAll(&aByte, 1) ) diff --git a/tests/Makefile.in b/tests/Makefile.in index da4b85106c..61f8a5ef65 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -565,7 +565,7 @@ data: data-images: @mkdir -p image - @for f in 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.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 wx.ico 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; do \ + @for f in 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 wx.ico 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; 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/image.cpp b/tests/image/image.cpp index 711d0b105f..009e94ca48 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1355,6 +1355,11 @@ void ImageTestCase::BMPFlippingAndRLECompression() CompareBMPImage("image/horse_rle8.bmp", "image/horse_rle8_flipped.bmp"); CompareBMPImage("image/horse_rle4.bmp", "image/horse_rle4_flipped.bmp"); + + CompareBMPImage("image/rle8-delta-320x240.bmp", + "image/rle8-delta-320x240-expected.bmp"); + CompareBMPImage("image/rle4-delta-320x240.bmp", + "image/rle8-delta-320x240-expected.bmp"); } diff --git a/tests/image/rle4-delta-320x240.bmp b/tests/image/rle4-delta-320x240.bmp new file mode 100644 index 0000000000000000000000000000000000000000..78a09278704143f846a944af2d59fe8f6d75fcf5 GIT binary patch literal 3686 zcmeHKF%H5o40N2dr2~k3fr*ik5g}H_d;y_8fLHb*jQv44C(Y0fkb%)oFRm*my;^Bb zx!xZ;O7=p31TKbXf;Z%d;ioOp+h*($i$%0-@cE(`BaP!&1x#!*n4SmXfrcCAV~w;D zx(f7v(7ix+MO6epOg})TnSOb?Wf!dwrMno=}&tJd)Se}Rv z`@8LFe9h&!eeKifG#!t}{%6oN@Sk4;cfSrgO<-ez{YJ-jKh|NhWBg1T@!kL7@E18Z z5d^^dv-^Olymz5~u)5mu^`#miWPfz3V{CtG@d_K8+To$*N^E({w{4RKJ z{1&tG`D?vA$uB=~tK#&X>+gIUzuv0n)4SO3zghGhznfh5FJ5=onBP_6vB!(wc!Qmf v<(+n1d&~22>0RDAuCJXJmzR70czgdYH>&!OUw)6>wYSe2_isl6|4!f!{9XB6|LT^42_rk{_6{6BkJVDX7pm8SSC9vRSQn 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