Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
Binary file added Tests/images/bmp/q/rgb32h52.bmp
Binary file not shown.
Binary file added Tests/images/bmp/q/rgba32h56.bmp
Binary file not shown.
2 changes: 2 additions & 0 deletions Tests/test_bmp_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ def test_questionable() -> None:
"pal8os2sp.bmp",
"pal8rletrns.bmp",
"rgb32bf-xbgr.bmp",
"rgb32h52.bmp",
"rgba32h56.bmp",
]
for f in get_files("q"):
try:
Expand Down
31 changes: 22 additions & 9 deletions src/PIL/BmpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def _accept(prefix: bytes) -> bool:


def _dib_accept(prefix):
return i32(prefix) in [12, 40, 64, 108, 124]
return i32(prefix) in [12, 40, 52, 56, 64, 108, 124]


# =============================================================================
Expand Down Expand Up @@ -83,8 +83,9 @@ def _bitmap(self, header=0, offset=0):
# read the rest of the bmp header, without its size
header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4)

# -------------------------------------------------- IBM OS/2 Bitmap v1
# ------------------------------- Windows Bitmap v2, IBM OS/2 Bitmap v1
# ----- This format has different offsets because of width/height types
# 12: BITMAPCOREHEADER/OS21XBITMAPHEADER
if file_info["header_size"] == 12:
file_info["width"] = i16(header_data, 0)
file_info["height"] = i16(header_data, 2)
Expand All @@ -93,9 +94,14 @@ def _bitmap(self, header=0, offset=0):
file_info["compression"] = self.RAW
file_info["palette_padding"] = 3

# --------------------------------------------- Windows Bitmap v2 to v5
# v3, OS/2 v2, v4, v5
elif file_info["header_size"] in (40, 64, 108, 124):
# --------------------------------------------- Windows Bitmap v3 to v5
# 40: BITMAPINFOHEADER
# 52: BITMAPV2HEADER
# 56: BITMAPV3HEADER
# 64: BITMAPCOREHEADER2/OS22XBITMAPHEADER
# 108: BITMAPV4HEADER
# 124: BITMAPV5HEADER
elif file_info["header_size"] in (40, 52, 56, 64, 108, 124):
file_info["y_flip"] = header_data[7] == 0xFF
file_info["direction"] = 1 if file_info["y_flip"] else -1
file_info["width"] = i32(header_data, 0)
Expand All @@ -117,10 +123,13 @@ def _bitmap(self, header=0, offset=0):
file_info["palette_padding"] = 4
self.info["dpi"] = tuple(x / 39.3701 for x in file_info["pixels_per_meter"])
if file_info["compression"] == self.BITFIELDS:
if len(header_data) >= 52:
for idx, mask in enumerate(
["r_mask", "g_mask", "b_mask", "a_mask"]
):
if len(header_data) >= 48:
masks = ["r_mask", "g_mask", "b_mask"]
if len(header_data) >= 52:
masks.append("a_mask")
else:
file_info["a_mask"] = 0x0
for idx, mask in enumerate(masks):
file_info[mask] = i32(header_data, 36 + idx * 4)
else:
# 40 byte headers only have the three components in the
Expand Down Expand Up @@ -175,9 +184,11 @@ def _bitmap(self, header=0, offset=0):
32: [
(0xFF0000, 0xFF00, 0xFF, 0x0),
(0xFF000000, 0xFF0000, 0xFF00, 0x0),
(0xFF000000, 0xFF00, 0xFF, 0x0),
(0xFF000000, 0xFF0000, 0xFF00, 0xFF),
(0xFF, 0xFF00, 0xFF0000, 0xFF000000),
(0xFF0000, 0xFF00, 0xFF, 0xFF000000),
(0xFF000000, 0xFF00, 0xFF, 0xFF0000),
(0x0, 0x0, 0x0, 0x0),
],
24: [(0xFF0000, 0xFF00, 0xFF)],
Expand All @@ -186,9 +197,11 @@ def _bitmap(self, header=0, offset=0):
MASK_MODES = {
(32, (0xFF0000, 0xFF00, 0xFF, 0x0)): "BGRX",
(32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): "XBGR",
(32, (0xFF000000, 0xFF00, 0xFF, 0x0)): "BGXR",
(32, (0xFF000000, 0xFF0000, 0xFF00, 0xFF)): "ABGR",
(32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): "RGBA",
(32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): "BGRA",
(32, (0xFF000000, 0xFF00, 0xFF, 0xFF0000)): "BGAR",
(32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
(24, (0xFF0000, 0xFF00, 0xFF)): "BGR",
(16, (0xF800, 0x7E0, 0x1F)): "BGR;16",
Expand Down
24 changes: 24 additions & 0 deletions src/libImaging/Unpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,17 @@ ImagingUnpackBGRX(UINT8 *_out, const UINT8 *in, int pixels) {
}
}

static void
ImagingUnpackBGXR(UINT8 *_out, const UINT8 *in, int pixels) {
int i;
for (i = 0; i < pixels; i++) {
UINT32 iv = MAKE_UINT32(in[3], in[1], in[0], 255);
memcpy(_out, &iv, sizeof(iv));
in += 4;
_out += 4;
}
}

static void
ImagingUnpackXRGB(UINT8 *_out, const UINT8 *in, int pixels) {
int i;
Expand Down Expand Up @@ -1090,6 +1101,17 @@ unpackBGRA16B(UINT8 *_out, const UINT8 *in, int pixels) {
}
}

static void
unpackBGAR(UINT8 *_out, const UINT8 *in, int pixels) {
int i;
for (i = 0; i < pixels; i++) {
UINT32 iv = MAKE_UINT32(in[3], in[1], in[0], in[2]);
memcpy(_out, &iv, sizeof(iv));
in += 4;
_out += 4;
}
}

/* Unpack to "CMYK" image */

static void
Expand Down Expand Up @@ -1584,6 +1606,7 @@ static struct {
{"RGB", "RGBA;L", 32, unpackRGBAL},
{"RGB", "RGBA;15", 16, ImagingUnpackRGBA15},
{"RGB", "BGRX", 32, ImagingUnpackBGRX},
{"RGB", "BGXR", 32, ImagingUnpackBGXR},
{"RGB", "XRGB", 32, ImagingUnpackXRGB},
{"RGB", "XBGR", 32, ImagingUnpackXBGR},
{"RGB", "YCC;P", 24, ImagingUnpackYCC},
Expand Down Expand Up @@ -1624,6 +1647,7 @@ static struct {
{"RGBA", "BGRA", 32, unpackBGRA},
{"RGBA", "BGRA;16L", 64, unpackBGRA16L},
{"RGBA", "BGRA;16B", 64, unpackBGRA16B},
{"RGBA", "BGAR", 32, unpackBGAR},
{"RGBA", "ARGB", 32, unpackARGB},
{"RGBA", "ABGR", 32, unpackABGR},
{"RGBA", "YCCA;P", 32, ImagingUnpackYCCA},
Expand Down