Skip to content

Commit d0819ee

Browse files
committed
Open black palette as mode 1
1 parent 767a3f1 commit d0819ee

3 files changed

Lines changed: 33 additions & 15 deletions

File tree

Tests/test_file_bmp.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,19 +202,10 @@ def test_rle4() -> None:
202202
assert_image_similar_tofile(im, "Tests/images/bmp/g/pal4.bmp", 12)
203203

204204

205-
def test_rle4_absolute_odd() -> None:
206-
# An RLE4 absolute run with an odd number of pixels is packed into
207-
# ceil(count / 2) bytes, the final nibble being padding. Build a 3x1
208-
# image whose single row is one absolute run of 3 pixels (indices 1, 2, 3).
209-
palette = b"\x00" * 4
210-
rle = (
211-
b"\x00\x03" # absolute mode, 3 pixels
212-
b"\x12\x30" # nibbles 1, 2, 3 and a padding nibble
213-
b"\x00\x01" # end of bitmap
214-
)
205+
def encode_rle4(width: int, palette: bytes, rle: bytes) -> io.BytesIO:
215206
header = (
216207
o32(40) # header size
217-
+ o32(3) # width
208+
+ o32(width) # width
218209
+ o32(1) # height
219210
+ o16(1) # planes
220211
+ o16(4) # bits per pixel
@@ -225,7 +216,7 @@ def test_rle4_absolute_odd() -> None:
225216
+ o32(0) # important colors
226217
)
227218
offset = 14 + len(header) + len(palette)
228-
data = (
219+
return io.BytesIO(
229220
b"BM"
230221
+ o32(offset + len(rle)) # file size
231222
+ o32(0) # reserved
@@ -235,7 +226,33 @@ def test_rle4_absolute_odd() -> None:
235226
+ rle
236227
)
237228

238-
with Image.open(io.BytesIO(data)) as im:
229+
230+
def test_rle4_black() -> None:
231+
rle = (
232+
b"\x00\x03" # absolute mode, 3 pixels
233+
b"\x00" # nibbles 0 and 0
234+
b"\x00\x01" # end of bitmap
235+
)
236+
b = encode_rle4(2, b"\x00" * 4, rle)
237+
238+
with Image.open(b) as im:
239+
assert im.mode == "1"
240+
assert [im.getpixel((x, 0)) for x in range(im.width)] == [0, 0]
241+
242+
243+
def test_rle4_absolute_odd() -> None:
244+
# An RLE4 absolute run with an odd number of pixels is packed into
245+
# ceil(count / 2) bytes, the final nibble being padding. Build a 3x1
246+
# image whose single row is one absolute run of 3 pixels (indices 1, 2, 3).
247+
palette = b"\x01" * 4
248+
rle = (
249+
b"\x00\x03" # absolute mode, 3 pixels
250+
b"\x12\x30" # nibbles 1, 2, 3 and a padding nibble
251+
b"\x00\x01" # end of bitmap
252+
)
253+
b = encode_rle4(3, palette, rle)
254+
255+
with Image.open(b) as im:
239256
assert [im.getpixel((x, 0)) for x in range(im.width)] == [1, 2, 3]
240257

241258

src/PIL/BmpImagePlugin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def _bitmap(self, header: int = 0, offset: int = 0) -> None:
280280

281281
# ------- If all colors are gray, white or black, ditch palette
282282
if grayscale:
283-
self._mode = "1" if file_info["colors"] == 2 else "L"
283+
self._mode = "1" if file_info["colors"] <= 2 else "L"
284284
raw_mode = self.mode
285285
else:
286286
self._mode = "P"
@@ -390,7 +390,7 @@ def decode(self, buffer: Image.DecoderInput) -> tuple[int, int]:
390390
# align to 16-bit word boundary
391391
if self.fd.tell() % 2 != 0:
392392
self.fd.seek(1, os.SEEK_CUR)
393-
rawmode = "L" if self.mode == "L" else "P"
393+
rawmode = "L" if self.mode in {"1", "L"} else "P"
394394
self.set_as_raw(bytes(data), rawmode, (0, self.args[-1]))
395395
return -1, 0
396396

src/libImaging/Unpack.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,7 @@ static struct {
15641564
{IMAGING_MODE_1, IMAGING_RAWMODE_1_R, 1, unpack1R},
15651565
{IMAGING_MODE_1, IMAGING_RAWMODE_1_IR, 1, unpack1IR},
15661566
{IMAGING_MODE_1, IMAGING_RAWMODE_1_8, 8, unpack18},
1567+
{IMAGING_MODE_1, IMAGING_RAWMODE_L, 8, unpack18},
15671568

15681569
/* grayscale */
15691570
{IMAGING_MODE_L, IMAGING_RAWMODE_L_2, 2, unpackL2},

0 commit comments

Comments
 (0)