Skip to content

Commit

Permalink
Improved error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Dec 2, 2024
1 parent 3730bf2 commit c40bcbf
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 116 deletions.
3 changes: 1 addition & 2 deletions .ci/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ if [[ $(uname) != CYGWIN* ]]; then
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
ghostscript libjpeg-turbo-progs libopenjp2-7-dev\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard libopenblas-dev\
ninja-build build-essential nasm
sway wl-clipboard libopenblas-dev nasm
fi

python3 -m pip install --upgrade pip
Expand Down
15 changes: 5 additions & 10 deletions .github/workflows/wheels-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ function install_rav1e {

curl -sLo - \
https://github.com/xiph/rav1e/releases/download/v$RAV1E_VERSION/librav1e-$RAV1E_VERSION-$suffix.tar.gz \
| tar -C $BUILD_PREFIX --exclude LICENSE --exclude LICENSE --exclude '*.so' --exclude '*.dylib' -zxf -
| tar -C $BUILD_PREFIX --exclude LICENSE --exclude '*.so' --exclude '*.dylib' -zxf -

if [ -z "$IS_MACOS" ]; then
sed -i 's/-lgcc_s/-lgcc_eh/g' "${BUILD_PREFIX}/lib/pkgconfig/rav1e.pc"
Expand All @@ -133,20 +133,19 @@ EOF
}

