Skip to content

Commit 9d3c8d5

Browse files
authored
Merge pull request #7870 from radarhere/j2k_pclr
2 parents 3bbc865 + f128d47 commit 9d3c8d5

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

Tests/test_file_jpeg2k.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,16 @@ def test_subsampling_decode(name: str) -> None:
364364
assert_image_similar(im, expected, epsilon)
365365

366366

367+
@pytest.mark.skipif(
368+
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
369+
)
370+
def test_pclr() -> None:
371+
with Image.open(f"{EXTRA_DIR}/issue104_jpxstream.jp2") as im:
372+
assert im.mode == "P"
373+
assert len(im.palette.colors) == 256
374+
assert im.palette.colors[(255, 255, 255)] == 0
375+
376+
367377
def test_comment() -> None:
368378
with Image.open("Tests/images/comment.jp2") as im:
369379
assert im.info["comment"] == b"Created by OpenJPEG version 2.5.0"

src/PIL/Jpeg2KImagePlugin.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import os
2020
import struct
2121

22-
from . import Image, ImageFile, _binary
22+
from . import Image, ImageFile, ImagePalette, _binary
2323

2424

2525
class BoxReader:
@@ -162,6 +162,7 @@ def _parse_jp2_header(fp):
162162
bpc = None
163163
nc = None
164164
dpi = None # 2-tuple of DPI info, or None
165+
palette = None
165166

166167
while header.has_next_box():
167168
tbox = header.next_box_type()
@@ -179,6 +180,14 @@ def _parse_jp2_header(fp):
179180
mode = "RGB"
180181
elif nc == 4:
181182
mode = "RGBA"
183+
elif tbox == b"pclr" and mode in ("L", "LA"):
184+
ne, npc = header.read_fields(">HB")
185+
bitdepths = header.read_fields(">" + ("B" * npc))
186+
if max(bitdepths) <= 8:
187+
palette = ImagePalette.ImagePalette()
188+
for i in range(ne):
189+
palette.getcolor(header.read_fields(">" + ("B" * npc)))
190+
mode = "P" if mode == "L" else "PA"
182191
elif tbox == b"res ":
183192
res = header.read_boxes()
184193
while res.has_next_box():
@@ -195,7 +204,7 @@ def _parse_jp2_header(fp):
195204
msg = "Malformed JP2 header"
196205
raise SyntaxError(msg)
197206

198-
return size, mode, mimetype, dpi
207+
return size, mode, mimetype, dpi, palette
199208

200209

201210
##
@@ -217,7 +226,7 @@ def _open(self):
217226
if sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a":
218227
self.codec = "jp2"
219228
header = _parse_jp2_header(self.fp)
220-
self._size, self._mode, self.custom_mimetype, dpi = header
229+
self._size, self._mode, self.custom_mimetype, dpi, self.palette = header
221230
if dpi is not None:
222231
self.info["dpi"] = dpi
223232
if self.fp.read(12).endswith(b"jp2c\xff\x4f\xff\x51"):

src/libImaging/Jpeg2KDecode.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,8 @@ j2ku_sycca_rgba(
615615

616616
static const struct j2k_decode_unpacker j2k_unpackers[] = {
617617
{"L", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_l},
618+
{"P", OPJ_CLRSPC_SRGB, 1, 0, j2ku_gray_l},
619+
{"PA", OPJ_CLRSPC_SRGB, 2, 0, j2ku_graya_la},
618620
{"I;16", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_i},
619621
{"I;16B", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_i},
620622
{"LA", OPJ_CLRSPC_GRAY, 2, 0, j2ku_graya_la},

0 commit comments

Comments
 (0)