testing new files
This commit is contained in:
parent
343ed5346b
commit
e14ecd308f
BIN
cricket.bmp
Normal file
BIN
cricket.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
140
seekablebitmap.py
Normal file
140
seekablebitmap.py
Normal file
@ -0,0 +1,140 @@
|
||||
# SPDX-FileCopyrightText: 2021 Jeff Epler for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import struct
|
||||
|
||||
class SeekableBitmap:
|
||||
"""Allow random access to an uncompressed bitmap file on disk"""
|
||||
def __init__(
|
||||
self,
|
||||
image_file,
|
||||
width,
|
||||
height,
|
||||
bits_per_pixel,
|
||||
*,
|
||||
bytes_per_row=None,
|
||||
data_start=None,
|
||||
stride=None,
|
||||
palette=None,
|
||||
):
|
||||
"""Construct a SeekableBitmap"""
|
||||
self.image_file = image_file
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.bits_per_pixel = bits_per_pixel
|
||||
self.bytes_per_row = (
|
||||
bytes_per_row if bytes_per_row else (bits_per_pixel * width + 7) // 8
|
||||
)
|
||||
self.stride = stride if stride else self.bytes_per_row
|
||||
self.palette = palette
|
||||
self.data_start = data_start if data_start else image_file.tell()
|
||||
|
||||
def get_row(self, row):
|
||||
self.image_file.seek(self.data_start + row * self.stride)
|
||||
return self.image_file.read(self.bytes_per_row)
|
||||
|
||||
|
||||
def _pnmopen(filename):
|
||||
"""
|
||||
Scan for netpbm format info, skip over comments, and read header data.
|
||||
|
||||
Return the format, header, and the opened file positioned at the start of
|
||||
the bitmap data.
|
||||
"""
|
||||
# pylint: disable=too-many-branches
|
||||
image_file = open(filename, "rb")
|
||||
magic_number = image_file.read(2)
|
||||
image_file.seek(2)
|
||||
pnm_header = []
|
||||
next_value = bytearray()
|
||||
while True:
|
||||
# We have all we need at length 3 for formats P2, P3, P5, P6
|
||||
if len(pnm_header) == 3:
|
||||
return image_file, magic_number, pnm_header
|
||||
|
||||
if len(pnm_header) == 2 and magic_number in [b"P1", b"P4"]:
|
||||
return image_file, magic_number, pnm_header
|
||||
|
||||
next_byte = image_file.read(1)
|
||||
if next_byte == b"":
|
||||
raise RuntimeError("Unsupported image format {}".format(magic_number))
|
||||
if next_byte == b"#": # comment found, seek until a newline or EOF is found
|
||||
while image_file.read(1) not in [b"", b"\n"]: # EOF or NL
|
||||
pass
|
||||
elif not next_byte.isdigit(): # boundary found in header data
|
||||
if next_value:
|
||||
# pull values until space is found
|
||||
pnm_header.append(int("".join(["%c" % char for char in next_value])))
|
||||
next_value = bytearray() # reset the byte array
|
||||
else:
|
||||
next_value += next_byte # push the digit into the byte array
|
||||
|
||||
|
||||
def pnmopen(filename):
|
||||
"""
|
||||
Interpret netpbm format info and construct a SeekableBitmap
|
||||
"""
|
||||
image_file, magic_number, pnm_header = _pnmopen(filename)
|
||||
if magic_number == b"P4":
|
||||
return SeekableBitmap(
|
||||
image_file,
|
||||
pnm_header[0],
|
||||
pnm_header[1],
|
||||
1,
|
||||
palette=b"\xff\xff\xff\x00\x00\x00\x00\x00",
|
||||
)
|
||||
if magic_number == b"P5":
|
||||
return SeekableBitmap(
|
||||
image_file, pnm_header[0], pnm_header[1], pnm_header[2].bit_length()
|
||||
)
|
||||
if magic_number == b"P6":
|
||||
return SeekableBitmap(
|
||||
image_file, pnm_header[0], pnm_header[1], 3 * pnm_header[2].bit_length()
|
||||
)
|
||||
raise ValueError(f"Unknown or unsupported magic number {magic_number}")
|
||||
|
||||
|
||||
def bmpopen(filename):
|
||||
"""
|
||||
Interpret bmp format info and construct a SeekableBitmap
|
||||
"""
|
||||
image_file = open(filename, "rb")
|
||||
|
||||
header = image_file.read(34)
|
||||
|
||||
data_start, header_size, width, height, _, bits_per_pixel, _ = struct.unpack(
|
||||
"<10x4l2hl", header
|
||||
)
|
||||
|
||||
bits_per_pixel = bits_per_pixel if bits_per_pixel != 0 else 1
|
||||
|
||||
palette_start = header_size + 14
|
||||
image_file.seek(palette_start)
|
||||
palette = image_file.read(4 << bits_per_pixel)
|
||||
|
||||
stride = (bits_per_pixel * width + 31) // 32 * 4
|
||||
if height < 0:
|
||||
height = -height
|
||||
else:
|
||||
data_start = data_start + stride * (height - 1)
|
||||
stride = -stride
|
||||
|
||||
return SeekableBitmap(
|
||||
image_file,
|
||||
width,
|
||||
height,
|
||||
bits_per_pixel,
|
||||
data_start=data_start,
|
||||
stride=stride,
|
||||
palette=palette,
|
||||
)
|
||||
|
||||
|
||||
def imageopen(filename):
|
||||
"""
|
||||
Open a bmp or pnm file as a seekable bitmap
|
||||
"""
|
||||
if filename.lower().endswith(".bmp"):
|
||||
return bmpopen(filename)
|
||||
return pnmopen(filename)
|
Loading…
Reference in New Issue
Block a user