CreateDibSection on Disk instead of physical memory - c++

I am having a memory issue with an algorithm I am using to "Flatten" a page in a PDF document.
HBITMAP hbmp = CreateDibSection(...);
ThirdPartyBmpManipulation(hbmp, "C:\\file.pdf", 0); //renders page 0 in file.pdf
void * hdib = ConvertBitmap(hbmp); //copy a Dib Section to a Dib
DeleteObject(hbmp); //frees the HBitmap while the Dib is now in memory
The problem is I have a really large bitmap and in some cases I cannot keep the HBitmap in memory while I allocate the DIB to be copied to.
So it is a long shot, but can I somehow allocate the Dib Section on disk and still have an HBITMAP for it? (use the same handle for my ConvertBitmap function)

What is the failure mode? You say "physical memory": windows uses virtual memory, it will page to disk, you don't need to worry about running out of physical memory beyond the performance hit. If you're running out of address space, using the disk may not be able to help you.
However, CreateDIBSection can take a HANDLE to a file mapping (created with CreateFileMapping ). If the internals of the function and related HBITMAP functions are smart enough, it may be possible to avoid exhausting your address space by leveraging that capability. If they are "smart" they will use MapViewOfFile to map relatively small "windows" of the file as needed into your process's address space.

Related

Convert HDC to 32bit bitmap [duplicate]

How could you copy the contents of an HDC to a bitmap?
Off the top of my head I think you need to:
Create a new DC compatible with the source DC. Call this the memory DC.
Create a new bitmap of the correct size.
Select the bitmap into the memory DC.
BitBlt the source DC into the memory DC.
The bitmap should now contain a copy of the source DC.
I'm at home so can't give you any code, so I hope this is enough to get you started. There is a good GDI section on Code Project.
http://www.codeproject.com/KB/graphics/
There is a good piece of sample code here that does just that (amongst other things).
I've used a similar technique before (many moons ago), but do not have the code to hand.

CreateCompatibleBitmap and CreateDIBSection (Memory DC's)

from what I've read here it seems that most of the Windows GDI functions are accelerated. So for instance a call to BitBlt or AlphaBlend uses hardware acceleration if available. It also mentions that the contents of a window are kept only in video memory. Now this is all good and true for a window DC, but how can I use a memory DC that resides in video card memory? And once we've accomplished that how to obtain direct access to the pixels, I think that would involve 1. temporary copying the data to system memory 2. alter the pixel data 3. copy back to video memory.
I've tried two approaches, both allocate system memory as I can see in the task manager...
CreateCompatibleBitmap
HDC hDC = GetDC(NULL);
m_hDC = CreateCompatibleDC(hDC);
m_hBmp = CreateCompatibleBitmap(hDC, cx, cy);
ReleaseDC(NULL, hDC);
m_hOldBmp = (HBITMAP)SelectObject(m_hDC, m_hBmp);
and then call to obtain the bits
GetBitmapBits(...)
according to various comments this should indeed create the compatible bitmap in video memory, but why can I still see an increase in system memory (even when I don't call GetBitmapBits)?
CreateDIBSection
HDC hDC = GetDC(NULL);
m_hDC = CreateCompatibleDC(hDC);
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = cx;
bmi.bmiHeader.biHeight = -cy; // top-down
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
m_hBmp = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&m_pBits, NULL, NULL);
ReleaseDC(NULL, hDC);
m_hOldBmp = (HBITMAP)SelectObject(m_hDC, m_hBmp);
in this case we receive the pointer to the bits immediately (m_pBits) so it's obvious that these reside in system memory...
Or is it a copy that is kept in system memory for both methods? But if I change the bits in system memory a call to BitBlt would still have to check/copy from system memory again... not very optimized IMHO.
EDIT: I've also tried creating memory DC's by using the BeginBufferedPaint and GetBufferedPaintBits. It allocates system memory as well, so in that respect I suppose it's just a wrapper for the above methods but caches the DC's so a next call doesn't necessarily has to recreate a memory DC. See Raymond Chen's article.
EDIT #2: I guess the actual question is: Am I doing the memory DC creation correct in method 1 or 2 to get hardware accelerated GDI operations? To me it all seems fast, and both methods provide the same speed too, so there's not really a way to check it...
Memory DCs are not created on a device. They are designed to put GDI output into memory.
From Memory Device Contexts on MSDN:
To enable applications to place output in memory rather than sending
it to an actual device, use a special device context for bitmap
operations called a memory device context. A memory DC enables the
system to treat a portion of memory as a virtual device.
If you want hardware accelerated 2d graphics, you should consider using Direct2D.

can not draw on GDI+ bitmap object

I am writing program in c++ gdi gdi+.
Drawing large image on gdi+ bitmap is slow is using gdi+ api.
So I used the following way to draw:
Bitmap img(xxx);
Graphics gr(&img);
HDC dc = gr.GetHDC();
::StretchDIBits(
dc,
rec.left, rec.top,
(rec.right - rec.left), (rec.bottom - rec.top),
m_recRegin.left , m_recRegin.top,
m_recRegin.right - m_recRegin.left, m_recRegin.bottom - m_recRegin.top,
XXX, XXX, DIB_RGB_COLORS, SRCCOPY);
gr.ReleaseHDC(dc);
this code run perfectly some time.
But when the system-wide pool is full by creating lots of compatibleDCs with large size of CBitmap. It seems can not draw any thing on the Bitmap.
What happened? when this part of code failed, I can still draw on the graphics using GDI+ APIs
GetLastError() return 8.
Many thanks!
GetLastError() return 8
8 is "Not enough storage is available to process this command."
So you ran out of storage for GDI to use to execute ::StretchDIBits.
In the future, you can lookup Windows errors from the command line with: net helpmsg <error in decimal>.
In addition to what others have said, Graphics objects implement IDisposable. This means they likely (and actually do) hold onto a limited resource. Ensure you are calling "gr.Dispose()" or placing things in a "using" block. Failing to do this will leave it up to the garbage collector to determine when the objects are finalized, and their resources released. That is a bad practice for resource intensive objects-- such as Graphics.
Depending on the size Bitmaps may also be resource hungry as they can eat a lot of RAM. If the bitmaps used in your code sample are never referenced after it, also ensure they're getting disposed of...

Does MemoryDC occupied memory or the memory on video card?

I am using the following code to create a compatible DC:
m_pDC=new CDC();
VERIFY(m_pDC->CreateCompatibleDC(sampleDC);
CBitmap bitmap;
if (bitmap.CreateCompatibleBitmap(sampleDC, rect.Width(), rect.Height()))
{
m_pOldBitmap = m_pDC->SelectObject(&bitmap);
}
My question is does CDC CBitmap occupied memory ?
If it is using memory, why does it get bad result when rect.width and rect.height are large. (There are enough memory).
Someone said it is using memory on video card. Is it true. I am not very sure about it.
Memory in CreateCompatibleBitmap are allocated from a system-wide pool that's typically limited to about 200 Megabytes on 32-bit versions of Windows.
Since WinNT4.0 CreateBitmap() API allocates the bitmap in kernel-mode paged memory. In WinNT4 it was impossible to create bitmaps greater than 48 MB.
What was your limit?

copy hdc contents to bitmap

How could you copy the contents of an HDC to a bitmap?
Off the top of my head I think you need to:
Create a new DC compatible with the source DC. Call this the memory DC.
Create a new bitmap of the correct size.
Select the bitmap into the memory DC.
BitBlt the source DC into the memory DC.
The bitmap should now contain a copy of the source DC.
I'm at home so can't give you any code, so I hope this is enough to get you started. There is a good GDI section on Code Project.
http://www.codeproject.com/KB/graphics/
There is a good piece of sample code here that does just that (amongst other things).
I've used a similar technique before (many moons ago), but do not have the code to hand.