"""
Bitmap class file
"""
class BmpFileHeader:
'''Bitmap file header class'''
def __init__(self):
self.bf_type = i_to_bytes(0, 2) # 0x4d42 对应BM
self.bf_size = i_to_bytes(0, 4) # file size
self.bf_reserved1 = i_to_bytes(0, 2)
self.bf_reserved2 = i_to_bytes(0, 2)
self.bf_off_bits = i_to_bytes(0, 4) # header info offset
class BmpInfoHeader:
'''Bitmap struct header class'''
def __init__(self):
self.bi_size = i_to_bytes(0, 4) # bmpheader size
self.bi_width = i_to_bytes(0, 4)
self.bi_height = i_to_bytes(0, 4)
self.bi_planes = i_to_bytes(0, 2) # default 1
self.bi_bit_count = i_to_bytes(0, 2) # one pixel occupy how many bits
self.bi_compression = i_to_bytes(0, 4)
self.bi_size_image = i_to_bytes(0, 4)
self.bi_xpels_per_meter = i_to_bytes(0, 4)
self.bi_ypels_per_meter = i_to_bytes(0, 4)
self.bi_clr_used = i_to_bytes(0, 4)
self.bi_clr_important = i_to_bytes(0, 4)
class Bmp(BmpFileHeader, BmpInfoHeader):
'''Bitmap class'''
def __init__(self):
BmpFileHeader.__init__(self)
BmpInfoHeader.__init__(self)
self.bytes = [] # pixel array
@property
def width(self):
"""width"""
return bytes_to_i(self.bi_width)
@property
def height(self):
"""height"""
return bytes_to_i(self.bi_height)
# unit is byte
@property
def bytes_per_pixel(self):
"""bit count"""
return bytes_to_i(self.bi_bit_count) // 8
@property
def pixel_count(self):
"""number of pixels"""
return self.width * self.height
def parse(self, file_name):
"""resolve a bmp file"""
file = open(file_name, 'rb')
# BmpFileHeader
print("=== BitmapFileHeader (14 B) ===")
self.bf_type = file.read(2)
print("bfType (2 B): ", self.bf_type.hex(" "))
self.bf_size = file.read(4)
self.bf_reserved1 = file.read(2)
self.bf_reserved2 = file.read(2)
self.bf_off_bits = file.read(4)
# BmpInfoHeader
print("=== BitmapInfoHeader (40 B) ===")
self.bi_size = file.read(4)
print("biSize (4 B):", self.bi_size.hex(" "))
self.bi_width = file.read(4)
self.bi_height = file.read(4)
self.bi_planes = file.read(2)
self.bi_bit_count = file.read(2)
self.bi_compression = file.read(4)
self.bi_size_image = file.read(4)
self.bi_xpels_per_meter = file.read(4)
self.bi_ypels_per_meter = file.read(4)
self.bi_clr_used = file.read(4)
self.bi_clr_important = file.read(4)
# load pixel data
print("=== Pixels ===")
pix_count = 0
while pix_count < self.pixel_count:
# pylint: disable=consider-using-f-string
print("pixel[%d]:" % (pix_count), end=" ")
count = 0
while count < self.bytes_per_pixel:
channel = file.read(1)
self.bytes.append(channel)
# TODO print(_______, end=" ")
count += 1
# padding: unsigned char = 1 B (0)
while count % 4 != 0:
file.read(1)
count += 1
print()
pix_count += 1
file.close()
def i_to_bytes(number, length, byteorder='little'):
"""int to bytes"""
return number.to_bytes(length, byteorder)
def bytes_to_i(mbytes, byteorder='little'):
"""bytes to int"""
return int.from_bytes(mbytes, byteorder)
if __name__ == "__main__":
bmp = Bmp()
bmp.parse('res/black.bmp')
评论0