Merge pull request #1845 from kleisauke/testsuite-avif
Adapt test suite for AVIF support
This commit is contained in:
commit
54097ef941
23
.github/workflows/test.yml
vendored
23
.github/workflows/test.yml
vendored
@ -3,21 +3,11 @@ name: Test
|
||||
# to-do:
|
||||
# - add a macos test with brew etc.
|
||||
# - build with clang/asan/etc. and run the fuzz tests
|
||||
# - libvips work with 1.6.1 in ubuntu-20.04, but fails with 1.10, strangely
|
||||
# - paste this back when it's working
|
||||
# - name: Add libheif PPA
|
||||
# run: |
|
||||
# sudo add-apt-repository ppa:strukturag/libde265
|
||||
# sudo add-apt-repository ppa:strukturag/libheif
|
||||
# you may also need to add libaom-dev, libde265-dev, libx265-dev to get
|
||||
# this to work, see https://github.com/strukturag/libheif/issues/404
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
- push
|
||||
- pull_request
|
||||
- workflow_dispatch # manually triggered workflow
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -33,6 +23,11 @@ jobs:
|
||||
run:
|
||||
sudo apt-get update -qq -o Acquire::Retries=3
|
||||
|
||||
- name: Add libheif PPA
|
||||
run: |
|
||||
sudo add-apt-repository ppa:strukturag/libde265
|
||||
sudo add-apt-repository ppa:strukturag/libheif
|
||||
|
||||
- name: Install platform dependencies
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
@ -72,7 +67,7 @@ jobs:
|
||||
--disable-deprecated
|
||||
|
||||
- name: Build libvips
|
||||
run: make V=0
|
||||
run: make V=0 -j$(nproc)
|
||||
|
||||
- name: Check libvips
|
||||
run: make V=0 check
|
||||
|
48
.travis.yml
48
.travis.yml
@ -9,7 +9,7 @@ addons:
|
||||
apt:
|
||||
update: true
|
||||
sources: &common_sources
|
||||
# add support for HEIF files
|
||||
# add support for AVIF files
|
||||
- sourceline: 'ppa:strukturag/libheif'
|
||||
- sourceline: 'ppa:strukturag/libde265'
|
||||
packages: &common_packages
|
||||
@ -41,26 +41,30 @@ addons:
|
||||
- libopenslide-dev
|
||||
- libffi-dev
|
||||
homebrew:
|
||||
update: true
|
||||
packages:
|
||||
- ccache
|
||||
- gtk-doc
|
||||
- gobject-introspection
|
||||
- fftw
|
||||
- libexif
|
||||
- libjpeg-turbo
|
||||
- webp
|
||||
- imagemagick
|
||||
- cfitsio
|
||||
- gsl
|
||||
- libmatio
|
||||
- orc
|
||||
- little-cms2
|
||||
- poppler
|
||||
- librsvg
|
||||
- openexr
|
||||
- pango
|
||||
- fftw
|
||||
- giflib
|
||||
- glib
|
||||
- gobject-introspection
|
||||
- gtk-doc
|
||||
- libexif
|
||||
- libgsf
|
||||
- libheif
|
||||
- libjpeg-turbo
|
||||
- libmatio
|
||||
- librsvg
|
||||
- libspng
|
||||
- libtiff
|
||||
- little-cms2
|
||||
- openexr
|
||||
- openslide
|
||||
- orc
|
||||
- pango
|
||||
- poppler
|
||||
- webp
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
@ -70,7 +74,7 @@ jobs:
|
||||
- os: linux
|
||||
dist: bionic
|
||||
compiler: gcc
|
||||
name: "Ubuntu 18.04 / GCC 10"
|
||||
name: "Linux x64 (Ubuntu 18.04) - GCC 10"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@ -92,7 +96,7 @@ jobs:
|
||||
- os: linux
|
||||
dist: bionic
|
||||
compiler: clang
|
||||
name: "Ubuntu 18.04 / Clang 10 with ASan and UBSan"
|
||||
name: "Linux x64 (Ubuntu 18.04) - Clang 10 with ASan and UBSan"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@ -127,16 +131,16 @@ jobs:
|
||||
cache: ccache
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
name: "macOS 10.14.6 / GCC 9"
|
||||
name: "macOS (10.14.6) - Xcode 11"
|
||||
env:
|
||||
- JPEG=/usr/local/opt/jpeg-turbo
|
||||
- JOBS="`sysctl -n hw.ncpu`"
|
||||
- WITH_MAGICK=yes
|
||||
- WITH_MAGICK=no
|
||||
- PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
- PKG_CONFIG_PATH="/usr/local/opt/jpeg-turbo/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
- HOMEBREW_NO_AUTO_UPDATE=1
|
||||
- CC="gcc-9"
|
||||
- CXX="g++-9"
|
||||
- CC="clang"
|
||||
- CXX="clang++"
|
||||
cache: ccache
|
||||
|
||||
install:
|
||||
|
@ -23,9 +23,9 @@ statistics and others. It supports a large range of [numeric
|
||||
types](http://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat),
|
||||
from 8-bit int to 128-bit complex. Images can have any number of bands.
|
||||
It supports a good range of image formats, including JPEG, TIFF, PNG,
|
||||
WebP, HEIC, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM / PGM / PFM, CSV,
|
||||
GIF, Analyze, NIfTI, DeepZoom, and OpenSlide. It can also load images via
|
||||
ImageMagick or GraphicsMagick, letting it work with formats like DICOM.
|
||||
WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM / PGM / PFM,
|
||||
CSV, GIF, Analyze, NIfTI, DeepZoom, and OpenSlide. It can also load images
|
||||
via ImageMagick or GraphicsMagick, letting it work with formats like DICOM.
|
||||
|
||||
It comes with bindings for
|
||||
[C](http://libvips.github.io/libvips/API/current/using-from-c.html),
|
||||
@ -279,7 +279,7 @@ files: Aperio, Hamamatsu, Leica, MIRAX, Sakura, Trestle, and Ventana.
|
||||
|
||||
### libheif
|
||||
|
||||
If available, libvips can load and save HEIC images.
|
||||
If available, libvips can load and save HEIC and AVIF images.
|
||||
|
||||
# Contributors
|
||||
|
||||
|
@ -41,7 +41,7 @@ DICOM_FILE = os.path.join(IMAGES, "dicom_test_image.dcm")
|
||||
BMP_FILE = os.path.join(IMAGES, "MARBLES.BMP")
|
||||
NIFTI_FILE = os.path.join(IMAGES, "avg152T1_LR_nifti.nii.gz")
|
||||
ICO_FILE = os.path.join(IMAGES, "favicon.ico")
|
||||
HEIC_FILE = os.path.join(IMAGES, "heic-orientation-6.heic")
|
||||
AVIF_FILE = os.path.join(IMAGES, "avif-orientation-6.avif")
|
||||
MOSAIC_FILES = [os.path.join(IMAGES, "cd1.1.jpg"), os.path.join(IMAGES, "cd1.2.jpg"),
|
||||
os.path.join(IMAGES, "cd2.1.jpg"), os.path.join(IMAGES, "cd2.2.jpg"),
|
||||
os.path.join(IMAGES, "cd3.1.jpg"), os.path.join(IMAGES, "cd3.2.jpg"),
|
||||
|
Binary file not shown.
BIN
test/test-suite/images/avif-orientation-6.avif
Normal file
BIN
test/test-suite/images/avif-orientation-6.avif
Normal file
Binary file not shown.
Binary file not shown.
@ -72,6 +72,8 @@ class TestCreate:
|
||||
assert im.max() == 255.0
|
||||
assert im.min() == 0.0
|
||||
|
||||
@pytest.mark.skipif(pyvips.type_find("VipsOperation", "fwfft") == 0,
|
||||
reason="no FFTW, skipping test")
|
||||
def test_fractsurf(self):
|
||||
im = pyvips.Image.fractsurf(100, 90, 2.5)
|
||||
assert im.width == 100
|
||||
|
@ -11,7 +11,7 @@ from helpers import \
|
||||
JPEG_FILE, SRGB_FILE, MATLAB_FILE, PNG_FILE, TIF_FILE, OME_FILE, \
|
||||
ANALYZE_FILE, GIF_FILE, WEBP_FILE, EXR_FILE, FITS_FILE, OPENSLIDE_FILE, \
|
||||
PDF_FILE, SVG_FILE, SVGZ_FILE, SVG_GZ_FILE, GIF_ANIM_FILE, DICOM_FILE, \
|
||||
BMP_FILE, NIFTI_FILE, ICO_FILE, HEIC_FILE, TRUNCATED_FILE, \
|
||||
BMP_FILE, NIFTI_FILE, ICO_FILE, AVIF_FILE, TRUNCATED_FILE, \
|
||||
GIF_ANIM_EXPECTED_PNG_FILE, GIF_ANIM_DISPOSE_BACKGROUND_FILE, \
|
||||
GIF_ANIM_DISPOSE_BACKGROUND_EXPECTED_PNG_FILE, \
|
||||
GIF_ANIM_DISPOSE_PREVIOUS_FILE, \
|
||||
@ -75,7 +75,7 @@ class TestForeign:
|
||||
max_diff = (im - x).abs().max()
|
||||
assert max_diff == 0
|
||||
|
||||
def save_load_file(self, format, options, im, thresh):
|
||||
def save_load_file(self, format, options, im, max_diff=0):
|
||||
# yuk!
|
||||
# but we can't set format parameters for pyvips.Image.new_temp_file()
|
||||
filename = temp_filename(self.tempdir, format)
|
||||
@ -86,8 +86,7 @@ class TestForeign:
|
||||
assert im.width == x.width
|
||||
assert im.height == x.height
|
||||
assert im.bands == x.bands
|
||||
max_diff = (im - x).abs().max()
|
||||
assert max_diff <= thresh
|
||||
assert (im - x).abs().max() <= max_diff
|
||||
x = None
|
||||
|
||||
def save_load_buffer(self, saver, loader, im, max_diff=0, **kwargs):
|
||||
@ -115,7 +114,7 @@ class TestForeign:
|
||||
assert (im - x).abs().max() <= max_diff
|
||||
|
||||
def test_vips(self):
|
||||
self.save_load_file(".v", "", self.colour, 0)
|
||||
self.save_load_file(".v", "", self.colour)
|
||||
|
||||
# check we can save and restore metadata
|
||||
filename = temp_filename(self.tempdir, ".v")
|
||||
@ -321,8 +320,8 @@ class TestForeign:
|
||||
self.save_load_buffer("pngsave_buffer", "pngload_buffer", self.colour)
|
||||
self.save_load("%s.png", self.mono)
|
||||
self.save_load("%s.png", self.colour)
|
||||
self.save_load_file(".png", "[interlace]", self.colour, 0)
|
||||
self.save_load_file(".png", "[interlace]", self.mono, 0)
|
||||
self.save_load_file(".png", "[interlace]", self.colour)
|
||||
self.save_load_file(".png", "[interlace]", self.mono)
|
||||
|
||||
# size of a regular mono PNG
|
||||
len_mono = len(self.mono.write_to_buffer(".png"))
|
||||
@ -391,30 +390,30 @@ class TestForeign:
|
||||
self.save_load("%s.tif", self.cmyk)
|
||||
|
||||
self.save_load("%s.tif", self.onebit)
|
||||
self.save_load_file(".tif", "[bitdepth=1]", self.onebit, 0)
|
||||
self.save_load_file(".tif", "[miniswhite]", self.onebit, 0)
|
||||
self.save_load_file(".tif", "[bitdepth=1,miniswhite]", self.onebit, 0)
|
||||
self.save_load_file(".tif", "[bitdepth=1]", self.onebit)
|
||||
self.save_load_file(".tif", "[miniswhite]", self.onebit)
|
||||
self.save_load_file(".tif", "[bitdepth=1,miniswhite]", self.onebit)
|
||||
|
||||
self.save_load_file(".tif",
|
||||
"[profile={0}]".format(SRGB_FILE),
|
||||
self.colour, 0)
|
||||
self.save_load_file(".tif", "[tile]", self.colour, 0)
|
||||
self.save_load_file(".tif", "[tile,pyramid]", self.colour, 0)
|
||||
self.save_load_file(".tif", "[tile,pyramid,subifd]", self.colour, 0)
|
||||
self.colour)
|
||||
self.save_load_file(".tif", "[tile]", self.colour)
|
||||
self.save_load_file(".tif", "[tile,pyramid]", self.colour)
|
||||
self.save_load_file(".tif", "[tile,pyramid,subifd]", self.colour)
|
||||
self.save_load_file(".tif",
|
||||
"[tile,pyramid,compression=jpeg]", self.colour, 80)
|
||||
self.save_load_file(".tif",
|
||||
"[tile,pyramid,subifd,compression=jpeg]",
|
||||
self.colour, 80)
|
||||
self.save_load_file(".tif", "[bigtiff]", self.colour, 0)
|
||||
self.save_load_file(".tif", "[bigtiff]", self.colour)
|
||||
self.save_load_file(".tif", "[compression=jpeg]", self.colour, 80)
|
||||
self.save_load_file(".tif",
|
||||
"[tile,tile-width=256]", self.colour, 10)
|
||||
|
||||
im = pyvips.Image.new_from_file(TIF2_FILE)
|
||||
self.save_load_file(".tif", "[bitdepth=2]", im, 0)
|
||||
self.save_load_file(".tif", "[bitdepth=2]", im)
|
||||
im = pyvips.Image.new_from_file(TIF4_FILE)
|
||||
self.save_load_file(".tif", "[bitdepth=4]", im, 0)
|
||||
self.save_load_file(".tif", "[bitdepth=4]", im)
|
||||
|
||||
filename = temp_filename(self.tempdir, '.tif')
|
||||
x = pyvips.Image.new_from_file(TIF_FILE)
|
||||
@ -1072,37 +1071,42 @@ class TestForeign:
|
||||
def test_heifload(self):
|
||||
def heif_valid(im):
|
||||
a = im(10, 10)
|
||||
# different versions of HEIC decode have slightly different
|
||||
# different versions of libheif decode have slightly different
|
||||
# rounding
|
||||
assert_almost_equal_objects(a, [197.0, 181.0, 158.0], threshold=2)
|
||||
assert im.width == 3024
|
||||
assert im.height == 4032
|
||||
assert im.bands == 3
|
||||
|
||||
self.file_loader("heifload", HEIC_FILE, heif_valid)
|
||||
self.buffer_loader("heifload_buffer", HEIC_FILE, heif_valid)
|
||||
self.file_loader("heifload", AVIF_FILE, heif_valid)
|
||||
self.buffer_loader("heifload_buffer", AVIF_FILE, heif_valid)
|
||||
|
||||
@skip_if_no("heifsave")
|
||||
def test_heifsave(self):
|
||||
self.save_load_buffer("heifsave_buffer", "heifload_buffer",
|
||||
self.colour, 80, compression="av1")
|
||||
# TODO: perhaps we should automatically set the compression to
|
||||
# av1 when we save to *.avif?
|
||||
#self.save_load("%s.avif", self.colour)
|
||||
self.save_load_file(".avif", "[compression=av1]",
|
||||
self.colour, 80)
|
||||
self.save_load("%s.heic", self.colour)
|
||||
|
||||
# test lossless mode
|
||||
im = pyvips.Image.new_from_file(HEIC_FILE)
|
||||
buf = im.heifsave_buffer(lossless=True)
|
||||
im2 = pyvips.Image.new_from_buffer(buf, "")
|
||||
# uncomment to test lossless mode, will take a while
|
||||
#im = pyvips.Image.new_from_file(AVIF_FILE)
|
||||
#buf = im.heifsave_buffer(lossless=True, compression="av1")
|
||||
#im2 = pyvips.Image.new_from_buffer(buf, "")
|
||||
# not in fact quite lossless
|
||||
assert abs(im.avg() - im2.avg()) < 3
|
||||
#assert abs(im.avg() - im2.avg()) < 3
|
||||
|
||||
# higher Q should mean a bigger buffer
|
||||
b1 = im.heifsave_buffer(Q=10)
|
||||
b2 = im.heifsave_buffer(Q=90)
|
||||
# higher Q should mean a bigger buffer, needs libheif >= v1.8.0,
|
||||
# see: https://github.com/libvips/libvips/issues/1757
|
||||
b1 = self.mono.heifsave_buffer(Q=10, compression="av1")
|
||||
b2 = self.mono.heifsave_buffer(Q=90, compression="av1")
|
||||
assert len(b2) > len(b1)
|
||||
|
||||
# try saving an image with an ICC profile and reading it back
|
||||
# not all libheif have profile support, so put it in an if
|
||||
buf = self.colour.heifsave_buffer()
|
||||
buf = self.colour.heifsave_buffer(Q=10, compression="av1")
|
||||
im = pyvips.Image.new_from_buffer(buf, "")
|
||||
p1 = self.colour.get("icc-profile-data")
|
||||
if im.get_typeof("icc-profile-data") != 0:
|
||||
@ -1113,18 +1117,16 @@ class TestForeign:
|
||||
# the exif test will need us to be able to walk the header,
|
||||
# we can't just check exif-data
|
||||
|
||||
# libheif 1.1 (on ubuntu 18.04, current LTS) does not support exif
|
||||
# write, so this test is commented out
|
||||
|
||||
# test that exif changes change the output of heifsave
|
||||
# first make sure we have exif support
|
||||
#z = pyvips.Image.new_from_file(JPEG_FILE)
|
||||
#if z.get_typeof("exif-ifd0-Orientation") != 0:
|
||||
# x = self.colour.copy()
|
||||
# x.set("exif-ifd0-Make", "banana")
|
||||
# buf = x.heifsave_buffer()
|
||||
# y = pyvips.Image.new_from_buffer(buf, "")
|
||||
# assert y.get("exif-ifd0-Make").split(" ")[0] == "banana"
|
||||
z = pyvips.Image.new_from_file(AVIF_FILE)
|
||||
if z.get_typeof("exif-ifd0-Make") != 0:
|
||||
x = z.copy()
|
||||
x.set("exif-ifd0-Make", "banana")
|
||||
buf = x.heifsave_buffer(Q=10, compression="av1")
|
||||
y = pyvips.Image.new_from_buffer(buf, "")
|
||||
assert y.get("exif-ifd0-Make").split(" ")[0] == "banana"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main()
|
||||
|
@ -2,7 +2,7 @@
|
||||
import pytest
|
||||
|
||||
import pyvips
|
||||
from helpers import JPEG_FILE, OME_FILE, HEIC_FILE, TIF_FILE, all_formats, have
|
||||
from helpers import JPEG_FILE, OME_FILE, AVIF_FILE, TIF_FILE, all_formats, have
|
||||
|
||||
|
||||
# Run a function expecting a complex image on a two-band image
|
||||
@ -195,8 +195,8 @@ class TestResample:
|
||||
|
||||
if have("heifload"):
|
||||
# this image is orientation 6 ... thumbnail should flip it
|
||||
im = pyvips.Image.new_from_file(HEIC_FILE)
|
||||
thumb = pyvips.Image.thumbnail(HEIC_FILE, 100)
|
||||
im = pyvips.Image.new_from_file(AVIF_FILE)
|
||||
thumb = pyvips.Image.thumbnail(AVIF_FILE, 100)
|
||||
|
||||
# thumb should be portrait
|
||||
assert thumb.width < thumb.height
|
||||
|
Loading…
Reference in New Issue
Block a user