mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:48:14 +00:00
LibGfx: Implement COLOR_TRANSFORM for webp lossless decoder
This commit is contained in:
parent
ebbe4dafa1
commit
55b2977d5d
1 changed files with 81 additions and 1 deletions
|
@ -923,6 +923,85 @@ ARGB32 PredictorTransform::inverse_transform(ARGB32 pixel, ARGB32 prediction)
|
|||
.value();
|
||||
}
|
||||
|
||||
// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#42_color_transform
|
||||
class ColorTransform : public Transform {
|
||||
public:
|
||||
static ErrorOr<NonnullOwnPtr<ColorTransform>> read(WebPLoadingContext&, LittleEndianInputBitStream&, IntSize const& image_size);
|
||||
virtual ErrorOr<void> transform(Bitmap&) override;
|
||||
|
||||
private:
|
||||
ColorTransform(int size_bits, NonnullRefPtr<Bitmap> color_bitmap)
|
||||
: m_size_bits(size_bits)
|
||||
, m_color_bitmap(move(color_bitmap))
|
||||
{
|
||||
}
|
||||
|
||||
static i8 ColorTransformDelta(i8 transform, i8 color)
|
||||
{
|
||||
return (transform * color) >> 5;
|
||||
}
|
||||
|
||||
static ARGB32 inverse_transform(ARGB32 pixel, ARGB32 transform);
|
||||
|
||||
int m_size_bits;
|
||||
NonnullRefPtr<Bitmap> m_color_bitmap;
|
||||
};
|
||||
|
||||
ErrorOr<NonnullOwnPtr<ColorTransform>> ColorTransform::read(WebPLoadingContext& context, LittleEndianInputBitStream& bit_stream, IntSize const& image_size)
|
||||
{
|
||||
// color-image = 3BIT ; sub-pixel code
|
||||
// entropy-coded-image
|
||||
int size_bits = TRY(bit_stream.read_bits(3)) + 2;
|
||||
int block_size = 1 << size_bits;
|
||||
IntSize color_image_size { ceil_div(image_size.width(), block_size), ceil_div(image_size.height(), block_size) };
|
||||
|
||||
auto color_bitmap = TRY(decode_webp_chunk_VP8L_image(context, ImageKind::EntropyCoded, BitmapFormat::BGRx8888, color_image_size, bit_stream));
|
||||
|
||||
return adopt_nonnull_own_or_enomem(new (nothrow) ColorTransform(size_bits, move(color_bitmap)));
|
||||
}
|
||||
|
||||
ErrorOr<void> ColorTransform::transform(Bitmap& bitmap)
|
||||
{
|
||||
for (int y = 0; y < bitmap.height(); ++y) {
|
||||
ARGB32* bitmap_scanline = bitmap.scanline(y);
|
||||
|
||||
int color_y = y >> m_size_bits;
|
||||
ARGB32* color_scanline = m_color_bitmap->scanline(color_y);
|
||||
|
||||
for (int x = 0; x < bitmap.width(); ++x) {
|
||||
int color_x = x >> m_size_bits;
|
||||
bitmap_scanline[x] = inverse_transform(bitmap_scanline[x], color_scanline[color_x]);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ARGB32 ColorTransform::inverse_transform(ARGB32 pixel, ARGB32 transform)
|
||||
{
|
||||
// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#51_roles_of_image_data
|
||||
// "Each ColorTransformElement 'cte' is treated as a pixel whose alpha component is 255,
|
||||
// red component is cte.red_to_blue, green component is cte.green_to_blue
|
||||
// and blue component is cte.green_to_red."
|
||||
auto transform_color = Color::from_argb(transform);
|
||||
i8 red_to_blue = static_cast<i8>(transform_color.red());
|
||||
i8 green_to_blue = static_cast<i8>(transform_color.green());
|
||||
i8 green_to_red = static_cast<i8>(transform_color.blue());
|
||||
|
||||
auto pixel_color = Color::from_argb(pixel);
|
||||
|
||||
// "Transformed values of red and blue components"
|
||||
int tmp_red = pixel_color.red();
|
||||
int green = pixel_color.green();
|
||||
int tmp_blue = pixel_color.blue();
|
||||
|
||||
// "Applying the inverse transform is just adding the color transform deltas"
|
||||
tmp_red += ColorTransformDelta(green_to_red, green);
|
||||
tmp_blue += ColorTransformDelta(green_to_blue, green);
|
||||
tmp_blue += ColorTransformDelta(red_to_blue, tmp_red & 0xff);
|
||||
|
||||
return Color(tmp_red & 0xff, green, tmp_blue & 0xff, pixel_color.alpha()).value();
|
||||
}
|
||||
|
||||
// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#43_subtract_green_transform
|
||||
class SubtractGreenTransform : public Transform {
|
||||
public:
|
||||
|
@ -1005,7 +1084,8 @@ static ErrorOr<void> decode_webp_chunk_VP8L(WebPLoadingContext& context, Chunk c
|
|||
TRY(transforms.try_append(TRY(PredictorTransform::read(context, bit_stream, context.size.value()))));
|
||||
break;
|
||||
case COLOR_TRANSFORM:
|
||||
return context.error("WebPImageDecoderPlugin: VP8L COLOR_TRANSFORM handling not yet implemented");
|
||||
TRY(transforms.try_append(TRY(ColorTransform::read(context, bit_stream, context.size.value()))));
|
||||
break;
|
||||
case SUBTRACT_GREEN_TRANSFORM:
|
||||
TRY(transforms.try_append(TRY(try_make<SubtractGreenTransform>())));
|
||||
break;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue