Как создать файл BMP с чистым Python?
Мне нужно создать черно-белый BMP файл с чистым Python.
Я прочитал статью о wikipedia, формат BMP файла, но я плохо разбираюсь в программировании на низком уровне и хочу заполнить этот пробел в мои знания.
Итак, вопрос в том, как мне создать черно-белый BMP файл с матрицей пикселей? Мне нужно сделать это с помощью чистого Python, не используя никаких модулей, таких как PIL. Это просто для моего образования.
Ответы
Ответ 1
construct - это библиотека pure-Python для синтаксического анализа и построения двоичных структур, протоколов и форматов файлов. Он имеет поддержку формата BMP из коробки.
Это может быть лучший подход, чем ручной дизайн с помощью struct
. Кроме того, у вас будет возможность изучить действительно полезную библиотеку (что construct
конечно)
Ответ 2
Это полный ответ для монохромных растровых изображений.
import math, struct
mult4 = lambda n: int(math.ceil(n/4))*4
mult8 = lambda n: int(math.ceil(n/8))*8
lh = lambda n: struct.pack("<h", n)
li = lambda n: struct.pack("<i", n)
def bmp(rows, w):
h, wB = len(rows), int(mult8(w)/8)
s, pad = li(mult4(wB)*h+0x20), [0]*(mult4(wB)-wB)
s = li(mult4(w)*h+0x20)
return (b"BM" + s + b"\x00\x00\x00\x00\x20\x00\x00\x00\x0C\x00\x00\x00" +
lh(w) + lh(h) + b"\x01\x00\x01\x00\xff\xff\xff\x00\x00\x00" +
b"".join([bytes(row+pad) for row in reversed(rows)]))
Например:
FF XXXXXXXX
81 X......X
A5 X.X..X.X
81 X......X
A5 X.X..X.X
BD X.XXXX.X
81 X......X
FF XXXXXXXX
Итак, кодируя это как ряд строк:
smile = [[0xFF], [0x81], [0xA5], [0x81], [0xA5], [0xBD], [0x81], [0xFF]]
Отрежьте его:
bmp(smile, 8)
Обратите внимание, что ответственность программиста заключается в том, чтобы обеспечить необходимое количество байтов в каждой поставляемой строке.
Черный цвет указан в \xff\xff\xff, а белый цвет указан в следующем \x00\x00\x00, если вы хотите их изменить.
Ответ 3
Вы должны использовать модуль Python struct
для создания двоичных заголовков, необходимых для BMP файла. Храните сами данные изображения в объекте bytearray
- bytearray - это малоизвестный родной тип данных python, который может вести себя как строки C: имеют изменяемые байты, которые принимают беззнаковые числа от 0 до 255 в каждой позиции, все еще могут быть напечатаны и использованы как строка (как аргумент file.write, например).
Вот небольшая программа, которая использует структурированные и другие инструменты для создания изображения и записывает его как TGA файл в чистом Python, как вы хотите: http://www.python.org.br/wiki/ImagemTGA (он не использует bytearrays, а вместо этого модуль python array (что тоже интересно)
Ответ 4
Моя реализация 24-битного растрового изображения в Python 3:
from struct import pack
class Bitmap():
def __init__(s, width, height):
s._bfType = 19778 # Bitmap signature
s._bfReserved1 = 0
s._bfReserved2 = 0
s._bcPlanes = 1
s._bcSize = 12
s._bcBitCount = 24
s._bfOffBits = 26
s._bcWidth = width
s._bcHeight = height
s._bfSize = 26+s._bcWidth*3*s._bcHeight
s.clear()
def clear(s):
s._graphics = [(0,0,0)]*s._bcWidth*s._bcHeight
def setPixel(s, x, y, color):
if isinstance(color, tuple):
if x<0 or y<0 or x>s._bcWidth-1 or y>s._bcHeight-1:
raise ValueError('Coords out of range')
if len(color) != 3:
raise ValueError('Color must be a tuple of 3 elems')
s._graphics[y*s._bcWidth+x] = (color[2], color[1], color[0])
else:
raise ValueError('Color must be a tuple of 3 elems')
def write(s, file):
with open(file, 'wb') as f:
f.write(pack('<HLHHL',
s._bfType,
s._bfSize,
s._bfReserved1,
s._bfReserved2,
s._bfOffBits)) # Writing BITMAPFILEHEADER
f.write(pack('<LHHHH',
s._bcSize,
s._bcWidth,
s._bcHeight,
s._bcPlanes,
s._bcBitCount)) # Writing BITMAPINFO
for px in s._graphics:
f.write(pack('<BBB', *px))
for i in range (4 - ((s._bcWidth*3) % 4)) % 4):
f.write(pack('B', 0))
def main():
side = 520
b = Bitmap(side, side)
for j in range(0, side):
b.setPixel(j, j, (255, 0, 0))
b.setPixel(j, side-j-1, (255, 0, 0))
b.setPixel(j, 0, (255, 0, 0))
b.setPixel(j, side-1, (255, 0, 0))
b.setPixel(0, j, (255, 0, 0))
b.setPixel(side-1, j, (255, 0, 0))
b.write('file.bmp')
if __name__ == '__main__':
main()