mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-06-29 09:23:11 +03:00
Merge branch 'python-pillow:main' into parametrize
This commit is contained in:
commit
69de03ba5f
|
@ -37,8 +37,7 @@ python3 -m pip install -U pytest-timeout
|
||||||
python3 -m pip install pyroma
|
python3 -m pip install pyroma
|
||||||
|
|
||||||
if [[ $(uname) != CYGWIN* ]]; then
|
if [[ $(uname) != CYGWIN* ]]; then
|
||||||
# TODO Remove condition when NumPy supports 3.11
|
python3 -m pip install numpy
|
||||||
if ! [ "$GHA_PYTHON_VERSION" == "3.11-dev" ]; then python3 -m pip install numpy ; fi
|
|
||||||
|
|
||||||
# PyQt6 doesn't support PyPy3
|
# PyQt6 doesn't support PyPy3
|
||||||
if [[ $GHA_PYTHON_VERSION == 3.* ]]; then
|
if [[ $GHA_PYTHON_VERSION == 3.* ]]; then
|
||||||
|
|
3
.github/workflows/cifuzz.yml
vendored
3
.github/workflows/cifuzz.yml
vendored
|
@ -11,6 +11,9 @@ on:
|
||||||
- "**.h"
|
- "**.h"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Fuzzing:
|
Fuzzing:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
3
.github/workflows/macos-install.sh
vendored
3
.github/workflows/macos-install.sh
vendored
|
@ -14,8 +14,7 @@ python3 -m pip install -U pytest-timeout
|
||||||
python3 -m pip install pyroma
|
python3 -m pip install pyroma
|
||||||
|
|
||||||
echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg
|
echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg
|
||||||
# TODO Remove condition when NumPy supports 3.11
|
python3 -m pip install numpy
|
||||||
if ! [ "$GHA_PYTHON_VERSION" == "3.11-dev" ]; then python3 -m pip install numpy ; fi
|
|
||||||
|
|
||||||
# extra test images
|
# extra test images
|
||||||
pushd depends && ./install_extra_test_images.sh && popd
|
pushd depends && ./install_extra_test_images.sh && popd
|
||||||
|
|
3
.github/workflows/test-cygwin.yml
vendored
3
.github/workflows/test-cygwin.yml
vendored
|
@ -2,6 +2,9 @@ name: Test Cygwin
|
||||||
|
|
||||||
on: [push, pull_request, workflow_dispatch]
|
on: [push, pull_request, workflow_dispatch]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
24
CHANGES.rst
24
CHANGES.rst
|
@ -5,6 +5,30 @@ Changelog (Pillow)
|
||||||
9.3.0 (unreleased)
|
9.3.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Copy palette when converting from P to PA #6497
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Allow RGB and RGBA values for PA image putpixel #6504
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Removed support for tkinter in PyPy before Python 3.6 #6551
|
||||||
|
[nulano]
|
||||||
|
|
||||||
|
- Do not use CCITTFaxDecode filter if libtiff is not available #6518
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Fallback to not using mmap if buffer is not large enough #6510
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Fixed writing bytes as ASCII tag #6493
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Open 1 bit EPS in mode 1 #6499
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
|
- Removed support for tkinter before Python 1.5.2 #6549
|
||||||
|
[radarhere]
|
||||||
|
|
||||||
- Allow default ImageDraw font to be set #6484
|
- Allow default ImageDraw font to be set #6484
|
||||||
[radarhere, hugovk]
|
[radarhere, hugovk]
|
||||||
|
|
||||||
|
|
BIN
Tests/images/1.eps
Normal file
BIN
Tests/images/1.eps
Normal file
Binary file not shown.
BIN
Tests/images/mmap_error.bmp
Normal file
BIN
Tests/images/mmap_error.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
|
@ -39,6 +39,13 @@ def test_invalid_file():
|
||||||
BmpImagePlugin.BmpImageFile(fp)
|
BmpImagePlugin.BmpImageFile(fp)
|
||||||
|
|
||||||
|
|
||||||
|
def test_fallback_if_mmap_errors():
|
||||||
|
# This image has been truncated,
|
||||||
|
# so that the buffer is not large enough when using mmap
|
||||||
|
with Image.open("Tests/images/mmap_error.bmp") as im:
|
||||||
|
assert_image_equal_tofile(im, "Tests/images/pal8_offset.bmp")
|
||||||
|
|
||||||
|
|
||||||
def test_save_to_bytes():
|
def test_save_to_bytes():
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
|
|
@ -146,6 +146,11 @@ def test_bytesio_object():
|
||||||
assert_image_similar(img, image1_scale1_compare, 5)
|
assert_image_similar(img, image1_scale1_compare, 5)
|
||||||
|
|
||||||
|
|
||||||
|
def test_1_mode():
|
||||||
|
with Image.open("Tests/images/1.eps") as im:
|
||||||
|
assert im.mode == "1"
|
||||||
|
|
||||||
|
|
||||||
def test_image_mode_not_supported(tmp_path):
|
def test_image_mode_not_supported(tmp_path):
|
||||||
im = hopper("RGBA")
|
im = hopper("RGBA")
|
||||||
tmpfile = str(tmp_path / "temp.eps")
|
tmpfile = str(tmp_path / "temp.eps")
|
||||||
|
|
|
@ -6,7 +6,7 @@ import time
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PIL import Image, PdfParser
|
from PIL import Image, PdfParser, features
|
||||||
|
|
||||||
from .helper import hopper, mark_if_feature_version
|
from .helper import hopper, mark_if_feature_version
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ def test_monochrome(tmp_path):
|
||||||
|
|
||||||
# Act / Assert
|
# Act / Assert
|
||||||
outfile = helper_save_as_pdf(tmp_path, mode)
|
outfile = helper_save_as_pdf(tmp_path, mode)
|
||||||
assert os.path.getsize(outfile) < 5000
|
assert os.path.getsize(outfile) < (5000 if features.check("libtiff") else 15000)
|
||||||
|
|
||||||
|
|
||||||
def test_greyscale(tmp_path):
|
def test_greyscale(tmp_path):
|
||||||
|
|
|
@ -185,6 +185,22 @@ def test_iptc(tmp_path):
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
|
||||||
|
|
||||||
|
def test_writing_bytes_to_ascii(tmp_path):
|
||||||
|
im = hopper()
|
||||||
|
info = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
|
|
||||||
|
tag = TiffTags.TAGS_V2[271]
|
||||||
|
assert tag.type == TiffTags.ASCII
|
||||||
|
|
||||||
|
info[271] = b"test"
|
||||||
|
|
||||||
|
out = str(tmp_path / "temp.tiff")
|
||||||
|
im.save(out, tiffinfo=info)
|
||||||
|
|
||||||
|
with Image.open(out) as reloaded:
|
||||||
|
assert reloaded.tag_v2[271] == "test"
|
||||||
|
|
||||||
|
|
||||||
def test_undefined_zero(tmp_path):
|
def test_undefined_zero(tmp_path):
|
||||||
# Check that the tag has not been changed since this test was created
|
# Check that the tag has not been changed since this test was created
|
||||||
tag = TiffTags.TAGS_V2[45059]
|
tag = TiffTags.TAGS_V2[45059]
|
||||||
|
|
|
@ -215,11 +215,14 @@ class TestImageGetPixel(AccessTest):
|
||||||
self.check(mode, 2**15 + 1)
|
self.check(mode, 2**15 + 1)
|
||||||
self.check(mode, 2**16 - 1)
|
self.check(mode, 2**16 - 1)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mode", ("P", "PA"))
|
||||||
@pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255)))
|
@pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255)))
|
||||||
def test_p_putpixel_rgb_rgba(self, color):
|
def test_p_putpixel_rgb_rgba(self, mode, color):
|
||||||
im = Image.new("P", (1, 1), 0)
|
im = Image.new(mode, (1, 1))
|
||||||
im.putpixel((0, 0), color)
|
im.putpixel((0, 0), color)
|
||||||
assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)
|
|
||||||
|
alpha = color[3] if len(color) == 4 and mode == "PA" else 255
|
||||||
|
assert im.convert("RGBA").getpixel((0, 0)) == (255, 0, 0, alpha)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(cffi is None, reason="No CFFI")
|
@pytest.mark.skipif(cffi is None, reason="No CFFI")
|
||||||
|
@ -340,12 +343,15 @@ class TestCffi(AccessTest):
|
||||||
# pixels can contain garbage if image is released
|
# pixels can contain garbage if image is released
|
||||||
assert px[i, 0] == 0
|
assert px[i, 0] == 0
|
||||||
|
|
||||||
def test_p_putpixel_rgb_rgba(self):
|
@pytest.mark.parametrize("mode", ("P", "PA"))
|
||||||
for color in [(255, 0, 0), (255, 0, 0, 255)]:
|
def test_p_putpixel_rgb_rgba(self, mode):
|
||||||
im = Image.new("P", (1, 1), 0)
|
for color in [(255, 0, 0), (255, 0, 0, 127)]:
|
||||||
|
im = Image.new(mode, (1, 1))
|
||||||
access = PyAccess.new(im, False)
|
access = PyAccess.new(im, False)
|
||||||
access.putpixel((0, 0), color)
|
access.putpixel((0, 0), color)
|
||||||
assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)
|
|
||||||
|
alpha = color[3] if len(color) == 4 and mode == "PA" else 255
|
||||||
|
assert im.convert("RGBA").getpixel((0, 0)) == (255, 0, 0, alpha)
|
||||||
|
|
||||||
|
|
||||||
class TestImagePutPixelError(AccessTest):
|
class TestImagePutPixelError(AccessTest):
|
||||||
|
|
|
@ -236,6 +236,12 @@ def test_p2pa_alpha():
|
||||||
assert im_a.getpixel((x, y)) == alpha
|
assert im_a.getpixel((x, y)) == alpha
|
||||||
|
|
||||||
|
|
||||||
|
def test_p2pa_palette():
|
||||||
|
with Image.open("Tests/images/tiny.png") as im:
|
||||||
|
im_pa = im.convert("PA")
|
||||||
|
assert im_pa.getpalette() == im.getpalette()
|
||||||
|
|
||||||
|
|
||||||
def test_matrix_illegal_conversion():
|
def test_matrix_illegal_conversion():
|
||||||
# Arrange
|
# Arrange
|
||||||
im = hopper("CMYK")
|
im = hopper("CMYK")
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# install libimagequant
|
# install libimagequant
|
||||||
|
|
||||||
archive=libimagequant-4.0.2
|
archive=libimagequant-4.0.4
|
||||||
|
|
||||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
||||||
|
|
||||||
|
|
|
@ -837,6 +837,24 @@ Pillow reads and writes TGA images containing ``L``, ``LA``, ``P``,
|
||||||
``RGB``, and ``RGBA`` data. Pillow can read and write both uncompressed and
|
``RGB``, and ``RGBA`` data. Pillow can read and write both uncompressed and
|
||||||
run-length encoded TGAs.
|
run-length encoded TGAs.
|
||||||
|
|
||||||
|
The :py:meth:`~PIL.Image.Image.save` method can take the following keyword arguments:
|
||||||
|
|
||||||
|
**compression**
|
||||||
|
If set to "tga_rle", the file will be run-length encoded.
|
||||||
|
|
||||||
|
.. versionadded:: 5.3.0
|
||||||
|
|
||||||
|
**id_section**
|
||||||
|
The identification field.
|
||||||
|
|
||||||
|
.. versionadded:: 5.3.0
|
||||||
|
|
||||||
|
**orientation**
|
||||||
|
If present and a positive number, the first pixel is for the top left corner,
|
||||||
|
rather than the bottom left corner.
|
||||||
|
|
||||||
|
.. versionadded:: 5.3.0
|
||||||
|
|
||||||
TIFF
|
TIFF
|
||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ Many of Pillow's features require external libraries:
|
||||||
|
|
||||||
* **libimagequant** provides improved color quantization
|
* **libimagequant** provides improved color quantization
|
||||||
|
|
||||||
* Pillow has been tested with libimagequant **2.6-4.0.2**
|
* Pillow has been tested with libimagequant **2.6-4.0.4**
|
||||||
* Libimagequant is licensed GPLv3, which is more restrictive than
|
* Libimagequant is licensed GPLv3, which is more restrictive than
|
||||||
the Pillow license, therefore we will not be distributing binaries
|
the Pillow license, therefore we will not be distributing binaries
|
||||||
with libimagequant support enabled.
|
with libimagequant support enabled.
|
||||||
|
|
|
@ -73,7 +73,7 @@ Access using negative indexes is also possible.
|
||||||
Modifies the pixel at x,y. The color is given as a single
|
Modifies the pixel at x,y. The color is given as a single
|
||||||
numerical value for single band images, and a tuple for
|
numerical value for single band images, and a tuple for
|
||||||
multi-band images. In addition to this, RGB and RGBA tuples
|
multi-band images. In addition to this, RGB and RGBA tuples
|
||||||
are accepted for P images.
|
are accepted for P and PA images.
|
||||||
|
|
||||||
:param xy: The pixel coordinate, given as (x, y).
|
:param xy: The pixel coordinate, given as (x, y).
|
||||||
:param color: The pixel value according to its mode. e.g. tuple (r, g, b) for RGB mode)
|
:param color: The pixel value according to its mode. e.g. tuple (r, g, b) for RGB mode)
|
||||||
|
|
|
@ -288,11 +288,14 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
# Encoded bitmapped image.
|
# Encoded bitmapped image.
|
||||||
x, y, bi, mo = s[11:].split(None, 7)[:4]
|
x, y, bi, mo = s[11:].split(None, 7)[:4]
|
||||||
|
|
||||||
if int(bi) != 8:
|
if int(bi) == 1:
|
||||||
break
|
self.mode = "1"
|
||||||
try:
|
elif int(bi) == 8:
|
||||||
self.mode = self.mode_map[int(mo)]
|
try:
|
||||||
except ValueError:
|
self.mode = self.mode_map[int(mo)]
|
||||||
|
except ValueError:
|
||||||
|
break
|
||||||
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
self._size = int(x), int(y)
|
self._size = int(x), int(y)
|
||||||
|
|
|
@ -1839,7 +1839,7 @@ class Image:
|
||||||
Modifies the pixel at the given position. The color is given as
|
Modifies the pixel at the given position. The color is given as
|
||||||
a single numerical value for single-band images, and a tuple for
|
a single numerical value for single-band images, and a tuple for
|
||||||
multi-band images. In addition to this, RGB and RGBA tuples are
|
multi-band images. In addition to this, RGB and RGBA tuples are
|
||||||
accepted for P images.
|
accepted for P and PA images.
|
||||||
|
|
||||||
Note that this method is relatively slow. For more extensive changes,
|
Note that this method is relatively slow. For more extensive changes,
|
||||||
use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
|
use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
|
||||||
|
@ -1864,12 +1864,17 @@ class Image:
|
||||||
return self.pyaccess.putpixel(xy, value)
|
return self.pyaccess.putpixel(xy, value)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.mode == "P"
|
self.mode in ("P", "PA")
|
||||||
and isinstance(value, (list, tuple))
|
and isinstance(value, (list, tuple))
|
||||||
and len(value) in [3, 4]
|
and len(value) in [3, 4]
|
||||||
):
|
):
|
||||||
# RGB or RGBA value for a P image
|
# RGB or RGBA value for a P or PA image
|
||||||
|
if self.mode == "PA":
|
||||||
|
alpha = value[3] if len(value) == 4 else 255
|
||||||
|
value = value[:3]
|
||||||
value = self.palette.getcolor(value, self)
|
value = self.palette.getcolor(value, self)
|
||||||
|
if self.mode == "PA":
|
||||||
|
value = (value, alpha)
|
||||||
return self.im.putpixel(xy, value)
|
return self.im.putpixel(xy, value)
|
||||||
|
|
||||||
def remap_palette(self, dest_map, source_palette=None):
|
def remap_palette(self, dest_map, source_palette=None):
|
||||||
|
|
|
@ -192,6 +192,9 @@ class ImageFile(Image.Image):
|
||||||
|
|
||||||
with open(self.filename) as fp:
|
with open(self.filename) as fp:
|
||||||
self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)
|
self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)
|
||||||
|
if offset + self.size[1] * args[1] > self.map.size():
|
||||||
|
# buffer is not large enough
|
||||||
|
raise OSError
|
||||||
self.im = Image.core.map_buffer(
|
self.im = Image.core.map_buffer(
|
||||||
self.map, self.size, decoder_name, offset, args
|
self.map, self.size, decoder_name, offset, args
|
||||||
)
|
)
|
||||||
|
|
|
@ -68,21 +68,7 @@ def _pyimagingtkcall(command, photo, id):
|
||||||
# may raise an error if it cannot attach to Tkinter
|
# may raise an error if it cannot attach to Tkinter
|
||||||
from . import _imagingtk
|
from . import _imagingtk
|
||||||
|
|
||||||
try:
|
_imagingtk.tkinit(tk.interpaddr())
|
||||||
if hasattr(tk, "interp"):
|
|
||||||
# Required for PyPy, which always has CFFI installed
|
|
||||||
from cffi import FFI
|
|
||||||
|
|
||||||
ffi = FFI()
|
|
||||||
|
|
||||||
# PyPy is using an FFI CDATA element
|
|
||||||
# (Pdb) self.tk.interp
|
|
||||||
# <cdata 'Tcl_Interp *' 0x3061b50>
|
|
||||||
_imagingtk.tkinit(int(ffi.cast("uintptr_t", tk.interp)), 1)
|
|
||||||
else:
|
|
||||||
_imagingtk.tkinit(tk.interpaddr(), 1)
|
|
||||||
except AttributeError:
|
|
||||||
_imagingtk.tkinit(id(tk), 0)
|
|
||||||
tk.call(command, photo, id)
|
tk.call(command, photo, id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import math
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from . import Image, ImageFile, ImageSequence, PdfParser, __version__
|
from . import Image, ImageFile, ImageSequence, PdfParser, __version__, features
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -130,20 +130,23 @@ def _save(im, fp, filename, save_all=False):
|
||||||
width, height = im.size
|
width, height = im.size
|
||||||
|
|
||||||
if im.mode == "1":
|
if im.mode == "1":
|
||||||
filter = "CCITTFaxDecode"
|
if features.check("libtiff"):
|
||||||
bits = 1
|
filter = "CCITTFaxDecode"
|
||||||
params = PdfParser.PdfArray(
|
bits = 1
|
||||||
[
|
params = PdfParser.PdfArray(
|
||||||
PdfParser.PdfDict(
|
[
|
||||||
{
|
PdfParser.PdfDict(
|
||||||
"K": -1,
|
{
|
||||||
"BlackIs1": True,
|
"K": -1,
|
||||||
"Columns": width,
|
"BlackIs1": True,
|
||||||
"Rows": height,
|
"Columns": width,
|
||||||
}
|
"Rows": height,
|
||||||
)
|
}
|
||||||
]
|
)
|
||||||
)
|
]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
filter = "DCTDecode"
|
||||||
colorspace = PdfParser.PdfName("DeviceGray")
|
colorspace = PdfParser.PdfName("DeviceGray")
|
||||||
procset = "ImageB" # grayscale
|
procset = "ImageB" # grayscale
|
||||||
elif im.mode == "L":
|
elif im.mode == "L":
|
||||||
|
|
|
@ -58,7 +58,7 @@ class PyAccess:
|
||||||
|
|
||||||
# Keep pointer to im object to prevent dereferencing.
|
# Keep pointer to im object to prevent dereferencing.
|
||||||
self._im = img.im
|
self._im = img.im
|
||||||
if self._im.mode == "P":
|
if self._im.mode in ("P", "PA"):
|
||||||
self._palette = img.palette
|
self._palette = img.palette
|
||||||
|
|
||||||
# Debugging is polluting test traces, only useful here
|
# Debugging is polluting test traces, only useful here
|
||||||
|
@ -89,12 +89,17 @@ class PyAccess:
|
||||||
(x, y) = self.check_xy((x, y))
|
(x, y) = self.check_xy((x, y))
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self._im.mode == "P"
|
self._im.mode in ("P", "PA")
|
||||||
and isinstance(color, (list, tuple))
|
and isinstance(color, (list, tuple))
|
||||||
and len(color) in [3, 4]
|
and len(color) in [3, 4]
|
||||||
):
|
):
|
||||||
# RGB or RGBA value for a P image
|
# RGB or RGBA value for a P or PA image
|
||||||
|
if self._im.mode == "PA":
|
||||||
|
alpha = color[3] if len(color) == 4 else 255
|
||||||
|
color = color[:3]
|
||||||
color = self._palette.getcolor(color, self._img)
|
color = self._palette.getcolor(color, self._img)
|
||||||
|
if self._im.mode == "PA":
|
||||||
|
color = (color, alpha)
|
||||||
|
|
||||||
return self.set_pixel(x, y, color)
|
return self.set_pixel(x, y, color)
|
||||||
|
|
||||||
|
|
|
@ -727,7 +727,9 @@ class ImageFileDirectory_v2(MutableMapping):
|
||||||
@_register_writer(2)
|
@_register_writer(2)
|
||||||
def write_string(self, value):
|
def write_string(self, value):
|
||||||
# remerge of https://github.com/python-pillow/Pillow/pull/1416
|
# remerge of https://github.com/python-pillow/Pillow/pull/1416
|
||||||
return b"" + value.encode("ascii", "replace") + b"\0"
|
if not isinstance(value, bytes):
|
||||||
|
value = value.encode("ascii", "replace")
|
||||||
|
return value + b"\0"
|
||||||
|
|
||||||
@_register_loader(5, 8)
|
@_register_loader(5, 8)
|
||||||
def load_rational(self, data, legacy_api=True):
|
def load_rational(self, data, legacy_api=True):
|
||||||
|
@ -1153,7 +1155,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
:returns: XMP tags in a dictionary.
|
:returns: XMP tags in a dictionary.
|
||||||
"""
|
"""
|
||||||
return self._getxmp(self.tag_v2[700]) if 700 in self.tag_v2 else {}
|
return self._getxmp(self.tag_v2[XMP]) if XMP in self.tag_v2 else {}
|
||||||
|
|
||||||
def get_photoshop_blocks(self):
|
def get_photoshop_blocks(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1328,7 +1330,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
logger.debug(f"- photometric_interpretation: {photo}")
|
logger.debug(f"- photometric_interpretation: {photo}")
|
||||||
logger.debug(f"- planar_configuration: {self._planar_configuration}")
|
logger.debug(f"- planar_configuration: {self._planar_configuration}")
|
||||||
logger.debug(f"- fill_order: {fillorder}")
|
logger.debug(f"- fill_order: {fillorder}")
|
||||||
logger.debug(f"- YCbCr subsampling: {self.tag.get(530)}")
|
logger.debug(f"- YCbCr subsampling: {self.tag.get(YCBCRSUBSAMPLING)}")
|
||||||
|
|
||||||
# size
|
# size
|
||||||
xsize = int(self.tag_v2.get(IMAGEWIDTH))
|
xsize = int(self.tag_v2.get(IMAGEWIDTH))
|
||||||
|
@ -1469,8 +1471,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
else:
|
else:
|
||||||
# tiled image
|
# tiled image
|
||||||
offsets = self.tag_v2[TILEOFFSETS]
|
offsets = self.tag_v2[TILEOFFSETS]
|
||||||
w = self.tag_v2.get(322)
|
w = self.tag_v2.get(TILEWIDTH)
|
||||||
h = self.tag_v2.get(323)
|
h = self.tag_v2.get(TILELENGTH)
|
||||||
|
|
||||||
for offset in offsets:
|
for offset in offsets:
|
||||||
if x + w > xsize:
|
if x + w > xsize:
|
||||||
|
|
|
@ -23,33 +23,16 @@ TkImaging_Init(Tcl_Interp *interp);
|
||||||
extern int
|
extern int
|
||||||
load_tkinter_funcs(void);
|
load_tkinter_funcs(void);
|
||||||
|
|
||||||
/* copied from _tkinter.c (this isn't as bad as it may seem: for new
|
|
||||||
versions, we use _tkinter's interpaddr hook instead, and all older
|
|
||||||
versions use this structure layout) */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PyObject_HEAD Tcl_Interp *interp;
|
|
||||||
} TkappObject;
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_tkinit(PyObject *self, PyObject *args) {
|
_tkinit(PyObject *self, PyObject *args) {
|
||||||
Tcl_Interp *interp;
|
Tcl_Interp *interp;
|
||||||
|
|
||||||
PyObject *arg;
|
PyObject *arg;
|
||||||
int is_interp;
|
if (!PyArg_ParseTuple(args, "O", &arg)) {
|
||||||
if (!PyArg_ParseTuple(args, "Oi", &arg, &is_interp)) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_interp) {
|
interp = (Tcl_Interp *)PyLong_AsVoidPtr(arg);
|
||||||
interp = (Tcl_Interp *)PyLong_AsVoidPtr(arg);
|
|
||||||
} else {
|
|
||||||
TkappObject *app;
|
|
||||||
/* Do it the hard way. This will break if the TkappObject
|
|
||||||
layout changes */
|
|
||||||
app = (TkappObject *)PyLong_AsVoidPtr(arg);
|
|
||||||
interp = app->interp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This will bomb if interp is invalid... */
|
/* This will bomb if interp is invalid... */
|
||||||
TkImaging_Init(interp);
|
TkImaging_Init(interp);
|
||||||
|
|
|
@ -1243,7 +1243,7 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) {
|
||||||
if (!imOut) {
|
if (!imOut) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (strcmp(mode, "P") == 0) {
|
if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0) {
|
||||||
ImagingPaletteDelete(imOut->palette);
|
ImagingPaletteDelete(imOut->palette);
|
||||||
imOut->palette = ImagingPaletteDuplicate(imIn->palette);
|
imOut->palette = ImagingPaletteDuplicate(imIn->palette);
|
||||||
}
|
}
|
||||||
|
|
|
@ -916,7 +916,7 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt
|
||||||
dump_state(clientstate);
|
dump_state(clientstate);
|
||||||
|
|
||||||
if (state->state == 0) {
|
if (state->state == 0) {
|
||||||
TRACE(("Encoding line bt line"));
|
TRACE(("Encoding line by line"));
|
||||||
while (state->y < state->ysize) {
|
while (state->y < state->ysize) {
|
||||||
state->shuffle(
|
state->shuffle(
|
||||||
state->buffer,
|
state->buffer,
|
||||||
|
|
|
@ -11,8 +11,8 @@ For more extensive info, see the [Windows build instructions](build.rst).
|
||||||
* Requires Microsoft Visual Studio 2017 or newer with C++ component.
|
* Requires Microsoft Visual Studio 2017 or newer with C++ component.
|
||||||
* Requires NASM for libjpeg-turbo, a required dependency when using this script.
|
* Requires NASM for libjpeg-turbo, a required dependency when using this script.
|
||||||
* Requires CMake 3.12 or newer (available as Visual Studio component).
|
* Requires CMake 3.12 or newer (available as Visual Studio component).
|
||||||
* Tested on Windows Server 2016 with Visual Studio 2017 Community (AppVeyor).
|
* Tested on Windows Server 2016 with Visual Studio 2017 Community, and Windows Server 2019 with Visual Studio 2022 Community (AppVeyor).
|
||||||
* Tested on Windows Server 2019 with Visual Studio 2019 Enterprise (GitHub Actions).
|
* Tested on Windows Server 2022 with Visual Studio 2022 Enterprise (GitHub Actions).
|
||||||
|
|
||||||
The following is a simplified version of the script used on AppVeyor:
|
The following is a simplified version of the script used on AppVeyor:
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in New Issue
Block a user