diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index d58797273ff..a723775c309 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -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(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) diff --git a/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp index 4937ffff7cb..53783df6cb9 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -67,6 +68,7 @@ struct PNGLoadingContext { RefPtr decoded_frame_bitmap; ErrorOr read_frames(png_structp, png_infop); + ErrorOr apply_exif_orientation(); }; ErrorOr> PNGImageDecoderPlugin::create(ReadonlyBytes bytes) @@ -196,10 +198,40 @@ ErrorOr 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 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> 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());