如何用纯Python创建BMP文件?

发布于 2024-12-25 00:10:46 字数 249 浏览 2 评论 0原文

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

我读了维基百科上的一篇文章,BMP 文件格式,但我不擅长低级编程,并且我想填补我的知识空白。

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

I need to create a black and white BMP file with pure Python.

I read an article on wikipedia, BMP file format, but I am not good at low level programming and want to fill this gap in my knowledge.

So the question is, how do I create a black and white BMP file having a matrix of pixels? I need to do this with pure Python, not using any modules like PIL. It is just for my education.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

短暂陪伴 2025-01-01 00:10:46

这是单色位图的完整答案。

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 中指定。

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.

幼儿园老大 2025-01-01 00:10:46

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

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

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)

半仙 2025-01-01 00:10:46

UPD:警告!这不适用于生产用途。您可以将它用于学习目的,但请注意,这段代码是在我刚开始学习编程时编写的,它存在一些与错误生成某些分辨率的图像相关的错误。如果您正在寻找更强大的生产解决方案,请考虑使用 PIL 等图形库,或查看已经提到的用于低级位图生成的库“构造”。

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

UPD: Warning! This is not for production use. You can use it for learning purposes, but please be aware that this code was written when I was only starting to learn programming and it has some bugs related to incorrect generation of images of some resolutions. If you're searching for more robust solution for production, consider using graphic libraries such as PIL or see already mentioned library "construct" for low-level bitmap generation.

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((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()
我做我的改变 2025-01-01 00:10:46

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

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

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文