【问题标题】:How do I create a BMP file with pure Python?如何使用纯 Python 创建 BMP 文件?
【发布时间】:2012-02-02 12:10:49
【问题描述】:

我需要用纯 Python 创建一个黑白 BMP 文件。

我在 wikipedia 上读过一篇文章,BMP file format,但我不擅长底层编程,想填补我的知识空白。

所以问题是,如何创建具有像素矩阵的黑白 BMP 文件?我需要用纯 Python 来做到这一点,而不是使用像 PIL 这样的任何模块。这只是为了我的教育。

【问题讨论】:

标签: python bmp


【解决方案1】:

有我在 Python 3 中实现的 24 位位图:

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

【讨论】:

  • 编写代码可能不是世界上最高效的,但它确实能胜任。
  • 填充计算不正确;它应该是(4 - ((s._bcWidth*3) % 4)) % 4)。由于某种原因,我的编辑被拒绝了。
  • @minexew ,我刚刚修复了它,但是正如我现在所看到的,阅读我的代码,填充代码是完全错误的,因为它会追踪所有像素,但必须在每一行像素之后.大约 2 年前,我正在编写这段代码,那时我刚刚学习编程。
【解决方案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】:

    construct 是一个纯 Python 库,用于解析和构建二进制结构、协议和文件格式。它具有开箱即用的 BMP 格式支持。

    这可能是比使用struct 手工制作更好的方法。此外,您将有机会学习一个非常有用的库(construct 肯定是)

    【讨论】:

      【解决方案4】:

      您必须使用 Python 的 struct 模块来创建 BMP 文件所需的二进制头文件。将图像数据本身保存在 bytearrayobject 中 - bytearray 是一种鲜为人知的原生 python 数据类型,其行为类似于 C 字符串:具有可变字节,在每个位置接受 0-255 的无符号数字,仍然可以打印并用作一个字符串(例如作为 file.write 的参数)。

      这是一个小程序,它使用 struct 和其他工具创建图像并将其编写为 TGA 文件,在纯 Python 中,就像你想做的那样:http://www.python.org.br/wiki/ImagemTGA(它不使用字节数组,但是改为python数组模块(这也很有趣)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-03
        • 2016-04-15
        • 2012-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多