我正在寻找类似问题的答案,但无法在“纯”python 中找到“快速”可理解的解决方案。
所以我写了一些代码来创建一个位图(从示例中转换为 RGB 值的字符数组数据)。请阅读下面代码示例的 MIT 许可后的 cmets。它们描述了从任何数据创建位图所需的信息。
我合并了来自http://blog.paphus.com/blog/2012/08/14/write-your-own-bitmaps/ 和enter link description here 的信息
我的输出是:
#!/usr/bin/python
# ----------------------- START MIT LICENSE -----------------------
# Copyright (c) 2018 Benjamin Spiegl
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ----------------------- END MIT LICENSE -----------------------
# The pixel data has to be written with some minor modifications.
# First, the bottom row of the image appears first in the data.
# If you forget this step your image will be vertically flipped.
# Second, the pixes are written in BGR (blue - green - red) format, which is the opposite of the normal RGB.
# Finally, at the end of each row you must pad it with bytes till it is a multiple of 4.
# All numbers in the headers must be LITTLE-ENDIAN.
# For instance, when representing 54 as four bytes, those four bytes must be 54, 0, 0, 0.
# To represent 24 as two bytes, the two bytes must be 24, 0.
from numpy import array
from math import floor
def make_hex_list(int_val=None, force_byte_len=None, little_endian=True):
if int_val is None:
return []
raw_pix_hex = hex(int_val)[2:]
first_hex_str = '' # is falsy
if len(raw_pix_hex) % 2: # odd number of hex vals
first_hex_str = '0x0' + raw_pix_hex[0]
raw_pix_hex = raw_pix_hex[1:]
if first_hex_str:
raw_pix_hex_list = [first_hex_str] + ['0x' + raw_pix_hex[lit_pair_idx * 2:lit_pair_idx * 2 + 2]
for lit_pair_idx in range(int(floor(len(raw_pix_hex) / 2)))]
else:
raw_pix_hex_list = ['0x' + raw_pix_hex[lit_pair_idx * 2:lit_pair_idx * 2 + 2]
for lit_pair_idx in
range(int(floor(len(raw_pix_hex) / 2)))] # max 4 bytes (32 bit) -> should be ok
if force_byte_len and len(raw_pix_hex_list) != force_byte_len: # force 4 bytes
raw_pix_hex_list = ['0x00'] * (force_byte_len - len(raw_pix_hex_list)) + raw_pix_hex_list
elif len(raw_pix_hex_list) > 4:
raise OverflowError('base matrix too large for 32 bit bitmap.')
if little_endian:
return list(reversed([int(hx, 16) for hx in raw_pix_hex_list]))
else:
return [int(hx, 16) for hx in raw_pix_hex_list]
# A=yellow, T=red, C=green, G=blue, D=grey, N=black
bmp_BGR_colors = {'A': (0, 255, 255), 'T': (0, 0, 255), 'C': (0, 255, 0), 'G': (255, 0, 0),
'N': (0, 0, 0), 'D': (150, 150, 150)}
bmp_name = 'bitmap_test.bmp'
magnify = 16
mybase_arr = array([['G', 'A', 'G', 'A', 'D', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['G', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N'],
['N', 'A', 'G', 'A', 'A', 'D', 'T', 'T', 'A', 'N']])
arr_height, arr_width = mybase_arr.shape
# prepare header information
pixel_width = arr_width * magnify # force 4 bytes
pixel_height = arr_height * magnify # force 4 bytes
linepad = pixel_width * 3 % 4 # ensure valid row bytes (3 bytes per pixel; 1 per color channel)
total_pad = pixel_height * linepad
pix_offset = [0x36, 0x00, 0x00, 0x00] # force 4 byte
raw_pix_data_size = pixel_width * pixel_height * 3 + total_pad
raw_pix_data_size_hex_list = make_hex_list(int_val=raw_pix_data_size, force_byte_len=4)
file_size = 0x36 + raw_pix_data_size # force 4 byte
# create header values for byte conversion
header_vals = [0x42, 0x4d] + make_hex_list(int_val=file_size, force_byte_len=4) + [0x00]*4 + pix_offset + \
[0x28, 0x00, 0x00, 0x00] + make_hex_list(int_val=pixel_width, force_byte_len=4) + \
make_hex_list(int_val=pixel_height, force_byte_len=4) + \
make_hex_list(int_val=1, force_byte_len=2) + \
make_hex_list(int_val=24, force_byte_len=2) + make_hex_list(int_val=0, force_byte_len=4) + \
raw_pix_data_size_hex_list + [0x13, 0x0b, 0x00, 0x00]*2 + [0x00, 0x00, 0x00, 0x00]*2
assert(len(header_vals) == pix_offset[0])
# create pixel values for byte conversion
if linepad: # need to 0-pad lines to a multiple of 4 bytes per line
pixel_vals = list()
for reverse_row in list(reversed(mybase_arr)):
for cpy in range(magnify): # repeat line 16 times (magnify)
pixel_vals.extend([val for pix in reverse_row for val in bmp_BGR_colors[pix] * magnify] + [0x00] * linepad)
else: # no padding needed
pixel_vals = [val for reverse_row in list(reversed(mybase_arr))
for cpy in range(magnify) for pix in reverse_row
for val in bmp_BGR_colors[pix]*magnify] # last for to unpack tuples
assert(len(pixel_vals) == raw_pix_data_size)
with open(bmp_name, 'wb') as bmp_file:
bmp_file.write(bytearray(header_vals + pixel_vals)) # convert values to bytes