mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
LibGfx: Apply Exif orientation for PNG images
Fixes wpt/png/exif-chunk.html. At some point there should probably be some mechanism to handle this outside of the individual decoder plugins. The TIFF decoder seems to have its own version of this, and as far as I can tell, the JPEG decoder doesn't handle this at all, even though that's probably the most common use case for Exif orientations. :^)
This commit is contained in:
parent
120bc52f23
commit
144907f5bd
Notes:
github-actions[bot]
2024-10-31 02:19:07 +00:00
Author: https://github.com/justus2510 Commit: https://github.com/LadybirdBrowser/ladybird/commit/144907f5bd9 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1821 Reviewed-by: https://github.com/tcl3 ✅
2 changed files with 36 additions and 1 deletions
|
@ -345,10 +345,13 @@ TEST_CASE(test_exif)
|
|||
EXPECT(Gfx::PNGImageDecoderPlugin::sniff(file->bytes()));
|
||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::PNGImageDecoderPlugin::create(file->bytes()));
|
||||
|
||||
TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 100, 200 }));
|
||||
auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 200, 100 }));
|
||||
EXPECT(plugin_decoder->metadata().has_value());
|
||||
auto const& exif_metadata = static_cast<Gfx::ExifMetadata const&>(plugin_decoder->metadata().value());
|
||||
EXPECT_EQ(*exif_metadata.orientation(), Gfx::TIFF::Orientation::Rotate90Clockwise);
|
||||
|
||||
EXPECT_EQ(frame.image->get_pixel(65, 70), Gfx::Color(0, 255, 0));
|
||||
EXPECT_EQ(frame.image->get_pixel(190, 10), Gfx::Color(255, 0, 0));
|
||||
}
|
||||
|
||||
TEST_CASE(test_png_malformed_frame)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/DeprecatedPainter.h>
|
||||
#include <LibGfx/ImageFormats/ExifOrientedBitmap.h>
|
||||
#include <LibGfx/ImageFormats/PNGLoader.h>
|
||||
#include <LibGfx/ImageFormats/TIFFLoader.h>
|
||||
#include <LibGfx/ImageFormats/TIFFMetadata.h>
|
||||
|
@ -67,6 +68,7 @@ struct PNGLoadingContext {
|
|||
RefPtr<Gfx::Bitmap> decoded_frame_bitmap;
|
||||
|
||||
ErrorOr<size_t> read_frames(png_structp, png_infop);
|
||||
ErrorOr<void> apply_exif_orientation();
|
||||
};
|
||||
|
||||
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> PNGImageDecoderPlugin::create(ReadonlyBytes bytes)
|
||||
|
@ -196,10 +198,40 @@ ErrorOr<bool> PNGImageDecoderPlugin::initialize()
|
|||
m_context->exif_metadata = TRY(TIFFImageDecoderPlugin::read_exif_metadata({ exif_data, exif_length }));
|
||||
}
|
||||
|
||||
if (m_context->exif_metadata) {
|
||||
if (auto result = m_context->apply_exif_orientation(); result.is_error())
|
||||
dbgln("Could not apply eXIf chunk orientation for PNG: {}", result.error());
|
||||
}
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> PNGLoadingContext::apply_exif_orientation()
|
||||
{
|
||||
auto orientation = exif_metadata->orientation().value_or(TIFF::Orientation::Default);
|
||||
if (orientation == TIFF::Orientation::Default)
|
||||
return {};
|
||||
|
||||
for (auto& img_frame_descriptor : frame_descriptors) {
|
||||
auto& img = img_frame_descriptor.image;
|
||||
auto oriented_bmp = TRY(ExifOrientedBitmap::create(orientation, img->size(), img->format()));
|
||||
|
||||
for (int y = 0; y < img->size().height(); ++y) {
|
||||
for (int x = 0; x < img->size().width(); ++x) {
|
||||
auto pixel = img->get_pixel(x, y);
|
||||
oriented_bmp.set_pixel(x, y, pixel.value());
|
||||
}
|
||||
}
|
||||
|
||||
img_frame_descriptor.image = oriented_bmp.bitmap();
|
||||
}
|
||||
|
||||
size = ExifOrientedBitmap::oriented_size(size, orientation);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static ErrorOr<NonnullRefPtr<Bitmap>> render_animation_frame(AnimationFrame const& prev_animation_frame, AnimationFrame const& animation_frame, Bitmap const& decoded_frame_bitmap)
|
||||
{
|
||||
auto rendered_bitmap = TRY(prev_animation_frame.bitmap->clone());
|
||||
|
|
Loading…
Reference in a new issue