LibGfx: Implement Gfx::AlphaType for SkiaPainter

Always assuming unpremultiplied color data only worked for PNGs (which
are specced as unpremultiplied) and bitmaps with alpha set to 100%.
Properly propagate the Gfx::AlphaType of a bitmap to Skia.

The reference tests were updated to reflect this change, but visually
it's practically impossible to see the difference. A new test was added
to clearly expose this issue.

Fixes #1104
This commit is contained in:
Jelle Raaijmakers 2024-08-20 12:20:19 +02:00 committed by Andreas Kling
commit bd55e85027
Notes: github-actions[bot] 2024-08-20 18:40:04 +00:00
8 changed files with 50 additions and 17 deletions

View file

@ -0,0 +1,12 @@
<link rel="match" href="reference/canvas-unpremultiplied-image-ref.html" />
<script type="module">
const canvas = document.querySelector('#canvas');
canvas.width = 100;
canvas.height = 100;
const ctx = canvas.getContext('2d');
const img = new Image();
img.addEventListener('load', () => ctx.drawImage(img, 25, 25, 50, 50));
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQIW2P43wAAAoEBgD2oaNcAAAAASUVORK5CYII=';
</script>
<canvas id="canvas" style="background-color: #f00"></canvas>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,9 @@
<style>
* {
margin: 0;
}
body {
background-color: white;
}
</style>
<img src="../images/canvas-unpremultiplied-image-ref.png">

View file

@ -28,6 +28,33 @@
namespace Gfx {
static SkColorType to_skia_color_type(Gfx::BitmapFormat format)
{
switch (format) {
case Gfx::BitmapFormat::Invalid:
return kUnknown_SkColorType;
case Gfx::BitmapFormat::BGRA8888:
case Gfx::BitmapFormat::BGRx8888:
return kBGRA_8888_SkColorType;
case Gfx::BitmapFormat::RGBA8888:
return kRGBA_8888_SkColorType;
default:
return kUnknown_SkColorType;
}
}
static SkAlphaType to_skia_alpha_type(Gfx::AlphaType alpha_type)
{
switch (alpha_type) {
case AlphaType::Premultiplied:
return kPremul_SkAlphaType;
case AlphaType::Unpremultiplied:
return kUnpremul_SkAlphaType;
default:
VERIFY_NOT_REACHED();
}
}
struct PainterSkia::Impl {
NonnullRefPtr<Gfx::Bitmap> gfx_bitmap;
OwnPtr<SkBitmap> sk_bitmap;
@ -37,7 +64,7 @@ struct PainterSkia::Impl {
: gfx_bitmap(move(target_bitmap))
{
sk_bitmap = make<SkBitmap>();
SkImageInfo info = SkImageInfo::Make(gfx_bitmap->width(), gfx_bitmap->height(), kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
SkImageInfo info = SkImageInfo::Make(gfx_bitmap->width(), gfx_bitmap->height(), to_skia_color_type(gfx_bitmap->format()), to_skia_alpha_type(gfx_bitmap->alpha_type()));
sk_bitmap->installPixels(info, gfx_bitmap->scanline(0), gfx_bitmap->pitch());
sk_canvas = make<SkCanvas>(*sk_bitmap);
@ -109,25 +136,10 @@ static SkSamplingOptions to_skia_sampling_options(Gfx::ScalingMode scaling_mode)
}
}
static SkColorType to_skia_color_type(Gfx::BitmapFormat format)
{
switch (format) {
case Gfx::BitmapFormat::Invalid:
return kUnknown_SkColorType;
case Gfx::BitmapFormat::BGRA8888:
case Gfx::BitmapFormat::BGRx8888:
return kBGRA_8888_SkColorType;
case Gfx::BitmapFormat::RGBA8888:
return kRGBA_8888_SkColorType;
default:
return kUnknown_SkColorType;
}
}
void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, float global_alpha)
{
SkBitmap sk_bitmap;
SkImageInfo info = SkImageInfo::Make(src_bitmap.width(), src_bitmap.height(), to_skia_color_type(src_bitmap.format()), kUnpremul_SkAlphaType);
SkImageInfo info = SkImageInfo::Make(src_bitmap.width(), src_bitmap.height(), to_skia_color_type(src_bitmap.format()), to_skia_alpha_type(src_bitmap.alpha_type()));
sk_bitmap.installPixels(info, const_cast<void*>(static_cast<void const*>(src_bitmap.scanline(0))), src_bitmap.pitch());
SkPaint paint;