BitBlt issues with Memory DC created from printer DC - c++

i have an issue with a fix i made to allow a flood filled object be printed...
so, the full story is we were using the windows GDI FloodFill function, which we noticed doesnt work on printers, so what i found on the inet, was to create a memory DC, compatible with the printer DC, and make all my drawing operations on the memory DC, and then BitBlt it all at once to the printer DC (i had to change to use a recursive, color replacment flood fill function too, since the memory DC only allows what the main DC did)
the problem is the memory DC seems to be a pixel or two bigger on the x and y, but i dont know what to do, when i get the selected bitmap from the memory DC, it shows it to be the correct size, i would like to use StretchBlt, but the values i have access to use as params for StretchBlt, make it no different than calling BitBlt
let me know if you need more info...
thanks in advance!!!
heres my code:
HDC hMemPrnDC = CreateCompatibleDC (hPrnDC);
HBITMAP hBitmap = CreateCompatibleBitmap (hPrnDC, iWidthLP, iHeightLP);
HBITMAP hOldBitmap = SelectBitmap (hMemPrnDC, hBitmap);
// paint the whole memory DC with the window color
HBRUSH hBrush = CreateSolidBrush (GetSysColor (COLOR_WINDOW));
RECT rect;
// add one to right and bottom, FillRect doesnt include the right and bottom edges
SetRect (&rect, 0, 0, iWidthLP + 1, iHeightLP + 1);
// NOTE: im doing this cause it starts out as all black
FillRect (hMemPrnDC, &rect, hBrush);
// delete object
DeleteBrush (hBrush);
//
// do all my MoveToEx, LineTo, Ellipse, Arc, TextOut,
// SetPixel, etc calls on hMemPrnDC here
//
// copy all the memory DC drawing data to the printer DC
BitBlt (hPrnDC, 0, 0, iWidthLP, iHeightLP, hMemPrnDC, 0, 0, SRCCOPY);
// select old bitmap, and clean up objects
SelectBitmap (hMemPrnDC, hOldBitmap);
DeleteBitmap (hBitmap);
DeleteDC (hMemPrnDC);
hMemPrnDC = NULL;
UPDATE (Sept 5):
here is a link to a PDF print where I draw straight to the printer DC:
hPrnDC.pdf
and here is the same but I draw to the memory DC then BitBlt it to the printer DC:
hMemPrnDC.pdf
now, I did enable my recursive flood fill function on the second, to show an example of what we are trying to achieve, it does the same without it, so that is not an issue
as you can see, the bottom and right edge are cut off, I'm also concerned about the differences in font & line weight between the two, but not as much as the sizing mismatch
NOTE: the filename printed at the top doesn't go through the memory DC, that is always drawn straight to the printer DC

I found a solution to my problem, more of a work-around, but it achieved the desired results...
I only used the memory DC as a go between on the items that needed the recursive flood fill (GetPixel and SetPixel), so I draw them first to the memory DC, copy it all over to the printer DC and then draw everything else straight to the printer DC, seems to work just fine
thanks for the help!

Related

BitBlit/Copy from D2D1DeviceContext target D2D1Bitmap1 to HDC

For a past few days I was looking for an option to use DirectX 2D in a pattern where I can render to 'something' and then this 'something' - use as input to other drawing.
All of RenderTargets like Hwnd, Dc, Wic bitmap - does not allow to do it (Wic target does not use HW acceleration).
Only one way I found is D2D1DeviceContext
M$ document
There I can create ID2D1Bitmap1 (which also, when created with CPU_READ flag - can be mapped and read) which can be set as target.
So far - so good, all is working fine.
However, at the end, we all want to display the result of drawing onto a user screen and for this purpose - we need to pass it to some WinAPI DC.
I've done it this way.
Create ID2D1Bitmap1 with GDI compatibility
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)
);
Get from ID2D1DeviceContext - ID2D1GdiInteropRenderTarget
_d2d1context->QueryInterface(IID_PPV_ARGS(&_d2d1GDIinterface))
And finally - using this interface, I get DC and use GDI function BitBlt
void paste_bitmap_into_dc(HDC dc, ID2D1Bitmap& bitmap) {
_d2d1context->SetTarget(&bitmap);
_d2d1context->BeginDraw();
HDC new_dc;
_d2d1GDIinterface->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &new_dc);
BitBlt(dc, 0, 0, bitmap.size().x, bitmap.size().y, new_dc, 0, 0, SRCCOPY);
RECT update_rect;
SetRect(&update_rect, 0, 0, 0, 0); // i don't want to actually update bitmap on ID2D1DeviceContext
_d2d1GDIinterface->ReleaseDC(&update_rect);
_d2d1context->EndDraw();
}
That works but I'm not sure that this is a proper (fastest) way, since there is DC created and its coppied twice (hopefuly - on HW side): from target ID2D1Bitmap to this new DC and then from new DC to input DC.
And actually this method is more for drawing with GDI on D2D1 content (ReleaceDC have argument which part of bitmap to update).
Someone could help/confirm this is the way?
Thanks in advance!

