mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-11 16:52:29 +03:00
Merge branch 'main' into context_manager
This commit is contained in:
commit
254e9292c9
|
@ -1,4 +1,4 @@
|
|||
mypy==1.15.0
|
||||
mypy==1.16.0
|
||||
IceSpringPySideStubs-PyQt6
|
||||
IceSpringPySideStubs-PySide6
|
||||
ipython
|
||||
|
|
60
.github/workflows/test-valgrind-memory.yml
vendored
Normal file
60
.github/workflows/test-valgrind-memory.yml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
name: Test Valgrind Memory Leaks
|
||||
|
||||
# like the Docker tests, but running valgrind only on *.c/*.h changes.
|
||||
|
||||
# this is very expensive. Only run on the pull request.
|
||||
on:
|
||||
# push:
|
||||
# branches:
|
||||
# - "**"
|
||||
# paths:
|
||||
# - ".github/workflows/test-valgrind.yml"
|
||||
# - "**.c"
|
||||
# - "**.h"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/test-valgrind.yml"
|
||||
- "**.c"
|
||||
- "**.h"
|
||||
- "depends/docker-test-valgrind-memory.sh"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
docker: [
|
||||
ubuntu-22.04-jammy-amd64-valgrind,
|
||||
]
|
||||
dockerTag: [main]
|
||||
|
||||
name: ${{ matrix.docker }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build system information
|
||||
run: python3 .github/workflows/system-info.py
|
||||
|
||||
- name: Docker pull
|
||||
run: |
|
||||
docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
|
||||
|
||||
- name: Build and Run Valgrind
|
||||
run: |
|
||||
# The Pillow user in the docker container is UID 1001
|
||||
sudo chown -R 1001 $GITHUB_WORKSPACE
|
||||
docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} /Pillow/depends/docker-test-valgrind-memory.sh
|
||||
sudo chown -R runner $GITHUB_WORKSPACE
|
5
.github/workflows/test-windows.yml
vendored
5
.github/workflows/test-windows.yml
vendored
|
@ -31,16 +31,15 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["pypy3.11", "pypy3.10", "3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
architecture: ["x64"]
|
||||
os: ["windows-latest"]
|
||||
include:
|
||||
# Test the oldest Python on 32-bit
|
||||
- { python-version: "3.9", architecture: "x86", os: "windows-2019" }
|
||||
- { python-version: "3.9", architecture: "x86" }
|
||||
|
||||
timeout-minutes: 45
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.8
|
||||
rev: v0.11.12
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--exit-non-zero-on-fix]
|
||||
|
@ -24,7 +24,7 @@ repos:
|
|||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v20.1.3
|
||||
rev: v20.1.5
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types: [c]
|
||||
|
@ -58,7 +58,7 @@ repos:
|
|||
- id: check-renovate
|
||||
|
||||
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
||||
rev: v1.6.0
|
||||
rev: v1.9.0
|
||||
hooks:
|
||||
- id: zizmor
|
||||
|
||||
|
@ -68,7 +68,7 @@ repos:
|
|||
- id: sphinx-lint
|
||||
|
||||
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||
rev: v2.5.1
|
||||
rev: v2.6.0
|
||||
hooks:
|
||||
- id: pyproject-fmt
|
||||
|
||||
|
|
16
Makefile
16
Makefile
|
@ -97,13 +97,27 @@ test:
|
|||
python3 -c "import pytest" > /dev/null 2>&1 || python3 -m pip install pytest
|
||||
python3 -m pytest -qq
|
||||
|
||||
.PHONY: test-p
|
||||
test-p:
|
||||
python3 -c "import xdist" > /dev/null 2>&1 || python3 -m pip install pytest-xdist
|
||||
python3 -m pytest -qq -n auto
|
||||
|
||||
|
||||
.PHONY: valgrind
|
||||
valgrind:
|
||||
python3 -c "import pytest_valgrind" > /dev/null 2>&1 || python3 -m pip install pytest-valgrind
|
||||
PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=no \
|
||||
PILLOW_VALGRIND_TEST=true PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=no \
|
||||
--log-file=/tmp/valgrind-output \
|
||||
python3 -m pytest --no-memcheck -vv --valgrind --valgrind-log=/tmp/valgrind-output
|
||||
|
||||
.PHONY: valgrind-leak
|
||||
valgrind-leak:
|
||||
python3 -c "import pytest_valgrind" > /dev/null 2>&1 || python3 -m pip install pytest-valgrind
|
||||
PILLOW_VALGRIND_TEST=true PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp \
|
||||
--leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \
|
||||
--log-file=/tmp/valgrind-output \
|
||||
python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output
|
||||
|
||||
.PHONY: readme
|
||||
readme:
|
||||
python3 -c "import markdown2" > /dev/null 2>&1 || python3 -m pip install markdown2
|
||||
|
|
|
@ -14,3 +14,23 @@
|
|||
fun:_TIFFReadEncodedTileAndAllocBuffer
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
<python_alloc_possible_leak>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: all
|
||||
fun:malloc
|
||||
fun:_PyMem_RawMalloc
|
||||
fun:PyObject_Malloc
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
<python_realloc_possible_leak>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: all
|
||||
fun:malloc
|
||||
fun:_PyMem_RawRealloc
|
||||
fun:PyMem_Realloc
|
||||
...
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ def test_unknown_version() -> None:
|
|||
],
|
||||
)
|
||||
def test_old_version(deprecated: str, plural: bool, expected: str) -> None:
|
||||
expected = r""
|
||||
with pytest.raises(RuntimeError, match=expected):
|
||||
_deprecate.deprecate(deprecated, 1, plural=plural)
|
||||
|
||||
|
|
|
@ -133,30 +133,30 @@ class TestFileJpeg:
|
|||
f = "Tests/images/pil_sample_cmyk.jpg"
|
||||
with Image.open(f) as im:
|
||||
# the source image has red pixels in the upper left corner.
|
||||
value = im.getpixel((0, 0))
|
||||
assert isinstance(value, tuple)
|
||||
c, m, y, k = (x / 255.0 for x in value)
|
||||
cmyk = im.getpixel((0, 0))
|
||||
assert isinstance(cmyk, tuple)
|
||||
c, m, y, k = (x / 255.0 for x in cmyk)
|
||||
assert c == 0.0
|
||||
assert m > 0.8
|
||||
assert y > 0.8
|
||||
assert k == 0.0
|
||||
# the opposite corner is black
|
||||
value = im.getpixel((im.size[0] - 1, im.size[1] - 1))
|
||||
assert isinstance(value, tuple)
|
||||
c, m, y, k = (x / 255.0 for x in value)
|
||||
cmyk = im.getpixel((im.size[0] - 1, im.size[1] - 1))
|
||||
assert isinstance(cmyk, tuple)
|
||||
k = cmyk[3] / 255.0
|
||||
assert k > 0.9
|
||||
# roundtrip, and check again
|
||||
im = self.roundtrip(im)
|
||||
value = im.getpixel((0, 0))
|
||||
assert isinstance(value, tuple)
|
||||
c, m, y, k = (x / 255.0 for x in value)
|
||||
cmyk = im.getpixel((0, 0))
|
||||
assert isinstance(cmyk, tuple)
|
||||
c, m, y, k = (x / 255.0 for x in cmyk)
|
||||
assert c == 0.0
|
||||
assert m > 0.8
|
||||
assert y > 0.8
|
||||
assert k == 0.0
|
||||
value = im.getpixel((im.size[0] - 1, im.size[1] - 1))
|
||||
assert isinstance(value, tuple)
|
||||
c, m, y, k = (x / 255.0 for x in value)
|
||||
cmyk = im.getpixel((im.size[0] - 1, im.size[1] - 1))
|
||||
assert isinstance(cmyk, tuple)
|
||||
k = cmyk[3] / 255.0
|
||||
assert k > 0.9
|
||||
|
||||
def test_rgb(self) -> None:
|
||||
|
|
11
depends/docker-test-valgrind-memory.sh
Executable file
11
depends/docker-test-valgrind-memory.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
## Run this as the test script in the Docker valgrind image.
|
||||
## Note -- can be included directly into the Docker image,
|
||||
## but requires the current python.supp.
|
||||
|
||||
source /vpy3/bin/activate
|
||||
cd /Pillow
|
||||
make clean
|
||||
make install
|
||||
make valgrind-leak
|
|
@ -194,9 +194,9 @@ Many of Pillow's features require external libraries:
|
|||
|
||||
pacman -S \
|
||||
mingw-w64-x86_64-gcc \
|
||||
mingw-w64-x86_64-python3 \
|
||||
mingw-w64-x86_64-python3-pip \
|
||||
mingw-w64-x86_64-python3-setuptools
|
||||
mingw-w64-x86_64-python \
|
||||
mingw-w64-x86_64-python-pip \
|
||||
mingw-w64-x86_64-python-setuptools
|
||||
|
||||
Prerequisites are installed on **MSYS2 MinGW 64-bit** with::
|
||||
|
||||
|
|
|
@ -42,15 +42,17 @@ These platforms are built and tested for every change.
|
|||
| macOS 14 Sonoma | 3.10, 3.11, 3.12, 3.13, | arm64 |
|
||||
| | PyPy3 | |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 22.04 LTS (Jammy) | 3.9, 3.10, 3.11, | x86-64 |
|
||||
| Ubuntu Linux 22.04 LTS (Jammy) | 3.10 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 24.04 LTS (Noble) | 3.9, 3.10, 3.11, | x86-64 |
|
||||
| | 3.12, 3.13, PyPy3 | |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.12 | arm64v8, ppc64le, |
|
||||
| | | s390x |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 24.04 LTS (Noble) | 3.12 | x86-64, arm64v8, |
|
||||
| | | ppc64le, s390x |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Windows Server 2019 | 3.9 | x86 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Windows Server 2022 | 3.10, 3.11, 3.12, 3.13, | x86-64 |
|
||||
| Windows Server 2022 | 3.9 | x86 |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.10, 3.11, 3.12, 3.13, | x86-64 |
|
||||
| | PyPy3 | |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.12 (MinGW) | x86-64 |
|
||||
|
|
|
@ -70,6 +70,7 @@ optional-dependencies.tests = [
|
|||
"pytest",
|
||||
"pytest-cov",
|
||||
"pytest-timeout",
|
||||
"pytest-xdist",
|
||||
"trove-classifiers>=2024.10.12",
|
||||
]
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
return (color, color, color)
|
||||
|
||||
self.dispose = None
|
||||
self.dispose_extent = frame_dispose_extent
|
||||
self.dispose_extent: tuple[int, int, int, int] | None = frame_dispose_extent
|
||||
if self.dispose_extent and self.disposal_method >= 2:
|
||||
try:
|
||||
if self.disposal_method == 2:
|
||||
|
|
|
@ -797,7 +797,9 @@ class Image:
|
|||
e = _getencoder(self.mode, encoder_name, encoder_args)
|
||||
e.setimage(self.im)
|
||||
|
||||
bufsize = max(65536, self.size[0] * 4) # see RawEncode.c
|
||||
from . import ImageFile
|
||||
|
||||
bufsize = max(ImageFile.MAXBLOCK, self.size[0] * 4) # see RawEncode.c
|
||||
|
||||
output = []
|
||||
while True:
|
||||
|
|
|
@ -33,11 +33,7 @@ class BitStream:
|
|||
|
||||
def peek(self, bits: int) -> int:
|
||||
while self.bits < bits:
|
||||
c = self.next()
|
||||
if c < 0:
|
||||
self.bits = 0
|
||||
continue
|
||||
self.bitbuffer = (self.bitbuffer << 8) + c
|
||||
self.bitbuffer = (self.bitbuffer << 8) + self.next()
|
||||
self.bits += 8
|
||||
return self.bitbuffer >> (self.bits - bits) & (1 << bits) - 1
|
||||
|
||||
|
|
|
@ -308,9 +308,9 @@ _new_arrow(PyObject *self, PyObject *args) {
|
|||
}
|
||||
|
||||
// ImagingBorrowArrow is responsible for retaining the array_capsule
|
||||
ret =
|
||||
PyImagingNew(ImagingNewArrow(mode, xsize, ysize, schema_capsule, array_capsule)
|
||||
);
|
||||
ret = PyImagingNew(
|
||||
ImagingNewArrow(mode, xsize, ysize, schema_capsule, array_capsule)
|
||||
);
|
||||
if (!ret) {
|
||||
return ImagingError_ValueError("Invalid Arrow array mode or size mismatch");
|
||||
}
|
||||
|
@ -1665,7 +1665,8 @@ _putdata(ImagingObject *self, PyObject *args) {
|
|||
int bigendian = 0;
|
||||
if (image->type == IMAGING_TYPE_SPECIAL) {
|
||||
// I;16*
|
||||
if (strcmp(image->mode, "I;16B") == 0
|
||||
if (
|
||||
strcmp(image->mode, "I;16B") == 0
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|| strcmp(image->mode, "I;16N") == 0
|
||||
#endif
|
||||
|
@ -2226,6 +2227,7 @@ _unsharp_mask(ImagingObject *self, PyObject *args) {
|
|||
}
|
||||
|
||||
if (!ImagingUnsharpMask(imOut, imIn, radius, percent, threshold)) {
|
||||
ImagingDelete(imOut);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -275,6 +275,7 @@ text_layout_raqm(
|
|||
if (!text || !size) {
|
||||
/* return 0 and clean up, no glyphs==no size,
|
||||
and raqm fails with empty strings */
|
||||
PyMem_Free(text);
|
||||
goto failed;
|
||||
}
|
||||
set_text = raqm_set_text(rq, text, size);
|
||||
|
@ -425,6 +426,7 @@ text_layout_fallback(
|
|||
"setting text direction, language or font features is not supported "
|
||||
"without libraqm"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PyUnicode_Check(string)) {
|
||||
|
|
|
@ -641,6 +641,10 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) {
|
|||
ImagingSectionLeave(&cookie);
|
||||
|
||||
WebPPictureFree(&pic);
|
||||
|
||||
output = writer.mem;
|
||||
ret_size = writer.size;
|
||||
|
||||
if (!ok) {
|
||||
int error_code = (&pic)->error_code;
|
||||
char message[50] = "";
|
||||
|
@ -652,10 +656,9 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) {
|
|||
);
|
||||
}
|
||||
PyErr_Format(PyExc_ValueError, "encoding error %d%s", error_code, message);
|
||||
free(output);
|
||||
return NULL;
|
||||
}
|
||||
output = writer.mem;
|
||||
ret_size = writer.size;
|
||||
|
||||
{
|
||||
/* I want to truncate the *_size items that get passed into WebP
|
||||
|
|
|
@ -327,11 +327,11 @@ PyImaging_GrabScreenWin32(PyObject *self, PyObject *args) {
|
|||
// added in Windows 10 (1607)
|
||||
// loaded dynamically to avoid link errors
|
||||
user32 = LoadLibraryA("User32.dll");
|
||||
SetThreadDpiAwarenessContext_function = (Func_SetThreadDpiAwarenessContext
|
||||
)GetProcAddress(user32, "SetThreadDpiAwarenessContext");
|
||||
SetThreadDpiAwarenessContext_function = (Func_SetThreadDpiAwarenessContext)
|
||||
GetProcAddress(user32, "SetThreadDpiAwarenessContext");
|
||||
if (SetThreadDpiAwarenessContext_function != NULL) {
|
||||
GetWindowDpiAwarenessContext_function = (Func_GetWindowDpiAwarenessContext
|
||||
)GetProcAddress(user32, "GetWindowDpiAwarenessContext");
|
||||
GetWindowDpiAwarenessContext_function = (Func_GetWindowDpiAwarenessContext)
|
||||
GetProcAddress(user32, "GetWindowDpiAwarenessContext");
|
||||
if (screens == -1 && GetWindowDpiAwarenessContext_function != NULL) {
|
||||
dpiAwareness = GetWindowDpiAwarenessContext_function(wnd);
|
||||
}
|
||||
|
|
|
@ -703,6 +703,8 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
encoder->cleanup = ImagingLibTiffEncodeCleanup;
|
||||
|
||||
num_core_tags = sizeof(core_tags) / sizeof(int);
|
||||
for (pos = 0; pos < tags_size; pos++) {
|
||||
item = PyList_GetItemRef(tags, pos);
|
||||
|
|
|
@ -36,7 +36,10 @@ ReleaseExportedSchema(struct ArrowSchema *array) {
|
|||
child->release(child);
|
||||
child->release = NULL;
|
||||
}
|
||||
// UNDONE -- should I be releasing the children?
|
||||
free(array->children[i]);
|
||||
}
|
||||
if (array->children) {
|
||||
free(array->children);
|
||||
}
|
||||
|
||||
// Release dictionary
|
||||
|
@ -117,6 +120,7 @@ export_imaging_schema(Imaging im, struct ArrowSchema *schema) {
|
|||
retval = export_named_type(schema->children[0], im->arrow_band_format, "pixel");
|
||||
if (retval != 0) {
|
||||
free(schema->children[0]);
|
||||
free(schema->children);
|
||||
schema->release(schema);
|
||||
return retval;
|
||||
}
|
||||
|
@ -127,9 +131,7 @@ static void
|
|||
release_const_array(struct ArrowArray *array) {
|
||||
Imaging im = (Imaging)array->private_data;
|
||||
|
||||
if (array->n_children == 0) {
|
||||
ImagingDelete(im);
|
||||
}
|
||||
ImagingDelete(im);
|
||||
|
||||
// Free the buffers and the buffers array
|
||||
if (array->buffers) {
|
||||
|
|
|
@ -118,8 +118,9 @@ ImagingFillRadialGradient(const char *mode) {
|
|||
|
||||
for (y = 0; y < 256; y++) {
|
||||
for (x = 0; x < 256; x++) {
|
||||
d = (int
|
||||
)sqrt((double)((x - 128) * (x - 128) + (y - 128) * (y - 128)) * 2.0);
|
||||
d = (int)sqrt(
|
||||
(double)((x - 128) * (x - 128) + (y - 128) * (y - 128)) * 2.0
|
||||
);
|
||||
if (d >= 255) {
|
||||
d = 255;
|
||||
}
|
||||
|
|
|
@ -155,7 +155,8 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
|||
} else {
|
||||
int bigendian = 0;
|
||||
if (im->type == IMAGING_TYPE_SPECIAL) {
|
||||
if (strcmp(im->mode, "I;16B") == 0
|
||||
if (
|
||||
strcmp(im->mode, "I;16B") == 0
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|| strcmp(im->mode, "I;16N") == 0
|
||||
#endif
|
||||
|
@ -308,7 +309,8 @@ ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) {
|
|||
} else {
|
||||
int bigendian = 0;
|
||||
if (im->type == IMAGING_TYPE_SPECIAL) {
|
||||
if (strcmp(im->mode, "I;16B") == 0
|
||||
if (
|
||||
strcmp(im->mode, "I;16B") == 0
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|| strcmp(im->mode, "I;16N") == 0
|
||||
#endif
|
||||
|
|
|
@ -207,8 +207,8 @@ j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) {
|
|||
|
||||
if (params->cp_cinema == OPJ_CINEMA4K_24) {
|
||||
float max_rate =
|
||||
((float)(components * im->xsize * im->ysize * 8) / (CINEMA_24_CS_LENGTH * 8)
|
||||
);
|
||||
((float)(components * im->xsize * im->ysize * 8) /
|
||||
(CINEMA_24_CS_LENGTH * 8));
|
||||
|
||||
params->POC[0].tile = 1;
|
||||
params->POC[0].resno0 = 0;
|
||||
|
@ -243,8 +243,8 @@ j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) {
|
|||
params->max_comp_size = COMP_24_CS_MAX_LENGTH;
|
||||
} else {
|
||||
float max_rate =
|
||||
((float)(components * im->xsize * im->ysize * 8) / (CINEMA_48_CS_LENGTH * 8)
|
||||
);
|
||||
((float)(components * im->xsize * im->ysize * 8) /
|
||||
(CINEMA_48_CS_LENGTH * 8));
|
||||
|
||||
for (n = 0; n < params->tcp_numlayers; ++n) {
|
||||
rate = 0;
|
||||
|
|
|
@ -131,6 +131,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
|
|||
break;
|
||||
default:
|
||||
state->errcode = IMAGING_CODEC_CONFIG;
|
||||
jpeg_destroy_compress(&context->cinfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -161,6 +162,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
|
|||
/* Would subsample the green and blue
|
||||
channels, which doesn't make sense */
|
||||
state->errcode = IMAGING_CODEC_CONFIG;
|
||||
jpeg_destroy_compress(&context->cinfo);
|
||||
return -1;
|
||||
}
|
||||
jpeg_set_colorspace(&context->cinfo, JCS_RGB);
|
||||
|
|
|
@ -197,8 +197,9 @@ ImagingPoint(Imaging imIn, const char *mode, const void *table) {
|
|||
return imOut;
|
||||
|
||||
mode_mismatch:
|
||||
return (Imaging
|
||||
)ImagingError_ValueError("point operation not supported for this mode");
|
||||
return (Imaging)ImagingError_ValueError(
|
||||
"point operation not supported for this mode"
|
||||
);
|
||||
}
|
||||
|
||||
Imaging
|
||||
|
|
|
@ -470,7 +470,8 @@ ImagingResampleHorizontal_16bpc(
|
|||
double *k;
|
||||
|
||||
int bigendian = 0;
|
||||
if (strcmp(imIn->mode, "I;16N") == 0
|
||||
if (
|
||||
strcmp(imIn->mode, "I;16N") == 0
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|| strcmp(imIn->mode, "I;16B") == 0
|
||||
#endif
|
||||
|
@ -509,7 +510,8 @@ ImagingResampleVertical_16bpc(
|
|||
double *k;
|
||||
|
||||
int bigendian = 0;
|
||||
if (strcmp(imIn->mode, "I;16N") == 0
|
||||
if (
|
||||
strcmp(imIn->mode, "I;16N") == 0
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|| strcmp(imIn->mode, "I;16B") == 0
|
||||
#endif
|
||||
|
|
|
@ -602,8 +602,9 @@ ImagingBorrowArrow(
|
|||
}
|
||||
|
||||
if (!borrowed_buffer) {
|
||||
return (Imaging
|
||||
)ImagingError_ValueError("Arrow Array, exactly 2 buffers required");
|
||||
return (Imaging)ImagingError_ValueError(
|
||||
"Arrow Array, exactly 2 buffers required"
|
||||
);
|
||||
}
|
||||
|
||||
for (y = i = 0; y < im->ysize; y++) {
|
||||
|
|
|
@ -557,7 +557,8 @@ _decodeStrip(
|
|||
(tdata_t)state->buffer,
|
||||
strip_size
|
||||
) == -1) {
|
||||
TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))
|
||||
TRACE(
|
||||
("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))
|
||||
);
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
return -1;
|
||||
|
@ -929,6 +930,27 @@ ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...) {
|
|||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
ImagingLibTiffEncodeCleanup(ImagingCodecState state) {
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
TIFF *tiff = clientstate->tiff;
|
||||
|
||||
if (!tiff) {
|
||||
return 0;
|
||||
}
|
||||
// TIFFClose in libtiff calls tif_closeproc and TIFFCleanup
|
||||
if (clientstate->fp) {
|
||||
// Python will manage the closing of the file rather than libtiff
|
||||
// So only call TIFFCleanup
|
||||
TIFFCleanup(tiff);
|
||||
} else {
|
||||
// When tif_closeproc refers to our custom _tiffCloseProc though,
|
||||
// that is fine, as it does not close the file
|
||||
TIFFClose(tiff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes) {
|
||||
/* One shot encoder. Encode everything to the tiff in the clientstate.
|
||||
|
@ -1010,16 +1032,6 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt
|
|||
TRACE(("Encode Error, row %d\n", state->y));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
|
||||
// TIFFClose in libtiff calls tif_closeproc and TIFFCleanup
|
||||
if (clientstate->fp) {
|
||||
// Python will manage the closing of the file rather than libtiff
|
||||
// So only call TIFFCleanup
|
||||
TIFFCleanup(tiff);
|
||||
} else {
|
||||
// When tif_closeproc refers to our custom _tiffCloseProc though,
|
||||
// that is fine, as it does not close the file
|
||||
TIFFClose(tiff);
|
||||
}
|
||||
if (!clientstate->fp) {
|
||||
free(clientstate->data);
|
||||
}
|
||||
|
@ -1036,22 +1048,11 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt
|
|||
TRACE(("Error flushing the tiff"));
|
||||
// likely reason is memory.
|
||||
state->errcode = IMAGING_CODEC_MEMORY;
|
||||
if (clientstate->fp) {
|
||||
TIFFCleanup(tiff);
|
||||
} else {
|
||||
TIFFClose(tiff);
|
||||
}
|
||||
if (!clientstate->fp) {
|
||||
free(clientstate->data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
TRACE(("Closing \n"));
|
||||
if (clientstate->fp) {
|
||||
TIFFCleanup(tiff);
|
||||
} else {
|
||||
TIFFClose(tiff);
|
||||
}
|
||||
// reset the clientstate metadata to use it to read out the buffer.
|
||||
clientstate->loc = 0;
|
||||
clientstate->size = clientstate->eof; // redundant?
|
||||
|
|
|
@ -40,6 +40,8 @@ ImagingLibTiffInit(ImagingCodecState state, int fp, uint32_t offset);
|
|||
extern int
|
||||
ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
|
||||
extern int
|
||||
ImagingLibTiffEncodeCleanup(ImagingCodecState state);
|
||||
extern int
|
||||
ImagingLibTiffMergeFieldInfo(
|
||||
ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length
|
||||
);
|
||||
|
|
|
@ -11,8 +11,7 @@ For more extensive info, see the [Windows build instructions](build.rst).
|
|||
* Requires Microsoft Visual Studio 2017 or newer with C++ component.
|
||||
* Requires NASM for libjpeg-turbo, a required dependency when using this script.
|
||||
* Requires CMake 3.15 or newer (available as Visual Studio component).
|
||||
* Tested on Windows Server 2022 with Visual Studio 2022 Enterprise and Windows Server
|
||||
2019 with Visual Studio 2019 Enterprise (GitHub Actions).
|
||||
* Tested on Windows Server 2022 with Visual Studio 2022 Enterprise (GitHub Actions).
|
||||
|
||||
Here's an example script to build on Windows:
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user