mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-26 07:59:51 +03:00
Merge branch 'main' into imagecms-typing
This commit is contained in:
commit
5cdaa1e46c
|
@ -1,10 +1,11 @@
|
|||
mypy==1.16.1
|
||||
mypy==1.17.0
|
||||
IceSpringPySideStubs-PyQt6
|
||||
IceSpringPySideStubs-PySide6
|
||||
ipython
|
||||
numpy
|
||||
packaging
|
||||
pyarrow-stubs
|
||||
pybind11
|
||||
pytest
|
||||
sphinx
|
||||
types-atheris
|
||||
|
|
19
.github/workflows/wheels-dependencies.sh
vendored
19
.github/workflows/wheels-dependencies.sh
vendored
|
@ -60,7 +60,7 @@ if [[ "$CIBW_PLATFORM" == "ios" ]]; then
|
|||
# on using the Xcode builder, which isn't very helpful for most of Pillow's
|
||||
# dependencies. Therefore, we lean on the OSX configurations, plus CC, CFLAGS
|
||||
# etc. to ensure the right sysroot is selected.
|
||||
HOST_CMAKE_FLAGS="-DCMAKE_SYSTEM_NAME=$CMAKE_SYSTEM_NAME -DCMAKE_SYSTEM_PROCESSOR=$GNU_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET -DCMAKE_OSX_SYSROOT=$IOS_SDK_PATH -DBUILD_SHARED_LIBS=NO"
|
||||
HOST_CMAKE_FLAGS="-DCMAKE_SYSTEM_NAME=$CMAKE_SYSTEM_NAME -DCMAKE_SYSTEM_PROCESSOR=$GNU_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET -DCMAKE_OSX_SYSROOT=$IOS_SDK_PATH -DBUILD_SHARED_LIBS=NO -DENABLE_SHARED=NO"
|
||||
|
||||
# Meson needs to be pointed at a cross-platform configuration file
|
||||
# This will be generated once CC etc. have been evaluated.
|
||||
|
@ -103,7 +103,7 @@ TIFF_VERSION=4.7.0
|
|||
LCMS2_VERSION=2.17
|
||||
ZLIB_VERSION=1.3.1
|
||||
ZLIB_NG_VERSION=2.2.4
|
||||
LIBWEBP_VERSION=1.5.0 # Patched; next release won't need patching. See patch file.
|
||||
LIBWEBP_VERSION=1.6.0
|
||||
BZIP2_VERSION=1.0.8
|
||||
LIBXCB_VERSION=1.17.0
|
||||
BROTLI_VERSION=1.1.0 # Patched; next release won't need patching. See patch file.
|
||||
|
@ -280,7 +280,11 @@ function build {
|
|||
if [[ -n "$IS_MACOS" ]]; then
|
||||
webp_cflags="$webp_cflags -Wl,-headerpad_max_install_names"
|
||||
fi
|
||||
CFLAGS="$CFLAGS $webp_cflags" build_simple libwebp $LIBWEBP_VERSION \
|
||||
webp_ldflags=""
|
||||
if [[ -n "$IOS_SDK" ]]; then
|
||||
webp_ldflags="$webp_ldflags -llzma -lz"
|
||||
fi
|
||||
CFLAGS="$CFLAGS $webp_cflags" LDFLAGS="$LDFLAGS $webp_ldflags" build_simple libwebp $LIBWEBP_VERSION \
|
||||
https://storage.googleapis.com/downloads.webmproject.org/releases/webp tar.gz \
|
||||
--enable-libwebpmux --enable-libwebpdemux
|
||||
|
||||
|
@ -380,6 +384,15 @@ fi
|
|||
|
||||
wrap_wheel_builder build
|
||||
|
||||
# A safety catch for iOS. iOS can't use dynamic libraries, but clang will prefer
|
||||
# to link dynamic libraries to static libraries. The only way to reliably
|
||||
# prevent this is to not have dynamic libraries available in the first place.
|
||||
# The build process *shouldn't* generate any dylibs... but just in case, purge
|
||||
# any dylibs that *have* been installed into the build prefix directory.
|
||||
if [[ -n "$IOS_SDK" ]]; then
|
||||
find "$BUILD_PREFIX" -name "*.dylib" -exec rm -rf {} \;
|
||||
fi
|
||||
|
||||
# Return to the project root to finish the build
|
||||
popd > /dev/null
|
||||
|
||||
|
|
12
MANIFEST.in
12
MANIFEST.in
|
@ -13,6 +13,7 @@ include LICENSE
|
|||
include Makefile
|
||||
include tox.ini
|
||||
graft Tests
|
||||
graft Tests/images
|
||||
graft checks
|
||||
graft patches
|
||||
graft src
|
||||
|
@ -28,8 +29,19 @@ exclude .editorconfig
|
|||
exclude .readthedocs.yml
|
||||
exclude codecov.yml
|
||||
exclude renovate.json
|
||||
exclude Tests/images/README.md
|
||||
exclude Tests/images/crash*.tif
|
||||
exclude Tests/images/string_dimension.tiff
|
||||
global-exclude .git*
|
||||
global-exclude *.pyc
|
||||
global-exclude *.so
|
||||
prune .ci
|
||||
prune wheels
|
||||
prune winbuild/build
|
||||
prune winbuild/depends
|
||||
prune Tests/errors
|
||||
prune Tests/images/jpeg2000
|
||||
prune Tests/images/msp
|
||||
prune Tests/images/picins
|
||||
prune Tests/images/sunraster
|
||||
prune Tests/test-images
|
||||
|
|
|
@ -291,16 +291,6 @@ def djpeg_available() -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def cjpeg_available() -> bool:
|
||||
if shutil.which("cjpeg"):
|
||||
try:
|
||||
subprocess.check_call(["cjpeg", "-version"])
|
||||
return True
|
||||
except subprocess.CalledProcessError: # pragma: no cover
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def netpbm_available() -> bool:
|
||||
return bool(shutil.which("ppmquant") and shutil.which("ppmtogif"))
|
||||
|
||||
|
|
BIN
Tests/images/unimplemented_pixel_format.dds
Normal file
BIN
Tests/images/unimplemented_pixel_format.dds
Normal file
Binary file not shown.
|
@ -380,21 +380,28 @@ def test_palette() -> None:
|
|||
assert_image_equal_tofile(im, "Tests/images/transparent.gif")
|
||||
|
||||
|
||||
def test_unsupported_header_size() -> None:
|
||||
with pytest.raises(OSError, match="Unsupported header size 0"):
|
||||
with Image.open(BytesIO(b"DDS " + b"\x00" * 4)):
|
||||
pass
|
||||
|
||||
|
||||
def test_unsupported_bitcount() -> None:
|
||||
with pytest.raises(OSError):
|
||||
with pytest.raises(OSError, match="Unsupported bitcount 24 for 131072"):
|
||||
with Image.open("Tests/images/unsupported_bitcount.dds"):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_file",
|
||||
"test_file, message",
|
||||
(
|
||||
"Tests/images/unimplemented_dxgi_format.dds",
|
||||
"Tests/images/unimplemented_pfflags.dds",
|
||||
("Tests/images/unimplemented_dxgi_format.dds", "Unimplemented DXGI format 93"),
|
||||
("Tests/images/unimplemented_pixel_format.dds", "Unimplemented pixel format 0"),
|
||||
("Tests/images/unimplemented_pfflags.dds", "Unknown pixel format flags 8"),
|
||||
),
|
||||
)
|
||||
def test_not_implemented(test_file: str) -> None:
|
||||
with pytest.raises(NotImplementedError):
|
||||
def test_not_implemented(test_file: str, message: str) -> None:
|
||||
with pytest.raises(NotImplementedError, match=message):
|
||||
with Image.open(test_file):
|
||||
pass
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ from .helper import (
|
|||
assert_image_equal_tofile,
|
||||
assert_image_similar,
|
||||
assert_image_similar_tofile,
|
||||
cjpeg_available,
|
||||
djpeg_available,
|
||||
hopper,
|
||||
is_win32,
|
||||
|
@ -731,14 +730,6 @@ class TestFileJpeg:
|
|||
img.load_djpeg()
|
||||
assert_image_similar_tofile(img, TEST_FILE, 5)
|
||||
|
||||
@pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available")
|
||||
def test_save_cjpeg(self, tmp_path: Path) -> None:
|
||||
with Image.open(TEST_FILE) as img:
|
||||
tempfile = str(tmp_path / "temp.jpg")
|
||||
JpegImagePlugin._save_cjpeg(img, BytesIO(), tempfile)
|
||||
# Default save quality is 75%, so a tiny bit of difference is alright
|
||||
assert_image_similar_tofile(img, tempfile, 17)
|
||||
|
||||
def test_no_duplicate_0x1001_tag(self) -> None:
|
||||
# Arrange
|
||||
tag_ids = {v: k for k, v in ExifTags.TAGS.items()}
|
||||
|
|
|
@ -873,8 +873,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert im.mode == "RGB"
|
||||
assert im.size == (128, 128)
|
||||
assert im.format == "TIFF"
|
||||
im2 = hopper()
|
||||
assert_image_similar(im, im2, 5)
|
||||
with hopper() as im2:
|
||||
assert_image_similar(im, im2, 5)
|
||||
except OSError:
|
||||
captured = capfd.readouterr()
|
||||
if "LZMA compression support is not configured" in captured.err:
|
||||
|
|
|
@ -44,6 +44,18 @@ def test_load_zero_inch() -> None:
|
|||
pass
|
||||
|
||||
|
||||
def test_load_unsupported_wmf() -> None:
|
||||
b = BytesIO(b"\xd7\xcd\xc6\x9a\x00\x00" + b"\x01" * 10)
|
||||
with pytest.raises(SyntaxError, match="Unsupported WMF file format"):
|
||||
WmfImagePlugin.WmfStubImageFile(b)
|
||||
|
||||
|
||||
def test_load_unsupported() -> None:
|
||||
b = BytesIO(b"\x01\x00\x00\x00")
|
||||
with pytest.raises(SyntaxError, match="Unsupported file format"):
|
||||
WmfImagePlugin.WmfStubImageFile(b)
|
||||
|
||||
|
||||
def test_render() -> None:
|
||||
with open("Tests/images/drawing.emf", "rb") as fp:
|
||||
data = fp.read()
|
||||
|
|
|
@ -315,3 +315,6 @@ int main(int argc, char* argv[])
|
|||
process = subprocess.Popen(["embed_pil.exe"], env=env)
|
||||
process.communicate()
|
||||
assert process.returncode == 0
|
||||
|
||||
def teardown_method(self) -> None:
|
||||
os.remove("embed_pil.c")
|
||||
|
|
|
@ -2,7 +2,9 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any
|
||||
|
||||
from PIL import Image, ImageMath
|
||||
import pytest
|
||||
|
||||
from PIL import Image, ImageMath, _imagingmath
|
||||
|
||||
|
||||
def pixel(im: Image.Image | int) -> str | int:
|
||||
|
@ -498,3 +500,31 @@ def test_logical_not_equal() -> None:
|
|||
)
|
||||
== "I 1"
|
||||
)
|
||||
|
||||
|
||||
def test_reflected_operands() -> None:
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 + args["A"], **images)) == "I 2"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 - args["A"], **images)) == "I 0"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 * args["A"], **images)) == "I 1"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 / args["A"], **images)) == "I 1"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 % args["A"], **images)) == "I 0"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 ** args["A"], **images)) == "I 1"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 & args["A"], **images)) == "I 1"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 | args["A"], **images)) == "I 1"
|
||||
assert pixel(ImageMath.lambda_eval(lambda args: 1 ^ args["A"], **images)) == "I 0"
|
||||
|
||||
|
||||
def test_unsupported_mode() -> None:
|
||||
im = Image.new("RGB", (1, 1))
|
||||
with pytest.raises(ValueError, match="unsupported mode: RGB"):
|
||||
ImageMath.lambda_eval(lambda args: args["im"] + 1, im=im)
|
||||
|
||||
|
||||
def test_bad_operand_type(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.delattr(_imagingmath, "abs_I")
|
||||
with pytest.raises(TypeError, match="bad operand type for 'abs'"):
|
||||
ImageMath.lambda_eval(lambda args: abs(args["I"]), I=I)
|
||||
|
||||
monkeypatch.delattr(_imagingmath, "max_F")
|
||||
with pytest.raises(TypeError, match="bad operand type for 'max'"):
|
||||
ImageMath.lambda_eval(lambda args: args["max"](args["I"], args["F"]), I=I, F=F)
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from importlib.metadata import metadata
|
||||
|
||||
import pytest
|
||||
|
||||
from PIL import __version__
|
||||
|
@ -11,7 +9,7 @@ pyroma = pytest.importorskip("pyroma", reason="Pyroma not installed")
|
|||
|
||||
def test_pyroma() -> None:
|
||||
# Arrange
|
||||
data = pyroma.projectdata.map_metadata_keys(metadata("Pillow"))
|
||||
data = pyroma.projectdata.get_data(".")
|
||||
|
||||
# Act
|
||||
rating = pyroma.ratings.rate(data)
|
||||
|
|
|
@ -9,7 +9,7 @@ import pytest
|
|||
|
||||
from PIL import GifImagePlugin, Image, JpegImagePlugin
|
||||
|
||||
from .helper import cjpeg_available, djpeg_available, is_win32, netpbm_available
|
||||
from .helper import djpeg_available, is_win32, netpbm_available
|
||||
|
||||
TEST_JPG = "Tests/images/hopper.jpg"
|
||||
TEST_GIF = "Tests/images/hopper.gif"
|
||||
|
@ -42,11 +42,6 @@ class TestShellInjection:
|
|||
assert isinstance(im, JpegImagePlugin.JpegImageFile)
|
||||
im.load_djpeg()
|
||||
|
||||
@pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available")
|
||||
def test_save_cjpeg_filename(self, tmp_path: Path) -> None:
|
||||
with Image.open(TEST_JPG) as im:
|
||||
self.assert_save_filename_check(tmp_path, im, JpegImagePlugin._save_cjpeg)
|
||||
|
||||
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
|
||||
def test_save_netpbm_filename_bmp_mode(self, tmp_path: Path) -> None:
|
||||
with Image.open(TEST_GIF) as im:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# install webp
|
||||
|
||||
archive=libwebp-1.5.0
|
||||
archive=libwebp-1.6.0
|
||||
|
||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
||||
|
||||
|
|
|
@ -12,13 +12,6 @@ Deprecated features
|
|||
Below are features which are considered deprecated. Where appropriate,
|
||||
a :py:exc:`DeprecationWarning` is issued.
|
||||
|
||||
ImageDraw.getdraw hints parameter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. deprecated:: 10.4.0
|
||||
|
||||
The ``hints`` parameter in :py:meth:`~PIL.ImageDraw.getdraw()` has been deprecated.
|
||||
|
||||
ExifTags.IFD.Makernote
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -195,6 +188,7 @@ ICNS (width, height, scale) sizes
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. deprecated:: 11.0.0
|
||||
.. versionremoved:: 12.0.0
|
||||
|
||||
Setting an ICNS image size to ``(width, height, scale)`` before loading has been
|
||||
removed. Instead, ``load(scale)`` can be used.
|
||||
|
|
|
@ -101,6 +101,28 @@ Palette
|
|||
The palette mode (``P``) uses a color palette to define the actual color for
|
||||
each pixel.
|
||||
|
||||
.. _colors:
|
||||
|
||||
Colors
|
||||
------
|
||||
|
||||
To specify colors, you can use tuples with a value for each channel in the image, e.g.
|
||||
``Image.new("RGB", (1, 1), (255, 0, 0))``.
|
||||
|
||||
If an image has a single channel, you can use a single number instead, e.g.
|
||||
``Image.new("L", (1, 1), 255)``. For "F" mode images, floating point values are also
|
||||
accepted. In the case of "P" mode images, these will be indexes for the color palette.
|
||||
|
||||
If a single value is used for an image with more than one channel, it will still be
|
||||
parsed::
|
||||
|
||||
>>> from PIL import Image
|
||||
>>> im = Image.new("RGBA", (1, 1), 0x04030201)
|
||||
>>> im.getpixel((0, 0))
|
||||
(1, 2, 3, 4)
|
||||
|
||||
Some methods accept other forms, such as color names. See :ref:`color-names`.
|
||||
|
||||
Info
|
||||
----
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ Many of Pillow's features require external libraries:
|
|||
|
||||
* **libtiff** provides compressed TIFF functionality
|
||||
|
||||
* Pillow has been tested with libtiff versions **3.x** and **4.0-4.7.0**
|
||||
* Pillow has been tested with libtiff versions **4.0-4.7.0**
|
||||
|
||||
* **libfreetype** provides type related services
|
||||
|
||||
|
@ -276,10 +276,9 @@ Build options
|
|||
|
||||
* Config setting: ``-C parallel=n``. Can also be given
|
||||
with environment variable: ``MAX_CONCURRENCY=n``. Pillow can use
|
||||
multiprocessing to build the extension. Setting ``-C parallel=n``
|
||||
multiprocessing to build the extensions. Setting ``-C parallel=n``
|
||||
sets the number of CPUs to use to ``n``, or can disable parallel building by
|
||||
using a setting of 1. By default, it uses 4 CPUs, or if 4 are not
|
||||
available, as many as are present.
|
||||
using a setting of 1. By default, it uses as many CPUs as are present.
|
||||
|
||||
* Config settings: ``-C zlib=disable``, ``-C jpeg=disable``,
|
||||
``-C tiff=disable``, ``-C freetype=disable``, ``-C raqm=disable``,
|
||||
|
|
|
@ -45,9 +45,7 @@ Colors
|
|||
^^^^^^
|
||||
|
||||
To specify colors, you can use numbers or tuples just as you would use with
|
||||
:py:meth:`PIL.Image.new` or :py:meth:`PIL.Image.Image.putpixel`. For “1”,
|
||||
“L”, and “I” images, use integers. For “RGB” images, use a 3-tuple containing
|
||||
integer values. For “F” images, use integer or floating point values.
|
||||
:py:meth:`PIL.Image.new`. See :ref:`colors` for more information.
|
||||
|
||||
For palette images (mode “P”), use integers as color indexes. In 1.1.4 and
|
||||
later, you can also use RGB 3-tuples or color names (see below). The drawing
|
||||
|
|
|
@ -59,7 +59,7 @@ Access using negative indexes is also possible. ::
|
|||
|
||||
Modifies the pixel at x,y. The color is given as a single
|
||||
numerical value for single band images, and a tuple for
|
||||
multi-band images.
|
||||
multi-band images. See :ref:`colors` for more information.
|
||||
|
||||
:param xy: The pixel coordinate, given as (x, y).
|
||||
:param color: The pixel value according to its mode,
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
# libwebp example binaries require dependencies that aren't available for iOS builds.
|
||||
# There's also no easy way to invoke the build to *exclude* the example builds.
|
||||
# Since we don't need the examples anyway, remove them from the Makefile.
|
||||
#
|
||||
# As a point of reference, libwebp provides an XCFramework build script that involves
|
||||
# 7 separate invocations of make to avoid building the examples. Patching the Makefile
|
||||
# to remove the examples is a simpler approach, and one that is more compatible with
|
||||
# the existing multibuild infrastructure.
|
||||
#
|
||||
# In the next release, it should be possible to pass --disable-libwebpexamples
|
||||
# instead of applying this patch.
|
||||
#
|
||||
diff -ur libwebp-1.5.0-orig/Makefile.am libwebp-1.5.0/Makefile.am
|
||||
--- libwebp-1.5.0-orig/Makefile.am 2024-12-20 09:17:50
|
||||
+++ libwebp-1.5.0/Makefile.am 2025-01-09 11:24:17
|
||||
@@ -5,5 +5,3 @@
|
||||
if BUILD_EXTRAS
|
||||
SUBDIRS += extras
|
||||
endif
|
||||
-
|
||||
-SUBDIRS += examples
|
||||
diff -ur libwebp-1.5.0-orig/Makefile.in libwebp-1.5.0/Makefile.in
|
||||
--- libwebp-1.5.0-orig/Makefile.in 2024-12-20 09:52:53
|
||||
+++ libwebp-1.5.0/Makefile.in 2025-01-09 11:24:17
|
||||
@@ -156,7 +156,7 @@
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
-DIST_SUBDIRS = sharpyuv src imageio man extras examples
|
||||
+DIST_SUBDIRS = sharpyuv src imageio man extras
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in \
|
||||
$(top_srcdir)/src/webp/config.h.in AUTHORS COPYING ChangeLog \
|
||||
NEWS README.md ar-lib compile config.guess config.sub \
|
||||
@@ -351,7 +351,7 @@
|
||||
top_srcdir = @top_srcdir@
|
||||
webp_libname_prefix = @webp_libname_prefix@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
-SUBDIRS = sharpyuv src imageio man $(am__append_1) examples
|
||||
+SUBDIRS = sharpyuv src imageio man $(am__append_1)
|
||||
EXTRA_DIST = COPYING autogen.sh
|
||||
all: all-recursive
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
[build-system]
|
||||
build-backend = "backend"
|
||||
requires = [
|
||||
"pybind11",
|
||||
"setuptools>=77",
|
||||
]
|
||||
backend-path = [
|
||||
|
|
23
setup.py
23
setup.py
|
@ -17,9 +17,20 @@ import sys
|
|||
import warnings
|
||||
from collections.abc import Iterator
|
||||
|
||||
from pybind11.setup_helpers import ParallelCompile
|
||||
from setuptools import Extension, setup
|
||||
from setuptools.command.build_ext import build_ext
|
||||
|
||||
configuration: dict[str, list[str]] = {}
|
||||
|
||||
# parse configuration from _custom_build/backend.py
|
||||
while sys.argv[-1].startswith("--pillow-configuration="):
|
||||
_, key, value = sys.argv.pop().split("=", 2)
|
||||
configuration.setdefault(key, []).append(value)
|
||||
|
||||
default = int(configuration.get("parallel", ["0"])[-1])
|
||||
ParallelCompile("MAX_CONCURRENCY", default).install()
|
||||
|
||||
|
||||
def get_version() -> str:
|
||||
version_file = "src/PIL/_version.py"
|
||||
|
@ -27,9 +38,6 @@ def get_version() -> str:
|
|||
return f.read().split('"')[1]
|
||||
|
||||
|
||||
configuration: dict[str, list[str]] = {}
|
||||
|
||||
|
||||
PILLOW_VERSION = get_version()
|
||||
AVIF_ROOT = None
|
||||
FREETYPE_ROOT = None
|
||||
|
@ -386,9 +394,7 @@ class pil_build_ext(build_ext):
|
|||
cpu_count = os.cpu_count()
|
||||
if cpu_count is not None:
|
||||
try:
|
||||
self.parallel = int(
|
||||
os.environ.get("MAX_CONCURRENCY", min(4, cpu_count))
|
||||
)
|
||||
self.parallel = int(os.environ.get("MAX_CONCURRENCY", cpu_count))
|
||||
except TypeError:
|
||||
pass
|
||||
for x in self.feature:
|
||||
|
@ -1083,11 +1089,6 @@ ext_modules = [
|
|||
]
|
||||
|
||||
|
||||
# parse configuration from _custom_build/backend.py
|
||||
while sys.argv[-1].startswith("--pillow-configuration="):
|
||||
_, key, value = sys.argv.pop().split("=", 2)
|
||||
configuration.setdefault(key, []).append(value)
|
||||
|
||||
try:
|
||||
setup(
|
||||
cmdclass={"build_ext": pil_build_ext},
|
||||
|
|
|
@ -1730,9 +1730,10 @@ class Image:
|
|||
details).
|
||||
|
||||
Instead of an image, the source can be a integer or tuple
|
||||
containing pixel values. The method then fills the region
|
||||
with the given color. When creating RGB images, you can
|
||||
also use color strings as supported by the ImageColor module.
|
||||
containing pixel values. The method then fills the region
|
||||
with the given color. When creating RGB images, you can
|
||||
also use color strings as supported by the ImageColor module. See
|
||||
:ref:`colors` for more information.
|
||||
|
||||
If a mask is given, this method updates only the regions
|
||||
indicated by the mask. You can use either "1", "L", "LA", "RGBA"
|
||||
|
@ -1988,7 +1989,8 @@ class Image:
|
|||
sequence ends. The scale and offset values are used to adjust the
|
||||
sequence values: **pixel = value*scale + offset**.
|
||||
|
||||
:param data: A flattened sequence object.
|
||||
:param data: A flattened sequence object. See :ref:`colors` for more
|
||||
information about values.
|
||||
:param scale: An optional scale value. The default is 1.0.
|
||||
:param offset: An optional offset value. The default is 0.0.
|
||||
"""
|
||||
|
@ -2047,7 +2049,7 @@ class Image:
|
|||
Modifies the pixel at the given position. The color is given as
|
||||
a single numerical value for single-band images, and a tuple for
|
||||
multi-band images. In addition to this, RGB and RGBA tuples are
|
||||
accepted for P and PA images.
|
||||
accepted for P and PA images. See :ref:`colors` for more information.
|
||||
|
||||
Note that this method is relatively slow. For more extensive changes,
|
||||
use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
|
||||
|
@ -3055,12 +3057,12 @@ def new(
|
|||
:param mode: The mode to use for the new image. See:
|
||||
:ref:`concept-modes`.
|
||||
:param size: A 2-tuple, containing (width, height) in pixels.
|
||||
:param color: What color to use for the image. Default is black.
|
||||
If given, this should be a single integer or floating point value
|
||||
for single-band modes, and a tuple for multi-band modes (one value
|
||||
per band). When creating RGB or HSV images, you can also use color
|
||||
strings as supported by the ImageColor module. If the color is
|
||||
None, the image is not initialised.
|
||||
:param color: What color to use for the image. Default is black. If given,
|
||||
this should be a single integer or floating point value for single-band
|
||||
modes, and a tuple for multi-band modes (one value per band). When
|
||||
creating RGB or HSV images, you can also use color strings as supported
|
||||
by the ImageColor module. See :ref:`colors` for more information. If the
|
||||
color is None, the image is not initialised.
|
||||
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||
"""
|
||||
|
||||
|
|
|
@ -845,16 +845,6 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
)
|
||||
|
||||
|
||||
def _save_cjpeg(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
||||
tempfile = im._dump()
|
||||
subprocess.check_call(["cjpeg", "-outfile", filename, tempfile])
|
||||
try:
|
||||
os.unlink(tempfile)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
##
|
||||
# Factory for making JPEG and MPO instances
|
||||
def jpeg_factory(
|
||||
|
|
|
@ -9,7 +9,6 @@ from typing import IO
|
|||
import PIL
|
||||
|
||||
from . import Image
|
||||
from ._deprecate import deprecate
|
||||
|
||||
modules = {
|
||||
"pil": ("PIL._imaging", "PILLOW_VERSION"),
|
||||
|
@ -120,7 +119,7 @@ def get_supported_codecs() -> list[str]:
|
|||
return [f for f in codecs if check_codec(f)]
|
||||
|
||||
|
||||
features: dict[str, tuple[str, str | bool, str | None]] = {
|
||||
features: dict[str, tuple[str, str, str | None]] = {
|
||||
"raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"),
|
||||
"fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"),
|
||||
"harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"),
|
||||
|
@ -146,12 +145,8 @@ def check_feature(feature: str) -> bool | None:
|
|||
|
||||
module, flag, ver = features[feature]
|
||||
|
||||
if isinstance(flag, bool):
|
||||
deprecate(f'check_feature("{feature}")', 12)
|
||||
try:
|
||||
imported_module = __import__(module, fromlist=["PIL"])
|
||||
if isinstance(flag, bool):
|
||||
return flag
|
||||
return getattr(imported_module, flag)
|
||||
except ModuleNotFoundError:
|
||||
return None
|
||||
|
@ -181,17 +176,7 @@ def get_supported_features() -> list[str]:
|
|||
"""
|
||||
:returns: A list of all supported features.
|
||||
"""
|
||||
supported_features = []
|
||||
for f, (module, flag, _) in features.items():
|
||||
if flag is True:
|
||||
for feature, (feature_module, _) in modules.items():
|
||||
if feature_module == module:
|
||||
if check_module(feature):
|
||||
supported_features.append(f)
|
||||
break
|
||||
elif check_feature(f):
|
||||
supported_features.append(f)
|
||||
return supported_features
|
||||
return [f for f in features if check_feature(f)]
|
||||
|
||||
|
||||
def check(feature: str) -> bool | None:
|
||||
|
|
|
@ -122,7 +122,7 @@ V = {
|
|||
"LIBAVIF": "1.3.0",
|
||||
"LIBIMAGEQUANT": "4.3.4",
|
||||
"LIBPNG": "1.6.49",
|
||||
"LIBWEBP": "1.5.0",
|
||||
"LIBWEBP": "1.6.0",
|
||||
"OPENJPEG": "2.5.3",
|
||||
"TIFF": "4.7.0",
|
||||
"XZ": "5.8.1",
|
||||
|
@ -149,18 +149,17 @@ DEPS: dict[str, dict[str, Any]] = {
|
|||
},
|
||||
"build": [
|
||||
*cmds_cmake(
|
||||
("jpeg-static", "cjpeg-static", "djpeg-static"),
|
||||
("jpeg-static", "djpeg-static"),
|
||||
"-DENABLE_SHARED:BOOL=FALSE",
|
||||
"-DWITH_JPEG8:BOOL=TRUE",
|
||||
"-DWITH_CRT_DLL:BOOL=TRUE",
|
||||
),
|
||||
cmd_copy("jpeg-static.lib", "libjpeg.lib"),
|
||||
cmd_copy("cjpeg-static.exe", "cjpeg.exe"),
|
||||
cmd_copy("djpeg-static.exe", "djpeg.exe"),
|
||||
],
|
||||
"headers": ["jconfig.h", r"src\j*.h"],
|
||||
"libs": ["libjpeg.lib"],
|
||||
"bins": ["cjpeg.exe", "djpeg.exe"],
|
||||
"bins": ["djpeg.exe"],
|
||||
},
|
||||
"zlib": {
|
||||
"url": f"https://github.com/zlib-ng/zlib-ng/archive/refs/tags/{V['ZLIBNG']}.tar.gz",
|
||||
|
|
Loading…
Reference in New Issue
Block a user