Read relevant info about the BMP
(self, header: int = 0, offset: int = 0)
| 75 | vars()[k] = v |
| 76 | |
| 77 | def _bitmap(self, header: int = 0, offset: int = 0) -> None: |
| 78 | """Read relevant info about the BMP""" |
| 79 | assert self.fp is not None |
| 80 | read, seek = self.fp.read, self.fp.seek |
| 81 | if header: |
| 82 | seek(header) |
| 83 | # read bmp header size @offset 14 (this is part of the header size) |
| 84 | file_info: dict[str, bool | int | tuple[int, ...]] = { |
| 85 | "header_size": i32(read(4)), |
| 86 | "direction": -1, |
| 87 | } |
| 88 | |
| 89 | # -------------------- If requested, read header at a specific position |
| 90 | # read the rest of the bmp header, without its size |
| 91 | assert isinstance(file_info["header_size"], int) |
| 92 | header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4) |
| 93 | |
| 94 | # ------------------------------- Windows Bitmap v2, IBM OS/2 Bitmap v1 |
| 95 | # ----- This format has different offsets because of width/height types |
| 96 | # 12: BITMAPCOREHEADER/OS21XBITMAPHEADER |
| 97 | if file_info["header_size"] == 12: |
| 98 | file_info["width"] = i16(header_data, 0) |
| 99 | file_info["height"] = i16(header_data, 2) |
| 100 | file_info["planes"] = i16(header_data, 4) |
| 101 | file_info["bits"] = i16(header_data, 6) |
| 102 | file_info["compression"] = self.COMPRESSIONS["RAW"] |
| 103 | file_info["palette_padding"] = 3 |
| 104 | |
| 105 | # --------------------------------------------- Windows Bitmap v3 to v5 |
| 106 | # 40: BITMAPINFOHEADER |
| 107 | # 52: BITMAPV2HEADER |
| 108 | # 56: BITMAPV3HEADER |
| 109 | # 64: BITMAPCOREHEADER2/OS22XBITMAPHEADER |
| 110 | # 108: BITMAPV4HEADER |
| 111 | # 124: BITMAPV5HEADER |
| 112 | elif file_info["header_size"] in (40, 52, 56, 64, 108, 124): |
| 113 | file_info["y_flip"] = header_data[7] == 0xFF |
| 114 | file_info["direction"] = 1 if file_info["y_flip"] else -1 |
| 115 | file_info["width"] = i32(header_data, 0) |
| 116 | file_info["height"] = ( |
| 117 | i32(header_data, 4) |
| 118 | if not file_info["y_flip"] |
| 119 | else 2**32 - i32(header_data, 4) |
| 120 | ) |
| 121 | file_info["planes"] = i16(header_data, 8) |
| 122 | file_info["bits"] = i16(header_data, 10) |
| 123 | file_info["compression"] = i32(header_data, 12) |
| 124 | # byte size of pixel data |
| 125 | file_info["data_size"] = i32(header_data, 16) |
| 126 | file_info["pixels_per_meter"] = ( |
| 127 | i32(header_data, 20), |
| 128 | i32(header_data, 24), |
| 129 | ) |
| 130 | file_info["colors"] = i32(header_data, 28) |
| 131 | file_info["palette_padding"] = 4 |
| 132 | assert isinstance(file_info["pixels_per_meter"], tuple) |
| 133 | self.info["dpi"] = tuple(x / 39.3701 for x in file_info["pixels_per_meter"]) |
| 134 | if file_info["compression"] == self.COMPRESSIONS["BITFIELDS"]: |