Saving a large-size picture in a small-size window

I am new to MFC. Now I have the following question:
I have a large-size picture (e.g. size of 2000*2000) display in a small-size window (e.g. size of 640*480). No wonder that the picture cannot show itself fully without zooming out. I know I can save the original picture without losing any pixel if the picture can fit into the window, however, I cannot do this at this time:
CClientDC SHDC(this); //"this" is a CMDIChildWnd derived class
CDC memDC;
CRect rect;
GetClientRect(&rect);
memDC.CreateCompatibleDC(&SHDC);
CBitmap bm;
int uWidth = rect.Width();
int uHeight = rect.Height();
bm.CreateCompatibleBitmap(&SHDC, uWidth, uHeight);
CBitmap *pOld = memDC.SelectObject(&bm);
memDC.BitBlt(0, 0, uWidth, uHeight, &SHDC, 0, 0, SRCCOPY);
......
The saved picture only show the client area, but I would like to get all of the picture saved.
Anyone who can help me? Thanks in advance.
Xi
Instead of BitBlt try StretchBlt. It'll handle the shrinking for you.
The StretchBlt function copies a bitmap from a source rectangle into a
destination rectangle, stretching or compressing the bitmap to fit the
dimensions of the destination rectangle, if necessary. The system
stretches or compresses the bitmap according to the stretching mode
currently set in the destination device context.
If you want higher quality stretching/shrinking look at GDI+. There's a variety of interpolation modes you can use. More info here:
http://msdn.microsoft.com/en-us/library/k0fsyd4e.aspx

Copy contents of one DeviceContext to another DeviceContext

I've never done any GDI programming and despite taking several shots in the dark and searching the documentation I haven't found the correct way to do copy the contents of one DC to another DC.
The code I have at the moment is below. I don't understand why it's not working (the window remains just remains blank after creation).
SIZE srcSize;
// ... Get size of source DC
HDC destDC = ...; // from GetDC(myWindow), myWindow was
// sized before this to properly contain source
HDC sourceDC = ...;
HBITMAP buffer = CreateCompatibleBitmap(sourceDC, srcSize.cx, srcSize.cy);
HGDIOBJ oldObj = SelectObject(destDC, buffer);
BitBlt(destDC, 0, 0, srcSize.cx, srcSize.cy, sourceDC, 0, 0, SRCCOPY);
SelectObject(destDC, oldObj);
DeleteObject(buffer);
//... ReleaseDC()s here
What's the proper way this is done?
The only thing necessary to copy from one DC to another is a BitBlt. Code that works is below.
SIZE srcSize;
// ... Get size of source DC
HDC destDC = ...; // from GetDC(myWindow), myWindow was
// sized before this to properly contain source
HDC sourceDC = ...;
BitBlt(destDC, 0, 0, srcSize.cx, srcSize.cy, sourceDC, 0, 0, SRCCOPY);
//... ReleaseDC()s here
It's not very clear to me what you are trying to do. First off, why create the new bitmap and select it into the window (sorry, "client area") DC? All you want is paint/draw the window, isn't it? This is not needed then. The destDC is exactly the window's client area surface.
Does sourceDC really contain anything? For example, does it have a bitmap slected into it?
And of course, you SHOULD process WM_PAINT. If you process this message the window is validated, and you are not required to validate it explicitly. Using GetDC()/ReleaseDC() is called "drawing", as opposed to "painting". In an application I made in the past I had to use both methods, painting (processing WM_PAINT) for responding to resizing, exiting from minimized state and bringing the window to foreground (if previously obscured by another) and drawing, for making certain changes immediately visible (instead of invalidating the window and waiting for the application to nearly enter the idle state first - pls note that WM_PAINT is a low-priority message).
Hope this helps

GDI+ only draws monochrome on memory DC

