Skip to content
Open
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
5 changes: 3 additions & 2 deletions Tests/test_file_pcx.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,6 @@ def test_break_padding(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
)
def test_truncated(data_len: int, rawmode: str) -> None:
data = b"\x00" * data_len
with pytest.raises(ValueError, match="not enough image data"):
Image.frombuffer("P", (9, 1), data, "raw", rawmode, 0, 1)
with pytest.warns(DeprecationWarning, match=rawmode):
with pytest.raises(ValueError, match="not enough image data"):
Image.frombuffer("P", (9, 1), data, "raw", rawmode, 0, 1)
9 changes: 9 additions & 0 deletions docs/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ Image getdata()
identical, except that it returns a tuple of pixel values, instead of an internal
Pillow data type.

Reading "P;2L" and "P;4L" raw mode data directly
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. deprecated:: 12.3.0

Using :py:func:`.Image.frombuffer()`, :py:func:`.Image.frombytes()` or
:py:meth:`~PIL.Image.Image.frombytes()` to read "P;2L" or "P;4L" raw mode data has been
deprecated.

Removed features
----------------

Expand Down
8 changes: 5 additions & 3 deletions docs/releasenotes/12.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ TODO
Deprecations
============

TODO
^^^^
Reading "P;2L" and "P;4L" raw mode data directly
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TODO
Using :py:func:`.Image.frombuffer()`, :py:func:`.Image.frombytes()` or
:py:meth:`~PIL.Image.Image.frombytes()` to read "P;2L" or "P;4L" raw mode data has been
deprecated.

API changes
===========
Expand Down
13 changes: 8 additions & 5 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,11 +943,14 @@ def frombytes(
# may pass tuple instead of argument list
decoder_args = decoder_args[0]

if decoder_args and decoder_args[0] in {"P;2L", "P;4L"}:
multiple = 4 if decoder_args[0] == "P;2L" else 8
if len(data) % multiple:
msg = "not enough image data"
raise ValueError(msg)
if decoder_args:
raw_mode = decoder_args[0]
if raw_mode in {"P;2L", "P;4L"}:
deprecate(raw_mode, 14)
multiple = 4 if raw_mode == "P;2L" else 8
if len(data) % multiple:
msg = "not enough image data"
raise ValueError(msg)

# default format
if decoder_name == "raw" and decoder_args == ():
Expand Down
9 changes: 8 additions & 1 deletion src/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "libImaging/Bit.h"
#include "libImaging/Bcn.h"
#include "libImaging/Gif.h"
#include "libImaging/PcxDecode.h"
#include "libImaging/Raw.h"
#include "libImaging/Sgi.h"

Expand Down Expand Up @@ -618,7 +619,13 @@ PyImaging_PcxDecoderNew(PyObject *self, PyObject *args) {
return NULL;
}

if (get_unpacker(decoder, mode, rawmode) < 0) {
if (strcmp(rawmode_name, "P;2L") == 0) {
decoder->state.shuffle = unpackP2L;
decoder->state.bits = 2;
} else if (strcmp(rawmode_name, "P;4L") == 0) {
decoder->state.shuffle = unpackP4L;
decoder->state.bits = 4;
} else if (get_unpacker(decoder, mode, rawmode) < 0) {
return NULL;
}

Expand Down
31 changes: 31 additions & 0 deletions src/libImaging/PcxDecode.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,37 @@

#include "Imaging.h"

void
unpackP2L(UINT8 *out, const UINT8 *in, int pixels) {
int i, j, m, s;
/* bit layers */
m = 128;
s = (pixels + 7) / 8;
for (i = j = 0; i < pixels; i++) {
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0);
if ((m >>= 1) == 0) {
m = 128;
j++;
}
}
}

void
unpackP4L(UINT8 *out, const UINT8 *in, int pixels) {
int i, j, m, s;
/* bit layers (trust the optimizer ;-) */
m = 128;
s = (pixels + 7) / 8;
for (i = j = 0; i < pixels; i++) {
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0) +
((in[j + 2 * s] & m) ? 4 : 0) + ((in[j + 3 * s] & m) ? 8 : 0);
if ((m >>= 1) == 0) {
m = 128;
j++;
}
}
}

int
ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
UINT8 n;
Expand Down
12 changes: 12 additions & 0 deletions src/libImaging/PcxDecode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* The Python Imaging Library.
* $Id$
*
* Declarations for PCX decoder.
*/

extern void
unpackP2L(UINT8 *out, const UINT8 *in, int pixels);

extern void
unpackP4L(UINT8 *out, const UINT8 *in, int pixels);
32 changes: 1 addition & 31 deletions src/libImaging/Unpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include "Imaging.h"
#include "Convert.h"
#include "PcxDecode.h"

#define R 0
#define G 1
Expand Down Expand Up @@ -548,37 +549,6 @@ unpackP4(UINT8 *out, const UINT8 *in, int pixels) {
}
}

static void
unpackP2L(UINT8 *out, const UINT8 *in, int pixels) {
int i, j, m, s;
/* bit layers */
m = 128;
s = (pixels + 7) / 8;
for (i = j = 0; i < pixels; i++) {
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0);
if ((m >>= 1) == 0) {
m = 128;
j++;
}
}
}

static void
unpackP4L(UINT8 *out, const UINT8 *in, int pixels) {
int i, j, m, s;
/* bit layers (trust the optimizer ;-) */
m = 128;
s = (pixels + 7) / 8;
for (i = j = 0; i < pixels; i++) {
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0) +
((in[j + 2 * s] & m) ? 4 : 0) + ((in[j + 3 * s] & m) ? 8 : 0);
if ((m >>= 1) == 0) {
m = 128;
j++;
}
}
}

/* Unpack to "RGB" image */

void
Expand Down
Loading