I'm trying to create a very big image from pixel data, using GDI+. The code looks something like this:
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;
}
In other words, I create a bitmap that's 16K pixels wide and tall, and fill the top with yellow pixels from a user input buffer (Gdiplus::ImageLockModeUserInputBuf).
This works only as long as height is small enough: 31K lines is okay, more than 32K results in bitmap.LockBits returning Gdiplus::InvalidParameter. The wider the image, the taller it can be, so I assume there is some logical barrier at 256 megapixels.
Where does that limit come from? I have not found any mention of it in the documentation.
How can I manipulate an image that's bigger?
I'm building a 32 bit application, but the same problem seems to exist when I target 64 bits.