diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 5e7add81c72..45849194ed2 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -1,5 +1,6 @@ from __future__ import annotations +import tempfile from io import BytesIO from typing import Any @@ -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 @@ -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") diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index c0ca038579d..5b4fc4be4aa 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -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 diff --git a/src/encode.c b/src/encode.c index 8129ddc2f08..fd035827cf8 100644 --- a/src/encode.c +++ b/src/encode.c @@ -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) */ @@ -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!!! */ @@ -155,7 +155,7 @@ _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??? @@ -163,9 +163,9 @@ _encode_to_pyfd(ImagingEncoderObject *encoder, PyObject *args) { 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; } @@ -173,7 +173,7 @@ _encode_to_pyfd(ImagingEncoderObject *encoder, PyObject *args) { static PyObject * _encode_to_file(ImagingEncoderObject *encoder, PyObject *args) { UINT8 *buf; - int status; + int bytes_consumed; ImagingSectionCookie cookie; /* Encode to a file handle */ @@ -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);