Solved

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

Posted on 2008-06-13
5
868 Views
Last Modified: 2013-12-04
Hi
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)?
thanks!
0
Comment
Question by:vsee
  • 2
5 Comments
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
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.
0
 

Author Comment

by:vsee
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!
0
 
LVL 39

Accepted Solution

by:
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?
0

Featured Post

Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Better understanding on C++ Class serialization and formats 9 86
c++ syntax question 9 58
Using MS Code on my Mac 6 72
Why isn't object file created? 6 92
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…
With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

733 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