Merge branch 'main' of ssh://github.com/python-pillow/Pillow into fix-alpha-for-overlapping-glyphs

This commit is contained in:
ZachNagengast 2023-11-07 06:34:31 -08:00
commit 11bea8fea6
35 changed files with 127 additions and 111 deletions

View File

@ -13,7 +13,7 @@ indent_style = space
trim_trailing_whitespace = true
[*.yml]
[*.{toml,yml}]
# Two-space indentation
indent_size = 2

View File

@ -1,3 +0,0 @@
[flake8]
extend-ignore = E203
max-line-length = 88

View File

@ -1,21 +1,16 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.13.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.4
hooks:
- id: pyupgrade
args: [--py38-plus]
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.9.1
rev: 23.10.1
hooks:
- id: black
args: [--target-version=py38]
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
@ -23,32 +18,19 @@ repos:
args: [--severity-level=high]
files: ^src/
- repo: https://github.com/asottile/yesqa
rev: v1.5.0
hooks:
- id: yesqa
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.4
hooks:
- id: remove-tabs
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies:
[flake8-2020, flake8-errmsg, flake8-implicit-str-concat, flake8-logging]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
- id: python-check-blanket-noqa
- id: rst-backticks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: check-executables-have-shebangs
- id: check-merge-conflict
@ -61,17 +43,17 @@ repos:
exclude: ^.github/.*TEMPLATE|^Tests/(fonts|images)/
- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v0.6.8
rev: v0.8.1
hooks:
- id: sphinx-lint
- repo: https://github.com/tox-dev/pyproject-fmt
rev: 1.2.0
rev: 1.4.1
hooks:
- id: pyproject-fmt
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.14
rev: v0.15
hooks:
- id: validate-pyproject

View File

@ -5,6 +5,7 @@ include *.md
include *.py
include *.rst
include *.sh
include *.toml
include *.txt
include *.yaml
include .flake8

View File

@ -49,7 +49,7 @@ help:
@echo " install make and install"
@echo " install-coverage make and install with C coverage"
@echo " lint run the lint checks"
@echo " lint-fix run Black and isort to (mostly) fix lint issues"
@echo " lint-fix run Ruff to (mostly) fix lint issues"
@echo " release-test run code and package tests before release"
@echo " test run tests on installed Pillow"
@ -118,6 +118,6 @@ lint:
.PHONY: lint-fix
lint-fix:
python3 -c "import black" > /dev/null 2>&1 || python3 -m pip install black
python3 -c "import isort" > /dev/null 2>&1 || python3 -m pip install isort
python3 -m black --target-version py38 .
python3 -m isort .
python3 -c "import ruff" > /dev/null 2>&1 || python3 -m pip install ruff
python3 -m ruff --fix .

View File

@ -45,7 +45,7 @@ def test_direct():
assert caccess[(0, 0)] == access[(0, 0)]
print("Size: %sx%s" % im.size)
print("Size: %sx%s" % im.size) # noqa: UP031
timer(iterate_get, "PyAccess - get", im.size, access)
timer(iterate_set, "PyAccess - set", im.size, access)
timer(iterate_get, "C-api - get", im.size, caccess)

View File

