Skip to content

Commit 82f7e02

Browse files
committed
Added support for 1 mode images
1 parent ffa84e5 commit 82f7e02

File tree

5 files changed

+30
-12
lines changed

5 files changed

+30
-12
lines changed

Tests/images/jxl/hopper_bw_500.jxl

90.3 KB
Binary file not shown.

Tests/test_file_jxl.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66

77
from PIL import Image, JpegXlImagePlugin, features
88

9-
from .helper import assert_image_similar_tofile, skip_unless_feature
9+
from .helper import (
10+
assert_image_equal_tofile,
11+
assert_image_similar_tofile,
12+
skip_unless_feature,
13+
)
1014

1115
try:
1216
from PIL import _jpegxl
@@ -34,12 +38,18 @@ def test_version(self) -> None:
3438
assert version is not None
3539
assert re.search(r"\d+\.\d+\.\d+$", version)
3640

37-
def test_read_rgb(self) -> None:
38-
"""
39-
Can we read an RGB mode JPEG XL file without error?
40-
Does it have the bits we expect?
41-
"""
41+
def test_read_1(self) -> None:
42+
with Image.open("Tests/images/jxl/hopper_bw_500.jxl") as im:
43+
assert im.mode == "1"
44+
assert im.size == (500, 500)
45+
assert im.format == "JPEG XL"
46+
im.getdata()
47+
48+
# generated with:
49+
# cjxl hopper_bw_500.jxl hopper_bw_500.jxl
50+
assert_image_equal_tofile(im, "Tests/images/hopper_bw_500.png")
4251

52+
def test_read_rgb(self) -> None:
4353
with Image.open("Tests/images/hopper.jxl") as im:
4454
assert im.mode == "RGB"
4555
assert im.size == (128, 128)
@@ -63,10 +73,6 @@ def test_read_rgba(self) -> None:
6373
assert_image_similar_tofile(im, "Tests/images/transparent.png", 1)
6474

6575
def test_read_i16(self) -> None:
66-
"""
67-
Can we read 16-bit Grayscale JPEG XL image?
68-
"""
69-
7076
with Image.open("Tests/images/jxl/16bit_subcutaneous.cropped.jxl") as im:
7177
assert im.mode == "I;16"
7278
assert im.size == (128, 64)
@@ -81,6 +87,5 @@ def test_JpegXlDecode_with_invalid_args(self) -> None:
8187
"""
8288
Calling decoder functions with no arguments should result in an error.
8389
"""
84-
8590
with pytest.raises(TypeError):
8691
_jpegxl.JpegXlDecoder()

src/PIL/JpegXlImagePlugin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ def _open(self) -> None:
5555
self.info["exif"] = exif[exif_start_offset + 4 :]
5656
if xmp := self._decoder.get_xmp():
5757
self.info["xmp"] = xmp
58-
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.mode)]
58+
rawmode = "L" if self.mode == "1" else self.mode
59+
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, rawmode)]
5960

6061
@property
6162
def n_frames(self) -> int:

src/_jpegxl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ _jxl_get_pixel_format(JxlPixelFormat *pf, const JxlBasicInfo *bi) {
2929
char *
3030
_jxl_get_mode(const JxlBasicInfo *bi) {
3131
if (bi->num_color_channels == 1 && !bi->alpha_bits) {
32+
if (bi->bits_per_sample == 1) {
33+
return "1";
34+
}
3235
if (bi->bits_per_sample == 16) {
3336
return "I;16";
3437
}

src/libImaging/Unpack.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,14 @@ unpack18(UINT8 *out, const UINT8 *in, int pixels) {
256256
}
257257
}
258258

259+
static void
260+
unpack1L(UINT8 *out, const UINT8 *in, int pixels) {
261+
int i;
262+
for (i = 0; i < pixels; i++) {
263+
out[i] = in[i] > 128 ? 255 : 0;
264+
}
265+
}
266+
259267
/* Unpack to "L" image */
260268

261269
static void
@@ -1564,6 +1572,7 @@ static struct {
15641572
{IMAGING_MODE_1, IMAGING_RAWMODE_1_R, 1, unpack1R},
15651573
{IMAGING_MODE_1, IMAGING_RAWMODE_1_IR, 1, unpack1IR},
15661574
{IMAGING_MODE_1, IMAGING_RAWMODE_1_8, 8, unpack18},
1575+
{IMAGING_MODE_1, IMAGING_RAWMODE_L, 8, unpack1L},
15671576

15681577
/* grayscale */
15691578
{IMAGING_MODE_L, IMAGING_RAWMODE_L_2, 2, unpackL2},

0 commit comments

Comments
 (0)