mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-09 23:04:45 +03:00
Merge branch 'main' into ipython-interop-tidy
This commit is contained in:
commit
54f3cefca0
20
.github/workflows/test-cygwin.yml
vendored
20
.github/workflows/test-cygwin.yml
vendored
|
@ -76,17 +76,23 @@ jobs:
|
|||
with:
|
||||
dirs: 'C:\cygwin\bin;C:\cygwin\lib\lapack'
|
||||
|
||||
- name: Select Python version
|
||||
run: |
|
||||
ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3
|
||||
|
||||
- name: Get latest NumPy version
|
||||
id: latest-numpy
|
||||
shell: bash.exe -eo pipefail -o igncr "{0}"
|
||||
run: |
|
||||
python3 -m pip list --outdated | grep numpy | sed -r 's/ +/ /g' | cut -d ' ' -f 3 | sed 's/^/version=/' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: pip cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: 'C:\cygwin\home\runneradmin\.cache\pip'
|
||||
key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-${{ hashFiles('.ci/install.sh') }}
|
||||
key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-numpy${{ steps.latest-numpy.outputs.version }}-${{ hashFiles('.ci/install.sh') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-
|
||||
|
||||
- name: Select Python version
|
||||
run: |
|
||||
ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3
|
||||
${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-numpy${{ steps.latest-numpy.outputs.version }}-
|
||||
|
||||
- name: Build system information
|
||||
run: |
|
||||
|
@ -96,7 +102,7 @@ jobs:
|
|||
run: |
|
||||
bash.exe .ci/install.sh
|
||||
|
||||
- name: Install a different NumPy
|
||||
- name: Install latest NumPy
|
||||
shell: dash.exe -l "{0}"
|
||||
run: |
|
||||
python3 -m pip install -U numpy
|
||||
|
|
12
CHANGES.rst
12
CHANGES.rst
|
@ -2,6 +2,18 @@
|
|||
Changelog (Pillow)
|
||||
==================
|
||||
|
||||
10.1.0 (unreleased)
|
||||
-------------------
|
||||
|
||||
- Silence exceptions in _repr_jpeg_ and _repr_png_ #7266
|
||||
[mtreinish, radarhere]
|
||||
|
||||
- Do not use transparency when saving GIF if it has been removed when normalizing mode #7284
|
||||
[radarhere]
|
||||
|
||||
- Fix missing symbols when libtiff depends on libjpeg #7270
|
||||
[heitbaum]
|
||||
|
||||
10.0.0 (2023-07-01)
|
||||
-------------------
|
||||
|
||||
|
|
|
@ -1086,6 +1086,21 @@ def test_transparent_optimize(tmp_path):
|
|||
assert reloaded.info["transparency"] == reloaded.getpixel((252, 0))
|
||||
|
||||
|
||||
def test_removed_transparency(tmp_path):
|
||||
out = str(tmp_path / "temp.gif")
|
||||
im = Image.new("RGB", (256, 1))
|
||||
|
||||
for x in range(256):
|
||||
im.putpixel((x, 0), (x, 0, 0))
|
||||
|
||||
im.info["transparency"] = (255, 255, 255)
|
||||
with pytest.warns(UserWarning):
|
||||
im.save(out)
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
assert "transparency" not in reloaded.info
|
||||
|
||||
|
||||
def test_rgb_transparency(tmp_path):
|
||||
out = str(tmp_path / "temp.gif")
|
||||
|
||||
|
|
|
@ -929,7 +929,7 @@ class TestFileJpeg:
|
|||
assert repr_jpeg.format == "JPEG"
|
||||
assert_image_similar(im, repr_jpeg, 17)
|
||||
|
||||
def test_repr_jpeg_error(self):
|
||||
def test_repr_jpeg_error_returns_none(self):
|
||||
im = hopper("BGR;24")
|
||||
assert im._repr_jpeg_() is None
|
||||
|
||||
|
|
|
@ -274,17 +274,15 @@ def test_sgnd(tmp_path):
|
|||
assert reloaded_signed.getpixel((0, 0)) == 128
|
||||
|
||||
|
||||
def test_rgba():
|
||||
@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
|
||||
def test_rgba(ext):
|
||||
# Arrange
|
||||
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
|
||||
with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2:
|
||||
# Act
|
||||
j2k.load()
|
||||
jp2.load()
|
||||
with Image.open("Tests/images/rgb_trns_ycbc" + ext) as im:
|
||||
# Act
|
||||
im.load()
|
||||
|
||||
# Assert
|
||||
assert j2k.mode == "RGBA"
|
||||
assert jp2.mode == "RGBA"
|
||||
# Assert
|
||||
assert im.mode == "RGBA"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
|
||||
|
|
|
@ -532,7 +532,7 @@ class TestFilePng:
|
|||
assert repr_png.format == "PNG"
|
||||
assert_image_equal(im, repr_png)
|
||||
|
||||
def test_repr_png_error(self):
|
||||
def test_repr_png_error_returns_none(self):
|
||||
im = hopper("BGR;24")
|
||||
assert im._repr_png_() is None
|
||||
|
||||
|
|
|
@ -861,6 +861,10 @@ PPM
|
|||
Pillow reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L``, ``I`` or
|
||||
``RGB`` data.
|
||||
|
||||
"Raw" (P4 to P6) formats can be read, and are used when writing.
|
||||
|
||||
Since Pillow 9.2.0, "plain" (P1 to P3) formats can be read as well.
|
||||
|
||||
SGI
|
||||
^^^
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
Python,3.11,3.10,3.9,3.8,3.7,3.6,3.5
|
||||
Pillow >= 10,Yes,Yes,Yes,Yes,,,
|
||||
Pillow 9.3 - 9.5,Yes,Yes,Yes,Yes,Yes,,
|
||||
Pillow 9.0 - 9.2,,Yes,Yes,Yes,Yes,,
|
||||
Pillow 8.3.2 - 8.4,,Yes,Yes,Yes,Yes,Yes,
|
||||
Pillow 8.0 - 8.3.1,,,Yes,Yes,Yes,Yes,
|
||||
Pillow 7.0 - 7.2,,,,Yes,Yes,Yes,Yes
|
||||
Python,3.12,3.11,3.10,3.9,3.8,3.7,3.6,3.5
|
||||
Pillow >= 10.1,Yes,Yes,Yes,Yes,Yes,,,
|
||||
Pillow 10.0,,Yes,Yes,Yes,Yes,,,
|
||||
Pillow 9.3 - 9.5,,Yes,Yes,Yes,Yes,Yes,,
|
||||
Pillow 9.0 - 9.2,,,Yes,Yes,Yes,Yes,,
|
||||
Pillow 8.3.2 - 8.4,,,Yes,Yes,Yes,Yes,Yes,
|
||||
Pillow 8.0 - 8.3.1,,,,Yes,Yes,Yes,Yes,
|
||||
Pillow 7.0 - 7.2,,,,,Yes,Yes,Yes,Yes
|
|
|
@ -538,7 +538,7 @@ Methods
|
|||
It should be a `BCP 47 language code`_.
|
||||
Requires libraqm.
|
||||
:param embedded_color: Whether to use font embedded color glyphs (COLR, CBDT, SBIX).
|
||||
:return: Width for horizontal, height for vertical text.
|
||||
:return: Either width for horizontal text, or height for vertical text.
|
||||
|
||||
.. py:method:: ImageDraw.textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, embedded_color=False)
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ classifiers =
|
|||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
Programming Language :: Python :: 3.11
|
||||
Programming Language :: Python :: 3.12
|
||||
Programming Language :: Python :: Implementation :: CPython
|
||||
Programming Language :: Python :: Implementation :: PyPy
|
||||
Topic :: Multimedia :: Graphics
|
||||
|
|
20
setup.py
20
setup.py
|
@ -39,7 +39,7 @@ TIFF_ROOT = None
|
|||
ZLIB_ROOT = None
|
||||
FUZZING_BUILD = "LIB_FUZZING_ENGINE" in os.environ
|
||||
|
||||
if sys.platform == "win32" and sys.version_info >= (3, 12):
|
||||
if sys.platform == "win32" and sys.version_info >= (3, 13):
|
||||
import atexit
|
||||
|
||||
atexit.register(
|
||||
|
@ -816,6 +816,15 @@ class pil_build_ext(build_ext):
|
|||
|
||||
libs = self.add_imaging_libs.split()
|
||||
defs = []
|
||||
if feature.tiff:
|
||||
libs.append(feature.tiff)
|
||||
defs.append(("HAVE_LIBTIFF", None))
|
||||
if sys.platform == "win32":
|
||||
# This define needs to be defined if-and-only-if it was defined
|
||||
# when compiling LibTIFF. LibTIFF doesn't expose it in `tiffconf.h`,
|
||||
# so we have to guess; by default it is defined in all Windows builds.
|
||||
# See #4237, #5243, #5359 for more information.
|
||||
defs.append(("USE_WIN32_FILEIO", None))
|
||||
if feature.jpeg:
|
||||
libs.append(feature.jpeg)
|
||||
defs.append(("HAVE_LIBJPEG", None))
|
||||
|
@ -830,15 +839,6 @@ class pil_build_ext(build_ext):
|
|||
if feature.imagequant:
|
||||
libs.append(feature.imagequant)
|
||||
defs.append(("HAVE_LIBIMAGEQUANT", None))
|
||||
if feature.tiff:
|
||||
libs.append(feature.tiff)
|
||||
defs.append(("HAVE_LIBTIFF", None))
|
||||
if sys.platform == "win32":
|
||||
# This define needs to be defined if-and-only-if it was defined
|
||||
# when compiling LibTIFF. LibTIFF doesn't expose it in `tiffconf.h`,
|
||||
# so we have to guess; by default it is defined in all Windows builds.
|
||||
# See #4237, #5243, #5359 for more information.
|
||||
defs.append(("USE_WIN32_FILEIO", None))
|
||||
if feature.xcb:
|
||||
libs.append(feature.xcb)
|
||||
defs.append(("HAVE_XCB", None))
|
||||
|
|
|
@ -683,11 +683,7 @@ def get_interlace(im):
|
|||
def _write_local_header(fp, im, offset, flags):
|
||||
transparent_color_exists = False
|
||||
try:
|
||||
if "transparency" in im.encoderinfo:
|
||||
transparency = im.encoderinfo["transparency"]
|
||||
else:
|
||||
transparency = im.info["transparency"]
|
||||
transparency = int(transparency)
|
||||
transparency = int(im.encoderinfo["transparency"])
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -318,7 +318,7 @@ class FreeTypeFont:
|
|||
<https://www.w3.org/International/articles/language-tags/>`_
|
||||
Requires libraqm.
|
||||
|
||||
:return: Width for horizontal, height for vertical text.
|
||||
:return: Either width for horizontal text, or height for vertical text.
|
||||
"""
|
||||
_string_length_check(text)
|
||||
return self.font.getlength(text, mode, direction, features, language) / 64
|
||||
|
|
|
@ -46,22 +46,11 @@ add_item(const char *mode) {
|
|||
/* fetch individual pixel */
|
||||
|
||||
static void
|
||||
get_pixel(Imaging im, int x, int y, void *color) {
|
||||
get_pixel_32_2bands(Imaging im, int x, int y, void *color) {
|
||||
char *out = color;
|
||||
|
||||
/* generic pixel access*/
|
||||
|
||||
if (im->image8) {
|
||||
out[0] = im->image8[y][x];
|
||||
} else {
|
||||
UINT8 *p = (UINT8 *)&im->image32[y][x];
|
||||
if (im->type == IMAGING_TYPE_UINT8 && im->bands == 2) {
|
||||
out[0] = p[0];
|
||||
out[1] = p[3];
|
||||
return;
|
||||
}
|
||||
memcpy(out, p, im->pixelsize);
|
||||
}
|
||||
UINT8 *p = (UINT8 *)&im->image32[y][x];
|
||||
out[0] = p[0];
|
||||
out[1] = p[3];
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -127,15 +116,6 @@ get_pixel_32B(Imaging im, int x, int y, void *color) {
|
|||
|
||||
/* store individual pixel */
|
||||
|
||||
static void
|
||||
put_pixel(Imaging im, int x, int y, const void *color) {
|
||||
if (im->image8) {
|
||||
im->image8[y][x] = *((UINT8 *)color);
|
||||
} else {
|
||||
memcpy(&im->image32[y][x], color, sizeof(INT32));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
put_pixel_8(Imaging im, int x, int y, const void *color) {
|
||||
im->image8[y][x] = *((UINT8 *)color);
|
||||
|
@ -186,8 +166,8 @@ ImagingAccessInit() {
|
|||
/* populate access table */
|
||||
ADD("1", get_pixel_8, put_pixel_8);
|
||||
ADD("L", get_pixel_8, put_pixel_8);
|
||||
ADD("LA", get_pixel, put_pixel);
|
||||
ADD("La", get_pixel, put_pixel);
|
||||
ADD("LA", get_pixel_32_2bands, put_pixel_32);
|
||||
ADD("La", get_pixel_32_2bands, put_pixel_32);
|
||||
ADD("I", get_pixel_32, put_pixel_32);
|
||||
ADD("I;16", get_pixel_16L, put_pixel_16L);
|
||||
ADD("I;16L", get_pixel_16L, put_pixel_16L);
|
||||
|
@ -197,7 +177,7 @@ ImagingAccessInit() {
|
|||
ADD("I;32B", get_pixel_32B, put_pixel_32B);
|
||||
ADD("F", get_pixel_32, put_pixel_32);
|
||||
ADD("P", get_pixel_8, put_pixel_8);
|
||||
ADD("PA", get_pixel, put_pixel);
|
||||
ADD("PA", get_pixel_32_2bands, put_pixel_32);
|
||||
ADD("RGB", get_pixel_32, put_pixel_32);
|
||||
ADD("RGBA", get_pixel_32, put_pixel_32);
|
||||
ADD("RGBa", get_pixel_32, put_pixel_32);
|
||||
|
|
2
tox.ini
2
tox.ini
|
@ -3,7 +3,7 @@ requires =
|
|||
tox>=4.2
|
||||
env_list =
|
||||
lint
|
||||
py{py3, 311, 310, 39, 38}
|
||||
py{py3, 312, 311, 310, 39, 38}
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
|
|
|
@ -335,9 +335,9 @@ deps = {
|
|||
"libs": [r"imagequant.lib"],
|
||||
},
|
||||
"harfbuzz": {
|
||||
"url": "https://github.com/harfbuzz/harfbuzz/archive/7.3.0.zip",
|
||||
"filename": "harfbuzz-7.3.0.zip",
|
||||
"dir": "harfbuzz-7.3.0",
|
||||
"url": "https://github.com/harfbuzz/harfbuzz/archive/8.0.0.zip",
|
||||
"filename": "harfbuzz-8.0.0.zip",
|
||||
"dir": "harfbuzz-8.0.0",
|
||||
"license": "COPYING",
|
||||
"build": [
|
||||
*cmds_cmake(
|
||||
|
|
Loading…
Reference in New Issue
Block a user