@ -350,7 +350,7 @@ def test_apng_save(tmp_path):
im.load()
assert not im.is_animated
assert im.n_frames == 1
assert im.get_format_mimetype() == "image/apng"
assert im.get_format_mimetype() == "image/png"
assert im.info.get("default_image") is None
assert im.getpixel((0, 0)) == (0, 255, 0, 255)
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
@ -450,26 +450,29 @@ def test_apng_save_duration_loop(tmp_path):
test_file, save_all=True, append_images=[frame, frame], duration=[500, 100, 150]
)
with Image.open(test_file) as im:
im.load()
assert im.n_frames == 1
assert im.info.get("duration") == 750
assert "duration" not in im.info
different_frame = Image.new("RGBA", (128, 64))
frame.save(
test_file,
save_all=True,
append_images=[frame, different_frame],
duration=[500, 100, 150],
)
with Image.open(test_file) as im:
assert im.n_frames == 2
assert im.info["duration"] == 600
im.seek(1)
assert im.info["duration"] == 150
# test info duration
frame.info["duration"] = 750
frame.save(test_file, save_all=True)
frame.info["duration"] = 300
frame.save(test_file, save_all=True, append_images=[frame, different_frame])
with Image.open(test_file) as im:
assert im.info.get("duration") == 750
def test_apng_save_duplicate_duration(tmp_path):
test_file = str(tmp_path / "temp.png")
frame = Image.new("RGB", (1, 1))
# Test a single duration is correctly combined across duplicate frames
frame.save(test_file, save_all=True, append_images=[frame, frame], duration=500)
with Image.open(test_file) as im:
assert im.n_frames == 1
assert im.info.get("duration") == 1500
assert im.n_frames == 2
assert im.info["duration"] == 600
def test_apng_save_disposal(tmp_path):
@ -674,7 +677,8 @@ def test_seek_after_close():
@pytest.mark.parametrize("mode", ("RGBA", "RGB", "P"))
@pytest.mark.parametrize("default_image", (True, False))
def test_different_modes_in_later_frames(mode, default_image, tmp_path):
@pytest.mark.parametrize("duplicate", (True, False))
def test_different_modes_in_later_frames(mode, default_image, duplicate, tmp_path):
test_file = str(tmp_path / "temp.png")
im = Image.new("L", (1, 1))
@ -682,7 +686,7 @@ def test_different_modes_in_later_frames(mode, default_image, tmp_path):
test_file,
save_all=True,
default_image=default_image,
append_images=[Image.new(mode, (1, 1))],
append_images=[im.convert(mode) if duplicate else Image.new(mode, (1, 1), 1)],
)
with Image.open(test_file) as reloaded:
assert reloaded.mode == mode

View File

@ -1,6 +1,6 @@
import sys
from setuptools.build_meta import * # noqa: F401, F403
from setuptools.build_meta import * # noqa: F403
from setuptools.build_meta import build_wheel
backend_class = build_wheel.__self__.__class__

View File

@ -318,14 +318,14 @@ def setup(app):
linkcheck_allowed_redirects = {
r"https://www.bestpractices.dev/projects/6331": r"https://www.bestpractices.dev/en/.*", # noqa: E501
r"https://badges.gitter.im/python-pillow/Pillow.svg": r"https://badges.gitter.im/repo.svg", # noqa: E501
r"https://gitter.im/python-pillow/Pillow?.*": r"https://app.gitter.im/#/room/#python-pillow_Pillow:gitter.im?.*", # noqa: E501
r"https://pillow.readthedocs.io/?badge=latest": r"https://pillow.readthedocs.io/en/stable/?badge=latest", # noqa: E501
r"https://www.bestpractices.dev/projects/6331": r"https://www.bestpractices.dev/en/.*",
r"https://badges.gitter.im/python-pillow/Pillow.svg": r"https://badges.gitter.im/repo.svg",
r"https://gitter.im/python-pillow/Pillow?.*": r"https://app.gitter.im/#/room/#python-pillow_Pillow:gitter.im?.*",
r"https://pillow.readthedocs.io/?badge=latest": r"https://pillow.readthedocs.io/en/stable/?badge=latest",
r"https://pillow.readthedocs.io": r"https://pillow.readthedocs.io/en/stable/",
r"https://tidelift.com/badges/package/pypi/Pillow?.*": r"https://img.shields.io/badge/.*", # noqa: E501
r"https://zenodo.org/badge/17549/python-pillow/Pillow.svg": r"https://zenodo.org/badge/doi/[\.0-9]+/zenodo.[0-9]+.svg", # noqa: E501
r"https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow": r"https://zenodo.org/record/[0-9]+", # noqa: E501
r"https://tidelift.com/badges/package/pypi/Pillow?.*": r"https://img.shields.io/badge/.*",
r"https://zenodo.org/badge/17549/python-pillow/Pillow.svg": r"https://zenodo.org/badge/doi/[\.0-9]+/zenodo.[0-9]+.svg",
r"https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow": r"https://zenodo.org/record/[0-9]+",
}
# sphinx.ext.extlinks

View File

