Skip to content

Commit c40bcbf

Browse files
committed
Improved error handling
1 parent 3730bf2 commit c40bcbf

File tree

9 files changed

+155
-116
lines changed

9 files changed

+155
-116
lines changed

.ci/install.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ if [[ $(uname) != CYGWIN* ]]; then
2323
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
2424
ghostscript libjpeg-turbo-progs libopenjp2-7-dev\
2525
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
26-
sway wl-clipboard libopenblas-dev\
27-
ninja-build build-essential nasm
26+
sway wl-clipboard libopenblas-dev nasm
2827
fi
2928

3029
python3 -m pip install --upgrade pip

.github/workflows/wheels-dependencies.sh

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ function install_rav1e {
114114

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

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

135135
function build_libavif {
136+
if [ -e libavif-stamp ]; then return; fi
136137
install_rav1e
137138
python3 -m pip install meson ninja
138139

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

143-
local cmake=$(get_modern_cmake)
144144
local out_dir=$(fetch_unpack https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$LIBAVIF_VERSION.tar.gz libavif-$LIBAVIF_VERSION.tar.gz)
145-
146145
(cd $out_dir \
147-
&& $cmake \
146+
&& cmake \
148147
-DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX \
149-
-DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib \
148+
-DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX/lib \
150149
-DCMAKE_BUILD_TYPE=Release \
151150
-DBUILD_SHARED_LIBS=OFF \
152151
-DAVIF_LIBSHARPYUV=LOCAL \
@@ -159,11 +158,7 @@ function build_libavif {
159158
-DCMAKE_MODULE_PATH=/tmp/cmake/Modules \
160159
. \
161160
&& make install)
162-
163-
if [[ "$MB_ML_LIBC" == "manylinux" ]]; then
164-
cp /usr/local/lib64/libavif.a /usr/local/lib
165-
cp /usr/local/lib64/pkgconfig/libavif.pc /usr/local/lib/pkgconfig
166-
fi
161+
touch libavif-stamp
167162
}
168163

169164
function build {

Tests/check_wheel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def test_wheel_modules() -> None:
1818
except ImportError:
1919
expected_modules.remove("tkinter")
2020

21-
# libavif is not available on windows for x86 and ARM64 architectures
21+
# libavif is not available on Windows for x86 and ARM64 architectures
2222
if sys.platform == "win32":
2323
if platform.machine() == "ARM64" or struct.calcsize("P") == 4:
2424
expected_modules.remove("avif")

Tests/test_file_avif.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@ def test_unsupported_open(self, monkeypatch: pytest.MonkeyPatch) -> None:
127127
@skip_unless_feature("avif")
128128
class TestFileAvif:
129129
def test_version(self) -> None:
130-
_avif.AvifCodecVersions()
131-
132130
version = features.version_module("avif")
133131
assert version is not None
134132
assert re.search(r"\d+\.\d+\.\d+$", version)

docs/handbook/image-file-formats.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,17 +1370,16 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
13701370
YUV range, either "full" or "limited". Defaults to "full"
13711371

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

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

13821381
**alpha_premultiplied**
1383-
Encode the image with premultiplied alpha, defaults ``False``
1382+
Encode the image with premultiplied alpha. Defaults to ``False``
13841383

13851384
**icc_profile**
13861385
The ICC Profile to include in the saved file.

docs/installation/building-from-source.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,11 @@ Many of Pillow's features require external libraries:
164164
The easiest way to install external libraries is via `Homebrew
165165
<https://brew.sh/>`_. After you install Homebrew, run::
166166

167-
brew install libjpeg libraqm libtiff little-cms2 openjpeg webp
167+
brew install libavif libjpeg libraqm libtiff little-cms2 openjpeg webp
168168

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

171173
brew install aom dav1d rav1e
172174

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

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

227-
See ``depends/install_raqm_cmake.sh`` to install libraqm and
228-
``depends/install_libavif.sh`` to install libavif.
229+
See ``depends/install_raqm_cmake.sh`` to install libraqm.
229230

230231
.. tab:: Android
231232

src/PIL/AvifImagePlugin.py

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,26 @@
2424
def _accept(prefix: bytes) -> bool | str:
2525
if prefix[4:8] != b"ftyp":
2626
return False
27-
coding_brands = (b"avif", b"avis")
28-
container_brands = (b"mif1", b"msf1")
2927
major_brand = prefix[8:12]
30-
if major_brand in coding_brands:
31-
if not SUPPORTED:
32-
return (
33-
"image file could not be identified because AVIF "
34-
"support not installed"
35-
)
36-
return True
37-
if major_brand in container_brands:
28+
if major_brand in (
29+
# coding brands
30+
b"avif",
31+
b"avis",
3832
# We accept files with AVIF container brands; we can't yet know if
3933
# the ftyp box has the correct compatible brands, but if it doesn't
4034
# then the plugin will raise a SyntaxError which Pillow will catch
4135
# before moving on to the next plugin that accepts the file.
4236
#
4337
# Also, because this file might not actually be an AVIF file, we
4438
# don't raise an error if AVIF support isn't properly compiled.
39+
b"mif1",
40+
b"msf1",
41+
):
42+
if not SUPPORTED:
43+
return (
44+
"image file could not be identified because AVIF "
45+
"support not installed"
46+
)
4547
return True
4648
return False
4749

@@ -72,6 +74,11 @@ def _open(self) -> None:
7274
)
7375
raise SyntaxError(msg)
7476

77+
if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
78+
DECODE_CODEC_CHOICE
79+
):
80+
msg = "Invalid opening codec"
81+
raise ValueError(msg)
7582
self._decoder = _avif.AvifDecoder(
7683
self.fp.read(),
7784
DECODE_CODEC_CHOICE,
@@ -104,10 +111,8 @@ def load(self) -> Image.core.PixelAccess | None:
104111
data, timescale, tsp_in_ts, dur_in_ts = self._decoder.get_frame(
105112
self.__frame
106113
)
107-
timestamp = round(1000 * (tsp_in_ts / timescale))
108-
duration = round(1000 * (dur_in_ts / timescale))
109-
self.info["timestamp"] = timestamp
110-
self.info["duration"] = duration
114+
self.info["timestamp"] = round(1000 * (tsp_in_ts / timescale))
115+
self.info["duration"] = round(1000 * (dur_in_ts / timescale))
111116
self.__loaded = self.__frame
112117

113118
# Set tile
@@ -153,6 +158,9 @@ def _save(
153158
speed = info.get("speed", 6)
154159
max_threads = info.get("max_threads", _get_default_max_threads())
155160
codec = info.get("codec", "auto")
161+
if codec != "auto" and not _avif.encoder_codec_available(codec):
162+
msg = "Invalid saving codec"
163+
raise ValueError(msg)
156164
range_ = info.get("range", "full")
157165
tile_rows_log2 = info.get("tile_rows", 0)
158166
tile_cols_log2 = info.get("tile_cols", 0)
@@ -199,7 +207,7 @@ def _save(
199207
)
200208
raise ValueError(msg)
201209
advanced = tuple(
202-
[(str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced]
210+
(str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced
203211
)
204212

205213
# Setup the AVIF encoder

0 commit comments

Comments
 (0)