Skip to content

Commit

Permalink
fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
fdintino committed Sep 24, 2023
1 parent e4fab18 commit 1a3d520
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 60 deletions.
12 changes: 7 additions & 5 deletions .ci/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ fi

set -e

sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard libopenblas-dev\
ninja-build build-essential nasm
if [[ $(uname) != CYGWIN* ]]; then
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard libopenblas-dev\
ninja-build build-essential nasm
fi

python3 -m pip install --upgrade pip
python3 -m pip install --upgrade wheel
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/macos-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
set -e

brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype openblas libraqm dav1d aom rav1e
export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"

PYTHONOPTIMIZE=0 python3 -m pip install cffi
python3 -m pip install coverage
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-cygwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ jobs:
liblcms2-devel
libopenjp2-devel
libraqm-devel
libavif-devel
libtiff-devel
libwebp-devel
libxcb-devel
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-mingw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
mingw-w64-x86_64-libimagequant \
mingw-w64-x86_64-libjpeg-turbo \
mingw-w64-x86_64-libraqm \
mingw-w64-x86_64-libavif \
mingw-w64-x86_64-libtiff \
mingw-w64-x86_64-libwebp \
mingw-w64-x86_64-openjpeg2 \
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ jobs:
run: "& winbuild\\build\\build_dep_fribidi.cmd"

- name: Build dependencies / libavif
if: steps.build-cache.outputs.cache-hit != 'true' && matrix.architecture == 'x64'
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libavif.cmd"

# trim ~150MB for each job
Expand Down
Binary file added Tests/images/avif/rgba10.heif
Binary file not shown.
98 changes: 80 additions & 18 deletions Tests/test_file_avif.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import re
import xml.etree.ElementTree
from contextlib import contextmanager
Expand All @@ -7,9 +8,10 @@

import pytest

from PIL import AvifImagePlugin, Image, features
from PIL import AvifImagePlugin, Image, UnidentifiedImageError, features

from .helper import (
PillowLeakTestCase,
assert_image,
assert_image_similar,
assert_image_similar_tofile,
Expand All @@ -19,11 +21,8 @@

try:
from PIL import _avif

HAVE_AVIF = True
except ImportError:
_avif = None
HAVE_AVIF = False


TEST_AVIF_FILE = "Tests/images/avif/hopper.avif"
Expand Down Expand Up @@ -63,6 +62,15 @@ def skip_unless_avif_encoder(codec_name):
)


def is_docker_qemu():
try:
init_proc_exe = os.readlink("/proc/1/exe")
except: # noqa: E722
return False
else:
return "qemu" in init_proc_exe


def skip_unless_avif_version_gte(version):
if not _avif:
reason = "AVIF unavailable"
Expand Down Expand Up @@ -109,14 +117,17 @@ def has_alpha_premultiplied(im_bytes):

class TestUnsupportedAvif:
def test_unsupported(self):
if HAVE_AVIF:
if features.check("avif"):
AvifImagePlugin.SUPPORTED = False

file_path = "Tests/images/avif/hopper.avif"
pytest.warns(UserWarning, lambda: pytest.raises(OSError, Image.open, file_path))

if HAVE_AVIF:
AvifImagePlugin.SUPPORTED = True
try:
file_path = "Tests/images/avif/hopper.avif"
pytest.warns(
UserWarning,
lambda: pytest.raises(UnidentifiedImageError, Image.open, file_path),
)
finally:
AvifImagePlugin.SUPPORTED = features.check("avif")


@skip_unless_feature("avif")
Expand Down Expand Up @@ -299,11 +310,6 @@ def test_exif(self):
exif = im.getexif()
assert exif[274] == 1

# With XMP tags
with Image.open("Tests/images/avif/xmp_tags_orientation.avif") as im:
exif = im.getexif()
assert exif[274] == 3

def test_exif_save(self, tmp_path):
with Image.open("Tests/images/avif/exif.avif") as im:
test_file = str(tmp_path / "temp.avif")
Expand Down Expand Up @@ -441,6 +447,35 @@ def test_encoder_codec_cannot_encode(self, tmp_path):
with pytest.raises(ValueError):
im.save(test_file, codec="dav1d")

@skip_unless_avif_encoder("aom")
@skip_unless_avif_version_gte((0, 8, 2))
@skip_unless_feature("avif")
def test_encoder_advanced_codec_options(self):
with Image.open(TEST_AVIF_FILE) as im:
ctrl_buf = BytesIO()
im.save(ctrl_buf, "AVIF", codec="aom")
test_buf = BytesIO()
im.save(
test_buf,
"AVIF",
codec="aom",
advanced={
"aq-mode": "1",
"enable-chroma-deltaq": "1",
},
)
assert ctrl_buf.getvalue() != test_buf.getvalue()

