Improve company productivity with a Business Account.Sign Up


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

Posted on 2008-06-13
Medium Priority
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 1000 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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

595 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