@ -10,7 +10,7 @@ Deprecated features
-------------------
Below are features which are considered deprecated. Where appropriate,
a ``DeprecationWarning`` is issued.
a :py:exc:`DeprecationWarning` is issued.
PSFile
~~~~~~
@ -267,7 +267,7 @@ ImageFile.raise_ioerror
.. deprecated:: 7.2.0
.. versionremoved:: 9.0.0
``IOError`` was merged into ``OSError`` in Python 3.3.
:py:exc:`IOError` was merged into :py:exc:`OSError` in Python 3.3.
So, ``ImageFile.raise_ioerror`` has been removed.
Use ``ImageFile.raise_oserror`` instead.
@ -293,9 +293,9 @@ im.offset
``im.offset()`` has been removed, call :py:func:`.ImageChops.offset()` instead.
It was documented as deprecated in PIL 1.1.2,
raised a ``DeprecationWarning`` since 1.1.5,
an ``Exception`` since Pillow 3.0.0
and ``NotImplementedError`` since 3.3.0.
raised a :py:exc:`DeprecationWarning` since 1.1.5,
an :py:exc:`Exception` since Pillow 3.0.0
and :py:exc:`NotImplementedError` since 3.3.0.
Image.fromstring, im.fromstring and im.tostring
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -307,9 +307,9 @@ Image.fromstring, im.fromstring and im.tostring
* ``im.fromstring()`` has been removed, call :py:meth:`~PIL.Image.Image.frombytes()` instead.
* ``im.tostring()`` has been removed, call :py:meth:`~PIL.Image.Image.tobytes()` instead.
They issued a ``DeprecationWarning`` since 2.0.0,
an ``Exception`` since 3.0.0
and ``NotImplementedError`` since 3.3.0.
They issued a :py:exc:`DeprecationWarning` since 2.0.0,
an :py:exc:`Exception` since 3.0.0
and :py:exc:`NotImplementedError` since 3.3.0.
ImageCms.CmsProfile attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -318,7 +318,7 @@ ImageCms.CmsProfile attributes
.. versionremoved:: 8.0.0
Some attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed. From 6.0.0,
they issued a ``DeprecationWarning``:
they issued a :py:exc:`DeprecationWarning`:
======================== ===================================================
Removed Use instead
@ -442,7 +442,7 @@ PIL.OleFileIO
.. deprecated:: 4.0.0
.. versionremoved:: 6.0.0
PIL.OleFileIO was removed as a vendored file in Pillow 4.0.0 (2017-01) in favour of
the upstream :pypi:`olefile` Python package, and replaced with an ``ImportError`` in 5.0.0
``PIL.OleFileIO`` was removed as a vendored file in Pillow 4.0.0 (2017-01) in favour of
the upstream :pypi:`olefile` Python package, and replaced with an :py:exc:`ImportError` in 5.0.0
(2018-01). The deprecated file has now been removed from Pillow. If needed, install from
PyPI (eg. ``python3 -m pip install olefile``).

View File

@ -20,7 +20,7 @@ the imToolkit package.
.. warning::
To protect against potential DOS attacks when using arbitrary strings as
text input, Pillow will raise a ``ValueError`` if the number of characters
text input, Pillow will raise a :py:exc:`ValueError` if the number of characters
is over a certain limit, :py:data:`MAX_STRING_LENGTH`.
This threshold can be changed by setting
@ -89,5 +89,5 @@ Constants
.. data:: MAX_STRING_LENGTH
Set to 1,000,000, to protect against potential DOS attacks. Pillow will
raise a ``ValueError`` if the number of characters is over this limit. The
raise a :py:exc:`ValueError` if the number of characters is over this limit. The
check can be disabled by setting ``ImageFont.MAX_STRING_LENGTH = None``.

View File

@ -8,7 +8,7 @@ Setting image mode
^^^^^^^^^^^^^^^^^^
If you attempt to set the mode of an image directly, e.g.
``im.mode = "RGBA"``, you will now receive an ``AttributeError``. This is
``im.mode = "RGBA"``, you will now receive an :py:exc:`AttributeError`. This is
not about removing existing functionality, but instead about raising an
explicit error to prevent later consequences. The ``convert`` method is the
correct way to change an image's mode.

View File

