mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-29 01:20:05 +03:00
Only use aom codec
This commit is contained in:
parent
cda26be10e
commit
3b5d4fbfeb
3
.github/workflows/macos-install.sh
vendored
3
.github/workflows/macos-install.sh
vendored
|
@ -7,7 +7,6 @@ if [[ "$ImageOS" == "macos13" ]]; then
|
||||||
fi
|
fi
|
||||||
brew install \
|
brew install \
|
||||||
aom \
|
aom \
|
||||||
dav1d \
|
|
||||||
freetype \
|
freetype \
|
||||||
ghostscript \
|
ghostscript \
|
||||||
jpeg-turbo \
|
jpeg-turbo \
|
||||||
|
@ -16,8 +15,6 @@ brew install \
|
||||||
libtiff \
|
libtiff \
|
||||||
little-cms2 \
|
little-cms2 \
|
||||||
openjpeg \
|
openjpeg \
|
||||||
rav1e \
|
|
||||||
svt-av1 \
|
|
||||||
webp
|
webp
|
||||||
export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"
|
export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"
|
||||||
|
|
||||||
|
|
13
.github/workflows/wheels-dependencies.sh
vendored
13
.github/workflows/wheels-dependencies.sh
vendored
|
@ -122,16 +122,6 @@ function build_libavif {
|
||||||
build_simple nasm 2.16.03 https://www.nasm.us/pub/nasm/releasebuilds/2.16.03
|
build_simple nasm 2.16.03 https://www.nasm.us/pub/nasm/releasebuilds/2.16.03
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For rav1e
|
|
||||||
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
|
||||||
. "$HOME/.cargo/env"
|
|
||||||
if [ -z "$IS_ALPINE" ] && [ -z "$SANITIZER" ] && [ -z "$IS_MACOS" ]; then
|
|
||||||
yum install -y perl
|
|
||||||
if [[ "$MB_ML_VER" == 2014 ]]; then
|
|
||||||
yum install -y perl-IPC-Cmd
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
local out_dir=$(fetch_unpack https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$LIBAVIF_VERSION.tar.gz libavif-$LIBAVIF_VERSION.tar.gz)
|
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 \
|
(cd $out_dir \
|
||||||
&& CMAKE_POLICY_VERSION_MINIMUM=3.5 cmake \
|
&& CMAKE_POLICY_VERSION_MINIMUM=3.5 cmake \
|
||||||
|
@ -142,9 +132,6 @@ function build_libavif {
|
||||||
-DAVIF_LIBSHARPYUV=LOCAL \
|
-DAVIF_LIBSHARPYUV=LOCAL \
|
||||||
-DAVIF_LIBYUV=LOCAL \
|
-DAVIF_LIBYUV=LOCAL \
|
||||||
-DAVIF_CODEC_AOM=LOCAL \
|
-DAVIF_CODEC_AOM=LOCAL \
|
||||||
-DAVIF_CODEC_DAV1D=LOCAL \
|
|
||||||
-DAVIF_CODEC_RAV1E=LOCAL \
|
|
||||||
-DAVIF_CODEC_SVT=LOCAL \
|
|
||||||
-DENABLE_NASM=ON \
|
-DENABLE_NASM=ON \
|
||||||
-DCMAKE_MODULE_PATH=/tmp/cmake/Modules \
|
-DCMAKE_MODULE_PATH=/tmp/cmake/Modules \
|
||||||
. \
|
. \
|
||||||
|
|
5
.github/workflows/wheels.yml
vendored
5
.github/workflows/wheels.yml
vendored
|
@ -160,11 +160,6 @@ jobs:
|
||||||
& python.exe winbuild\build_prepare.py -v --no-imagequant --architecture=${{ matrix.cibw_arch }}
|
& python.exe winbuild\build_prepare.py -v --no-imagequant --architecture=${{ matrix.cibw_arch }}
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
- name: Update rust
|
|
||||||
if: matrix.cibw_arch == 'AMD64'
|
|
||||||
run: |
|
|
||||||
rustup update
|
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
run: |
|
run: |
|
||||||
setlocal EnableDelayedExpansion
|
setlocal EnableDelayedExpansion
|
||||||
|
|
|
@ -51,20 +51,6 @@ def roundtrip(im: ImageFile.ImageFile, **options: Any) -> ImageFile.ImageFile:
|
||||||
return Image.open(out)
|
return Image.open(out)
|
||||||
|
|
||||||
|
|
||||||
def skip_unless_avif_decoder(codec_name: str) -> pytest.MarkDecorator:
|
|
||||||
reason = f"{codec_name} decode not available"
|
|
||||||
return pytest.mark.skipif(
|
|
||||||
not HAVE_AVIF or not _avif.decoder_codec_available(codec_name), reason=reason
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def skip_unless_avif_encoder(codec_name: str) -> pytest.MarkDecorator:
|
|
||||||
reason = f"{codec_name} encode not available"
|
|
||||||
return pytest.mark.skipif(
|
|
||||||
not HAVE_AVIF or not _avif.encoder_codec_available(codec_name), reason=reason
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_docker_qemu() -> bool:
|
def is_docker_qemu() -> bool:
|
||||||
try:
|
try:
|
||||||
init_proc_exe = os.readlink("/proc/1/exe")
|
init_proc_exe = os.readlink("/proc/1/exe")
|
||||||
|
@ -99,15 +85,12 @@ class TestFileAvif:
|
||||||
def test_codec_version(self) -> None:
|
def test_codec_version(self) -> None:
|
||||||
assert AvifImagePlugin.get_codec_version("unknown") is None
|
assert AvifImagePlugin.get_codec_version("unknown") is None
|
||||||
|
|
||||||
for codec_name in ("aom", "dav1d", "rav1e", "svt"):
|
codec_version = AvifImagePlugin.get_codec_version("aom")
|
||||||
codec_version = AvifImagePlugin.get_codec_version(codec_name)
|
if _avif.decoder_codec_available() or _avif.encoder_codec_available():
|
||||||
if _avif.decoder_codec_available(
|
assert codec_version is not None
|
||||||
codec_name
|
assert re.search(r"^v?\d+\.\d+\.\d+(-([a-z\d])+)*$", codec_version)
|
||||||
) or _avif.encoder_codec_available(codec_name):
|
else:
|
||||||
assert codec_version is not None
|
assert codec_version is None
|
||||||
assert re.search(r"^v?\d+\.\d+\.\d+(-([a-z\d])+)*$", codec_version)
|
|
||||||
else:
|
|
||||||
assert codec_version is None
|
|
||||||
|
|
||||||
def test_read(self) -> None:
|
def test_read(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -181,6 +164,10 @@ class TestFileAvif:
|
||||||
"""Save should raise an OSError if AvifEncoder.finish returns None"""
|
"""Save should raise an OSError if AvifEncoder.finish returns None"""
|
||||||
|
|
||||||
class _mock_avif:
|
class _mock_avif:
|
||||||
|
@classmethod
|
||||||
|
def encoder_codec_available(cls) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
class AvifEncoder:
|
class AvifEncoder:
|
||||||
def __init__(self, *args: Any) -> None:
|
def __init__(self, *args: Any) -> None:
|
||||||
pass
|
pass
|
||||||
|
@ -434,26 +421,6 @@ class TestFileAvif:
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
im.save(test_file, range="foo")
|
im.save(test_file, range="foo")
|
||||||
|
|
||||||
@skip_unless_avif_encoder("aom")
|
|
||||||
def test_encoder_codec_param(self, tmp_path: Path) -> None:
|
|
||||||
with Image.open(TEST_AVIF_FILE) as im:
|
|
||||||
test_file = tmp_path / "temp.avif"
|
|
||||||
im.save(test_file, codec="aom")
|
|
||||||
|
|
||||||
def test_encoder_codec_invalid(self, tmp_path: Path) -> None:
|
|
||||||
with Image.open(TEST_AVIF_FILE) as im:
|
|
||||||
test_file = tmp_path / "temp.avif"
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
im.save(test_file, codec="foo")
|
|
||||||
|
|
||||||
@skip_unless_avif_decoder("dav1d")
|
|
||||||
def test_decoder_codec_cannot_encode(self, tmp_path: Path) -> None:
|
|
||||||
with Image.open(TEST_AVIF_FILE) as im:
|
|
||||||
test_file = tmp_path / "temp.avif"
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
im.save(test_file, codec="dav1d")
|
|
||||||
|
|
||||||
@skip_unless_avif_encoder("aom")
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"advanced",
|
"advanced",
|
||||||
[
|
[
|
||||||
|
@ -470,17 +437,15 @@ class TestFileAvif:
|
||||||
) -> None:
|
) -> None:
|
||||||
with Image.open(TEST_AVIF_FILE) as im:
|
with Image.open(TEST_AVIF_FILE) as im:
|
||||||
ctrl_buf = BytesIO()
|
ctrl_buf = BytesIO()
|
||||||
im.save(ctrl_buf, "AVIF", codec="aom")
|
im.save(ctrl_buf, "AVIF")
|
||||||
test_buf = BytesIO()
|
test_buf = BytesIO()
|
||||||
im.save(
|
im.save(
|
||||||
test_buf,
|
test_buf,
|
||||||
"AVIF",
|
"AVIF",
|
||||||
codec="aom",
|
|
||||||
advanced=advanced,
|
advanced=advanced,
|
||||||
)
|
)
|
||||||
assert ctrl_buf.getvalue() != test_buf.getvalue()
|
assert ctrl_buf.getvalue() != test_buf.getvalue()
|
||||||
|
|
||||||
@skip_unless_avif_encoder("aom")
|
|
||||||
@pytest.mark.parametrize("advanced", [{"foo": "bar"}, {"foo": 1234}, 1234])
|
@pytest.mark.parametrize("advanced", [{"foo": "bar"}, {"foo": 1234}, 1234])
|
||||||
def test_encoder_advanced_codec_options_invalid(
|
def test_encoder_advanced_codec_options_invalid(
|
||||||
self, tmp_path: Path, advanced: dict[str, str] | int
|
self, tmp_path: Path, advanced: dict[str, str] | int
|
||||||
|
@ -488,46 +453,7 @@ class TestFileAvif:
|
||||||
with Image.open(TEST_AVIF_FILE) as im:
|
with Image.open(TEST_AVIF_FILE) as im:
|
||||||
test_file = tmp_path / "temp.avif"
|
test_file = tmp_path / "temp.avif"
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
im.save(test_file, codec="aom", advanced=advanced)
|
im.save(test_file, advanced=advanced)
|
||||||
|
|
||||||
@skip_unless_avif_decoder("aom")
|
|
||||||
def test_decoder_codec_param(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
||||||
monkeypatch.setattr(AvifImagePlugin, "DECODE_CODEC_CHOICE", "aom")
|
|
||||||
|
|
||||||
with Image.open(TEST_AVIF_FILE) as im:
|
|
||||||
assert im.size == (128, 128)
|
|
||||||
|
|
||||||
@skip_unless_avif_encoder("rav1e")
|
|
||||||
def test_encoder_codec_cannot_decode(
|
|
||||||
self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
||||||
) -> None:
|
|
||||||
monkeypatch.setattr(AvifImagePlugin, "DECODE_CODEC_CHOICE", "rav1e")
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
with Image.open(TEST_AVIF_FILE):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_decoder_codec_invalid(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
||||||
monkeypatch.setattr(AvifImagePlugin, "DECODE_CODEC_CHOICE", "foo")
|
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
with Image.open(TEST_AVIF_FILE):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@skip_unless_avif_encoder("aom")
|
|
||||||
def test_encoder_codec_available(self) -> None:
|
|
||||||
assert _avif.encoder_codec_available("aom") is True
|
|
||||||
|
|
||||||
def test_encoder_codec_available_bad_params(self) -> None:
|
|
||||||
with pytest.raises(TypeError):
|
|
||||||
_avif.encoder_codec_available()
|
|
||||||
|
|
||||||
@skip_unless_avif_decoder("dav1d")
|
|
||||||
def test_encoder_codec_available_cannot_decode(self) -> None:
|
|
||||||
assert _avif.encoder_codec_available("dav1d") is False
|
|
||||||
|
|
||||||
def test_encoder_codec_available_invalid(self) -> None:
|
|
||||||
assert _avif.encoder_codec_available("foo") is False
|
|
||||||
|
|
||||||
def test_encoder_quality_valueerror(self, tmp_path: Path) -> None:
|
def test_encoder_quality_valueerror(self, tmp_path: Path) -> None:
|
||||||
with Image.open(TEST_AVIF_FILE) as im:
|
with Image.open(TEST_AVIF_FILE) as im:
|
||||||
|
@ -535,21 +461,6 @@ class TestFileAvif:
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
im.save(test_file, quality="invalid")
|
im.save(test_file, quality="invalid")
|
||||||
|
|
||||||
@skip_unless_avif_decoder("aom")
|
|
||||||
def test_decoder_codec_available(self) -> None:
|
|
||||||
assert _avif.decoder_codec_available("aom") is True
|
|
||||||
|
|
||||||
def test_decoder_codec_available_bad_params(self) -> None:
|
|
||||||
with pytest.raises(TypeError):
|
|
||||||
_avif.decoder_codec_available()
|
|
||||||
|
|
||||||
@skip_unless_avif_encoder("rav1e")
|
|
||||||
def test_decoder_codec_available_cannot_decode(self) -> None:
|
|
||||||
assert _avif.decoder_codec_available("rav1e") is False
|
|
||||||
|
|
||||||
def test_decoder_codec_available_invalid(self) -> None:
|
|
||||||
assert _avif.decoder_codec_available("foo") is False
|
|
||||||
|
|
||||||
def test_p_mode_transparency(self, tmp_path: Path) -> None:
|
def test_p_mode_transparency(self, tmp_path: Path) -> None:
|
||||||
im = Image.new("P", size=(64, 64))
|
im = Image.new("P", size=(64, 64))
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
|
@ -570,16 +481,10 @@ class TestFileAvif:
|
||||||
with Image.open("Tests/images/avif/hopper-missing-pixi.avif") as im:
|
with Image.open("Tests/images/avif/hopper-missing-pixi.avif") as im:
|
||||||
assert im.size == (128, 128)
|
assert im.size == (128, 128)
|
||||||
|
|
||||||
@skip_unless_avif_encoder("aom")
|
|
||||||
@pytest.mark.parametrize("speed", [-1, 1, 11])
|
@pytest.mark.parametrize("speed", [-1, 1, 11])
|
||||||
def test_aom_optimizations(self, tmp_path: Path, speed: int) -> None:
|
def test_aom_optimizations(self, tmp_path: Path, speed: int) -> None:
|
||||||
test_file = tmp_path / "temp.avif"
|
test_file = tmp_path / "temp.avif"
|
||||||
hopper().save(test_file, codec="aom", speed=speed)
|
hopper().save(test_file, speed=speed)
|
||||||
|
|
||||||
@skip_unless_avif_encoder("svt")
|
|
||||||
def test_svt_optimizations(self, tmp_path: Path) -> None:
|
|
||||||
test_file = tmp_path / "temp.avif"
|
|
||||||
hopper().save(test_file, codec="svt", speed=1)
|
|
||||||
|
|
||||||
|
|
||||||
@skip_unless_feature("avif")
|
@skip_unless_feature("avif")
|
||||||
|
|
|
@ -25,26 +25,6 @@ if $PKGCONFIG --exists aom; then
|
||||||
HAS_DECODER=1
|
HAS_DECODER=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if $PKGCONFIG --exists dav1d; then
|
|
||||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_DAV1D=SYSTEM)
|
|
||||||
HAS_DECODER=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $PKGCONFIG --exists libgav1; then
|
|
||||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_LIBGAV1=SYSTEM)
|
|
||||||
HAS_DECODER=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $PKGCONFIG --exists rav1e; then
|
|
||||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_RAV1E=SYSTEM)
|
|
||||||
HAS_ENCODER=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $PKGCONFIG --exists SvtAv1Enc; then
|
|
||||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_SVT=SYSTEM)
|
|
||||||
HAS_ENCODER=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$HAS_ENCODER" != 1 ] || [ "$HAS_DECODER" != 1 ]; then
|
if [ "$HAS_ENCODER" != 1 ] || [ "$HAS_DECODER" != 1 ]; then
|
||||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_AOM=LOCAL)
|
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_AOM=LOCAL)
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -50,17 +50,11 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
||||||
Quality/speed trade-off (0=slower/better, 10=fastest). Defaults to 6.
|
Quality/speed trade-off (0=slower/better, 10=fastest). Defaults to 6.
|
||||||
|
|
||||||
**max_threads**
|
**max_threads**
|
||||||
Limit the number of active threads used. By default, there is no limit. If the aom
|
Limit the number of active threads used. There is a maximum of 64.
|
||||||
codec is used, there is a maximum of 64.
|
|
||||||
|
|
||||||
**range**
|
**range**
|
||||||
YUV range, either "full" or "limited". Defaults to "full".
|
YUV range, either "full" or "limited". Defaults to "full".
|
||||||
|
|
||||||
**codec**
|
|
||||||
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**
|
**tile_rows** / **tile_cols**
|
||||||
For tile encoding, the (log 2) number of tile rows and columns to use.
|
For tile encoding, the (log 2) number of tile rows and columns to use.
|
||||||
Valid values are 0-6, default 0. Ignored if "autotiling" is set to true.
|
Valid values are 0-6, default 0. Ignored if "autotiling" is set to true.
|
||||||
|
|
|
@ -92,10 +92,9 @@ Many of Pillow's features require external libraries:
|
||||||
* **libavif** provides support for the AVIF format.
|
* **libavif** provides support for the AVIF format.
|
||||||
|
|
||||||
* Pillow requires libavif version **1.0.0** or greater.
|
* Pillow requires libavif version **1.0.0** or greater.
|
||||||
* libavif is merely an API that wraps AVIF codecs. If you are compiling
|
* libavif is merely an API that wraps AVIF codecs. If you are compiling libavif from
|
||||||
libavif from source, you will also need to install both an AVIF encoder
|
source, you will also need to install libaom, which both encodes and decodes AVIF
|
||||||
and decoder, such as rav1e and dav1d, or libaom, which both encodes and
|
images.
|
||||||
decodes AVIF images.
|
|
||||||
|
|
||||||
.. tab:: Linux
|
.. tab:: Linux
|
||||||
|
|
||||||
|
@ -164,14 +163,6 @@ Many of Pillow's features require external libraries:
|
||||||
|
|
||||||
brew install libavif libjpeg libraqm libtiff little-cms2 openjpeg webp
|
brew install libavif libjpeg libraqm libtiff little-cms2 openjpeg webp
|
||||||
|
|
||||||
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 svt-av1
|
|
||||||
|
|
||||||
Then see ``depends/install_libavif.sh`` to install libavif.
|
|
||||||
|
|
||||||
.. tab:: Windows
|
.. tab:: Windows
|
||||||
|
|
||||||
We recommend you use prebuilt wheels from PyPI.
|
We recommend you use prebuilt wheels from PyPI.
|
||||||
|
|
|
@ -13,9 +13,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
SUPPORTED = False
|
SUPPORTED = False
|
||||||
|
|
||||||
# Decoder options as module globals, until there is a way to pass parameters
|
|
||||||
# to Image.open (see https://github.com/python-pillow/Pillow/issues/569)
|
|
||||||
DECODE_CODEC_CHOICE = "auto"
|
|
||||||
# Decoding is only affected by this for libavif **0.8.4** or greater.
|
# Decoding is only affected by this for libavif **0.8.4** or greater.
|
||||||
DEFAULT_MAX_THREADS = 0
|
DEFAULT_MAX_THREADS = 0
|
||||||
|
|
||||||
|
@ -73,14 +70,11 @@ class AvifImageFile(ImageFile.ImageFile):
|
||||||
msg = "image file could not be opened because AVIF support not installed"
|
msg = "image file could not be opened because AVIF support not installed"
|
||||||
raise SyntaxError(msg)
|
raise SyntaxError(msg)
|
||||||
|
|
||||||
if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
|
if not _avif.decoder_codec_available():
|
||||||
DECODE_CODEC_CHOICE
|
msg = "Codec not available"
|
||||||
):
|
|
||||||
msg = "Invalid opening codec"
|
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
self._decoder = _avif.AvifDecoder(
|
self._decoder = _avif.AvifDecoder(
|
||||||
self.fp.read(),
|
self.fp.read(),
|
||||||
DECODE_CODEC_CHOICE,
|
|
||||||
_get_default_max_threads(),
|
_get_default_max_threads(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -165,9 +159,8 @@ def _save(
|
||||||
subsampling = info.get("subsampling", "4:2:0")
|
subsampling = info.get("subsampling", "4:2:0")
|
||||||
speed = info.get("speed", 6)
|
speed = info.get("speed", 6)
|
||||||
max_threads = info.get("max_threads", _get_default_max_threads())
|
max_threads = info.get("max_threads", _get_default_max_threads())
|
||||||
codec = info.get("codec", "auto")
|
if not _avif.encoder_codec_available():
|
||||||
if codec != "auto" and not _avif.encoder_codec_available(codec):
|
msg = "Codec not available"
|
||||||
msg = "Invalid saving codec"
|
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
range_ = info.get("range", "full")
|
range_ = info.get("range", "full")
|
||||||
tile_rows_log2 = info.get("tile_rows", 0)
|
tile_rows_log2 = info.get("tile_rows", 0)
|
||||||
|
@ -218,7 +211,6 @@ def _save(
|
||||||
quality,
|
quality,
|
||||||
speed,
|
speed,
|
||||||
max_threads,
|
max_threads,
|
||||||
codec,
|
|
||||||
range_,
|
range_,
|
||||||
tile_rows_log2,
|
tile_rows_log2,
|
||||||
tile_cols_log2,
|
tile_cols_log2,
|
||||||
|
|
37
src/_avif.c
37
src/_avif.c
|
@ -142,21 +142,13 @@ _codec_available(const char *name, avifCodecFlags flags) {
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_decoder_codec_available(PyObject *self, PyObject *args) {
|
_decoder_codec_available(PyObject *self, PyObject *args) {
|
||||||
char *codec_name;
|
int is_available = _codec_available("aom", AVIF_CODEC_FLAG_CAN_DECODE);
|
||||||
if (!PyArg_ParseTuple(args, "s", &codec_name)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int is_available = _codec_available(codec_name, AVIF_CODEC_FLAG_CAN_DECODE);
|
|
||||||
return PyBool_FromLong(is_available);
|
return PyBool_FromLong(is_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_encoder_codec_available(PyObject *self, PyObject *args) {
|
_encoder_codec_available(PyObject *self, PyObject *args) {
|
||||||
char *codec_name;
|
int is_available = _codec_available("aom", AVIF_CODEC_FLAG_CAN_ENCODE);
|
||||||
if (!PyArg_ParseTuple(args, "s", &codec_name)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int is_available = _codec_available(codec_name, AVIF_CODEC_FLAG_CAN_ENCODE);
|
|
||||||
return PyBool_FromLong(is_available);
|
return PyBool_FromLong(is_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +221,6 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
int tile_rows_log2;
|
int tile_rows_log2;
|
||||||
int tile_cols_log2;
|
int tile_cols_log2;
|
||||||
|
|
||||||
char *codec;
|
|
||||||
char *range;
|
char *range;
|
||||||
|
|
||||||
PyObject *advanced;
|
PyObject *advanced;
|
||||||
|
@ -237,14 +228,13 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(
|
if (!PyArg_ParseTuple(
|
||||||
args,
|
args,
|
||||||
"(II)siiissiippy*y*iy*O",
|
"(II)siiisiippy*y*iy*O",
|
||||||
&width,
|
&width,
|
||||||
&height,
|
&height,
|
||||||
&subsampling,
|
&subsampling,
|
||||||
&quality,
|
&quality,
|
||||||
&speed,
|
&speed,
|
||||||
&max_threads,
|
&max_threads,
|
||||||
&codec,
|
|
||||||
&range,
|
&range,
|
||||||
&tile_rows_log2,
|
&tile_rows_log2,
|
||||||
&tile_cols_log2,
|
&tile_cols_log2,
|
||||||
|
@ -310,18 +300,10 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_aom_encode = strcmp(codec, "aom") == 0 ||
|
encoder->maxThreads = max_threads > 64 ? 64 : max_threads;
|
||||||
(strcmp(codec, "auto") == 0 &&
|
|
||||||
_codec_available("aom", AVIF_CODEC_FLAG_CAN_ENCODE));
|
|
||||||
encoder->maxThreads = is_aom_encode && max_threads > 64 ? 64 : max_threads;
|
|
||||||
|
|
||||||
encoder->quality = quality;
|
encoder->quality = quality;
|
||||||
|
|
||||||
if (strcmp(codec, "auto") == 0) {
|
|
||||||
encoder->codecChoice = AVIF_CODEC_CHOICE_AUTO;
|
|
||||||
} else {
|
|
||||||
encoder->codecChoice = avifCodecChoiceFromName(codec);
|
|
||||||
}
|
|
||||||
if (speed < AVIF_SPEED_SLOWEST) {
|
if (speed < AVIF_SPEED_SLOWEST) {
|
||||||
speed = AVIF_SPEED_SLOWEST;
|
speed = AVIF_SPEED_SLOWEST;
|
||||||
} else if (speed > AVIF_SPEED_FASTEST) {
|
} else if (speed > AVIF_SPEED_FASTEST) {
|
||||||
|
@ -616,22 +598,14 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
|
||||||
AvifDecoderObject *self = NULL;
|
AvifDecoderObject *self = NULL;
|
||||||
avifDecoder *decoder;
|
avifDecoder *decoder;
|
||||||
|
|
||||||
char *codec_str;
|
|
||||||
avifCodecChoice codec;
|
|
||||||
int max_threads;
|
int max_threads;
|
||||||
|
|
||||||
avifResult result;
|
avifResult result;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "y*si", &buffer, &codec_str, &max_threads)) {
|
if (!PyArg_ParseTuple(args, "y*i", &buffer, &max_threads)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(codec_str, "auto") == 0) {
|
|
||||||
codec = AVIF_CODEC_CHOICE_AUTO;
|
|
||||||
} else {
|
|
||||||
codec = avifCodecChoiceFromName(codec_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
self = PyObject_New(AvifDecoderObject, &AvifDecoder_Type);
|
self = PyObject_New(AvifDecoderObject, &AvifDecoder_Type);
|
||||||
if (!self) {
|
if (!self) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "could not create decoder object");
|
PyErr_SetString(PyExc_RuntimeError, "could not create decoder object");
|
||||||
|
@ -653,7 +627,6 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
|
||||||
// items. libheif v1.11.0 and older does not add the 'pixi' item property to
|
// items. libheif v1.11.0 and older does not add the 'pixi' item property to
|
||||||
// AV1 image items.
|
// AV1 image items.
|
||||||
decoder->strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED;
|
decoder->strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED;
|
||||||
decoder->codecChoice = codec;
|
|
||||||
|
|
||||||
result = avifDecoderSetIOMemory(decoder, buffer.buf, buffer.len);
|
result = avifDecoderSetIOMemory(decoder, buffer.buf, buffer.len);
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
Copyright © 2018-2019, VideoLAN and dav1d authors
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,25 +0,0 @@
|
||||||
BSD 2-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2017-2023, the rav1e contributors
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,26 +0,0 @@
|
||||||
Copyright (c) 2019, Alliance for Open Media. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in
|
|
||||||
the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -392,9 +392,6 @@ DEPS: dict[str, dict[str, Any]] = {
|
||||||
"-DAVIF_LIBSHARPYUV=LOCAL",
|
"-DAVIF_LIBSHARPYUV=LOCAL",
|
||||||
"-DAVIF_LIBYUV=LOCAL",
|
"-DAVIF_LIBYUV=LOCAL",
|
||||||
"-DAVIF_CODEC_AOM=LOCAL",
|
"-DAVIF_CODEC_AOM=LOCAL",
|
||||||
"-DAVIF_CODEC_DAV1D=LOCAL",
|
|
||||||
"-DAVIF_CODEC_RAV1E=LOCAL",
|
|
||||||
"-DAVIF_CODEC_SVT=LOCAL",
|
|
||||||
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
||||||
),
|
),
|
||||||
cmd_xcopy("include", "{inc_dir}"),
|
cmd_xcopy("include", "{inc_dir}"),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user