有一张非常大的图片一次无法加载到内存中。因为它可能会导致内存不足异常。我需要把这张照片放大到小尺寸。所以我该怎么做?
简单的想法是打开一个输入流,一次处理一个缓冲区大小。但是缩放算法呢?
如果您可以逐行访问图片(例如它是位图),您可以做的最简单的事情就是对其进行下采样,例如仅读取每第 n 行的每第 n 个像素。
// n is an integer that is the downsampling factor
// width, height are the width and height of the original image, in pixels
// down is a new image that is (height/n * width/n) pixels in size
for (y = 0; y < height; y += n) {
row = ... // read row y from original image into a buffer
for (x = 0; x < width; x += n) {
down[y/n, x/n] = row[x]; // image[row,col] -- shorthand for accessing a pixel
}
}
这是一种快速而肮脏的方式,可以快速且廉价地调整原始图像的大小,而无需将整个图像加载到内存中。不幸的是,它还在输出图像中引入了锯齿(下)。处理混叠需要执行插值——仍然可以使用上述逐行方法,但涉及更多。
如果您不能轻松地逐行访问图像,例如它是 JPEG,它将数据编码为 8x8 块,您仍然可以执行类似于我上面描述的方法的操作。您只需读取一行块而不是一行像素 - 算法的其余部分将相同。此外,如果您要进行 8 倍的下采样,那么使用 JPEG 非常容易——您只需获取每个块的 DC 系数。使用这种方法也可以按 8 的倍数进行下采样。
我已经忽略了许多其他细节(例如颜色通道、像素步幅等),但这应该足以让您入门。
有许多不同的大小调整算法,它们提供不同级别的质量,权衡的是 CPU 时间。
我相信使用其中任何一种方法,您都应该能够相对轻松地以块的形式处理大量文件,但是,您可能应该尝试现有工具,看看它们是否已经可以处理大量文件。
我相信 Gd 图形库允许您定义它可以使用多少工作内存,因此它显然已经具有用于处理块文件的逻辑。