mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-04 20:03:20 +03:00
Merge branch 'main' into fromarray_mode
This commit is contained in:
commit
78bc045db9
|
@ -1,4 +1,4 @@
|
||||||
mypy==1.16.0
|
mypy==1.16.1
|
||||||
IceSpringPySideStubs-PyQt6
|
IceSpringPySideStubs-PyQt6
|
||||||
IceSpringPySideStubs-PySide6
|
IceSpringPySideStubs-PySide6
|
||||||
ipython
|
ipython
|
||||||
|
|
2
.github/workflows/wheels-dependencies.sh
vendored
2
.github/workflows/wheels-dependencies.sh
vendored
|
@ -39,7 +39,7 @@ ARCHIVE_SDIR=pillow-depends-main
|
||||||
# Package versions for fresh source builds
|
# Package versions for fresh source builds
|
||||||
FREETYPE_VERSION=2.13.3
|
FREETYPE_VERSION=2.13.3
|
||||||
HARFBUZZ_VERSION=11.2.1
|
HARFBUZZ_VERSION=11.2.1
|
||||||
LIBPNG_VERSION=1.6.48
|
LIBPNG_VERSION=1.6.49
|
||||||
JPEGTURBO_VERSION=3.1.1
|
JPEGTURBO_VERSION=3.1.1
|
||||||
OPENJPEG_VERSION=2.5.3
|
OPENJPEG_VERSION=2.5.3
|
||||||
XZ_VERSION=5.8.1
|
XZ_VERSION=5.8.1
|
||||||
|
|
|
@ -7,9 +7,8 @@ import pytest
|
||||||
from PIL import BlpImagePlugin, Image
|
from PIL import BlpImagePlugin, Image
|
||||||
|
|
||||||
from .helper import (
|
from .helper import (
|
||||||
assert_image_equal,
|
|
||||||
assert_image_equal_tofile,
|
assert_image_equal_tofile,
|
||||||
assert_image_similar,
|
assert_image_similar_tofile,
|
||||||
hopper,
|
hopper,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,18 +51,16 @@ def test_save(tmp_path: Path) -> None:
|
||||||
im = hopper("P")
|
im = hopper("P")
|
||||||
im.save(f, blp_version=version)
|
im.save(f, blp_version=version)
|
||||||
|
|
||||||
with Image.open(f) as reloaded:
|
assert_image_equal_tofile(im.convert("RGB"), f)
|
||||||
assert_image_equal(im.convert("RGB"), reloaded)
|
|
||||||
|
|
||||||
with Image.open("Tests/images/transparent.png") as im:
|
with Image.open("Tests/images/transparent.png") as im:
|
||||||
f = tmp_path / "temp.blp"
|
f = tmp_path / "temp.blp"
|
||||||
im.convert("P").save(f, blp_version=version)
|
im.convert("P").save(f, blp_version=version)
|
||||||
|
|
||||||
with Image.open(f) as reloaded:
|
assert_image_similar_tofile(im, f, 8)
|
||||||
assert_image_similar(im, reloaded, 8)
|
|
||||||
|
|
||||||
im = hopper()
|
im = hopper()
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError, match="Unsupported BLP image mode"):
|
||||||
im.save(f)
|
im.save(f)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -100,11 +100,11 @@ class TestFilePng:
|
||||||
assert im.format == "PNG"
|
assert im.format == "PNG"
|
||||||
assert im.get_format_mimetype() == "image/png"
|
assert im.get_format_mimetype() == "image/png"
|
||||||
|
|
||||||
for mode in ["1", "L", "P", "RGB", "I", "I;16", "I;16B"]:
|
for mode in ["1", "L", "P", "RGB", "I;16", "I;16B"]:
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
im.save(test_file)
|
im.save(test_file)
|
||||||
with Image.open(test_file) as reloaded:
|
with Image.open(test_file) as reloaded:
|
||||||
if mode in ("I", "I;16B"):
|
if mode == "I;16B":
|
||||||
reloaded = reloaded.convert(mode)
|
reloaded = reloaded.convert(mode)
|
||||||
assert_image_equal(reloaded, im)
|
assert_image_equal(reloaded, im)
|
||||||
|
|
||||||
|
@ -801,6 +801,16 @@ class TestFilePng:
|
||||||
with Image.open("Tests/images/truncated_end_chunk.png") as im:
|
with Image.open("Tests/images/truncated_end_chunk.png") as im:
|
||||||
assert_image_equal_tofile(im, "Tests/images/hopper.png")
|
assert_image_equal_tofile(im, "Tests/images/hopper.png")
|
||||||
|
|
||||||
|
def test_deprecation(self, tmp_path: Path) -> None:
|
||||||
|
test_file = tmp_path / "out.png"
|
||||||
|
|
||||||
|
im = hopper("I")
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
im.save(test_file)
|
||||||
|
|
||||||
|
with Image.open(test_file) as reloaded:
|
||||||
|
assert_image_equal(im, reloaded.convert("I"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
|
@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
|
||||||
@skip_unless_feature("zlib")
|
@skip_unless_feature("zlib")
|
||||||
|
|
|
@ -294,9 +294,10 @@ def test_header_token_too_long(tmp_path: Path, data: bytes) -> None:
|
||||||
with open(path, "wb") as f:
|
with open(path, "wb") as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
with pytest.raises(ValueError, match="Token too long in file header: "):
|
with pytest.raises(ValueError) as e:
|
||||||
with Image.open(path):
|
with Image.open(path):
|
||||||
pass
|
pass
|
||||||
|
assert "Token too long in file header: " in repr(e)
|
||||||
|
|
||||||
|
|
||||||
def test_truncated_file(tmp_path: Path) -> None:
|
def test_truncated_file(tmp_path: Path) -> None:
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PIL import Image, QoiImagePlugin
|
from PIL import Image, QoiImagePlugin
|
||||||
|
|
||||||
from .helper import assert_image_equal_tofile
|
from .helper import assert_image_equal_tofile, hopper
|
||||||
|
|
||||||
|
|
||||||
def test_sanity() -> None:
|
def test_sanity() -> None:
|
||||||
|
@ -34,3 +36,22 @@ def test_op_index() -> None:
|
||||||
# QOI_OP_INDEX as the first chunk
|
# QOI_OP_INDEX as the first chunk
|
||||||
with Image.open("Tests/images/op_index.qoi") as im:
|
with Image.open("Tests/images/op_index.qoi") as im:
|
||||||
assert im.getpixel((0, 0)) == (0, 0, 0, 0)
|
assert im.getpixel((0, 0)) == (0, 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_save(tmp_path: Path) -> None:
|
||||||
|
f = tmp_path / "temp.qoi"
|
||||||
|
|
||||||
|
im = hopper()
|
||||||
|
im.save(f, colorspace="sRGB")
|
||||||
|
|
||||||
|
assert_image_equal_tofile(im, f)
|
||||||
|
|
||||||
|
for path in ("Tests/images/default_font.png", "Tests/images/pil123rgba.png"):
|
||||||
|
with Image.open(path) as im:
|
||||||
|
im.save(f)
|
||||||
|
|
||||||
|
assert_image_equal_tofile(im, f)
|
||||||
|
|
||||||
|
im = hopper("P")
|
||||||
|
with pytest.raises(ValueError, match="Unsupported QOI image mode"):
|
||||||
|
im.save(f)
|
||||||
|
|
|
@ -201,6 +201,20 @@ Image.fromarray mode parameter
|
||||||
The ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` has been deprecated. The
|
The ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` has been deprecated. The
|
||||||
mode can be automatically determined from the object's shape and type instead.
|
mode can be automatically determined from the object's shape and type instead.
|
||||||
|
|
||||||
|
Saving I mode images as PNG
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. deprecated:: 11.3.0
|
||||||
|
|
||||||
|
In order to fit the 32 bits of I mode images into PNG, when PNG images can only contain
|
||||||
|
at most 16 bits for a channel, Pillow has been clipping the values. Rather than quietly
|
||||||
|
changing the data, this is now deprecated. Instead, the image can be converted to
|
||||||
|
another mode before saving::
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
im = Image.new("I", (1, 1))
|
||||||
|
im.convert("I;16").save("out.png")
|
||||||
|
|
||||||
Removed features
|
Removed features
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
|
@ -1082,6 +1082,26 @@ Pillow reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L``, ``I
|
||||||
|
|
||||||
Since Pillow 9.2.0, "plain" (P1 to P3) formats can be read as well.
|
Since Pillow 9.2.0, "plain" (P1 to P3) formats can be read as well.
|
||||||
|
|
||||||
|
QOI
|
||||||
|
^^^
|
||||||
|
|
||||||
|
.. versionadded:: 9.5.0
|
||||||
|
|
||||||
|
Pillow reads and writes images in Quite OK Image format using a Python codec. If you
|
||||||
|
wish to write code specifically for this format, :pypi:`qoi` is an alternative library
|
||||||
|
that uses C to decode the image and interfaces with NumPy.
|
||||||
|
|
||||||
|
.. _qoi-saving:
|
||||||
|
|
||||||
|
Saving
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
The :py:meth:`~PIL.Image.Image.save` method can take the following keyword arguments:
|
||||||
|
|
||||||
|
**colorspace**
|
||||||
|
If set to "sRGB", the colorspace will be written as sRGB with linear alpha, instead
|
||||||
|
of all channels being linear.
|
||||||
|
|
||||||
SGI
|
SGI
|
||||||
^^^
|
^^^
|
||||||
|
|
||||||
|
@ -1578,15 +1598,6 @@ PSD
|
||||||
|
|
||||||
Pillow identifies and reads PSD files written by Adobe Photoshop 2.5 and 3.0.
|
Pillow identifies and reads PSD files written by Adobe Photoshop 2.5 and 3.0.
|
||||||
|
|
||||||
QOI
|
|
||||||
^^^
|
|
||||||
|
|
||||||
.. versionadded:: 9.5.0
|
|
||||||
|
|
||||||
Pillow reads images in Quite OK Image format using a Python decoder. If you wish to
|
|
||||||
write code specifically for this format, :pypi:`qoi` is an alternative library that
|
|
||||||
uses C to decode the image and interfaces with NumPy.
|
|
||||||
|
|
||||||
SUN
|
SUN
|
||||||
^^^
|
^^^
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,18 @@ Image.fromarray mode parameter
|
||||||
The ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` has been deprecated. The
|
The ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` has been deprecated. The
|
||||||
mode can be automatically determined from the object's shape and type instead.
|
mode can be automatically determined from the object's shape and type instead.
|
||||||
|
|
||||||
|
Saving I mode images as PNG
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
In order to fit the 32 bits of I mode images into PNG, when PNG images can only contain
|
||||||
|
at most 16 bits for a channel, Pillow has been clipping the values. Rather than quietly
|
||||||
|
changing the data, this is now deprecated. Instead, the image can be converted to
|
||||||
|
another mode before saving::
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
im = Image.new("I", (1, 1))
|
||||||
|
im.convert("I;16").save("out.png")
|
||||||
|
|
||||||
API changes
|
API changes
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@ -48,6 +60,26 @@ TODO
|
||||||
Other changes
|
Other changes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
Added QOI saving
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Support has been added for saving QOI images. ``colorspace`` can be used to specify the
|
||||||
|
colorspace as sRGB with linear alpha, e.g. ``im.save("out.qoi", colorspace="sRGB")``.
|
||||||
|
By default, all channels will be linear.
|
||||||
|
|
||||||
|
Support using more screenshot utilities with ImageGrab on Linux
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
:py:meth:`~PIL.ImageGrab.grab` is now able to use GNOME Screenshot, grim or Spectacle
|
||||||
|
on Linux in order to take a snapshot of the screen.
|
||||||
|
|
||||||
|
Do not build against libavif < 1
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Pillow only supports libavif 1.0.0 or later. In order to prevent errors when building
|
||||||
|
from source, if a user happens to have an earlier libavif on their system, Pillow will
|
||||||
|
now ignore it.
|
||||||
|
|
||||||
Python 3.14 beta
|
Python 3.14 beta
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ from ._binary import i32be as i32
|
||||||
from ._binary import o8
|
from ._binary import o8
|
||||||
from ._binary import o16be as o16
|
from ._binary import o16be as o16
|
||||||
from ._binary import o32be as o32
|
from ._binary import o32be as o32
|
||||||
|
from ._deprecate import deprecate
|
||||||
from ._util import DeferredError
|
from ._util import DeferredError
|
||||||
|
|
||||||
TYPE_CHECKING = False
|
TYPE_CHECKING = False
|
||||||
|
@ -1368,6 +1369,8 @@ def _save(
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
msg = f"cannot write mode {mode} as PNG"
|
msg = f"cannot write mode {mode} as PNG"
|
||||||
raise OSError(msg) from e
|
raise OSError(msg) from e
|
||||||
|
if outmode == "I":
|
||||||
|
deprecate("Saving I mode images as PNG", 13, stacklevel=4)
|
||||||
|
|
||||||
#
|
#
|
||||||
# write minimal PNG file
|
# write minimal PNG file
|
||||||
|
|
|
@ -8,9 +8,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
from . import Image, ImageFile
|
from . import Image, ImageFile
|
||||||
from ._binary import i32be as i32
|
from ._binary import i32be as i32
|
||||||
|
from ._binary import o8
|
||||||
|
from ._binary import o32be as o32
|
||||||
|
|
||||||
|
|
||||||
def _accept(prefix: bytes) -> bool:
|
def _accept(prefix: bytes) -> bool:
|
||||||
|
@ -110,6 +113,122 @@ class QoiDecoder(ImageFile.PyDecoder):
|
||||||
return -1, 0
|
return -1, 0
|
||||||
|
|
||||||
|
|
||||||
|
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||||
|
if im.mode == "RGB":
|
||||||
|
channels = 3
|
||||||
|
elif im.mode == "RGBA":
|
||||||
|
channels = 4
|
||||||
|
else:
|
||||||
|
msg = "Unsupported QOI image mode"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
colorspace = 0 if im.encoderinfo.get("colorspace") == "sRGB" else 1
|
||||||
|
|
||||||
|
fp.write(b"qoif")
|
||||||
|
fp.write(o32(im.size[0]))
|
||||||
|
fp.write(o32(im.size[1]))
|
||||||
|
fp.write(o8(channels))
|
||||||
|
fp.write(o8(colorspace))
|
||||||
|
|
||||||
|
ImageFile._save(im, fp, [ImageFile._Tile("qoi", (0, 0) + im.size)])
|
||||||
|
|
||||||
|
|
||||||
|
class QoiEncoder(ImageFile.PyEncoder):
|
||||||
|
_pushes_fd = True
|
||||||
|
_previous_pixel: tuple[int, int, int, int] | None = None
|
||||||
|
_previously_seen_pixels: dict[int, tuple[int, int, int, int]] = {}
|
||||||
|
_run = 0
|
||||||
|
|
||||||
|
def _write_run(self) -> bytes:
|
||||||
|
data = o8(0b11000000 | (self._run - 1)) # QOI_OP_RUN
|
||||||
|
self._run = 0
|
||||||
|
return data
|
||||||
|
|
||||||
|
def _delta(self, left: int, right: int) -> int:
|
||||||
|
result = (left - right) & 255
|
||||||
|
if result >= 128:
|
||||||
|
result -= 256
|
||||||
|
return result
|
||||||
|
|
||||||
|
def encode(self, bufsize: int) -> tuple[int, int, bytes]:
|
||||||
|
assert self.im is not None
|
||||||
|
|
||||||
|
self._previously_seen_pixels = {0: (0, 0, 0, 0)}
|
||||||
|
self._previous_pixel = (0, 0, 0, 255)
|
||||||
|
|
||||||
|
data = bytearray()
|
||||||
|
w, h = self.im.size
|
||||||
|
bands = Image.getmodebands(self.mode)
|
||||||
|
|
||||||
|
for y in range(h):
|
||||||
|
for x in range(w):
|
||||||
|
pixel = self.im.getpixel((x, y))
|
||||||
|
if bands == 3:
|
||||||
|
pixel = (*pixel, 255)
|
||||||
|
|
||||||
|
if pixel == self._previous_pixel:
|
||||||
|
self._run += 1
|
||||||
|
if self._run == 62:
|
||||||
|
data += self._write_run()
|
||||||
|
else:
|
||||||
|
if self._run:
|
||||||
|
data += self._write_run()
|
||||||
|
|
||||||
|
r, g, b, a = pixel
|
||||||
|
hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64
|
||||||
|
if self._previously_seen_pixels.get(hash_value) == pixel:
|
||||||
|
data += o8(hash_value) # QOI_OP_INDEX
|
||||||
|
elif self._previous_pixel:
|
||||||
|
self._previously_seen_pixels[hash_value] = pixel
|
||||||
|
|
||||||
|
prev_r, prev_g, prev_b, prev_a = self._previous_pixel
|
||||||
|
if prev_a == a:
|
||||||
|
delta_r = self._delta(r, prev_r)
|
||||||
|
delta_g = self._delta(g, prev_g)
|
||||||
|
delta_b = self._delta(b, prev_b)
|
||||||
|
|
||||||
|
if (
|
||||||
|
-2 <= delta_r < 2
|
||||||
|
and -2 <= delta_g < 2
|
||||||
|
and -2 <= delta_b < 2
|
||||||
|
):
|
||||||
|
data += o8(
|
||||||
|
0b01000000
|
||||||
|
| (delta_r + 2) << 4
|
||||||
|
| (delta_g + 2) << 2
|
||||||
|
| (delta_b + 2)
|
||||||
|
) # QOI_OP_DIFF
|
||||||
|
else:
|
||||||
|
delta_gr = self._delta(delta_r, delta_g)
|
||||||
|
delta_gb = self._delta(delta_b, delta_g)
|
||||||
|
if (
|
||||||
|
-8 <= delta_gr < 8
|
||||||
|
and -32 <= delta_g < 32
|
||||||
|
and -8 <= delta_gb < 8
|
||||||
|
):
|
||||||
|
data += o8(
|
||||||
|
0b10000000 | (delta_g + 32)
|
||||||
|
) # QOI_OP_LUMA
|
||||||
|
data += o8((delta_gr + 8) << 4 | (delta_gb + 8))
|
||||||
|
else:
|
||||||
|
data += o8(0b11111110) # QOI_OP_RGB
|
||||||
|
data += bytes(pixel[:3])
|
||||||
|
else:
|
||||||
|
data += o8(0b11111111) # QOI_OP_RGBA
|
||||||
|
data += bytes(pixel)
|
||||||
|
|
||||||
|
self._previous_pixel = pixel
|
||||||
|
|
||||||
|
if self._run:
|
||||||
|
data += self._write_run()
|
||||||
|
data += bytes((0, 0, 0, 0, 0, 0, 0, 1)) # padding
|
||||||
|
|
||||||
|
return len(data), 0, data
|
||||||
|
|
||||||
|
|
||||||
Image.register_open(QoiImageFile.format, QoiImageFile, _accept)
|
Image.register_open(QoiImageFile.format, QoiImageFile, _accept)
|
||||||
Image.register_decoder("qoi", QoiDecoder)
|
Image.register_decoder("qoi", QoiDecoder)
|
||||||
Image.register_extension(QoiImageFile.format, ".qoi")
|
Image.register_extension(QoiImageFile.format, ".qoi")
|
||||||
|
|
||||||
|
Image.register_save(QoiImageFile.format, _save)
|
||||||
|
Image.register_encoder("qoi", QoiEncoder)
|
||||||
|
|
|
@ -12,6 +12,7 @@ def deprecate(
|
||||||
*,
|
*,
|
||||||
action: str | None = None,
|
action: str | None = None,
|
||||||
plural: bool = False,
|
plural: bool = False,
|
||||||
|
stacklevel: int = 3,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Deprecations helper.
|
Deprecations helper.
|
||||||
|
@ -67,5 +68,5 @@ def deprecate(
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
f"{deprecated} {is_} deprecated and will be removed in {removed}{action}",
|
f"{deprecated} {is_} deprecated and will be removed in {removed}{action}",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=3,
|
stacklevel=stacklevel,
|
||||||
)
|
)
|
||||||
|
|
|
@ -338,12 +338,6 @@ static const char *no_palette = "image has no palette";
|
||||||
static const char *readonly = "image is readonly";
|
static const char *readonly = "image is readonly";
|
||||||
/* static const char* no_content = "image has no content"; */
|
/* static const char* no_content = "image has no content"; */
|
||||||
|
|
||||||
void *
|
|
||||||
ImagingError_OSError(void) {
|
|
||||||
PyErr_SetString(PyExc_OSError, "error when accessing file");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ImagingError_MemoryError(void) {
|
ImagingError_MemoryError(void) {
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
@ -369,11 +363,6 @@ ImagingError_ValueError(const char *message) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ImagingError_Clear(void) {
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* HELPERS */
|
/* HELPERS */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
|
@ -54,7 +54,7 @@ ImagingSavePPM(Imaging im, const char *outfile) {
|
||||||
|
|
||||||
fp = fopen(outfile, "wb");
|
fp = fopen(outfile, "wb");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
(void)ImagingError_OSError();
|
PyErr_SetString(PyExc_OSError, "error when accessing file");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -270,8 +270,6 @@ ImagingSectionLeave(ImagingSectionCookie *cookie);
|
||||||
/* Exceptions */
|
/* Exceptions */
|
||||||
/* ---------- */
|
/* ---------- */
|
||||||
|
|
||||||
extern void *
|
|
||||||
ImagingError_OSError(void);
|
|
||||||
extern void *
|
extern void *
|
||||||
ImagingError_MemoryError(void);
|
ImagingError_MemoryError(void);
|
||||||
extern void *
|
extern void *
|
||||||
|
@ -280,8 +278,6 @@ extern void *
|
||||||
ImagingError_Mismatch(void); /* maps to ValueError by default */
|
ImagingError_Mismatch(void); /* maps to ValueError by default */
|
||||||
extern void *
|
extern void *
|
||||||
ImagingError_ValueError(const char *message);
|
ImagingError_ValueError(const char *message);
|
||||||
extern void
|
|
||||||
ImagingError_Clear(void);
|
|
||||||
|
|
||||||
/* Transform callbacks */
|
/* Transform callbacks */
|
||||||
/* ------------------- */
|
/* ------------------- */
|
||||||
|
|
|
@ -645,7 +645,7 @@ ImagingNewInternal(const char *mode, int xsize, int ysize, int dirty) {
|
||||||
return im;
|
return im;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingError_Clear();
|
PyErr_Clear();
|
||||||
|
|
||||||
// Try to allocate the image once more with smallest possible block size
|
// Try to allocate the image once more with smallest possible block size
|
||||||
MUTEX_LOCK(&ImagingDefaultArena.mutex);
|
MUTEX_LOCK(&ImagingDefaultArena.mutex);
|
||||||
|
|
|
@ -118,7 +118,7 @@ V = {
|
||||||
"LCMS2": "2.17",
|
"LCMS2": "2.17",
|
||||||
"LIBAVIF": "1.3.0",
|
"LIBAVIF": "1.3.0",
|
||||||
"LIBIMAGEQUANT": "4.3.4",
|
"LIBIMAGEQUANT": "4.3.4",
|
||||||
"LIBPNG": "1.6.48",
|
"LIBPNG": "1.6.49",
|
||||||
"LIBWEBP": "1.5.0",
|
"LIBWEBP": "1.5.0",
|
||||||
"OPENJPEG": "2.5.3",
|
"OPENJPEG": "2.5.3",
|
||||||
"TIFF": "4.7.0",
|
"TIFF": "4.7.0",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user