@ -10,7 +10,7 @@ operations. As a result PIL was unable to open them as images, requiring a wrap
``cStringIO`` or ``BytesIO``.
Now new functionality has been added to ``Image.open()`` by way of an ``.seek(0)`` check and
catch on exception ``AttributeError`` or ``io.UnsupportedOperation``. If this is caught we
catch on exception :py:exc:`AttributeError` or :py:exc:`io.UnsupportedOperation`. If this is caught we
attempt to wrap the object using ``io.BytesIO`` (which will only work on buffer-file-like
objects).

View File

@ -19,7 +19,7 @@ Deprecation Warning when Saving JPEGs
JPEG images cannot contain an alpha channel. Pillow prior to 3.4.0
silently drops the alpha channel. With this release Pillow will now
issue a ``DeprecationWarning`` when attempting to save a ``RGBA`` mode
issue a :py:exc:`DeprecationWarning` when attempting to save a ``RGBA`` mode
image as a JPEG. This will become an error in Pillow 4.2.
New DDS Decoders

View File

@ -8,7 +8,7 @@ Image size
^^^^^^^^^^
If you attempt to set the size of an image directly, e.g.
``im.size = (100, 100)``, you will now receive an ``AttributeError``. This is
``im.size = (100, 100)``, you will now receive an :py:exc:`AttributeError`. This is
not about removing existing functionality, but instead about raising an
explicit error to prevent later consequences. The ``resize`` method is the
correct way to change an image's size.
@ -16,7 +16,8 @@ correct way to change an image's size.
The exceptions to this are:
* The ICO and ICNS image formats, which use ``im.size = (100, 100)`` to select a subimage.
* The TIFF image format, which now has a ``DeprecationWarning`` for this action, as direct image size setting was previously necessary to work around an issue with tile extents.
* The TIFF image format, which now has a :py:exc:`DeprecationWarning` for this action,
as direct image size setting was previously necessary to work around an issue with tile extents.
API Additions

View File

@ -15,7 +15,7 @@ PNG: Handle IDAT chunks after image end
Some PNG images have multiple IDAT chunks. In some cases, Pillow will stop
reading image data before the IDAT chunks finish. A regression caused an
``EOFError`` exception when previously there was none. This is now fixed, and
:py:exc:`EOFError` exception when previously there was none. This is now fixed, and
file reading continues in case there are subsequent text chunks.
PNG: MIME type
@ -30,7 +30,7 @@ File closing
^^^^^^^^^^^^
A regression caused an unsupported image file to report a
``ValueError: seek of closed file`` exception instead of an ``OSError``. This
``ValueError: seek of closed file`` exception instead of an :py:exc:`OSError`. This
has been fixed by ensuring that image plugins only close their internal ``__fp``
if they are not the same as ``ImageFile``'s ``fp``, allowing each to manage their own
file pointers.

View File

@ -103,7 +103,7 @@ ImageCms.CmsProfile attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some attributes in ``ImageCms.CmsProfile`` have been deprecated since Pillow 3.2.0. From
6.0.0, they issue a ``DeprecationWarning``:
6.0.0, they issue a :py:exc:`DeprecationWarning`:
======================== ===============================
Deprecated Use instead

View File

@ -58,7 +58,7 @@ file. ``ImageFont.FreeTypeFont`` has four new methods,
:py:meth:`PIL.ImageFont.FreeTypeFont.set_variation_by_name` for using named styles, and
:py:meth:`PIL.ImageFont.FreeTypeFont.get_variation_axes` and
:py:meth:`PIL.ImageFont.FreeTypeFont.set_variation_by_axes` for using font axes
instead. An ``IOError`` will be raised if the font is not a variation font. FreeType
instead. An :py:exc:`IOError` will be raised if the font is not a variation font. FreeType
2.9.1 or greater is required.
Other Changes

View File

@ -85,7 +85,7 @@ Custom unidentified image error
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Pillow will now throw a custom ``UnidentifiedImageError`` when an image cannot be
identified. For backwards compatibility, this will inherit from ``OSError``.
identified. For backwards compatibility, this will inherit from :py:exc:`OSError`.
New argument ``reducing_gap`` for Image.resize() and Image.thumbnail() methods
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -7,7 +7,7 @@ Fix another regression seeking PNG files
This fixes a regression introduced in 7.1.0 when adding support for APNG files.
When calling ``seek(n)`` on a regular PNG where ``n > 0``, it failed to raise an
``EOFError`` as it should have done, resulting in:
:py:exc:`EOFError` as it should have done, resulting in:
.. code-block:: pycon

