How to wrap an existing memory buffer as a DC for GDI

Posted on 2008-06-13
Last Modified: 2013-12-04
I have a memory buffer corresponding to my screen resolution (1280x800 at 24-bits-per-pixel) that contains my screen contents at 24bpp. I want to convert this to 8-bpp (ie. Halftone color palette in Windows).
I currently do this:
1. Use CreateDIBSection to allocate a new 1280x800 24-bpp buffer and access it as a DC, as well as a plain memory buffer
2. Use memcpy to copy from my original buffer to this new buffer from step 1
3. Use BitBlt to let GDI perform the color conversion

I want to avoid the extra memcpy of step 2. To do this, I can think of two approaches:

a. Wrap my original mem buf in a DC to perform BitBlt directly from it

b. Write my own 24-bpp to 8-bpp color conversion. I can't find any info on how Windows implements this halftone color conversion. Besides even if I find out, I won't be using the accelerated features of GDI that BitBlt has access to.

So how do I do either (a) or (b)?
Question by:vsee
  • 2
LVL 39

Expert Comment

ID: 21789166
To (1)

Here is an excerpt from MSDN regarding your issue
Managing Graphics
Whenever possible be sure to use PolyTextOut, PolyPolyline, PolylineTo, PolyDraw, PolyBezier, and PolyBezierTo functions. These functions exploit the fact that many drawing calls use identical attributes, and so multiple items can be drawn in a single call once the brushes, pens, colors, and fonts have been selected. For example, the console window uses PolyTextOut. This change reduced scrolling time in a console window by 30% when it was implemented during the development of Windows NT.

If you are writing an application that draws on the display, then theCreateDIBSection function can improve performance. This function allows you to share a memory section directly with the system, and thus avoid having it copied from your process to the system each time there is a change. Previously, a common practice was to call theGetDIBits function, make the required changes, then call theSetDIBits function. These steps were often repeated on different scan lines of the bitmap before the image was ready for updating. Using CreateDIBSection is much simpler.

One word of caution if you decide to use CreateDIBSection. You need to be sure that any calls that might affect your bitmap have completed before you start to draw in it. This is because the batching of GDI calls may cause their delayed execution. For example, suppose you make aPatBlt call to clear your bitmap, then you start to change the bits in your DIB section. If the PatBlt call was batched, it might not actually execute until after you start to make the bitmap changes. So, before you make changes to your DIB section, be sure to callGdiFlush if you have made changes to the bitmap with earlier GDI calls.

You see the CreateDIBSection is to make it faster (not slower as your question seem to imply). You could make the CreateDIBSection not allocating new memory by passing a handle to 'shared memory' allocated by CreateFileMapping. You actually wouldn't need a 'file' for this function but  could create memory only (you get a pointer to that memory by calling MapViewOfFile).
>>>> I can't find any info on how Windows implements this halftone color conversion.
Hmm. Any 8bpp color conversion was using a color palette. So, you could use 256 colors (8bit) out of 24-bit (16 millions) colors. But I don't know whether these colors are sufficient for that you want to do.

Author Comment

ID: 21818425
Hi itsme...
Thanks for your reply!
I didn't mean to imply CreateDIBSection is slow in general, it's certainly faster than GetDIBits/SetDIBits.
But for my purpose, as mentioned in original posting, there is an extra memcpy I'm seeking to avoid.

Could you give details of how to use CreateDIBSection with CreateFileMapping/MapViewOfFile. I'm new to memory-mapping and file-mapping, sorry. Remember, I aready have existing memory which I'm not free to create wherever convenient (It comes from another process, I can only read/write to it, not change its location).
thanks again!
LVL 39

Accepted Solution

itsmeandnobodyelse earned 250 total points
ID: 21819679
>>>> Remember, I aready have existing memory
The memory you have is local memory accessible only in the (virtual) address space of your process and its thread. GDI cannot use it as it runs in a different address space. Hence, the only way to 'share' memory with GDI is to use the *same* global memory which individually was mapped to the local address space. So the general steps would be

1. call   CreateFileMapping with a unique name for the memory you want to reserve

gives a handle to a shared (global) memory region. Any process can get a handle as well by using the same name.

2. call MapViewOfFile to get a (local) pointer to the shared memory

The pointer points to an address in your local address space where the shared memory was mapped to

3. Use that pointer for storing the bitmap of your screen

4. Use the handle of the shared memory to force GDI to use the same memory

>>>> Could you give details of how to use CreateDIBSection with CreateFileMapping/MapViewOfFile

    /* allocate a segment of the swap file for shared memory 2*Size of ini file */    
    if (!(hMMFile = CreateFileMapping ((HANDLE)0xffffffff,    NULL,    PAGE_READWRITE,    0,    nFileSize * 2,    szMapFileName)))
           return FALSE;    
    /* map a view of this file for writing */    
     lpMMFile = (char *)MapViewOfFile (hMMFile, FILE_MAP_WRITE, 0, 0, 0);  

     unsigned char* pBits = NULL;
     HBITMAP hbmp = CreateDIBSection(hdc, pbmi,  DIB_PAL_COLORS, &pBits, hMMFile, 0);

Note, because of the handle to the shared memory you pass to CreateDIBSection, the returned pointer in pBits would point to the shared memory you provided, same as the lpMMFile pointer.

>>>> there is an extra memcpy I'm seeking to avoid.
That is not quite clear for me. The purpose of CreateDIBSection is to provide an allocation for a new bitmap associated to a DC. So, after calling CreateDIBSection the bits are empty and you have to copy an existing bitmap somehow to the memory. I can't see a way how you could force CreateDIBSection to not initialize the buffer but taking the contents you already had copied/set before. Why not simply change the order: first call CreateDIBSection, then get your screenshot and use the memory  CreateDIBSection has allocated?

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Vb.Net Loading Word 11 98
VS2015 compilation and missing DLLs 9 114
wordpress limitations 4 103
Why isn't object file created? 6 39
When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

937 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now