LibGfx: Support missing pixel formats in get_pixel()

Bitmap::get_pixel() was only handling two out of the four possible pixel
formats, asserting when called with the other two. The asserting code
path was triggered when loading JPEG XL images, causing crashes on pages
like https://jpegxl.info/resources/jpeg-xl-test-page or
https://html5test.co/.
This commit is contained in:
InvalidUsernameException 2025-04-19 17:26:56 +02:00 committed by Jelle Raaijmakers
commit 578a3af87d
Notes: github-actions[bot] 2025-04-23 07:31:25 +00:00
11 changed files with 92 additions and 0 deletions

View file

@ -244,6 +244,18 @@ ALWAYS_INLINE Color Bitmap::unchecked_get_pixel<StorageFormat::BGRA8888>(int x,
return Color::from_argb(unchecked_scanline(y)[x]); return Color::from_argb(unchecked_scanline(y)[x]);
} }
template<>
ALWAYS_INLINE Color Bitmap::unchecked_get_pixel<StorageFormat::RGBx8888>(int x, int y) const
{
return Color::from_bgr(unchecked_scanline(y)[x]);
}
template<>
ALWAYS_INLINE Color Bitmap::unchecked_get_pixel<StorageFormat::RGBA8888>(int x, int y) const
{
return Color::from_abgr(unchecked_scanline(y)[x]);
}
template<StorageFormat storage_format> template<StorageFormat storage_format>
ALWAYS_INLINE Color Bitmap::get_pixel(int x, int y) const ALWAYS_INLINE Color Bitmap::get_pixel(int x, int y) const
{ {
@ -259,6 +271,10 @@ ALWAYS_INLINE Color Bitmap::get_pixel(int x, int y) const
return get_pixel<StorageFormat::BGRx8888>(x, y); return get_pixel<StorageFormat::BGRx8888>(x, y);
case StorageFormat::BGRA8888: case StorageFormat::BGRA8888:
return get_pixel<StorageFormat::BGRA8888>(x, y); return get_pixel<StorageFormat::BGRA8888>(x, y);
case StorageFormat::RGBA8888:
return get_pixel<StorageFormat::RGBA8888>(x, y);
case StorageFormat::RGBx8888:
return get_pixel<StorageFormat::RGBx8888>(x, y);
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }

View file

@ -95,6 +95,12 @@ public:
static constexpr Color from_rgb(unsigned rgb) { return Color(rgb | 0xff000000); } static constexpr Color from_rgb(unsigned rgb) { return Color(rgb | 0xff000000); }
static constexpr Color from_argb(unsigned argb) { return Color(argb); } static constexpr Color from_argb(unsigned argb) { return Color(argb); }
static constexpr Color from_abgr(unsigned abgr)
{
unsigned argb = (abgr & 0xff00ff00) | ((abgr & 0xff0000) >> 16) | ((abgr & 0xff) << 16);
return Color::from_argb(argb);
}
static constexpr Color from_bgr(unsigned bgr) { return Color::from_abgr(bgr | 0xff000000); }
static constexpr Color from_yuv(YUV const& yuv) { return from_yuv(yuv.y, yuv.u, yuv.v); } static constexpr Color from_yuv(YUV const& yuv) { return from_yuv(yuv.y, yuv.u, yuv.v); }
static constexpr Color from_yuv(float y, float u, float v) static constexpr Color from_yuv(float y, float u, float v)

View file

@ -15,6 +15,52 @@ TEST_CASE(color)
} }
} }
TEST_CASE(from_rgb)
{
EXPECT_EQ(Color(0x00, 0x00, 0xff), Color::from_rgb(0x000000ff));
EXPECT_EQ(Color(0x00, 0xff, 0x00), Color::from_rgb(0x0000ff00));
EXPECT_EQ(Color(0xff, 0x00, 0x00), Color::from_rgb(0x00ff0000));
EXPECT_EQ(Color(0x00, 0x00, 0xff), Color::from_rgb(0xff0000ff));
EXPECT_EQ(Color(0x00, 0xff, 0x00), Color::from_rgb(0xff00ff00));
EXPECT_EQ(Color(0xff, 0x00, 0x00), Color::from_rgb(0xffff0000));
EXPECT_EQ(Color(0xaa, 0xbb, 0xcc), Color::from_rgb(0x00aabbcc));
}
TEST_CASE(from_argb)
{
EXPECT_EQ(Color(0x00, 0x00, 0x00, 0xff), Color::from_argb(0xff000000));
EXPECT_EQ(Color(0x00, 0x00, 0xff, 0x00), Color::from_argb(0x000000ff));
EXPECT_EQ(Color(0x00, 0xff, 0x00, 0x00), Color::from_argb(0x0000ff00));
EXPECT_EQ(Color(0xff, 0x00, 0x00, 0x00), Color::from_argb(0x00ff0000));
EXPECT_EQ(Color(0xaa, 0xbb, 0xcc, 0xdd), Color::from_argb(0xddaabbcc));
}
TEST_CASE(from_bgr)
{
EXPECT_EQ(Color(0x00, 0x00, 0xff), Color::from_bgr(0x00ff0000));
EXPECT_EQ(Color(0x00, 0xff, 0x00), Color::from_bgr(0x0000ff00));
EXPECT_EQ(Color(0xff, 0x00, 0x00), Color::from_bgr(0x000000ff));
EXPECT_EQ(Color(0x00, 0x00, 0xff), Color::from_bgr(0xffff0000));
EXPECT_EQ(Color(0x00, 0xff, 0x00), Color::from_bgr(0xff00ff00));
EXPECT_EQ(Color(0xff, 0x00, 0x00), Color::from_bgr(0xff0000ff));
EXPECT_EQ(Color(0xaa, 0xbb, 0xcc), Color::from_bgr(0x00ccbbaa));
}
TEST_CASE(from_abgr)
{
EXPECT_EQ(Color(0x00, 0x00, 0x00, 0xff), Color::from_abgr(0xff000000));
EXPECT_EQ(Color(0x00, 0x00, 0xff, 0x00), Color::from_abgr(0x00ff0000));
EXPECT_EQ(Color(0x00, 0xff, 0x00, 0x00), Color::from_abgr(0x0000ff00));
EXPECT_EQ(Color(0xff, 0x00, 0x00, 0x00), Color::from_abgr(0x000000ff));
EXPECT_EQ(Color(0xaa, 0xbb, 0xcc, 0xdd), Color::from_abgr(0xddccbbaa));
}
TEST_CASE(all_green) TEST_CASE(all_green)
{ {
EXPECT_EQ(Color(Color::NamedColor::Green), Color::from_lab(87.8185, -79.2711, 80.9946)); EXPECT_EQ(Color(Color::NamedColor::Green), Color::from_lab(87.8185, -79.2711, 80.9946));

View file

@ -0,0 +1,4 @@
<!DOCTYPE html>
<title>JPEG XL test reference</title>
<img src="./resources/3x3_srgb_lossless.png" style="height:525px;image-rendering:crisp-edges;">

View file

@ -0,0 +1,4 @@
<!DOCTYPE html>
<title>JPEG XL test reference</title>
<img src="./resources/3x3a_srgb_lossless.png" style="height:525px;image-rendering:crisp-edges;">

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<title>JPEG XL test</title>
<meta name=fuzzy content="0-4;0-275625">
<link rel="help" href="https://jpeg.org/jpegxl/">
<link rel="match" href="../../../expected/wpt-import/jpegxl/3x3_srgb_lossless-ref.html">
<meta name="assert" content="JPEG XL image is rendered correctly">
<img src="./resources/3x3_srgb_lossless.jxl" style="height:525px;image-rendering:crisp-edges;">

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<title>JPEG XL test</title>
<meta name=fuzzy content="0-4;0-275625">
<link rel="help" href="https://jpeg.org/jpegxl/">
<link rel="match" href="../../../expected/wpt-import/jpegxl/3x3a_srgb_lossless-ref.html">
<meta name="assert" content="JPEG XL image is rendered correctly">
<img src="./resources/3x3a_srgb_lossless.jxl" style="height:525px;image-rendering:crisp-edges;">