View File

@ -53,6 +53,6 @@ a custom :py:class:`~PIL.ImageShow.Viewer` class.
ImageFile.raise_ioerror
~~~~~~~~~~~~~~~~~~~~~~~
``IOError`` was merged into ``OSError`` in Python 3.3. So, ``ImageFile.raise_ioerror``
:py:exc:`IOError` was merged into :py:exc:`OSError` in Python 3.3. So, ``ImageFile.raise_ioerror``
is now deprecated and will be removed in a future release. Use
``ImageFile.raise_oserror`` instead.

View File

@ -168,7 +168,7 @@ offset.
Error for large BMP files
^^^^^^^^^^^^^^^^^^^^^^^^^
Previously, if a BMP file was too large, an ``OSError`` would be raised. Now,
Previously, if a BMP file was too large, an :py:exc:`OSError` would be raised. Now,
``DecompressionBombError`` is used instead, as Pillow already uses for other formats.
Dark theme for docs

View File

@ -22,9 +22,10 @@ Catch OSError when checking if destination is sys.stdout
========================================================
In 8.3.0, a check to see if the destination was ``sys.stdout`` when saving an image was
updated. This lead to an OSError being raised if the environment restricted access.
updated. This lead to an :py:exc:`OSError` being raised if the environment restricted
access.
The OSError is now silently caught.
The :py:exc:`OSError` is now silently caught.
Fixed removing orientation in ImageOps.exif_transpose
=====================================================
@ -34,7 +35,7 @@ original image EXIF data was not modified, and the orientation was only removed
the modified copy.
However, for certain images the orientation was already missing from the modified
image, leading to a KeyError.
image, leading to a :py:exc:`KeyError`.
This error has been resolved, and the copying of metadata to the modified image
improved.

View File

@ -63,7 +63,7 @@ a custom :py:class:`~PIL.ImageShow.Viewer` class.
ImageFile.raise_ioerror
^^^^^^^^^^^^^^^^^^^^^^^
``IOError`` was merged into ``OSError`` in Python 3.3. So, ``ImageFile.raise_ioerror``
:py:exc:`IOError` was merged into :py:exc:`OSError` in Python 3.3. So, ``ImageFile.raise_ioerror``
has been removed. Use ``ImageFile.raise_oserror`` instead.

View File

@ -8,14 +8,14 @@ Raise an error when performing a negative crop
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Performing a negative crop on an image previously just returned a ``(0, 0)`` image. Now
it will raise a ``ValueError``, to help reduce confusion if a user has unintentionally
it will raise a :py:exc:`ValueError`, to help reduce confusion if a user has unintentionally
provided the wrong arguments.
Added specific error if path coordinate type is incorrect
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Rather than returning a ``SystemError``, passing the incorrect types of coordinates into
a path will now raise a more specific ``ValueError``, with the message "incorrect
Rather than returning a :py:exc:`SystemError`, passing the incorrect types of coordinates into
a path will now raise a more specific :py:exc:`ValueError`, with the message "incorrect
coordinate type".
Replace requirements.txt with extras

View File

@ -77,8 +77,34 @@ package-dir = {"" = "src"}
[tool.setuptools.dynamic]
version = {attr = "PIL.__version__"}
[tool.isort]
profile = "black"
[tool.ruff]
target-version = "py38"
line-length = 88
select = [
"E", # pycodestyle errors
"EM", # flake8-errmsg
"F", # pyflakes errors
"I", # isort
"ISC", # flake8-implicit-str-concat
"PGH", # pygrep-hooks
"RUF100", # unused noqa (yesqa)
"UP", # pyupgrade
"W", # pycodestyle warnings
"YTT", # flake8-2020
# "LOG", # TODO: enable flake8-logging when it's not in preview anymore
]
extend-ignore = [
"E203", # Whitespace before ':'
"E221", # Multiple spaces before operator
"E226", # Missing whitespace around arithmetic operator
"E241", # Multiple spaces after ','
]
[tool.ruff.per-file-ignores]
"Tests/*.py" = ["I001"]
[tool.ruff.isort]
known-first-party = ["PIL"]
[tool.pytest.ini_options]
addopts = "-ra --color=yes"

