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.
This commit is contained in:
David Costanzo
2021-11-17 20:38:43 -08:00
committed by Vadim Zeitlin
parent 94f10eba4e
commit 0985996d01
10 changed files with 41 additions and 18 deletions

View File

@@ -146,6 +146,9 @@ set(TEST_GUI_DATA
horse.xpm horse.xpm
image/8bpp-colorsused-large.bmp image/8bpp-colorsused-large.bmp
image/8bpp-colorsused-negative.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.bmp
image/horse_grey_flipped.bmp image/horse_grey_flipped.bmp
image/horse_rle4.bmp image/horse_rle4.bmp

View File

@@ -772,11 +772,15 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
if ( first == 0 ) if ( first == 0 )
{ {
// This is an escape sequence with special meaning.
if ( aByte == 0 ) if ( aByte == 0 )
{ {
// end of scanline marker // end of scanline marker
// 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; column = width;
row--;
} }
else if ( aByte == 1 ) else if ( aByte == 1 )
{ {
@@ -787,18 +791,23 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
else if ( aByte == 2 ) else if ( aByte == 2 )
{ {
// delta marker, move in image // delta marker, move in image
// process column offset
aByte = stream.GetC(); aByte = stream.GetC();
if ( !stream.IsOk() ) if ( !stream.IsOk() )
return false; return false;
column += aByte; column += aByte;
linepos = column * bpp / 4;
// process row offset
aByte = stream.GetC(); aByte = stream.GetC();
if ( !stream.IsOk() ) if ( !stream.IsOk() )
return false; return false;
row += aByte; // upside down row += aByte;
line = isUpsideDown ? height - 1 - row : row;
} }
else else
{ {
// absolute mode (pixels not runs)
int absolute = aByte; int absolute = aByte;
wxUint8 nibble[2] ; wxUint8 nibble[2] ;
int readBytes = 0 ; 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 + 1] = cmap[nibble[k%2]].g;
ptr[poffset + 2] = cmap[nibble[k%2]].b; ptr[poffset + 2] = cmap[nibble[k%2]].b;
column++; column++;
if ( k % 2 )
linepos++;
} }
if ( readBytes & 0x01 ) 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 + 1] = cmap[nibble[l%2]].g;
ptr[poffset + 2] = cmap[nibble[l%2]].b; ptr[poffset + 2] = cmap[nibble[l%2]].b;
column++; column++;
if ( l % 2 )
linepos++;
} }
} }
} }
@@ -874,8 +879,11 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
if ( aByte == 0 ) if ( aByte == 0 )
{ {
// end of scanline marker // end of scanline marker
// 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; column = width;
row--;
} }
else if ( aByte == 1 ) else if ( aByte == 1 )
{ {
@@ -886,22 +894,26 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
else if ( aByte == 2 ) else if ( aByte == 2 )
{ {
// delta marker, move in image // delta marker, move in image
// process column offset
aByte = stream.GetC(); aByte = stream.GetC();
if ( !stream.IsOk() ) if ( !stream.IsOk() )
return false; return false;
column += aByte; column += aByte;
linepos = column * bpp / 8;
// process row offset
aByte = stream.GetC(); aByte = stream.GetC();
if ( !stream.IsOk() ) if ( !stream.IsOk() )
return false; return false;
row -= aByte; row += aByte;
line = isUpsideDown ? height - 1 - row : row;
} }
else else
{ {
// absolute mode (pixels not runs)
int absolute = aByte; int absolute = aByte;
for (int k = 0; k < absolute; k++) for (int k = 0; k < absolute; k++)
{ {
linepos++;
aByte = stream.GetC(); aByte = stream.GetC();
if ( !stream.IsOk() ) if ( !stream.IsOk() )
return false; return false;
@@ -920,13 +932,13 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
} }
else else
{ {
// encoded mode (repeat aByte first times)
for ( int l = 0; l < first && column < width; l++ ) for ( int l = 0; l < first && column < width; l++ )
{ {
ptr[poffset ] = cmap[aByte].r; ptr[poffset ] = cmap[aByte].r;
ptr[poffset + 1] = cmap[aByte].g; ptr[poffset + 1] = cmap[aByte].g;
ptr[poffset + 2] = cmap[aByte].b; ptr[poffset + 2] = cmap[aByte].b;
column++; column++;
linepos++;
} }
} }
} }
@@ -994,7 +1006,7 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height,
column++; column++;
} }
} }
while ( (linepos < linesize) && (comp != 1) && (comp != 2) ) while ( (linepos < linesize) && (comp != BI_RLE8) && (comp != BI_RLE4) )
{ {
++linepos; ++linepos;
if ( !stream.ReadAll(&aByte, 1) ) if ( !stream.ReadAll(&aByte, 1) )

View File

@@ -565,7 +565,7 @@ data:
data-images: data-images:
@mkdir -p image @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 ; \ if test ! -f image/$$f -a ! -d image/$$f ; \
then x=yep ; \ then x=yep ; \
else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \ else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \

View File

@@ -1355,6 +1355,11 @@ void ImageTestCase::BMPFlippingAndRLECompression()
CompareBMPImage("image/horse_rle8.bmp", "image/horse_rle8_flipped.bmp"); CompareBMPImage("image/horse_rle8.bmp", "image/horse_rle8_flipped.bmp");
CompareBMPImage("image/horse_rle4.bmp", "image/horse_rle4_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");
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -555,7 +555,7 @@ data:
data-images: data-images:
if not exist image mkdir image if not exist image mkdir 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 if not exist image\%%f copy .\image\%%f image 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 not exist image\%%f copy .\image\%%f image
fr: fr:
if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr

View File

@@ -989,7 +989,7 @@ data:
data-images: data-images:
if not exist image mkdir image if not exist image mkdir 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 if not exist image\%f copy .\image\%f image 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 not exist image\%f copy .\image\%f image
fr: fr:
if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr

View File

@@ -351,6 +351,9 @@
<files> <files>
8bpp-colorsused-large.bmp 8bpp-colorsused-large.bmp
8bpp-colorsused-negative.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_grey.bmp horse_grey_flipped.bmp
horse_rle4.bmp horse_rle4_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp