极客挑战:生成一张 1000 亿像素的 PNG 图片

你是否想过生成一张分辨率达到 1000 亿像素的图片?比如 316230 x 316230 这样巨大的尺寸。

如果直接使用普通的绘图库(如 PIL/Pillow),创建一个这样尺寸的 RGB 图片,未压缩的原始数据将占用约 300GB 的内存(316230 * 316230 * 3 bytes)。如果你的机器内存有限,程序很可能会直接崩溃。

挑战目标

不安装任何第三方库(如 Pillow, NumPy),仅使用 Python 标准库,生成一张 1000 亿像素的 PNG 图片,而且内存占用极低,速度极快。

警告:电脑配置低的同学,请不要尝试打开生成的图片。

核心思路

要解决内存和性能问题,我们不能一次性在内存中创建完整的像素数组。我们需要使用流式处理格式优化

PNG 格式本质上是分块的,其中图像数据存储在 IDAT 块中。我们可以:

  1. 手动构建 PNG 文件头和元数据块 (IHDR)。
  2. 选择合适的图像模式:使用 1-bit 灰度模式,数据量极小。
  3. 高效压缩:使用 zlib level 1 (最快压缩),因为纯色图片压缩率极高,无需高压缩比。
  4. 逐行生成像素数据并流式写入。

无论图片多大,我们同一时间只在内存中保存一行的像素数据。

代码实现

下面是完整的 Python 脚本。它利用了 zlibstruct 模块来手动封装 PNG 格式。

#!/usr/bin/env python3
"""
生成超大分辨率(1000亿像素)的空白 PNG 图片
特点:
1. 无第三方依赖,仅使用 Python 标准库 (zlib, struct)
2. 极速生成:采用 1-bit 灰度模式 + 低压缩级别
3. 内存友好:流式写入,不占用大量内存

原文: https://www.rehiy.com/post/608/
作者: 若海
"""

import sys
import struct
import zlib

def p32(num):
    """打包32位整数 (大端序)"""
    return struct.pack('>I', num)

def write_chunk(f, chunk_type, data):
    """
    写入标准的 PNG 数据块 (Chunk)
    结构: Length(4) + Type(4) + Data(Length) + CRC(4)
    """
    f.write(p32(len(data)))
    f.write(chunk_type)
    f.write(data)
    crc = zlib.crc32(chunk_type)
    crc = zlib.crc32(data, crc)
    f.write(p32(crc & 0xffffffff))

def generate_large_blank_png():
    # 配置参数: 1000亿像素 (316230 x 316230)
    width = 316230
    height = 316230
    output_file = "blank_100billion_pixels.png"

    print(f"开始生成 {width}x{height} 像素的空白 PNG 图片")
    print("正在计算和写入数据...")

    try:
        with open(output_file, 'wb') as f:
            # 1. PNG 文件签名
            f.write(b'\x89PNG\r\n\x1a\n')

            # 2. IHDR 图像头
            # BitDepth=1 (1-bit), ColorType=0 (Grayscale)
            # 使用 1-bit 灰度模式以最小化数据量
            ihdr_data = p32(width) + p32(height) + b'\x01\x00\x00\x00\x00'
            write_chunk(f, b'IHDR', ihdr_data)

            # 3. IDAT 图像数据
            # 使用 zlib level=1 (最快压缩)
            compressor = zlib.compressobj(level=1)

            # 准备单行数据: Filter(0) + Pixels(1-bit grayscale)
            # 全白图片: 所有位均为 1 (0xFF)
            row_bytes = (width + 7) // 8
            raw_row = b'\x00' + b'\xff' * row_bytes

            # 数据缓冲区 (64KB chunks)
            compressed_buffer = bytearray()
            CHUNK_SIZE = 65536

            print("正在压缩并写入 IDAT 数据...")
            for y in range(height):
                # 压缩当前行
                if compressed := compressor.compress(raw_row):
                    compressed_buffer.extend(compressed)

                    # 缓冲区满则写入文件
                    while len(compressed_buffer) >= CHUNK_SIZE:
                        write_chunk(f, b'IDAT', compressed_buffer[:CHUNK_SIZE])
                        compressed_buffer = compressed_buffer[CHUNK_SIZE:]

                # 进度显示
                if y % 1000 == 0:
                    percent = (y / height) * 100
                    sys.stdout.write(f"\r进度: {percent:.1f}% ({y}/{height})")
                    sys.stdout.flush()

            # 结束压缩,写入剩余数据
            compressed_buffer.extend(compressor.flush())

            while len(compressed_buffer) > 0:
                chunk_len = min(len(compressed_buffer), CHUNK_SIZE)
                write_chunk(f, b'IDAT', compressed_buffer[:chunk_len])
                compressed_buffer = compressed_buffer[chunk_len:]

            sys.stdout.write(f"\r进度: 100.0% ({height}/{height})\n")

            # 4. IEND 文件结束
            write_chunk(f, b'IEND', b'')

        print(f"✓ 成功生成图片: {output_file}")
        print("提示: 由于是纯色图片,PNG压缩效率极高,文件体积会很小。")

    except Exception as e:
        print(f"\n❌ 发生错误: {e}")

if __name__ == "__main__":
    generate_large_blank_png()

代码解析

1. PNG 文件结构

PNG 文件由一个 8 字节的签名和一系列数据块(Chunk)组成。每个块包含长度、类型码、数据和 CRC 校验。我们定义了 write_chunk 函数来处理这种结构。

2. 关键策略

这是实现 1000 亿像素生成的关键。

a. 1-bit 灰度模式
使用 BitDepth=1ColorType=0(灰度),8 个像素仅占 1 字节。这极大降低了内存需求和 I/O 压力。

b. 极速压缩
我们使用 zlib.compressobj(level=1)。对于纯色图片,Level 1 的压缩率已经极高,使用默认的 Level 6 只会浪费 CPU 时间而不会显著减小文件体积。

compressor = zlib.compressobj(level=1)

3. 极小的文件体积

因为我们生成的是纯色(空白)图片,PNG 的压缩算法(Deflate)对重复数据的压缩效率极高。虽然图片展开后有 300GB 大小的像素数据,但最终生成的 PNG 文件依然非常小。

文章作者: 若海; 原文链接: https://www.rehiy.com/post/608/; 转载需声明来自若海观澜

仅有一条评论

  1. 学到了新知识 海哥好棒

添加新评论