View File

@ -122,7 +122,7 @@ def Ghostscript(tile, size, fp, scale=1, transparency=False):
gs_binary,
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-r%fx%f" % res, # set input DPI (dots per inch) # noqa: UP031
"-dBATCH", # exit after processing
"-dNOPAUSE", # don't pause between pages
"-dSAFER", # safe mode

View File

@ -392,7 +392,7 @@ if __name__ == "__main__":
imf = IcnsImageFile(fp)
for size in imf.info["sizes"]:
imf.size = size
imf.save("out-%s-%s-%s.png" % size)
imf.save("out-%s-%s-%s.png" % size) # noqa: UP031
with Image.open(sys.argv[1]) as im:
im.save("out.png")
if sys.platform == "windows":

View File

@ -3100,7 +3100,7 @@ def fromarray(obj, mode=None):
try:
mode, rawmode = _fromarray_typemap[typekey]
except KeyError as e:
msg = "Cannot handle this data type: %s, %s" % typekey
msg = "Cannot handle this data type: %s, %s" % typekey # noqa: UP031
raise TypeError(msg) from e
else:
rawmode = mode

View File

@ -222,7 +222,7 @@ class UnsharpMask(MultibandFilter):
.. _digital unsharp masking: https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking
""" # noqa: E501
"""
name = "UnsharpMask"

View File

@ -18,10 +18,9 @@ import os
import tempfile
from . import Image, ImageFile
from ._binary import i8
from ._binary import i8, o8
from ._binary import i16be as i16
from ._binary import i32be as i32
from ._binary import o8
COMPRESSION = {1: "raw", 5: "jpeg"}

View File

@ -82,7 +82,7 @@ class IndirectReference(
collections.namedtuple("IndirectReferenceTuple", ["object_id", "generation"])
):
def __str__(self):
return "%s %s R" % self
return "%s %s R" % self # noqa: UP031
def __bytes__(self):
return self.__str__().encode("us-ascii")
@ -103,7 +103,7 @@ class IndirectReference(
class IndirectObjectDef(IndirectReference):
def __str__(self):
return "%s %s obj" % self
return "%s %s obj" % self # noqa: UP031
class XrefTable:

View File

@ -1156,6 +1156,9 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
encoderinfo["duration"] = duration
im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo})
if len(im_frames) == 1 and not default_image:
return im_frames[0]["im"]
# animation control
chunk(
fp,
@ -1391,8 +1394,10 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
chunk(fp, b"eXIf", exif)
if save_all:
_write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
else:
im = _write_multiple_frames(
im, fp, chunk, rawmode, default_image, append_images
)
if im:
ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
if info:

View File

@ -244,7 +244,7 @@ class _PyAccessI16_L(PyAccess):
except TypeError:
color = min(color[0], 65535)
pixel.l = color & 0xFF # noqa: E741
pixel.l = color & 0xFF
pixel.r = color >> 8
@ -265,7 +265,7 @@ class _PyAccessI16_B(PyAccess):
except Exception:
color = min(color[0], 65535)
pixel.l = color >> 8 # noqa: E741
pixel.l = color >> 8
pixel.r = color & 0xFF

View File

@ -239,7 +239,7 @@ DEPS = {
"libs": ["*.lib"],
},
"freetype": {
"url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.gz", # noqa: E501
"url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.gz",
"filename": "freetype-2.13.2.tar.gz",
"dir": "freetype-2.13.2",
"license": ["LICENSE.TXT", r"docs\FTL.TXT", r"docs\GPLv2.TXT"],
@ -321,7 +321,7 @@ DEPS = {
},
"libimagequant": {
# commit: Merge branch 'master' into msvc (matches 2.17.0 tag)
"url": "https://github.com/ImageOptim/libimagequant/archive/e4c1334be0eff290af5e2b4155057c2953a313ab.zip", # noqa: E501
"url": "https://github.com/ImageOptim/libimagequant/archive/e4c1334be0eff290af5e2b4155057c2953a313ab.zip",
"filename": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab.zip",
"dir": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab",
"license": "COPYRIGHT",