1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 11:07:45 +00:00

LibGfx: Don't mix up red/blue channels when blitting RGBA8888 bitmap

This makes CanvasRenderingContext2D.putImageData() actually paint the
right colors into the canvas.
This commit is contained in:
Andreas Kling 2022-03-06 00:14:34 +01:00
parent 72689ce7bd
commit 9fa78b1a05

View file

@ -769,8 +769,21 @@ struct BlitState {
int row_count; int row_count;
int column_count; int column_count;
float opacity; float opacity;
BitmapFormat src_format;
}; };
// FIXME: This is a hack to support blit_with_opacity() with RGBA8888 source.
// Ideally we'd have a more generic solution that allows any source format.
static void swap_red_and_blue_channels(Color& color)
{
u32 rgba = color.value();
u32 bgra = (rgba & 0xff00ff00)
| ((rgba & 0x000000ff) << 16)
| ((rgba & 0x00ff0000) >> 16);
color = Color::from_argb(bgra);
}
// FIXME: This function is very unoptimized.
template<BlitState::AlphaState has_alpha> template<BlitState::AlphaState has_alpha>
static void do_blit_with_opacity(BlitState& state) static void do_blit_with_opacity(BlitState& state)
{ {
@ -779,11 +792,15 @@ static void do_blit_with_opacity(BlitState& state)
Color dest_color = (has_alpha & BlitState::DstAlpha) ? Color::from_argb(state.dst[x]) : Color::from_rgb(state.dst[x]); Color dest_color = (has_alpha & BlitState::DstAlpha) ? Color::from_argb(state.dst[x]) : Color::from_rgb(state.dst[x]);
if constexpr (has_alpha & BlitState::SrcAlpha) { if constexpr (has_alpha & BlitState::SrcAlpha) {
Color src_color_with_alpha = Color::from_argb(state.src[x]); Color src_color_with_alpha = Color::from_argb(state.src[x]);
if (state.src_format == BitmapFormat::RGBA8888)
swap_red_and_blue_channels(src_color_with_alpha);
float pixel_opacity = src_color_with_alpha.alpha() / 255.0; float pixel_opacity = src_color_with_alpha.alpha() / 255.0;
src_color_with_alpha.set_alpha(255 * (state.opacity * pixel_opacity)); src_color_with_alpha.set_alpha(255 * (state.opacity * pixel_opacity));
state.dst[x] = dest_color.blend(src_color_with_alpha).value(); state.dst[x] = dest_color.blend(src_color_with_alpha).value();
} else { } else {
Color src_color_with_alpha = Color::from_rgb(state.src[x]); Color src_color_with_alpha = Color::from_rgb(state.src[x]);
if (state.src_format == BitmapFormat::RGBA8888)
swap_red_and_blue_channels(src_color_with_alpha);
src_color_with_alpha.set_alpha(state.opacity * 255); src_color_with_alpha.set_alpha(state.opacity * 255);
state.dst[x] = dest_color.blend(src_color_with_alpha).value(); state.dst[x] = dest_color.blend(src_color_with_alpha).value();
} }
@ -826,7 +843,8 @@ void Painter::blit_with_opacity(IntPoint const& position, Gfx::Bitmap const& sou
.dst_pitch = m_target->pitch() / sizeof(ARGB32), .dst_pitch = m_target->pitch() / sizeof(ARGB32),
.row_count = last_row - first_row + 1, .row_count = last_row - first_row + 1,
.column_count = last_column - first_column + 1, .column_count = last_column - first_column + 1,
.opacity = opacity .opacity = opacity,
.src_format = source.format(),
}; };
if (source.has_alpha_channel() && apply_alpha) { if (source.has_alpha_channel() && apply_alpha) {