diff --git a/Tests/LibGfx/TestImageWriter.cpp b/Tests/LibGfx/TestImageWriter.cpp index 72b90dd0fd8..c9cbd844565 100644 --- a/Tests/LibGfx/TestImageWriter.cpp +++ b/Tests/LibGfx/TestImageWriter.cpp @@ -213,7 +213,9 @@ TEST_CASE(test_webp_icc) auto sRGB_icc_data = MUST(Gfx::ICC::encode(sRGB_icc_profile)); auto rgba_bitmap = TRY_OR_FAIL(create_test_rgba_bitmap()); - auto encoded_rgba_bitmap = TRY_OR_FAIL((encode_bitmap(rgba_bitmap, Gfx::WebPEncoderOptions { .icc_data = sRGB_icc_data }))); + Gfx::WebPEncoderOptions options; + options.icc_data = sRGB_icc_data; + auto encoded_rgba_bitmap = TRY_OR_FAIL((encode_bitmap(rgba_bitmap, options))); auto decoded_rgba_plugin = TRY_OR_FAIL(Gfx::WebPImageDecoderPlugin::create(encoded_rgba_bitmap)); expect_bitmaps_equal(*TRY_OR_FAIL(expect_single_frame_of_size(*decoded_rgba_plugin, rgba_bitmap->size())), rgba_bitmap); diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp index a7e012dba99..2a3287bf31b 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp @@ -14,7 +14,6 @@ #include #include #include -#include namespace Gfx { @@ -183,7 +182,7 @@ ErrorOr WebPWriter::encode(Stream& stream, Bitmap const& bitmap, Options c { // The chunk headers need to know their size, so we either need a SeekableStream or need to buffer the data. We're doing the latter. bool is_fully_opaque; - auto vp8l_data_bytes = TRY(compress_VP8L_image_data(bitmap, is_fully_opaque)); + auto vp8l_data_bytes = TRY(compress_VP8L_image_data(bitmap, options.vp8l_options, is_fully_opaque)); bool alpha_is_used_hint = !is_fully_opaque; dbgln_if(WEBP_DEBUG, "Writing WebP of size {} with alpha hint: {}", bitmap.size(), alpha_is_used_hint); @@ -216,10 +215,11 @@ ErrorOr WebPWriter::encode(Stream& stream, Bitmap const& bitmap, Options c class WebPAnimationWriter : public AnimationWriter { public: - WebPAnimationWriter(SeekableStream& stream, IntSize dimensions, u8 original_vp8x_flags) + WebPAnimationWriter(SeekableStream& stream, IntSize dimensions, u8 original_vp8x_flags, VP8LEncoderOptions vp8l_options) : m_stream(stream) , m_dimensions(dimensions) , m_vp8x_flags(original_vp8x_flags) + , m_vp8l_options(vp8l_options) { } @@ -232,6 +232,7 @@ private: SeekableStream& m_stream; IntSize m_dimensions; u8 m_vp8x_flags { 0 }; + VP8LEncoderOptions m_vp8l_options; }; static ErrorOr align_to_two(SeekableStream& stream) @@ -307,7 +308,7 @@ ErrorOr WebPAnimationWriter::add_frame(Bitmap& bitmap, int duration_ms, In // compress the frame data directly to the stream, and then go back and update the two sizes. // That's pretty messy though, and the compressed image data is smaller than the uncompressed bitmap passed in. So we'll buffer it. bool is_fully_opaque; - auto vp8l_data_bytes = TRY(compress_VP8L_image_data(bitmap, is_fully_opaque)); + auto vp8l_data_bytes = TRY(compress_VP8L_image_data(bitmap, m_vp8l_options, is_fully_opaque)); ANMFChunkHeader chunk; chunk.frame_x = static_cast(at.x()); @@ -387,7 +388,7 @@ ErrorOr> WebPWriter::start_encoding_animation(See TRY(write_ANIM_chunk(stream, { .background_color = background_color.value(), .loop_count = static_cast(loop_count) })); - auto writer = make(stream, dimensions, vp8x_flags_from_header(vp8x_header)); + auto writer = make(stream, dimensions, vp8x_flags_from_header(vp8x_header), options.vp8l_options); TRY(writer->update_size_in_header()); return writer; } diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.h b/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.h index 1ecaaa5994e..64062ce74b1 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.h +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPWriter.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace Gfx { @@ -16,6 +17,7 @@ namespace Gfx { class AnimationWriter; struct WebPEncoderOptions { + VP8LEncoderOptions vp8l_options; Optional icc_data; }; diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp index 70fc0e9c5e9..db8b1b0e1ec 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp @@ -411,13 +411,14 @@ static ErrorOr> maybe_write_color_indexing_transform(Littl return new_bitmap; } -static ErrorOr write_VP8L_image_data(Stream& stream, NonnullRefPtr bitmap, IsOpaque& is_fully_opaque) +static ErrorOr write_VP8L_image_data(Stream& stream, NonnullRefPtr bitmap, VP8LEncoderOptions const& options, IsOpaque& is_fully_opaque) { LittleEndianOutputBitStream bit_stream { MaybeOwned(stream) }; // image-stream = optional-transform spatially-coded-image // optional-transform = (%b1 transform optional-transform) / %b0 - bitmap = TRY(maybe_write_color_indexing_transform(bit_stream, bitmap, is_fully_opaque)); + if (options.allowed_transforms & (1u << COLOR_INDEXING_TRANSFORM)) + bitmap = TRY(maybe_write_color_indexing_transform(bit_stream, bitmap, is_fully_opaque)); TRY(bit_stream.write_bits(0u, 1u)); // No further transforms for now. TRY(write_VP8L_coded_image(ImageKind::SpatiallyCoded, bit_stream, *bitmap, is_fully_opaque)); @@ -429,11 +430,11 @@ static ErrorOr write_VP8L_image_data(Stream& stream, NonnullRefPtr return {}; } -ErrorOr compress_VP8L_image_data(Bitmap const& bitmap, bool& is_fully_opaque) +ErrorOr compress_VP8L_image_data(Bitmap const& bitmap, VP8LEncoderOptions const& options, bool& is_fully_opaque) { AllocatingMemoryStream vp8l_data_stream; IsOpaque is_opaque_struct; - TRY(write_VP8L_image_data(vp8l_data_stream, bitmap, is_opaque_struct)); + TRY(write_VP8L_image_data(vp8l_data_stream, bitmap, options, is_opaque_struct)); VERIFY(is_opaque_struct.is_opacity_known); is_fully_opaque = is_opaque_struct.is_fully_opaque; return vp8l_data_stream.read_until_eof(); diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.h b/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.h index bba42f9046e..035765696bc 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.h +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.h @@ -11,6 +11,11 @@ namespace Gfx { -ErrorOr compress_VP8L_image_data(Bitmap const&, bool& is_fully_opaque); +struct VP8LEncoderOptions { + // For each TransformType, set bit `1 << transform_type` if that transform type is allowed. + unsigned allowed_transforms { 0xf }; +}; + +ErrorOr compress_VP8L_image_data(Bitmap const&, VP8LEncoderOptions const&, bool& is_fully_opaque); }