Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Tests/test_imagefile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import tempfile
from io import BytesIO
from typing import Any

Expand Down Expand Up @@ -275,7 +276,7 @@ def __init__(self, mode: str, *args: Any) -> None:
super().__init__(mode, *args)

def encode(self, bufsize: int) -> tuple[int, int, bytes]:
return 1, 1, b""
return 1, 1, b"a"

def cleanup(self) -> None:
self.cleanup_called = True
Expand Down Expand Up @@ -437,6 +438,13 @@ def test_encode(self) -> None:
with pytest.raises(NotImplementedError):
encoder.encode_to_file(0, 0)

mock_encoder = MockPyEncoder("")
with tempfile.TemporaryFile() as fp:
mock_encoder.encode_to_file(fp.fileno(), 1)

fp.seek(0)
assert fp.read() == b"a"

def test_zero_height(self) -> None:
with pytest.raises(UnidentifiedImageError):
Image.open("Tests/images/zero_height.j2k")
6 changes: 3 additions & 3 deletions src/PIL/ImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ def encode_to_file(self, fh: int, bufsize: int) -> int:
"""
errcode = 0
while errcode == 0:
status, errcode, buf = self.encode(bufsize)
if status > 0:
os.write(fh, buf[status:])
bytes_consumed, errcode, buf = self.encode(bufsize)
if bytes_consumed > 0:
os.write(fh, buf[:bytes_consumed])
return errcode
22 changes: 11 additions & 11 deletions src/encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ static PyObject *
_encode(ImagingEncoderObject *encoder, PyObject *args) {
PyObject *buf;
PyObject *result;
int status;
int bytes_consumed;

/* Encode to a Python string (allocated by this method) */

Expand All @@ -136,16 +136,16 @@ _encode(ImagingEncoderObject *encoder, PyObject *args) {
return NULL;
}

status = encoder->encode(
bytes_consumed = encoder->encode(
encoder->im, &encoder->state, (UINT8 *)PyBytes_AsString(buf), bufsize
);

/* adjust string length to avoid slicing in encoder */
if (_PyBytes_Resize(&buf, (status > 0) ? status : 0) < 0) {
if (_PyBytes_Resize(&buf, (bytes_consumed > 0) ? bytes_consumed : 0) < 0) {
return NULL;
}

result = Py_BuildValue("iiO", status, encoder->state.errcode, buf);
result = Py_BuildValue("iiO", bytes_consumed, encoder->state.errcode, buf);

Py_DECREF(buf); /* must release buffer!!! */

Expand All @@ -155,25 +155,25 @@ _encode(ImagingEncoderObject *encoder, PyObject *args) {
static PyObject *
_encode_to_pyfd(ImagingEncoderObject *encoder, PyObject *args) {
PyObject *result;
int status;
int bytes_consumed;

if (!encoder->pushes_fd) {
// UNDONE, appropriate errcode???
result = Py_BuildValue("ii", 0, IMAGING_CODEC_CONFIG);
return result;
}

status = encoder->encode(encoder->im, &encoder->state, (UINT8 *)NULL, 0);
bytes_consumed = encoder->encode(encoder->im, &encoder->state, (UINT8 *)NULL, 0);

result = Py_BuildValue("ii", status, encoder->state.errcode);
result = Py_BuildValue("ii", bytes_consumed, encoder->state.errcode);

return result;
}

static PyObject *
_encode_to_file(ImagingEncoderObject *encoder, PyObject *args) {
UINT8 *buf;
int status;
int bytes_consumed;
ImagingSectionCookie cookie;

/* Encode to a file handle */
Expand All @@ -198,10 +198,10 @@ _encode_to_file(ImagingEncoderObject *encoder, PyObject *args) {
/* This replaces the inner loop in the ImageFile _save
function. */

status = encoder->encode(encoder->im, &encoder->state, buf, bufsize);
bytes_consumed = encoder->encode(encoder->im, &encoder->state, buf, bufsize);

if (status > 0) {
if (write(fh, buf, status) < 0) {
if (bytes_consumed > 0) {
if (write(fh, buf, bytes_consumed) < 0) {
ImagingSectionLeave(&cookie);
free(buf);
return PyErr_SetFromErrno(PyExc_OSError);
Expand Down
Loading