How do I create a BMP file with pure Python?

时光怂恿深爱的人放手 提交于 2019-11-28 23:43:49
Eli Bendersky

construct is a pure-Python library for parsing and building binary structures, protocols and file formats. It has BMP format support out-of-the-box.

This could be a better approach than hand-crafting it with struct. Besides, you will have a chance to learn a really useful library (which construct certainly is)

This is a complete answer for monochrome bitmaps.

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)]))

For example:

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

So, encoding this as a series of rows:

smile = [[0xFF], [0x81], [0xA5], [0x81], [0xA5], [0xBD], [0x81], [0xFF]]

Render it with:

bmp(smile, 8)

Note that it is the programmer's responsibility to ensure that the required number of bytes are present in each row supplied.

The black color is specified in the \xff \xff \xff and the white color is specified in the following \x00 \x00 \x00, should you want to change them.

There is my implementation of 24-bit bitmap in 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 (0, (s._bcWidth*3) % 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()

You have to use Python's struct module to create the binary headers the BMP file will need. Keep the image data itself in a bytearrayobject - bytearray is a little known native python data type that can behave like C strings: have mutable bytes which accept unsigned numbers from 0-255 in each position, still can be printed and used as a string (as an argument to file.write, for example).

Here is a small program that uses struct and other tools to create an image and write it as a TGA file, in pure Python, just as you want to do: http://www.python.org.br/wiki/ImagemTGA (it does not make use of bytearrays, but python array module instead (which is also interesting)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!