From bd52eb9be27f647cbec5475a920b79ce61953c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 19 Dec 2025 02:03:13 +0100 Subject: [PATCH] AnyImageImporter: attempt to detect AVIF files. What a mess. Modern formats stand on a shaky pile of ancient tech. --- doc/changelog.dox | 2 +- .../AnyImageImporter/AnyImageImporter.cpp | 15 +++++++++++++++ .../AnyImageImporter/AnyImageImporter.h | 2 ++ .../Test/AnyImageImporterTest.cpp | 9 ++++++++- .../AnyImageImporter/Test/CMakeLists.txt | 1 + src/MagnumPlugins/AnyImageImporter/Test/rgb.avif | Bin 0 -> 335 bytes 6 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/MagnumPlugins/AnyImageImporter/Test/rgb.avif diff --git a/doc/changelog.dox b/doc/changelog.dox index 97b41fee0..57535fd37 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -1010,7 +1010,7 @@ See also: a file extension and MIME type corresponding to a file format produced by a particular plugin. - Recognizing BMP and TIFF file header magic in @relativeref{Trade,AnyImageImporter} -- Recognizing ASTC and WebP files and data in +- Recognizing ASTC, AVIF and WebP files and data in @relativeref{Trade,AnyImageImporter} - Recognizing also a second variant of Radiance HDR file headers in @relativeref{Trade,AnyImageImporter} (see [mosra/magnum#652](https://github.com/mosra/magnum/issues/652)) diff --git a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp index 31cb4c891..645b90f0e 100644 --- a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp +++ b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp @@ -73,6 +73,8 @@ void AnyImageImporter::doOpenFile(const Containers::StringView filename) { Containers::StringView plugin; if(normalizedExtension == ".astc"_s) plugin = "AstcImporter"_s; + else if(normalizedExtension == ".avif"_s) + plugin = "AvifImporter"_s; else if(normalizedExtension == ".basis"_s) plugin = "BasisImporter"_s; else if(normalizedExtension == ".bmp"_s) @@ -206,6 +208,19 @@ void AnyImageImporter::doOpenData(Containers::Array&& data, DataFlags) { unfortunately it being in LE means it's SCALABLE in reverse :) */ if(dataString.hasPrefix("\x13\xAB\xA1\x5C"_s)) plugin = "AstcImporter"_s; + /* Total guesswork. AVIF is an image format inside a HEIF container, which + itself is a ISOBMFF format, for which the spec isn't open (yay haha): + https://en.wikipedia.org/wiki/ISO_base_media_file_format + According to https://github.com/strukturag/libheif/issues/83 what + matters is a FourCC after the `ftyp` "box", which starts at the fourth + bytes, with the initial four bytes not specified anywhere. It *seems* + that for AVIF it's `ftypavif`, so let's check for that. In case of HEIF + there can be many other "brands" in a "box", whatever that is, but + that's suffering for another day. */ + /** @todo https://github.com/file/file/blob/9ed4d8c65854d9d28519291f21dd92c44c4abc18/magic/Magdir/animation#L298 + lists `avis` for image sequences, maybe detect that also? */ + else if(dataString.size() >= 12 && dataString.slice(4, 12) == "ftypavif"_s) + plugin = "AvifImporter"_s; /* https://github.com/BinomialLLC/basis_universal/blob/7d784c728844c007d8c95d63231f7adcc0f65364/transcoder/basisu_file_headers.h#L78 */ else if(dataString.hasPrefix("sB"_s)) plugin = "BasisImporter"_s; diff --git a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h index a0f326290..bd72e6928 100644 --- a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h +++ b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h @@ -61,6 +61,8 @@ Supported formats: - Adaptive Scalable Texture Compression (`*.astc` or data with corresponding signature), loaded with @ref AstcImporter or any other plugin that provides it +- AV1 Image File Format (`*.avif` or data with corresponding signature), + loaded with @ref AvifImporter or any other plugin that provides it - Basis Universal (`*.basis` or data with corresponding signature), loaded with @ref BasisImporter or any other plugin that provides it - Windows Bitmap (`*.bmp` or data with corresponding signature), loaded with diff --git a/src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp b/src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp index 4522da154..cf03eba90 100644 --- a/src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp +++ b/src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp @@ -98,6 +98,8 @@ constexpr struct { variants if there are */ {"ASTC", "8x8.astc", false, "AstcImporter"}, {"ASTC data", "8x8.astc", true, "AstcImporter"}, + {"AVIF", "rgb.avif", false, "AvifImporter"}, + {"AVIF data", "rgb.avif", true, "AvifImporter"}, {"Basis", "rgb.basis", false, "BasisImporter"}, {"Basis data", "rgb.basis", true, "BasisImporter"}, {"BMP", "rgb.bmp", false, "BmpImporter"}, @@ -186,7 +188,12 @@ const struct { {"TIFF, but no zero byte", "MM\xff\x2a"_s, "4d4dff2a"}, {"KTX, but wrong version", "\xabKTX 30\xbb\r\n\x1a\n"_s, "ab4b5458"}, {"RIFF (for WebP), but only 4 bytes", "RIFF"_s, "52494646"}, - {"WebP, but only 11 bytes", "RIFF WEB"_s, "52494646"} + {"WebP, but only 11 bytes", "RIFF WEB"_s, "52494646"}, + /* Yeah can't do \x20ftypavi because it's interpreted as 0x20f. Who thought + such variable-length encoding was a good idea?! Also, UGH, this message + in particular is rather useless, because the signature is only right + after that :/ */ + {"AVIF, but not enough bytes", "\x00\x00\x00\x20" "ftypavi"_s, "00000020"}, }; constexpr struct { diff --git a/src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt b/src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt index 990023fcb..ec082cafa 100644 --- a/src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt +++ b/src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt @@ -66,6 +66,7 @@ corrade_add_test(AnyImageImporterTest AnyImageImporterTest.cpp image.exr image.tiff pngs.ico + rgb.avif rgb.basis rgb.bmp rgb.hdr diff --git a/src/MagnumPlugins/AnyImageImporter/Test/rgb.avif b/src/MagnumPlugins/AnyImageImporter/Test/rgb.avif new file mode 100644 index 0000000000000000000000000000000000000000..65086c4f253f0ac1f17d9db62bf5c3a3c19fc061 GIT binary patch literal 335 zcmZQzU{FXasVqn=%S>Yc0uY^>nP!-qnV9D5Xy^zOdYzkEk_eIm0>zA!oFWL5fuSHX zxdg_B(R>A&CAnY@BaoEK%*js%@mv@f7=aK(GB64QX&WHc$jr5-7;5$OH>;aBu)=p2RXk z=SBsP2!n8Peoj$da!v)%WL^e_2B465WSS?tz zSsIKC1sE9qtoE85|NsB9$G4(&**8|-`~H4o#i8pxK^JOsvjb(L3?@h`OWQrab@6Ka I6y?SQ0DQ7W^#A|> literal 0 HcmV?d00001