Skip to content

Commit 0f28129

Browse files
committed
Deprecate P;2L and P;4L in frombytes()
1 parent 1cf685c commit 0f28129

8 files changed

Lines changed: 77 additions & 42 deletions

File tree

Tests/test_file_pcx.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,5 +213,6 @@ def test_break_padding(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
213213
)
214214
def test_truncated(data_len: int, rawmode: str) -> None:
215215
data = b"\x00" * data_len
216-
with pytest.raises(ValueError, match="not enough image data"):
217-
Image.frombuffer("P", (9, 1), data, "raw", rawmode, 0, 1)
216+
with pytest.warns(DeprecationWarning, match=rawmode):
217+
with pytest.raises(ValueError, match="not enough image data"):
218+
Image.frombuffer("P", (9, 1), data, "raw", rawmode, 0, 1)

docs/deprecations.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ Image getdata()
3030
identical, except that it returns a tuple of pixel values, instead of an internal
3131
Pillow data type.
3232

33+
Reading "P;2L" and "P;4L" raw mode data directly
34+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35+
36+
.. deprecated:: 13.0.0
37+
38+
Using :py:func:`.Image.frombuffer()`, :py:func:`.Image.frombytes()` or
39+
:py:meth:`~PIL.Image.Image.frombytes()` to read "P;2L" or "P;4L" raw mode data has been
40+
deprecated.
41+
3342
Removed features
3443
----------------
3544

docs/releasenotes/13.0.0.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ ImageCms.ImageCmsProfile.product_name and .product_info
6363
Deprecations
6464
============
6565

66-
TODO
67-
^^^^
66+
Reading "P;2L" and "P;4L" raw mode data directly
67+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6868

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

7173
API changes
7274
===========

src/PIL/Image.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -943,11 +943,14 @@ def frombytes(
943943
# may pass tuple instead of argument list
944944
decoder_args = decoder_args[0]
945945

946-
if decoder_args and decoder_args[0] in {"P;2L", "P;4L"}:
947-
multiple = 4 if decoder_args[0] == "P;2L" else 8
948-
if len(data) % multiple:
949-
msg = "not enough image data"
950-
raise ValueError(msg)
946+
if decoder_args:
947+
raw_mode = decoder_args[0]
948+
if raw_mode in {"P;2L", "P;4L"}:
949+
deprecate(raw_mode, 14)
950+
multiple = 4 if raw_mode == "P;2L" else 8
951+
if len(data) % multiple:
952+
msg = "not enough image data"
953+
raise ValueError(msg)
951954

952955
# default format
953956
if decoder_name == "raw" and decoder_args == ():

src/decode.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "libImaging/Bit.h"
3838
#include "libImaging/Bcn.h"
3939
#include "libImaging/Gif.h"
40+
#include "libImaging/PcxDecode.h"
4041
#include "libImaging/Raw.h"
4142
#include "libImaging/Sgi.h"
4243

@@ -622,7 +623,13 @@ PyImaging_PcxDecoderNew(PyObject *self, PyObject *args) {
622623
return NULL;
623624
}
624625

625-
if (get_unpacker(decoder, mode, rawmode) < 0) {
626+
if (strcmp(rawmode_name, "P;2L") == 0) {
627+
decoder->state.shuffle = unpackP2L;
628+
decoder->state.bits = 2;
629+
} else if (strcmp(rawmode_name, "P;4L") == 0) {
630+
decoder->state.shuffle = unpackP4L;
631+
decoder->state.bits = 4;
632+
} else if (get_unpacker(decoder, mode, rawmode) < 0) {
626633
return NULL;
627634
}
628635

src/libImaging/PcxDecode.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,37 @@
1515

1616
#include "Imaging.h"
1717

18+
void
19+
unpackP2L(UINT8 *out, const UINT8 *in, int pixels) {
20+
int i, j, m, s;
21+
/* bit layers */
22+
m = 128;
23+
s = (pixels + 7) / 8;
24+
for (i = j = 0; i < pixels; i++) {
25+
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0);
26+
if ((m >>= 1) == 0) {
27+
m = 128;
28+
j++;
29+
}
30+
}
31+
}
32+
33+
void
34+
unpackP4L(UINT8 *out, const UINT8 *in, int pixels) {
35+
int i, j, m, s;
36+
/* bit layers (trust the optimizer ;-) */
37+
m = 128;
38+
s = (pixels + 7) / 8;
39+
for (i = j = 0; i < pixels; i++) {
40+
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0) +
41+
((in[j + 2 * s] & m) ? 4 : 0) + ((in[j + 3 * s] & m) ? 8 : 0);
42+
if ((m >>= 1) == 0) {
43+
m = 128;
44+
j++;
45+
}
46+
}
47+
}
48+
1849
int
1950
ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
2051
UINT8 n;

src/libImaging/PcxDecode.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* The Python Imaging Library.
3+
* $Id$
4+
*
5+
* Declarations for PCX decoder.
6+
*/
7+
8+
extern void
9+
unpackP2L(UINT8 *out, const UINT8 *in, int pixels);
10+
11+
extern void
12+
unpackP4L(UINT8 *out, const UINT8 *in, int pixels);

src/libImaging/Unpack.c

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "Imaging.h"
3434
#include "Convert.h"
35+
#include "PcxDecode.h"
3536

3637
#define R 0
3738
#define G 1
@@ -548,37 +549,6 @@ unpackP4(UINT8 *out, const UINT8 *in, int pixels) {
548549
}
549550
}
550551

551-
static void
552-
unpackP2L(UINT8 *out, const UINT8 *in, int pixels) {
553-
int i, j, m, s;
554-
/* bit layers */
555-
m = 128;
556-
s = (pixels + 7) / 8;
557-
for (i = j = 0; i < pixels; i++) {
558-
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0);
559-
if ((m >>= 1) == 0) {
560-
m = 128;
561-
j++;
562-
}
563-
}
564-
}
565-
566-
static void
567-
unpackP4L(UINT8 *out, const UINT8 *in, int pixels) {
568-
int i, j, m, s;
569-
/* bit layers (trust the optimizer ;-) */
570-
m = 128;
571-
s = (pixels + 7) / 8;
572-
for (i = j = 0; i < pixels; i++) {
573-
out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0) +
574-
((in[j + 2 * s] & m) ? 4 : 0) + ((in[j + 3 * s] & m) ? 8 : 0);
575-
if ((m >>= 1) == 0) {
576-
m = 128;
577-
j++;
578-
}
579-
}
580-
}
581-
582552
/* Unpack to "RGB" image */
583553

584554
void

0 commit comments

Comments
 (0)