mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 02:06:18 +03:00
Merge branch 'main' into types-cms2
This commit is contained in:
commit
46b0b0e57d
15
.github/ISSUE_TEMPLATE/ISSUE_REPORT.md
vendored
15
.github/ISSUE_TEMPLATE/ISSUE_REPORT.md
vendored
|
@ -48,6 +48,21 @@ Thank you.
|
||||||
* Python:
|
* Python:
|
||||||
* Pillow:
|
* Pillow:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Please paste here the output of running:
|
||||||
|
|
||||||
|
python3 -m PIL.report
|
||||||
|
or
|
||||||
|
python3 -m PIL --report
|
||||||
|
|
||||||
|
Or the output of the following Python code:
|
||||||
|
|
||||||
|
from PIL import report
|
||||||
|
# or
|
||||||
|
from PIL import features
|
||||||
|
features.pilinfo(supported_formats=False)
|
||||||
|
```
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.
|
Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.
|
||||||
|
|
||||||
|
|
2
.github/workflows/wheels-dependencies.sh
vendored
2
.github/workflows/wheels-dependencies.sh
vendored
|
@ -16,7 +16,7 @@ ARCHIVE_SDIR=pillow-depends-main
|
||||||
|
|
||||||
# Package versions for fresh source builds
|
# Package versions for fresh source builds
|
||||||
FREETYPE_VERSION=2.13.2
|
FREETYPE_VERSION=2.13.2
|
||||||
HARFBUZZ_VERSION=8.3.1
|
HARFBUZZ_VERSION=8.4.0
|
||||||
LIBPNG_VERSION=1.6.43
|
LIBPNG_VERSION=1.6.43
|
||||||
JPEGTURBO_VERSION=3.0.2
|
JPEGTURBO_VERSION=3.0.2
|
||||||
OPENJPEG_VERSION=2.5.2
|
OPENJPEG_VERSION=2.5.2
|
||||||
|
|
2
.github/workflows/wheels.yml
vendored
2
.github/workflows/wheels.yml
vendored
|
@ -5,6 +5,7 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- ".ci/requirements-cibw.txt"
|
- ".ci/requirements-cibw.txt"
|
||||||
- ".github/workflows/wheel*"
|
- ".github/workflows/wheel*"
|
||||||
|
- "setup.py"
|
||||||
- "wheels/*"
|
- "wheels/*"
|
||||||
- "winbuild/build_prepare.py"
|
- "winbuild/build_prepare.py"
|
||||||
- "winbuild/fribidi.cmake"
|
- "winbuild/fribidi.cmake"
|
||||||
|
@ -14,6 +15,7 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- ".ci/requirements-cibw.txt"
|
- ".ci/requirements-cibw.txt"
|
||||||
- ".github/workflows/wheel*"
|
- ".github/workflows/wheel*"
|
||||||
|
- "setup.py"
|
||||||
- "wheels/*"
|
- "wheels/*"
|
||||||
- "winbuild/build_prepare.py"
|
- "winbuild/build_prepare.py"
|
||||||
- "winbuild/fribidi.cmake"
|
- "winbuild/fribidi.cmake"
|
||||||
|
|
|
@ -5,6 +5,15 @@ Changelog (Pillow)
|
||||||
10.3.0 (unreleased)
|
10.3.0 (unreleased)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
- Determine MPO size from markers, not EXIF data #7884
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Improved conversion from RGB to RGBa, LA and La #7888
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Support FITS images with GZIP_1 compression #7894
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
- Use I;16 mode for 9-bit JPEG 2000 images #7900
|
- Use I;16 mode for 9-bit JPEG 2000 images #7900
|
||||||
[scaramallion, radarhere]
|
[scaramallion, radarhere]
|
||||||
|
|
||||||
|
|
|
@ -263,8 +263,6 @@ def hopper(mode: str | None = None, cache: dict[str, Image.Image] = {}) -> Image
|
||||||
if im is None:
|
if im is None:
|
||||||
if mode == "F":
|
if mode == "F":
|
||||||
im = hopper("L").convert(mode)
|
im = hopper("L").convert(mode)
|
||||||
elif mode[:4] == "I;16":
|
|
||||||
im = hopper("I").convert(mode)
|
|
||||||
else:
|
else:
|
||||||
im = hopper().convert(mode)
|
im = hopper().convert(mode)
|
||||||
cache[mode] = im
|
cache[mode] = im
|
||||||
|
|
|
@ -117,9 +117,10 @@ def test_unsupported_module() -> None:
|
||||||
features.version_module(module)
|
features.version_module(module)
|
||||||
|
|
||||||
|
|
||||||
def test_pilinfo() -> None:
|
@pytest.mark.parametrize("supported_formats", (True, False))
|
||||||
|
def test_pilinfo(supported_formats) -> None:
|
||||||
buf = io.StringIO()
|
buf = io.StringIO()
|
||||||
features.pilinfo(buf)
|
features.pilinfo(buf, supported_formats=supported_formats)
|
||||||
out = buf.getvalue()
|
out = buf.getvalue()
|
||||||
lines = out.splitlines()
|
lines = out.splitlines()
|
||||||
assert lines[0] == "-" * 68
|
assert lines[0] == "-" * 68
|
||||||
|
@ -129,9 +130,15 @@ def test_pilinfo() -> None:
|
||||||
while lines[0].startswith(" "):
|
while lines[0].startswith(" "):
|
||||||
lines = lines[1:]
|
lines = lines[1:]
|
||||||
assert lines[0] == "-" * 68
|
assert lines[0] == "-" * 68
|
||||||
assert lines[1].startswith("Python modules loaded from ")
|
assert lines[1].startswith("Python executable is")
|
||||||
assert lines[2].startswith("Binary modules loaded from ")
|
lines = lines[2:]
|
||||||
assert lines[3] == "-" * 68
|
if lines[0].startswith("Environment Python files loaded from"):
|
||||||
|
lines = lines[1:]
|
||||||
|
assert lines[0].startswith("System Python files loaded from")
|
||||||
|
assert lines[1] == "-" * 68
|
||||||
|
assert lines[2].startswith("Python Pillow modules loaded from ")
|
||||||
|
assert lines[3].startswith("Binary Pillow modules loaded from ")
|
||||||
|
assert lines[4] == "-" * 68
|
||||||
jpeg = (
|
jpeg = (
|
||||||
"\n"
|
"\n"
|
||||||
+ "-" * 68
|
+ "-" * 68
|
||||||
|
@ -142,4 +149,4 @@ def test_pilinfo() -> None:
|
||||||
+ "-" * 68
|
+ "-" * 68
|
||||||
+ "\n"
|
+ "\n"
|
||||||
)
|
)
|
||||||
assert jpeg in out
|
assert supported_formats == (jpeg in out)
|
||||||
|
|
|
@ -825,7 +825,7 @@ class TestFileJpeg:
|
||||||
with Image.open("Tests/images/no-dpi-in-exif.jpg") as im:
|
with Image.open("Tests/images/no-dpi-in-exif.jpg") as im:
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
# "When the image resolution is unknown, 72 [dpi] is designated."
|
# "When the image resolution is unknown, 72 [dpi] is designated."
|
||||||
# https://exiv2.org/tags.html
|
# https://web.archive.org/web/20240227115053/https://exiv2.org/tags.html
|
||||||
assert im.info.get("dpi") == (72, 72)
|
assert im.info.get("dpi") == (72, 72)
|
||||||
|
|
||||||
def test_invalid_exif(self) -> None:
|
def test_invalid_exif(self) -> None:
|
||||||
|
|
|
@ -33,36 +33,38 @@ from .helper import (
|
||||||
skip_unless_feature,
|
skip_unless_feature,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# name, pixel size
|
||||||
|
image_modes = (
|
||||||
|
("1", 1),
|
||||||
|
("L", 1),
|
||||||
|
("LA", 4),
|
||||||
|
("La", 4),
|
||||||
|
("P", 1),
|
||||||
|
("PA", 4),
|
||||||
|
("F", 4),
|
||||||
|
("I", 4),
|
||||||
|
("I;16", 2),
|
||||||
|
("I;16L", 2),
|
||||||
|
("I;16B", 2),
|
||||||
|
("I;16N", 2),
|
||||||
|
("RGB", 4),
|
||||||
|
("RGBA", 4),
|
||||||
|
("RGBa", 4),
|
||||||
|
("RGBX", 4),
|
||||||
|
("BGR;15", 2),
|
||||||
|
("BGR;16", 2),
|
||||||
|
("BGR;24", 3),
|
||||||
|
("CMYK", 4),
|
||||||
|
("YCbCr", 4),
|
||||||
|
("HSV", 4),
|
||||||
|
("LAB", 4),
|
||||||
|
)
|
||||||
|
|
||||||
|
image_mode_names = [name for name, _ in image_modes]
|
||||||
|
|
||||||
|
|
||||||
class TestImage:
|
class TestImage:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize("mode", image_mode_names)
|
||||||
"mode",
|
|
||||||
(
|
|
||||||
"1",
|
|
||||||
"P",
|
|
||||||
"PA",
|
|
||||||
"L",
|
|
||||||
"LA",
|
|
||||||
"La",
|
|
||||||
"F",
|
|
||||||
"I",
|
|
||||||
"I;16",
|
|
||||||
"I;16L",
|
|
||||||
"I;16B",
|
|
||||||
"I;16N",
|
|
||||||
"RGB",
|
|
||||||
"RGBX",
|
|
||||||
"RGBA",
|
|
||||||
"RGBa",
|
|
||||||
"BGR;15",
|
|
||||||
"BGR;16",
|
|
||||||
"BGR;24",
|
|
||||||
"CMYK",
|
|
||||||
"YCbCr",
|
|
||||||
"LAB",
|
|
||||||
"HSV",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
def test_image_modes_success(self, mode: str) -> None:
|
def test_image_modes_success(self, mode: str) -> None:
|
||||||
Image.new(mode, (1, 1))
|
Image.new(mode, (1, 1))
|
||||||
|
|
||||||
|
@ -1042,6 +1044,35 @@ class TestImage:
|
||||||
assert im.fp is None
|
assert im.fp is None
|
||||||
|
|
||||||
|
|
||||||
|
class TestImageBytes:
|
||||||
|
@pytest.mark.parametrize("mode", image_mode_names)
|
||||||
|
def test_roundtrip_bytes_constructor(self, mode: str) -> None:
|
||||||
|
im = hopper(mode)
|
||||||
|
source_bytes = im.tobytes()
|
||||||
|
|
||||||
|
reloaded = Image.frombytes(mode, im.size, source_bytes)
|
||||||
|
assert reloaded.tobytes() == source_bytes
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mode", image_mode_names)
|
||||||
|
def test_roundtrip_bytes_method(self, mode: str) -> None:
|
||||||
|
im = hopper(mode)
|
||||||
|
source_bytes = im.tobytes()
|
||||||
|
|
||||||
|
reloaded = Image.new(mode, im.size)
|
||||||
|
reloaded.frombytes(source_bytes)
|
||||||
|
assert reloaded.tobytes() == source_bytes
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("mode", "pixelsize"), image_modes)
|
||||||
|
def test_getdata_putdata(self, mode: str, pixelsize: int) -> None:
|
||||||
|
im = Image.new(mode, (2, 2))
|
||||||
|
source_bytes = bytes(range(im.width * im.height * pixelsize))
|
||||||
|
im.frombytes(source_bytes)
|
||||||
|
|
||||||
|
reloaded = Image.new(mode, im.size)
|
||||||
|
reloaded.putdata(im.getdata())
|
||||||
|
assert_image_equal(im, reloaded)
|
||||||
|
|
||||||
|
|
||||||
class MockEncoder(ImageFile.PyEncoder):
|
class MockEncoder(ImageFile.PyEncoder):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,16 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
def test_main() -> None:
|
|
||||||
out = subprocess.check_output([sys.executable, "-m", "PIL"]).decode("utf-8")
|
@pytest.mark.parametrize(
|
||||||
|
"args, report",
|
||||||
|
((["PIL"], False), (["PIL", "--report"], True), (["PIL.report"], True)),
|
||||||
|
)
|
||||||
|
def test_main(args, report) -> None:
|
||||||
|
args = [sys.executable, "-m"] + args
|
||||||
|
out = subprocess.check_output(args).decode("utf-8")
|
||||||
lines = out.splitlines()
|
lines = out.splitlines()
|
||||||
assert lines[0] == "-" * 68
|
assert lines[0] == "-" * 68
|
||||||
assert lines[1].startswith("Pillow ")
|
assert lines[1].startswith("Pillow ")
|
||||||
|
@ -15,9 +22,15 @@ def test_main() -> None:
|
||||||
while lines[0].startswith(" "):
|
while lines[0].startswith(" "):
|
||||||
lines = lines[1:]
|
lines = lines[1:]
|
||||||
assert lines[0] == "-" * 68
|
assert lines[0] == "-" * 68
|
||||||
assert lines[1].startswith("Python modules loaded from ")
|
assert lines[1].startswith("Python executable is")
|
||||||
assert lines[2].startswith("Binary modules loaded from ")
|
lines = lines[2:]
|
||||||
assert lines[3] == "-" * 68
|
if lines[0].startswith("Environment Python files loaded from"):
|
||||||
|
lines = lines[1:]
|
||||||
|
assert lines[0].startswith("System Python files loaded from")
|
||||||
|
assert lines[1] == "-" * 68
|
||||||
|
assert lines[2].startswith("Python Pillow modules loaded from ")
|
||||||
|
assert lines[3].startswith("Binary Pillow modules loaded from ")
|
||||||
|
assert lines[4] == "-" * 68
|
||||||
jpeg = (
|
jpeg = (
|
||||||
os.linesep
|
os.linesep
|
||||||
+ "-" * 68
|
+ "-" * 68
|
||||||
|
@ -31,4 +44,4 @@ def test_main() -> None:
|
||||||
+ "-" * 68
|
+ "-" * 68
|
||||||
+ os.linesep
|
+ os.linesep
|
||||||
)
|
)
|
||||||
assert jpeg in out
|
assert report == (jpeg not in out)
|
||||||
|
|
|
@ -11,41 +11,12 @@ backend_class = build_wheel.__self__.__class__
|
||||||
class _CustomBuildMetaBackend(backend_class):
|
class _CustomBuildMetaBackend(backend_class):
|
||||||
def run_setup(self, setup_script="setup.py"):
|
def run_setup(self, setup_script="setup.py"):
|
||||||
if self.config_settings:
|
if self.config_settings:
|
||||||
|
for key, values in self.config_settings.items():
|
||||||
|
if not isinstance(values, list):
|
||||||
|
values = [values]
|
||||||
|
for value in values:
|
||||||
|
sys.argv.append(f"--pillow-configuration={key}={value}")
|
||||||
|
|
||||||
def config_has(key, value):
|
|
||||||
settings = self.config_settings.get(key)
|
|
||||||
if settings:
|
|
||||||
if not isinstance(settings, list):
|
|
||||||
settings = [settings]
|
|
||||||
return value in settings
|
|
||||||
|
|
||||||
flags = []
|
|
||||||
for dependency in (
|
|
||||||
"zlib",
|
|
||||||
"jpeg",
|
|
||||||
"tiff",
|
|
||||||
"freetype",
|
|
||||||
"raqm",
|
|
||||||
"lcms",
|
|
||||||
"webp",
|
|
||||||
"webpmux",
|
|
||||||
"jpeg2000",
|
|
||||||
"imagequant",
|
|
||||||
"xcb",
|
|
||||||
):
|
|
||||||
if config_has(dependency, "enable"):
|
|
||||||
flags.append("--enable-" + dependency)
|
|
||||||
elif config_has(dependency, "disable"):
|
|
||||||
flags.append("--disable-" + dependency)
|
|
||||||
for dependency in ("raqm", "fribidi"):
|
|
||||||
if config_has(dependency, "vendor"):
|
|
||||||
flags.append("--vendor-" + dependency)
|
|
||||||
if self.config_settings.get("platform-guessing") == "disable":
|
|
||||||
flags.append("--disable-platform-guessing")
|
|
||||||
if self.config_settings.get("debug") == "true":
|
|
||||||
flags.append("--debug")
|
|
||||||
if flags:
|
|
||||||
sys.argv = sys.argv[:1] + ["build_ext"] + flags + sys.argv[1:]
|
|
||||||
return super().run_setup(setup_script)
|
return super().run_setup(setup_script)
|
||||||
|
|
||||||
def build_wheel(
|
def build_wheel(
|
||||||
|
@ -54,5 +25,15 @@ class _CustomBuildMetaBackend(backend_class):
|
||||||
self.config_settings = config_settings
|
self.config_settings = config_settings
|
||||||
return super().build_wheel(wheel_directory, config_settings, metadata_directory)
|
return super().build_wheel(wheel_directory, config_settings, metadata_directory)
|
||||||
|
|
||||||
|
def build_editable(
|
||||||
|
self, wheel_directory, config_settings=None, metadata_directory=None
|
||||||
|
):
|
||||||
|
self.config_settings = config_settings
|
||||||
|
return super().build_editable(
|
||||||
|
wheel_directory, config_settings, metadata_directory
|
||||||
|
)
|
||||||
|
|
||||||
build_wheel = _CustomBuildMetaBackend().build_wheel
|
|
||||||
|
_backend = _CustomBuildMetaBackend()
|
||||||
|
build_wheel = _backend.build_wheel
|
||||||
|
build_editable = _backend.build_editable
|
||||||
|
|
|
@ -266,9 +266,10 @@ After navigating to the Pillow directory, run::
|
||||||
Build Options
|
Build Options
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
* Environment variable: ``MAX_CONCURRENCY=n``. Pillow can use
|
* Config setting: ``-C parallel=n``. Can also be given
|
||||||
multiprocessing to build the extension. Setting ``MAX_CONCURRENCY``
|
with environment variable: ``MAX_CONCURRENCY=n``. Pillow can use
|
||||||
sets the number of CPUs to use, or can disable parallel building by
|
multiprocessing to build the extension. 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
|
using a setting of 1. By default, it uses 4 CPUs, or if 4 are not
|
||||||
available, as many as are present.
|
available, as many as are present.
|
||||||
|
|
||||||
|
@ -293,14 +294,13 @@ Build Options
|
||||||
used to compile the standard Pillow wheels. Compiling libraqm requires
|
used to compile the standard Pillow wheels. Compiling libraqm requires
|
||||||
a C99-compliant compiler.
|
a C99-compliant compiler.
|
||||||
|
|
||||||
* Build flag: ``-C platform-guessing=disable``. Skips all of the
|
* Config setting: ``-C platform-guessing=disable``. Skips all of the
|
||||||
platform dependent guessing of include and library directories for
|
platform dependent guessing of include and library directories for
|
||||||
automated build systems that configure the proper paths in the
|
automated build systems that configure the proper paths in the
|
||||||
environment variables (e.g. Buildroot).
|
environment variables (e.g. Buildroot).
|
||||||
|
|
||||||
* Build flag: ``-C debug=true``. Adds a debugging flag to the include and
|
* Config setting: ``-C debug=true``. Adds a debugging flag to the include and
|
||||||
library search process to dump all paths searched for and found to
|
library search process to dump all paths searched for and found to stdout.
|
||||||
stdout.
|
|
||||||
|
|
||||||
|
|
||||||
Sample usage::
|
Sample usage::
|
||||||
|
|
26
setup.py
26
setup.py
|
@ -27,6 +27,9 @@ def get_version():
|
||||||
return locals()["__version__"]
|
return locals()["__version__"]
|
||||||
|
|
||||||
|
|
||||||
|
configuration = {}
|
||||||
|
|
||||||
|
|
||||||
PILLOW_VERSION = get_version()
|
PILLOW_VERSION = get_version()
|
||||||
FREETYPE_ROOT = None
|
FREETYPE_ROOT = None
|
||||||
HARFBUZZ_ROOT = None
|
HARFBUZZ_ROOT = None
|
||||||
|
@ -333,15 +336,24 @@ class pil_build_ext(build_ext):
|
||||||
+ [("add-imaging-libs=", None, "Add libs to _imaging build")]
|
+ [("add-imaging-libs=", None, "Add libs to _imaging build")]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_configuration(option, value):
|
||||||
|
return True if value in configuration.get(option, []) else None
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
self.disable_platform_guessing = None
|
self.disable_platform_guessing = self.check_configuration(
|
||||||
|
"platform-guessing", "disable"
|
||||||
|
)
|
||||||
self.add_imaging_libs = ""
|
self.add_imaging_libs = ""
|
||||||
build_ext.initialize_options(self)
|
build_ext.initialize_options(self)
|
||||||
for x in self.feature:
|
for x in self.feature:
|
||||||
setattr(self, f"disable_{x}", None)
|
setattr(self, f"disable_{x}", self.check_configuration(x, "disable"))
|
||||||
setattr(self, f"enable_{x}", None)
|
setattr(self, f"enable_{x}", self.check_configuration(x, "enable"))
|
||||||
for x in ("raqm", "fribidi"):
|
for x in ("raqm", "fribidi"):
|
||||||
setattr(self, f"vendor_{x}", None)
|
setattr(self, f"vendor_{x}", self.check_configuration(x, "vendor"))
|
||||||
|
if self.check_configuration("debug", "true"):
|
||||||
|
self.debug = True
|
||||||
|
self.parallel = configuration.get("parallel", [None])[-1]
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
build_ext.finalize_options(self)
|
build_ext.finalize_options(self)
|
||||||
|
@ -987,6 +999,12 @@ ext_modules = [
|
||||||
Extension("PIL._imagingmorph", ["src/_imagingmorph.c"]),
|
Extension("PIL._imagingmorph", ["src/_imagingmorph.c"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# 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:
|
try:
|
||||||
setup(
|
setup(
|
||||||
cmdclass={"build_ext": pil_build_ext},
|
cmdclass={"build_ext": pil_build_ext},
|
||||||
|
|
|
@ -37,7 +37,7 @@ You can get the subsampling of a JPEG with the
|
||||||
:func:`.JpegImagePlugin.get_sampling` function.
|
:func:`.JpegImagePlugin.get_sampling` function.
|
||||||
|
|
||||||
In JPEG compressed data a JPEG marker is used instead of an EXIF tag.
|
In JPEG compressed data a JPEG marker is used instead of an EXIF tag.
|
||||||
(ref.: https://exiv2.org/tags.html)
|
(ref.: https://web.archive.org/web/20240227115053/https://exiv2.org/tags.html)
|
||||||
|
|
||||||
|
|
||||||
Quantization tables
|
Quantization tables
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
from .features import pilinfo
|
from .features import pilinfo
|
||||||
|
|
||||||
pilinfo()
|
pilinfo(supported_formats="--report" not in sys.argv)
|
||||||
|
|
|
@ -230,6 +230,9 @@ def pilinfo(out=None, supported_formats=True):
|
||||||
"""
|
"""
|
||||||
Prints information about this installation of Pillow.
|
Prints information about this installation of Pillow.
|
||||||
This function can be called with ``python3 -m PIL``.
|
This function can be called with ``python3 -m PIL``.
|
||||||
|
It can also be called with ``python3 -m PIL.report`` or ``python3 -m PIL --report``
|
||||||
|
to have "supported_formats" set to ``False``, omitting the list of all supported
|
||||||
|
image file formats.
|
||||||
|
|
||||||
:param out:
|
:param out:
|
||||||
The output stream to print to. Defaults to ``sys.stdout`` if ``None``.
|
The output stream to print to. Defaults to ``sys.stdout`` if ``None``.
|
||||||
|
@ -249,12 +252,17 @@ def pilinfo(out=None, supported_formats=True):
|
||||||
for py_version in py_version[1:]:
|
for py_version in py_version[1:]:
|
||||||
print(f" {py_version.strip()}", file=out)
|
print(f" {py_version.strip()}", file=out)
|
||||||
print("-" * 68, file=out)
|
print("-" * 68, file=out)
|
||||||
|
print(f"Python executable is {sys.executable or 'unknown'}", file=out)
|
||||||
|
if sys.prefix != sys.base_prefix:
|
||||||
|
print(f"Environment Python files loaded from {sys.prefix}", file=out)
|
||||||
|
print(f"System Python files loaded from {sys.base_prefix}", file=out)
|
||||||
|
print("-" * 68, file=out)
|
||||||
print(
|
print(
|
||||||
f"Python modules loaded from {os.path.dirname(Image.__file__)}",
|
f"Python Pillow modules loaded from {os.path.dirname(Image.__file__)}",
|
||||||
file=out,
|
file=out,
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
f"Binary modules loaded from {os.path.dirname(Image.core.__file__)}",
|
f"Binary Pillow modules loaded from {os.path.dirname(Image.core.__file__)}",
|
||||||
file=out,
|
file=out,
|
||||||
)
|
)
|
||||||
print("-" * 68, file=out)
|
print("-" * 68, file=out)
|
||||||
|
|
5
src/PIL/report.py
Normal file
5
src/PIL/report.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .features import pilinfo
|
||||||
|
|
||||||
|
pilinfo(supported_formats=False)
|
|
@ -1578,7 +1578,17 @@ if (PySequence_Check(op)) { \
|
||||||
int bigendian = 0;
|
int bigendian = 0;
|
||||||
if (image->type == IMAGING_TYPE_SPECIAL) {
|
if (image->type == IMAGING_TYPE_SPECIAL) {
|
||||||
// I;16*
|
// I;16*
|
||||||
bigendian = strcmp(image->mode, "I;16B") == 0;
|
if (strcmp(image->mode, "I;16N") == 0) {
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
bigendian = 1;
|
||||||
|
#else
|
||||||
|
bigendian = 0;
|
||||||
|
#endif
|
||||||
|
} else if (strcmp(image->mode, "I;16B") == 0) {
|
||||||
|
bigendian = 1;
|
||||||
|
} else {
|
||||||
|
bigendian = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (i = x = y = 0; i < n; i++) {
|
for (i = x = y = 0; i < n; i++) {
|
||||||
set_value_to_item(seq, i);
|
set_value_to_item(seq, i);
|
||||||
|
|
|
@ -250,6 +250,26 @@ rgb2i(UINT8 *out_, const UINT8 *in, int xsize) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rgb2i16l(UINT8 *out_, const UINT8 *in, int xsize) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < xsize; x++, in += 4) {
|
||||||
|
UINT8 v = CLIP16(L24(in) >> 16);
|
||||||
|
*out_++ = v;
|
||||||
|
*out_++ = v >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rgb2i16b(UINT8 *out_, const UINT8 *in, int xsize) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < xsize; x++, in += 4) {
|
||||||
|
UINT8 v = CLIP16(L24(in) >> 16);
|
||||||
|
*out_++ = v >> 8;
|
||||||
|
*out_++ = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rgb2f(UINT8 *out_, const UINT8 *in, int xsize) {
|
rgb2f(UINT8 *out_, const UINT8 *in, int xsize) {
|
||||||
int x;
|
int x;
|
||||||
|
@ -944,6 +964,14 @@ static struct {
|
||||||
{"RGB", "LA", rgb2la},
|
{"RGB", "LA", rgb2la},
|
||||||
{"RGB", "La", rgb2la},
|
{"RGB", "La", rgb2la},
|
||||||
{"RGB", "I", rgb2i},
|
{"RGB", "I", rgb2i},
|
||||||
|
{"RGB", "I;16", rgb2i16l},
|
||||||
|
{"RGB", "I;16L", rgb2i16l},
|
||||||
|
{"RGB", "I;16B", rgb2i16b},
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
{"RGB", "I;16N", rgb2i16b},
|
||||||
|
#else
|
||||||
|
{"RGB", "I;16N", rgb2i16l},
|
||||||
|
#endif
|
||||||
{"RGB", "F", rgb2f},
|
{"RGB", "F", rgb2f},
|
||||||
{"RGB", "BGR;15", rgb2bgr15},
|
{"RGB", "BGR;15", rgb2bgr15},
|
||||||
{"RGB", "BGR;16", rgb2bgr16},
|
{"RGB", "BGR;16", rgb2bgr16},
|
||||||
|
|
|
@ -87,11 +87,18 @@ are set by running ``winbuild\build\build_env.cmd`` and install Pillow with pip:
|
||||||
winbuild\build\build_env.cmd
|
winbuild\build\build_env.cmd
|
||||||
python.exe -m pip install -v -C raqm=vendor -C fribidi=vendor .
|
python.exe -m pip install -v -C raqm=vendor -C fribidi=vendor .
|
||||||
|
|
||||||
To build a wheel instead, run::
|
You can also install Pillow in `editable mode`_::
|
||||||
|
|
||||||
|
winbuild\build\build_env.cmd
|
||||||
|
python.exe -m pip install -v -C raqm=vendor -C fribidi=vendor -e .
|
||||||
|
|
||||||
|
To build a binary wheel instead, run::
|
||||||
|
|
||||||
winbuild\build\build_env.cmd
|
winbuild\build\build_env.cmd
|
||||||
python.exe -m pip wheel -v -C raqm=vendor -C fribidi=vendor .
|
python.exe -m pip wheel -v -C raqm=vendor -C fribidi=vendor .
|
||||||
|
|
||||||
|
.. _editable mode: https://setuptools.pypa.io/en/stable/userguide/development_mode.html
|
||||||
|
|
||||||
Testing Pillow
|
Testing Pillow
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ V = {
|
||||||
"BROTLI": "1.1.0",
|
"BROTLI": "1.1.0",
|
||||||
"FREETYPE": "2.13.2",
|
"FREETYPE": "2.13.2",
|
||||||
"FRIBIDI": "1.0.13",
|
"FRIBIDI": "1.0.13",
|
||||||
"HARFBUZZ": "8.3.1",
|
"HARFBUZZ": "8.4.0",
|
||||||
"JPEGTURBO": "3.0.2",
|
"JPEGTURBO": "3.0.2",
|
||||||
"LCMS2": "2.16",
|
"LCMS2": "2.16",
|
||||||
"LIBPNG": "1.6.43",
|
"LIBPNG": "1.6.43",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user