I'm trying to do some double buffering in an MFC application and trying to draw on the memory DC with GDI+. However, although I called CreateCompatibleDC(), I'm only getting a monochrome image. Here is the code:
CDC bufferDC;
CBitmap bufferBitmap;
bufferDC.CreateCompatibleDC(&dc);
bufferBitmap.CreateCompatibleBitmap(&bufferDC, 300, 300);
bufferDC.SelectObject(bufferBitmap);
Graphics g(bufferDC);
g.Clear(Color::Green);
dc.BitBlt(0, 0, 300, 300, &bufferDC, 0, 0, SRCCOPY);
Instead of a green patch, I see a rectangle of dithered black and white dots. I even tried to save the bitmap to disk after the g.Clear() call. It is indeed a 1-bit depth file.
Any ideas what went wrong? Thanks.
A common mistake. A memory DC takes on the properties of the bitmap selected into it, no matter what compatibility it was created with. The default bitmap selected into a DC is monochrome. If you create a bitmap compatible with that DC, it will be monochrome too.
Create the bitmap to be compatible with the original DC, not the memory DC.
Both the bitnmap and the bufferDC should be compatible with dc (whatever device it refers to), not the bitmap compatible ... with its own DC.
Try to give &dc to CreateCopmpatibleBitmap.
Your code snippet does not show where the dc variable comes from. ThIs guy probably contains a monochrome bitmap, the default. You dont need it anyway. Instead, pass NULL to CreateCompatibleDC and it will be the same format as your display, which is probably color.

How to Convert a gdi+ Bitmap-like struct into an HDC?

How to Convert a Bitmap-like struct into an HDC?
I am now writting image processing program in c++, gdi.
If I got a HDC.
I can draw whatever I like on the HDC in gdi by the following code.
// HDC is handy.
HDC dc;
dc.DrawXXX // I can draw using gdi method.
Graphics gr(dc); // now I can also draw on the dc using gdi+ method.
My Application is based on FreeImage.
I make of fipImage. ( use data struct like Bitmap )
However if I want to draw on fipWinImage, now I have to copy fipWinImageto Bitmap, then draw on the Bitmap, and finally convert the bitmap into fipImage again, which is time comsuming and memory comsuming.
Convert fipImage to Bitmap -> Draw on the bitmap -> convert bitmap to fipWinImage
fipWinImage imagefip;
Bitmap* tempImg = new Bitmap(imagefip->GetWidth(), imagefip.GetHeigt(), PixelFormat24bppRGB); // memory comsuming is image is large
Graphics *pGr = Graphics::FromImage(tempImg);
HDC dc = pGr->GetHDC();
RECT rec;
rec.left = 0;
rec.top = 0;
rec.right = imagefip.GetWidth();
rec.bottom = imagefip.GetHeight();
fipImage.draw(dc, rec); // using stretchdibits()
pGr->ReleaseHDC(dc);
Graphics gr(tempImg);
HDC dc = gr.GetHDC(); // Get an Hdc, draw using gdi method
gr.ReleaseHDC(tempDC); //
gr.drawXXX // Draw using gdi+ method.
fipWinImage fipImg; // final result fipWinImage.
HBITMAP temp;
Color color;
tempImg->GetHBITMAP(color, &temp);
fipImg->copyFromBitmap(temp);
I want to construct a HDC directly from fipImage. and draw directly on fipWinImage
How can I do this?
First a few clarifications:
A Device Context is basically a structure that remembers things like foreground and background colors, brushes, font info, and the physical drawing surface (bitmap).
This is a handy thing, so that you don't have to keep specifying all of these things when you're doing one graphics operation after another. You can also pass all of these settings around more easily this way. That's all that a DC really is - just a collection of drawing parameters, including the surface to draw upon.
An "HDC" is just a handle (reference) to one of these structs. Being a "Handle" lets window move the struct around in memory to manage free space without your pointers to it getting messed up.
If you have access to the source code for the library you're using, examine the fipWinImage::draw(...) method. If they're using StretchDIBits, then they must get their raw bitmap data into a compatible format at some point. It's also possible that the fipWinImage class is wrapping an underlying BITMAP or DIB, etc.
The final step to getting your own HDC...
A bitmap is "SELECTED" into a device context, and can only be selected into a single DC at one time. If you can get the internal HBITMAP from fipWinImage, you can select it into another DC (assuming that it isn't still selected into another HC).
When you create a DC, windows automatically creates a 1x1 bitmap for it (since a DC must have a selected bitmap at all times). When you select in a new bitmap, you get the handle to the previously selected bitmap returned to you. Hang on to that, because you're going to need to put it back when you're done.
Hope that helps.
I don't know FreeImage, but if you can get a pointer to the actual pixel data (DIB section) out of it, you could just create a HBITMAP that shares it without having to copy the data every time.