@skip_unless_avif_encoder("aom")
@skip_unless_avif_version_gte((0, 8, 2))
@skip_unless_feature("avif")
@pytest.mark.parametrize("val", [{"foo": "bar"}, 1234])
def test_encoder_advanced_codec_options_invalid(self, tmp_path, val):
with Image.open(TEST_AVIF_FILE) as im:
test_file = str(tmp_path / "temp.avif")
with pytest.raises(ValueError):
im.save(test_file, codec="aom", advanced=val)

@skip_unless_avif_decoder("aom")
@skip_unless_feature("avif")
def test_decoder_codec_param(self):
Expand Down Expand Up @@ -494,7 +529,7 @@ def test_encoder_codec_available_invalid(self):
[0, (63, 63)],
[100, (0, 0)],
[90, (0, 10)],
[None, (0, 10)], # default
[None, (0, 25)], # default
[50, (14, 50)],
],
)
Expand Down Expand Up @@ -592,12 +627,12 @@ def test_write_animation_L(self, tmp_path):
# Compare first and second-to-last frames to the original animated GIF
orig.load()
im.load()
assert_image_similar(im, orig.convert("RGB"), 25.0)
assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0)
orig.seek(orig.n_frames - 2)
im.seek(im.n_frames - 2)
orig.load()
im.load()
assert_image_similar(im, orig.convert("RGB"), 25.0)
assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0)

def test_write_animation_RGB(self, tmp_path):
"""
Expand Down Expand Up @@ -644,6 +679,11 @@ def test_sequence_dimension_mismatch_check(self, tmp_path):
with pytest.raises(ValueError):
frame1.save(temp_file, save_all=True, append_images=[frame2], duration=100)

def test_heif_raises_unidentified_image_error(self):
with pytest.raises(UnidentifiedImageError):
with Image.open("Tests/images/avif/rgba10.heif"):
pass

@skip_unless_avif_version_gte((0, 9, 0))
@pytest.mark.parametrize("alpha_premultipled", [False, True])
def test_alpha_premultiplied_true(self, alpha_premultipled):
Expand Down Expand Up @@ -718,3 +758,25 @@ def test_seek_errors(self):

with pytest.raises(EOFError):
im.seek(42)


MAX_THREADS = os.cpu_count()


@skip_unless_feature("avif")
class TestAvifLeaks(PillowLeakTestCase):
mem_limit = MAX_THREADS * 3 * 1024
iterations = 100

@pytest.mark.skipif(
is_docker_qemu(), reason="Skipping on cross-architecture containers"
)
def test_leak_load(self):
with open(TEST_AVIF_FILE, "rb") as f:
im_data = f.read()

def core():
with Image.open(BytesIO(im_data)) as im:
im.load()

self._test_leak(core)
26 changes: 17 additions & 9 deletions depends/install_libavif.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
#!/usr/bin/env bash
set -eo pipefail

LIBAVIF_VERSION=0.9.2
LIBAVIF_VERSION=${LIBAVIF_VERSION:-1.0.1}

LIBAVIF_CMAKE_FLAGS=()

if uname -s | grep -q Darwin; then
PREFIX=/usr/local
MAKE_INSTALL=(make install)
else
PREFIX=/usr
MAKE_INSTALL=(sudo make install)
fi

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PKGCONFIG=${PKGCONFIG:-pkg-config}

export CFLAGS="-fPIC -O3 $CFLAGS"
export CXXFLAGS="-fPIC -O3 $CXXFLAGS"

./download-and-extract.sh libavif-$LIBAVIF_VERSION https://github.com/AOMediaCodec/libavif/archive/v$LIBAVIF_VERSION.tar.gz

mkdir -p libavif-$LIBAVIF_VERSION
curl -sLo - \
https://github.com/AOMediaCodec/libavif/archive/v$LIBAVIF_VERSION.tar.gz \
| tar --strip-components=1 -C libavif-$LIBAVIF_VERSION -zxf -
pushd libavif-$LIBAVIF_VERSION

if [ "$LIBAVIF_VERSION" == "1.0.1" ]; then
patch -p1 < "${SCRIPT_DIR}/libavif-1.0.1-local-static.patch"
fi

HAS_DECODER=0
HAS_ENCODER=0

Expand Down Expand Up @@ -63,13 +71,13 @@ if uname -s | grep -q Darwin; then
fi

mkdir build
cd build
pushd build
cmake .. \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DCMAKE_BUILD_TYPE=Release \
"${LIBAVIF_CMAKE_FLAGS[@]}"
make && "${MAKE_INSTALL[@]}"
cd ..

make
sudo make install
popd

popd
Loading

0 comments on commit 1a3d520

Please sign in to comment.