Browse Source

AnyImageImporter: attempt to detect AVIF files.

What a mess. Modern formats stand on a shaky pile of ancient tech.
pull/686/head
Vladimír Vondruš 5 months ago
parent
commit
bd52eb9be2
  1. 2
      doc/changelog.dox
  2. 15
      src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp
  3. 2
      src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h
  4. 9
      src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp
  5. 1
      src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt
  6. BIN
      src/MagnumPlugins/AnyImageImporter/Test/rgb.avif

2
doc/changelog.dox

@ -1010,7 +1010,7 @@ See also:
a file extension and MIME type corresponding to a file format produced by a file extension and MIME type corresponding to a file format produced by
a particular plugin. a particular plugin.
- Recognizing BMP and TIFF file header magic in @relativeref{Trade,AnyImageImporter} - 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} @relativeref{Trade,AnyImageImporter}
- Recognizing also a second variant of Radiance HDR file headers in - 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)) @relativeref{Trade,AnyImageImporter} (see [mosra/magnum#652](https://github.com/mosra/magnum/issues/652))

15
src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp

@ -73,6 +73,8 @@ void AnyImageImporter::doOpenFile(const Containers::StringView filename) {
Containers::StringView plugin; Containers::StringView plugin;
if(normalizedExtension == ".astc"_s) if(normalizedExtension == ".astc"_s)
plugin = "AstcImporter"_s; plugin = "AstcImporter"_s;
else if(normalizedExtension == ".avif"_s)
plugin = "AvifImporter"_s;
else if(normalizedExtension == ".basis"_s) else if(normalizedExtension == ".basis"_s)
plugin = "BasisImporter"_s; plugin = "BasisImporter"_s;
else if(normalizedExtension == ".bmp"_s) else if(normalizedExtension == ".bmp"_s)
@ -206,6 +208,19 @@ void AnyImageImporter::doOpenData(Containers::Array<char>&& data, DataFlags) {
unfortunately it being in LE means it's SCALABLE in reverse :) */ unfortunately it being in LE means it's SCALABLE in reverse :) */
if(dataString.hasPrefix("\x13\xAB\xA1\x5C"_s)) if(dataString.hasPrefix("\x13\xAB\xA1\x5C"_s))
plugin = "AstcImporter"_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 */ /* https://github.com/BinomialLLC/basis_universal/blob/7d784c728844c007d8c95d63231f7adcc0f65364/transcoder/basisu_file_headers.h#L78 */
else if(dataString.hasPrefix("sB"_s)) else if(dataString.hasPrefix("sB"_s))
plugin = "BasisImporter"_s; plugin = "BasisImporter"_s;

2
src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h

@ -61,6 +61,8 @@ Supported formats:
- Adaptive Scalable Texture Compression (`*.astc` or data with corresponding - Adaptive Scalable Texture Compression (`*.astc` or data with corresponding
signature), loaded with @ref AstcImporter or any other plugin that provides signature), loaded with @ref AstcImporter or any other plugin that provides
it 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 - Basis Universal (`*.basis` or data with corresponding signature), loaded
with @ref BasisImporter or any other plugin that provides it with @ref BasisImporter or any other plugin that provides it
- Windows Bitmap (`*.bmp` or data with corresponding signature), loaded with - Windows Bitmap (`*.bmp` or data with corresponding signature), loaded with

9
src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp

@ -98,6 +98,8 @@ constexpr struct {
variants if there are */ variants if there are */
{"ASTC", "8x8.astc", false, "AstcImporter"}, {"ASTC", "8x8.astc", false, "AstcImporter"},
{"ASTC data", "8x8.astc", true, "AstcImporter"}, {"ASTC data", "8x8.astc", true, "AstcImporter"},
{"AVIF", "rgb.avif", false, "AvifImporter"},
{"AVIF data", "rgb.avif", true, "AvifImporter"},
{"Basis", "rgb.basis", false, "BasisImporter"}, {"Basis", "rgb.basis", false, "BasisImporter"},
{"Basis data", "rgb.basis", true, "BasisImporter"}, {"Basis data", "rgb.basis", true, "BasisImporter"},
{"BMP", "rgb.bmp", false, "BmpImporter"}, {"BMP", "rgb.bmp", false, "BmpImporter"},
@ -186,7 +188,12 @@ const struct {
{"TIFF, but no zero byte", "MM\xff\x2a"_s, "4d4dff2a"}, {"TIFF, but no zero byte", "MM\xff\x2a"_s, "4d4dff2a"},
{"KTX, but wrong version", "\xabKTX 30\xbb\r\n\x1a\n"_s, "ab4b5458"}, {"KTX, but wrong version", "\xabKTX 30\xbb\r\n\x1a\n"_s, "ab4b5458"},
{"RIFF (for WebP), but only 4 bytes", "RIFF"_s, "52494646"}, {"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 { constexpr struct {

1
src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt

@ -66,6 +66,7 @@ corrade_add_test(AnyImageImporterTest AnyImageImporterTest.cpp
image.exr image.exr
image.tiff image.tiff
pngs.ico pngs.ico
rgb.avif
rgb.basis rgb.basis
rgb.bmp rgb.bmp
rgb.hdr rgb.hdr

BIN
src/MagnumPlugins/AnyImageImporter/Test/rgb.avif

Binary file not shown.
Loading…
Cancel
Save