我正在尝试使用 GDI+ 从像素数据创建一个非常大的图像。代码看起来像这样:
Gdiplus::Status CreatePNG(int tileSize, int height = 16 * 1024)
{
Gdiplus::Status status = Gdiplus::Ok;
int width = 1024 * 16;
Gdiplus::Bitmap bitmap(width, height, PixelFormat32bppRGB);
Gdiplus::BitmapData bitmapData;
INT *pixels = new INT[width * tileSize];
ZeroMemory(pixels, width * tileSize * sizeof(INT));
for (int y = 0; y != tileSize; ++y) {
for (int x = 0; x != width; ++x) {
INT color = 0xffff00;
pixels[y * width + x] = color;
}
}
ZeroMemory(&bitmapData, sizeof(bitmapData));
bitmapData.Scan0 = pixels;
bitmapData.Stride = width * sizeof(INT);
bitmapData.Width = width;
bitmapData.Height = tileSize;
bitmapData.PixelFormat = bitmap.GetPixelFormat();
Gdiplus::Rect tile(0, 0, width, tileSize);
status = bitmap.LockBits(&tile, Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf,
bitmap.GetPixelFormat(), &bitmapData);
if (status == Gdiplus::Ok)
status = bitmap.UnlockBits(&bitmapData);
if (status == Gdiplus::Ok) {
CLSID encoderClsid;
if (GetEncoderClsid(L"image/png", &encoderClsid) >= 0) {
status = bitmap.Save(TEXT("big.png"), &encoderClsid);
}
}
return status;
}
换句话说,我创建了一个宽和高均为 16K 像素的位图,并用来自用户输入缓冲区 (Gdiplus::ImageLockModeUserInputBuf) 的黄色像素填充顶部。仅当高度足够小时,此方法才有效:31K 行可以,32K 不行。图像越宽,它就可以越高,所以我认为 256 兆像素存在一些逻辑障碍。
这个限制从何而来?
如何操作更大的图像?
这看起来很可疑:
INT *pixels = new INT[width * tileSize];
当
width*tileSize
都超过 32K 时,您开始接近整数溢出限制。
这个怎么样:
uint64_t uWidth = (unsigned)width;
uint64_t uTileSize = (unsigned)tileSize;
uint64_t totalPixels = uWidth * uTileSize;
INT *pixels = new INT[width * tileSize];
所有这些都假设是 64 位操作系统,并且您编译为 64 位进程。 您无法在 32 位进程上可靠地分配 32Kx32K ARGB 位图,因为那时您将耗尽内存.