function build_libavif {
if [ -e libavif-stamp ]; then return; fi
install_rav1e
python3 -m pip install meson ninja

if [[ "$PLAT" == "x86_64" ]]; then
build_simple nasm 2.16.03 https://www.nasm.us/pub/nasm/releasebuilds/2.16.03/
fi

local cmake=$(get_modern_cmake)
local out_dir=$(fetch_unpack https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$LIBAVIF_VERSION.tar.gz libavif-$LIBAVIF_VERSION.tar.gz)

(cd $out_dir \
&& $cmake \
&& cmake \
-DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX \
-DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib \
-DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX/lib \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \
-DAVIF_LIBSHARPYUV=LOCAL \
Expand All @@ -159,11 +158,7 @@ function build_libavif {
-DCMAKE_MODULE_PATH=/tmp/cmake/Modules \
. \
&& make install)

if [[ "$MB_ML_LIBC" == "manylinux" ]]; then
cp /usr/local/lib64/libavif.a /usr/local/lib
cp /usr/local/lib64/pkgconfig/libavif.pc /usr/local/lib/pkgconfig
fi
touch libavif-stamp
}

function build {
Expand Down
2 changes: 1 addition & 1 deletion Tests/check_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_wheel_modules() -> None:
except ImportError:
expected_modules.remove("tkinter")

# libavif is not available on windows for x86 and ARM64 architectures
# libavif is not available on Windows for x86 and ARM64 architectures
if sys.platform == "win32":
if platform.machine() == "ARM64" or struct.calcsize("P") == 4:
expected_modules.remove("avif")
Expand Down
2 changes: 0 additions & 2 deletions Tests/test_file_avif.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,6 @@ def test_unsupported_open(self, monkeypatch: pytest.MonkeyPatch) -> None:
@skip_unless_feature("avif")
class TestFileAvif:
def test_version(self) -> None:
_avif.AvifCodecVersions()

version = features.version_module("avif")
assert version is not None
assert re.search(r"\d+\.\d+\.\d+$", version)
Expand Down
9 changes: 4 additions & 5 deletions docs/handbook/image-file-formats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1370,17 +1370,16 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
YUV range, either "full" or "limited". Defaults to "full"

**codec**
AV1 codec to use for encoding. Possible values are "aom", "rav1e", and
"svt", depending on what codecs were compiled with libavif. Defaults to
"auto", which will choose the first available codec in the order of the
preceding list.
AV1 codec to use for encoding. Specific values are "aom", "rav1e", and
"svt", presuming the chosen codec is available. Defaults to "auto", which
will choose the first available codec in the order of the preceding list.

**tile_rows** / **tile_cols**
For tile encoding, the (log 2) number of tile rows and columns to use.
Valid values are 0-6, default 0.

**alpha_premultiplied**
Encode the image with premultiplied alpha, defaults ``False``
Encode the image with premultiplied alpha. Defaults to ``False``

**icc_profile**
The ICC Profile to include in the saved file.
Expand Down
9 changes: 5 additions & 4 deletions docs/installation/building-from-source.rst
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ Many of Pillow's features require external libraries:
The easiest way to install external libraries is via `Homebrew
<https://brew.sh/>`_. After you install Homebrew, run::

brew install libjpeg libraqm libtiff little-cms2 openjpeg webp
brew install libavif libjpeg libraqm libtiff little-cms2 openjpeg webp

To install libavif on macOS use Homebrew to install its build dependencies::
If you would like to use libavif with more codecs than just aom, then
instead of installing libavif through Homebrew directly, you can use
Homebrew to install libavif's build dependencies::

brew install aom dav1d rav1e

Expand Down Expand Up @@ -224,8 +226,7 @@ Many of Pillow's features require external libraries:

sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 openjpeg harfbuzz fribidi libxcb libavif

See ``depends/install_raqm_cmake.sh`` to install libraqm and
``depends/install_libavif.sh`` to install libavif.
See ``depends/install_raqm_cmake.sh`` to install libraqm.

.. tab:: Android

Expand Down
38 changes: 23 additions & 15 deletions src/PIL/AvifImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,26 @@
def _accept(prefix: bytes) -> bool | str:
if prefix[4:8] != b"ftyp":
return False
coding_brands = (b"avif", b"avis")
container_brands = (b"mif1", b"msf1")
major_brand = prefix[8:12]
if major_brand in coding_brands:
if not SUPPORTED:
return (
"image file could not be identified because AVIF "
"support not installed"
)
return True
if major_brand in container_brands:
if major_brand in (
# coding brands
b"avif",
b"avis",
# We accept files with AVIF container brands; we can't yet know if
# the ftyp box has the correct compatible brands, but if it doesn't
# then the plugin will raise a SyntaxError which Pillow will catch
# before moving on to the next plugin that accepts the file.
#
# Also, because this file might not actually be an AVIF file, we
# don't raise an error if AVIF support isn't properly compiled.
b"mif1",
b"msf1",
):
if not SUPPORTED:
return (
"image file could not be identified because AVIF "
"support not installed"
)
return True
return False

Expand Down Expand Up @@ -72,6 +74,11 @@ def _open(self) -> None:
)
raise SyntaxError(msg)

if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
DECODE_CODEC_CHOICE
):
msg = "Invalid opening codec"
raise ValueError(msg)
self._decoder = _avif.AvifDecoder(
self.fp.read(),
DECODE_CODEC_CHOICE,
Expand Down Expand Up @@ -104,10 +111,8 @@ def load(self) -> Image.core.PixelAccess | None:
data, timescale, tsp_in_ts, dur_in_ts = self._decoder.get_frame(
self.__frame
)
timestamp = round(1000 * (tsp_in_ts / timescale))
duration = round(1000 * (dur_in_ts / timescale))
self.info["timestamp"] = timestamp
self.info["duration"] = duration
self.info["timestamp"] = round(1000 * (tsp_in_ts / timescale))
self.info["duration"] = round(1000 * (dur_in_ts / timescale))
self.__loaded = self.__frame

# Set tile
Expand Down Expand Up @@ -153,6 +158,9 @@ def _save(
speed = info.get("speed", 6)
max_threads = info.get("max_threads", _get_default_max_threads())
codec = info.get("codec", "auto")
if codec != "auto" and not _avif.encoder_codec_available(codec):
msg = "Invalid saving codec"
raise ValueError(msg)
range_ = info.get("range", "full")
tile_rows_log2 = info.get("tile_rows", 0)
tile_cols_log2 = info.get("tile_cols", 0)
Expand Down Expand Up @@ -199,7 +207,7 @@ def _save(
)
raise ValueError(msg)
advanced = tuple(
[(str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced]
(str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced
)

# Setup the AVIF encoder
Expand Down
Loading

0 comments on commit c40bcbf

Please sign in to comment.