生成图像文件而不将整个图像保存在内存中

Generate image file without keeping the whole image in memory

我编写了一个程序,使用三个方程生成 RGB 颜色值并将它们写入数据文件:

from struct import pack

#User-set variables
size = [16384, 16384]
center = [0, 0]
r_equation = "x ^ y"
g_equation = "x - y"
b_equation = "x + y"
data_path = "data.dat"

#Calculate x and y offset
offset = [center[0] - (size[0] // 2), center[1] - (size[1] // 2)]

#Compile code for calculating RGB values
r_code = compile(r_equation, "r_equation", "eval")
g_code = compile(g_equation, "g_equation", "eval")
b_code = compile(b_equation, "b_equation", "eval")

data_file = open(data_path, "wb")

#Pack image size as first 4 bytes
data_file.write(pack("HH", *size))

#Iterate through the graph
for y in range(offset[1], size[1] + offset[1]):
    for x in range(offset[0], size[0] + offset[0]):
        #Calculate the RGB values
        rgb = [int(eval(r_code)) % 256,
               int(eval(g_code)) % 256,
               int(eval(b_code)) % 256]
        #Pack the RGB values as 3 bytes
        data_file.write(pack("BBB", *rgb))

data_file.close()

我想从数据文件创建图像,但我没有足够的 RAM 来加载整个图像。我写了这个程序来读取文件的片段:

from struct import unpack

#User-set variables
data_path = "data.dat"
image_path = "image.xxx"

data_file = open(data_path, "rb")

#Unpack first 4 bytes to get image size
size = unpack("HH", data_file.read(4))

#create_image(size, image_path)

for data in data_file.read(1048576 * 3): #Read 1M pixels at a time
    #write_to_image(data)

如果我尝试使用 PIL 写入整个图像文件,它很快就会耗尽内存。有没有办法将图像文件分段写入,以便一次在内存中写入一个?

您可以尝试使用这个 python 库: https://github.com/libvips/pyvips

Programs that use pyvips don't manipulate images directly, instead they create pipelines of image processing operations building on a source image. When the end of the pipe is connected to a destination, the whole pipeline executes at once, streaming the image in parallel from source to destination a section at a time.

Vips 使处理大图像成为可能,而且速度非常快。

Because pyvips is parallel, it's quick, and because it doesn't need to keep entire images in memory, it's light.

这是你的程序(我认为!)用 pyvips:

完成
#!/usr/bin/python3

import sys
import pyvips

# make a huge two-band image where each pixel has the value of its (x, y)
# coordinate
xy = pyvips.Image.xyz(16384, 16384)

# subtract the half way point, so each pixel is now -8192 to +8191
xy -= [8192, 8192]

# compute three one-band images from (x, y) ... image[n] gets the nth band
r = xy[0] ^ xy[1]
g = xy[0] + xy[1]
b = xy[0] - xy[1]

# join as an RGB image, modulo 256
rgb = r.bandjoin([g, b]).copy(interpretation="srgb") & 0xff

rgb.write_to_file(sys.argv[1])

在这台普通的笔记本电脑上,我看到:

$ /usr/bin/time -f %M:%e ./pattern.py x.jpg
136712:5.81s

6s 和 137mb 内存。