tags:

views:

2165

answers:

5

I'd like to be able to create a large (say 20,000 x 20,000) pixel bitmap in a C++ MFC application, using a CDC derived class to write to the bitmap. I've tried using memory DCs as described in the MSDN docs, but these appear to be restricted to sizes compatible with the current display driver.

I'm currently using a bitmap print driver to do the job, but it is extremely slow and uses very large amounts of intermediate storage due to spooling GDI information.

The solution I'm looking for should not involve metafiles or spooling, as the model that I am drawing takes many millions of GDI calls to render.

I could use a divide and conquer approach via multiple memory DCs, but it seems like a pretty cumborsome and inelegant technique.

any thoughts?

+1  A: 

This is unusual as I often created a DC based on the screen that will be used for a bitmap image that is much larger than the screen - 3000 pixels plus in some cases - with no problems at all. Do you have some sample code showing this problem in action?

Rob
+2  A: 

CDC and CBitmap appears to only support device dependant bitmaps, you might have more luck creating your bitmap with ::CreateDIBSection, then attaching a CBitmap to that. The raw GDI interfaces are a little hoary, unfortunately.

You probably won't have much luck with 20,000 x 20,000 at 32 BPP, at least in a 32-bit application, as that comes out at about 1.5 GB of memory, but I got a valid HBITMAP back with 16 bpp:

BITMAPINFOHEADER bmi = { sizeof(bmi) };
bmi.biWidth = 20000;
bmi.biHeight = 20000;
bmi.biPlanes = 1;
bmi.biBitCount = 16;
HDC hdc = CreateCompatibleDC(NULL);
BYTE* pbData = 0;
HBITMAP hbm = CreateDIBSection(hdc, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, (void**)&pbData, NULL, 0);
DeleteObject(SelectObject(hdc, hbm));
Simon Buchan
Thanks Simon, just what I'm after. I'm at 8 bits per pixel so should be ok on this.
Shane MacLaughlin
+1  A: 

Considering such a big image resolution, you cannot create the image using compatible bitmaps.

Example:

pixel depth = 32 bits = 4 bytes per pixel

pixel count = 20.000 * 20.000 = 400.000.000

total bytes = pixel count * 4 = 1.600.000.000 bytes = 1.562.500 kb ~= 1525 MB ~= 1.5GB

I'm speculating about the final intentions, but suppose you want to create and allow users to explore an immense map with very detailed zooms. You should create a custom image file format; you can put inside that file various layers containing grids of bitmaps for example, to speedup rendering. The render process can use GDI DIBs or GDI+ to create partial images and then render them together. Of course this need some experimenting/optimizing to reach the perfect user feeling.

good luck

xoreax
Or use SVG, of course :)
Simon Buchan
xoreax, quite right about the size, and spot on with the mapping application. Color depth is a palletized 8 bits, which comes in at a bit less than 400mb for a raw bitmap, much smaller as a JPEG. Simon, your CreateDIB answer did the trick for now. I'll check out SVG later.
Shane MacLaughlin
A: 

If the image has to be this resolution - say a hi-res scan of an x-ray - then you might want to look at writing custom spooling routines for it - 1.5 gb is very expensive - even for modern desktops.

If it is vector based then you can look at SVG as it supports view ports and most allow you to render to other formats. I use SVG to JPG via Batik (java) so it is possible to do.

graham.reeds
+1  A: 

To keep your memory usage within acceptable limits, you'll have to use your 'divide and conquer' strategy. It's not a hack, if implemented right it's actually a very elegant way of dealing with bitmaps of unlimited size. If you design it right, you can combine the 'only render/show part of the image', 'render the whole image at low resolution for on-screen display' and 'render the whole thing to an on-disk bitmap' approaches in one engine and shield users of your code (most likely yourself in two weeks ;) ) from the internals. I work on a product with the same issues: rendering (potentially large) maps either to the screen or to .bmp files.

Roel
Thanks, Roel. I think a divide and conquer combined with Simon's large bitmap code is a good long term solution. Probably using a rolling vertical scan, a biggish buffer, and flush and repeat when and if the buffer is exhausted.
Shane MacLaughlin