From 4ef76f3198dbbf4eb9d3f71a79ea4822ebf806b4 Mon Sep 17 00:00:00 2001 From: doctortheemh Date: Sat, 6 Jul 2024 00:33:38 -0700 Subject: [PATCH] LibGfx: Decode AVIF images Use libavif to decode AVIF images in LibGfx. --- .github/actions/setup/action.yml | 4 +- Tests/LibGfx/TestImageDecoder.cpp | 62 ++++++ .../LibGfx/test-inputs/avif/icc_profile.avif | Bin 0 -> 5965 bytes .../test-inputs/avif/simple-bitdepth10.avif | Bin 0 -> 1063 bytes .../test-inputs/avif/simple-lossless.avif | Bin 0 -> 64011 bytes .../LibGfx/test-inputs/avif/simple-lossy.avif | Bin 0 -> 1134 bytes Userland/Libraries/LibGfx/CMakeLists.txt | 4 +- .../LibGfx/ImageFormats/AVIFLoader.cpp | 196 ++++++++++++++++++ .../LibGfx/ImageFormats/AVIFLoader.h | 38 ++++ .../LibGfx/ImageFormats/ImageDecoder.cpp | 2 + vcpkg.json | 10 + 11 files changed, 313 insertions(+), 3 deletions(-) create mode 100755 Tests/LibGfx/test-inputs/avif/icc_profile.avif create mode 100644 Tests/LibGfx/test-inputs/avif/simple-bitdepth10.avif create mode 100644 Tests/LibGfx/test-inputs/avif/simple-lossless.avif create mode 100644 Tests/LibGfx/test-inputs/avif/simple-lossy.avif create mode 100644 Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.cpp create mode 100644 Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.h diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index fd0d2ee372..4b6ad27c6f 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -26,7 +26,7 @@ runs: sudo apt-get update sudo apt-get install autoconf autoconf-archive automake build-essential cmake libavcodec-dev fonts-liberation2 zip curl tar ccache clang-18 clang++-18 lld-18 gcc-13 g++-13 libstdc++-13-dev \ - ninja-build unzip qt6-base-dev qt6-tools-dev-tools libqt6svg6-dev qt6-multimedia-dev libgl1-mesa-dev libpulse-dev libssl-dev libegl1-mesa-dev + ninja-build unzip qt6-base-dev qt6-tools-dev-tools libqt6svg6-dev qt6-multimedia-dev libgl1-mesa-dev libpulse-dev libssl-dev libegl1-mesa-dev nasm sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100 sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100 @@ -52,7 +52,7 @@ runs: set -e sudo xcode-select --switch /Applications/Xcode_15.4.app brew update - brew install autoconf autoconf-archive automake coreutils bash ffmpeg ninja wabt ccache unzip qt llvm@18 + brew install autoconf autoconf-archive automake coreutils bash ffmpeg ninja wabt ccache unzip qt llvm@18 nasm - name: 'Install vcpkg' shell: bash diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index 6d2bcb4433..d5c68c4a66 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -1007,3 +1008,64 @@ TEST_CASE(test_jxl_modular_property_8) } } } + +TEST_CASE(test_avif_simple_lossy) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("avif/simple-lossy.avif"sv))); + EXPECT(Gfx::AVIFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::AVIFImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 240, 240 })); + + // While AVIF YUV contents are defined bit-exact, the YUV->RGB conversion isn't. + // So pixels changing by 1 or so below is fine if you change code. + EXPECT_EQ(frame.image->get_pixel(120, 232), Gfx::Color(0xf1, 0xef, 0xf0, 255)); + EXPECT_EQ(frame.image->get_pixel(198, 202), Gfx::Color(0x7b, 0xaa, 0xd6, 255)); +} + +TEST_CASE(test_avif_simple_lossless) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("avif/simple-lossless.avif"sv))); + EXPECT(Gfx::AVIFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::AVIFImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 386, 395 })); + EXPECT_EQ(frame.image->get_pixel(0, 0), Gfx::Color(0, 0, 0, 0)); + EXPECT_EQ(frame.image->get_pixel(289, 332), Gfx::Color(0xf2, 0xee, 0xd3, 255)); +} + +TEST_CASE(test_avif_simple_lossy_bitdepth10) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("avif/simple-bitdepth10.avif"sv))); + EXPECT(!Gfx::AVIFImageDecoderPlugin::sniff(file->bytes())); +} + +TEST_CASE(test_avif_icc_profile) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("avif/icc_profile.avif"sv))); + EXPECT(Gfx::AVIFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::AVIFImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 240, 240 })); + EXPECT(TRY_OR_FAIL(plugin_decoder->icc_data()).has_value()); +} + +TEST_CASE(test_avif_no_icc_profile) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("avif/simple-lossy.avif"sv))); + EXPECT(Gfx::AVIFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::AVIFImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 240, 240 })); + EXPECT(!TRY_OR_FAIL(plugin_decoder->icc_data()).has_value()); +} + +TEST_CASE(test_avif_frame_out_of_bounds) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("avif/simple-lossy.avif"sv))); + EXPECT(Gfx::AVIFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::AVIFImageDecoderPlugin::create(file->bytes())); + + auto frame1 = TRY_OR_FAIL(plugin_decoder->frame(0)); + EXPECT(plugin_decoder->frame(1).is_error()); +} diff --git a/Tests/LibGfx/test-inputs/avif/icc_profile.avif b/Tests/LibGfx/test-inputs/avif/icc_profile.avif new file mode 100755 index 0000000000000000000000000000000000000000..d79c6a2f1dcbdd3d660a3bb9d9b3c49b10ac2f94 GIT binary patch literal 5965 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 literal 0 HcmV?d00001 diff --git a/Tests/LibGfx/test-inputs/avif/simple-bitdepth10.avif b/Tests/LibGfx/test-inputs/avif/simple-bitdepth10.avif new file mode 100644 index 0000000000000000000000000000000000000000..ebd56a8f83509b6ff0faf902c1d606c40a716722 GIT binary patch literal 1063 zcmZQzU{FXasVqn=%S>Yc0uY^>nP!-qnV9D5Xy^zO`jnemk_eIm0*#E6oFWL5fuSHX zxdg@r(K(q(Fk|=%GD~v7a*RMyE;A=T8N_p8U|1git>_kDu5>QGO#rOg~T%pauY#vKmc?Y3nNoA3sA3UZc1W_ z5Ca#dh3xO&Hx4*EE;0Jc>XO1R$x|g@OWggNUAm{-1g~;<+AJ1toI7Qqwerl$BVPAv zR&1U1{My&a<>E%~-rp8V?e+InxHd)D`FNDYT=|X#_cXiB;$zO~DzN0Pnm2peEunnQ z2uWSO#)?Hf+jeaH^Y!++H-@_v&D8Hc;HVe*lryVk<;6Gu%)Hp<-C_K+|LMVrCp4EO zUp%UJ?^GqTWFT!?5vC92frt4zx^Zn8Hn#Q}* zHlzd{U%FN3MhJ`C$)!U1TgBF#o{-rQ^L4(|Wba!CXC*!9-gA?2Rr1GawW&*=o8P+m z$xJyjQ9rnPlG6LbZX2Eo@v=-4501R>w)}2%+h?ejiU=Ec$v zda3$Xnjdj3dGvkzo=9oyqbIGa)a73vo5<6-=xI@p?sGJS8^k)D*pii51nAPgllYS6Lr=?^aV`mb|vyFQXEh58d$_>nA>b+y9a)P~D;V*}i~GuQiH4BGzqB z-fOYPVAACe>A3|SYo6bj@Ro_?fRe}Z3lhmw9-nS4Qnk8xG)dfjnPFMr2GPAhIVXCLme*T_{_n*keFYcXm7KpB3nqny^J?ocd(!-(|PX%5* zn&=~9b9~lfqZj8ko|~~l@?zI5yF-qLmx|~2P4Y?!c1vZQyj;$t!+E*ute#s2v)!!u z?K!n)h(*2@{V>hx{QpmKPZX2YZmNCpS{^ukYUtNXcO>`Dp0xkOg zQrgax#NjsCf8)#vvX6qVim>1L8<)x&G~u|tBm3iRlYTKCY35-`Rk8ZBZAKx>V)rk) yPKP(=ZB6i4pdu8Ztr4)(X>D?CmIJGRLTKDUzOT!e9&od@Z{KEkveKoOvkm~qWwMq4 literal 0 HcmV?d00001 diff --git a/Tests/LibGfx/test-inputs/avif/simple-lossless.avif b/Tests/LibGfx/test-inputs/avif/simple-lossless.avif new file mode 100644 index 0000000000000000000000000000000000000000..66a3d864daa5d667a20270a15c6e2bd185a63dda GIT binary patch literal 64011 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%0Dp~@CBscr{p`16q;9m+$y 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 CBx0uk literal 0 HcmV?d00001 diff --git a/Tests/LibGfx/test-inputs/avif/simple-lossy.avif b/Tests/LibGfx/test-inputs/avif/simple-lossy.avif new file mode 100644 index 0000000000000000000000000000000000000000..1aaffad649e08082f3b333d9bb8b607b642c37ea GIT binary patch literal 1134 zcmZQzU{FXasVqn=%S>Yc0uY^>nP!-qnV9D5Xy^zO`jnemk_eIm0*#E6oFWL5fuSHX zxdg@r(K(q(Fk|=%GD~v7a*RMyE;A=T8N_p8U|B&nQ)=ZYH$mn3J5}#npKXk6eLnw$x_!n| z#>{1$)0C|r{$jk7zhPRIU=CCH-L1JBMI>v=T4G~dK78gfxfZD6;#p#D@-p|QB4d!_ zsts<_7g-#9BtPX_`?bDjnlUa$FXs9PWu978usd$bg1es8S<)Y7JbiC0B*1aV_JA7u z(UnU}uiRzp4lXU>P)qCei#TU_=j3$r)*m(Xa1$0_$wBn zp`DZPmg$1X^SWTpFyE7xPnPUuU|ZGr+9@#Uz0<{oa~3|9s+cMIbYIdPb}7!OcHISc zEbd>GvdxoTQ+ZR*a6w>^uhp)Kf+h|1^$)*C&0VjzCSNUZ!!e5{^K8Gh4aQM9 zh7&Hgs?M>VSz+#>$fbM9tS~4p*^=4m*ylO*&Y6e4x-Z^cJx|P3g5cVv@8@qWNj+F}FWF$bZ(7pd8M9VRS(91w@@cx2lCxBd-vZTy z51bd|MR>ZBpFO*g6c+VI(yAb8%|?k;CojYB^g!K8a|Hh{w&7qa9Y< zt(@~*=8>tk7Nh(oKi#zq>XH8?jKuD8h-$Ah`~PWy&&}1-CL29r-1yggRX*?jPm*gj zthhfp`a8YY@@wCp2}bqT81IF<>1@k0iF5h0L*-kPz{JaM4uwCLvNE61HRr?c*Y8C2 zP0UVfap^m-ZSYU(|CzL@R_c6jf=K}XZ>iMw{G>#$qxZN&MHl&t#uoBValM_gC3W}N z!Wf19Y45x=phBt<)X2DPd;L zpJs>dJ$*s=?Dy9@0*8Wfs?ss>Oen z_)XEhHi`M>*_FSIWEFHhpH$_2$k}jB?C5p2oS#4QK1^p6i)a^qvgg>p+bU^N0ViMg R{JqbgEj2wuIlnl*0RV@Q#Q*>R literal 0 HcmV?d00001 diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index 77c920428d..ee1d354bab 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -52,6 +52,7 @@ set(SOURCES ImageFormats/WebPSharedLossless.cpp ImageFormats/WebPWriter.cpp ImageFormats/WebPWriterLossless.cpp + ImageFormats/AVIFLoader.cpp ImmutableBitmap.cpp MedianCut.cpp Painter.cpp @@ -96,5 +97,6 @@ find_package(PkgConfig) pkg_check_modules(WOFF2 REQUIRED IMPORTED_TARGET libwoff2dec) find_package(JPEG REQUIRED) find_package(PNG REQUIRED) +find_package(LIBAVIF REQUIRED) -target_link_libraries(LibGfx PRIVATE PkgConfig::WOFF2 JPEG::JPEG PNG::PNG) +target_link_libraries(LibGfx PRIVATE PkgConfig::WOFF2 JPEG::JPEG PNG::PNG avif) diff --git a/Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.cpp new file mode 100644 index 0000000000..f10030bbcc --- /dev/null +++ b/Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2023, Nico Weber + * Copyright (c) 2024, doctortheemh + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include + +namespace Gfx { + +class AVIFLoadingContext { + AK_MAKE_NONMOVABLE(AVIFLoadingContext); + AK_MAKE_NONCOPYABLE(AVIFLoadingContext); + +public: + enum State { + NotDecoded = 0, + Error, + HeaderDecoded, + BitmapDecoded, + }; + + State state { State::NotDecoded }; + ReadonlyBytes data; + + avifDecoder* decoder { nullptr }; + + // image properties + Optional size; + bool has_alpha { false }; + size_t image_count { 0 }; + size_t repetition_count { 0 }; + ByteBuffer icc_data; + + Vector frame_descriptors; + + AVIFLoadingContext() = default; + ~AVIFLoadingContext() + { + avifDecoderDestroy(decoder); + decoder = nullptr; + } +}; + +AVIFImageDecoderPlugin::AVIFImageDecoderPlugin(ReadonlyBytes data, OwnPtr context) + : m_context(move(context)) +{ + m_context->data = data; +} + +AVIFImageDecoderPlugin::~AVIFImageDecoderPlugin() +{ +} + +static ErrorOr decode_avif_header(AVIFLoadingContext& context) +{ + if (context.state >= AVIFLoadingContext::HeaderDecoded) + return {}; + + if (context.decoder == nullptr) { + context.decoder = avifDecoderCreate(); + + if (context.decoder == nullptr) { + return Error::from_string_literal("failed to allocate AVIF decoder"); + } + } + + avifResult result = avifDecoderSetIOMemory(context.decoder, context.data.data(), context.data.size()); + if (result != AVIF_RESULT_OK) + return Error::from_string_literal("Cannot set IO on avifDecoder"); + + result = avifDecoderParse(context.decoder); + if (result != AVIF_RESULT_OK) + return Error::from_string_literal("Failed to decode AVIF"); + + if (context.decoder->image->depth != 8) + return Error::from_string_literal("Unsupported bitdepth"); + + // Image header now decoded, save some results for fast access in other parts of the plugin. + context.size = IntSize { context.decoder->image->width, context.decoder->image->height }; + context.has_alpha = context.decoder->alphaPresent == 1; + context.image_count = context.decoder->imageCount; + context.repetition_count = context.decoder->repetitionCount <= 0 ? 0 : context.decoder->repetitionCount; + context.state = AVIFLoadingContext::State::HeaderDecoded; + + if (context.decoder->image->icc.size > 0) { + context.icc_data.resize(context.decoder->image->icc.size); + memcpy(context.icc_data.data(), context.decoder->image->icc.data, context.decoder->image->icc.size); + } + + return {}; +} + +static ErrorOr decode_avif_image(AVIFLoadingContext& context) +{ + VERIFY(context.state >= AVIFLoadingContext::State::HeaderDecoded); + + avifRGBImage rgb; + while (avifDecoderNextImage(context.decoder) == AVIF_RESULT_OK) { + auto bitmap_format = context.has_alpha ? BitmapFormat::BGRA8888 : BitmapFormat::BGRx8888; + auto bitmap = TRY(Bitmap::create(bitmap_format, context.size.value())); + + avifRGBImageSetDefaults(&rgb, context.decoder->image); + rgb.pixels = bitmap->scanline_u8(0); + rgb.rowBytes = bitmap->pitch(); + rgb.format = avifRGBFormat::AVIF_RGB_FORMAT_BGRA; + + avifResult result = avifImageYUVToRGB(context.decoder->image, &rgb); + if (result != AVIF_RESULT_OK) + return Error::from_string_literal("Conversion from YUV to RGB failed"); + + auto duration = context.decoder->imageCount == 1 ? 0 : static_cast(context.decoder->imageTiming.duration * 1000); + context.frame_descriptors.append(ImageFrameDescriptor { bitmap, duration }); + + context.state = AVIFLoadingContext::BitmapDecoded; + } + + return {}; +} + +IntSize AVIFImageDecoderPlugin::size() +{ + return m_context->size.value(); +} + +bool AVIFImageDecoderPlugin::sniff(ReadonlyBytes data) +{ + AVIFLoadingContext context; + context.data = data; + return !decode_avif_header(context).is_error(); +} + +ErrorOr> AVIFImageDecoderPlugin::create(ReadonlyBytes data) +{ + auto context = TRY(try_make()); + auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) AVIFImageDecoderPlugin(data, move(context)))); + TRY(decode_avif_header(*plugin->m_context)); + return plugin; +} + +bool AVIFImageDecoderPlugin::is_animated() +{ + return m_context->image_count > 1; +} + +size_t AVIFImageDecoderPlugin::loop_count() +{ + return is_animated() ? m_context->repetition_count : 0; +} + +size_t AVIFImageDecoderPlugin::frame_count() +{ + if (!is_animated()) + return 1; + return m_context->image_count; +} + +size_t AVIFImageDecoderPlugin::first_animated_frame_index() +{ + return 0; +} + +ErrorOr AVIFImageDecoderPlugin::frame(size_t index, Optional) +{ + if (index >= frame_count()) + return Error::from_string_literal("AVIFImageDecoderPlugin: Invalid frame index"); + + if (m_context->state == AVIFLoadingContext::State::Error) + return Error::from_string_literal("AVIFImageDecoderPlugin: Decoding failed"); + + if (m_context->state < AVIFLoadingContext::State::BitmapDecoded) { + TRY(decode_avif_image(*m_context)); + m_context->state = AVIFLoadingContext::State::BitmapDecoded; + } + + if (index >= m_context->frame_descriptors.size()) + return Error::from_string_literal("AVIFImageDecoderPlugin: Invalid frame index"); + return m_context->frame_descriptors[index]; +} + +ErrorOr> AVIFImageDecoderPlugin::icc_data() +{ + if (m_context->state < AVIFLoadingContext::State::HeaderDecoded) + (void)frame(0); + + if (!m_context->icc_data.is_empty()) + return m_context->icc_data; + return OptionalNone {}; +} + +} diff --git a/Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.h b/Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.h new file mode 100644 index 0000000000..5b03f449ab --- /dev/null +++ b/Userland/Libraries/LibGfx/ImageFormats/AVIFLoader.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023, Nico Weber + * Copyright (c) 2024, doctortheemh + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Gfx { + +class AVIFLoadingContext; + +class AVIFImageDecoderPlugin final : public ImageDecoderPlugin { +public: + static bool sniff(ReadonlyBytes); + static ErrorOr> create(ReadonlyBytes); + + virtual ~AVIFImageDecoderPlugin() override; + + virtual IntSize size() override; + + virtual bool is_animated() override; + virtual size_t loop_count() override; + virtual size_t frame_count() override; + virtual size_t first_animated_frame_index() override; + virtual ErrorOr frame(size_t index, Optional ideal_size = {}) override; + virtual ErrorOr> icc_data() override; + +private: + AVIFImageDecoderPlugin(ReadonlyBytes, OwnPtr); + + OwnPtr m_context; +}; + +} diff --git a/Userland/Libraries/LibGfx/ImageFormats/ImageDecoder.cpp b/Userland/Libraries/LibGfx/ImageFormats/ImageDecoder.cpp index d565687292..7e62da9e1a 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/ImageDecoder.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/ImageDecoder.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -35,6 +36,7 @@ static ErrorOr> probe_and_sniff_for_appropriate_plugi { TIFFImageDecoderPlugin::sniff, TIFFImageDecoderPlugin::create }, { TinyVGImageDecoderPlugin::sniff, TinyVGImageDecoderPlugin::create }, { WebPImageDecoderPlugin::sniff, WebPImageDecoderPlugin::create }, + { AVIFImageDecoderPlugin::sniff, AVIFImageDecoderPlugin::create } }; for (auto& plugin : s_initializers) { diff --git a/vcpkg.json b/vcpkg.json index b6b76ea3f3..853a93410f 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -13,6 +13,12 @@ "apng" ] }, + { + "name": "libavif", + "features": [ + "dav1d" + ] + }, { "name": "skia", "platform": "osx", @@ -59,6 +65,10 @@ "name": "libpng", "version": "1.6.43#1" }, + { + "name": "libavif", + "version": "1.0.4#1" + }, { "name": "skia", "version": "124#0"