If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register or Login
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Unable to implement DIB printing with GDI (MFC)

MFC doc/view architecture, GDI drawing/printing. I have a DIB backbuffer I need to display and print.

After the long and painful road I came to the conclusion than I need to use DIB created with CreateDIBSection (rather than DDB created with CreateCompatibleBitmap), and I have to blit it onto printer dc with StretchDIBits (rather than StretchBlt).

The problem is, the commented-out code of StretchBlt works flawlessly (except printing on some printers), but I can't use it because some printers have troubles with it. So I have to use StretchDIBits. Note that I firstly unselect the DIB from its memory dc temporarily, so that it is not associated with any dc. Then I use StretchDIBits but things just don't work! Output is messed up, like I give incorrect coordinates, areas are drawn off-set from where they should be drawn, and sometimes totally black. So I must be missing something (maybe something very trivial). Help! I tried changing signs of rectClipBoxBackBuffer.top and bitmapInfo.bmiHeader.biHeight, the results change, but nothing works like it should.

What am I doing wrong??

Last edited by TX_; January 28th, 2012 at 01:15 PM.
Reason: Formatting

Re: Unable to implement DIB printing with GDI (MFC)

1) Use code tags when posting code. The code you posted is practically unreadable, so I won't comment on it fully. Code tags allows code to appear formatted and readable. Example:

Code:

void foo()
{
int x = 1;
int y = 2;
}

Note how that code is indented and formatted.

2) You should be checking the return values from those MFC/API functions you're calling. If those functions are returning error codes to you, your program should be processing those errors. Instead, you assume that all of those functions return success and proceed as if nothing is wrong. This is especially the case if you are targeting your code to systems that you have no idea what printers they may be using.

I once had to overhaul an entire code base because the code looked like yours -- no or very minimal error checking and assumptions that functions just "work". What wound up happening is crashes, black printout, and other weird behaviour, all because error return codes were not checked.

Variables with underscores are (private) member variables, declared like this:

3) You should not be starting your variable names with underscores. Names with underscores are reserved for the compiler implementation. There is a chance that name you started with underscores conflicts with a macro, function, constant, or other entity that the compiler has reserved for itself.

4)

The problem is, the commented-out code of StretchBlt works flawlessly (except printing on some printers), but I can't use it because some printers have troubles with it. So I have to use StretchDIBits

GDI functions are highly device dependent. What works with one device does not necessarily work with another. You can check device capabilities before calling any GDI function by calling GetDeviceCaps():

Then you can adjust your code, knowing exactly the capabilities of the device you're writing to.

5) If this code is repeatedly called, then you are slowing down your program doing this:

Code:

_pMemDc = new CDC;

If the device context is deleted at the end of that code, then there is no need to call the allocator to create one. Just create one on the stack and let the destructor do the work of clean up. Otherwise, your code looks like it has a resource/memory leak (and performs slower than it should due to calling the allocator/deallocator functions):

Code:

CDC pMemDc;
//..

What am I doing wrong??

Start with suggestion number 2 -- check for error return codes. Also code that prints using GDI is prevalent in numerous places on the web. Have you tried some simple examples first to see if they work?

Re: Unable to implement DIB printing with GDI (MFC)

Thanks for the reply

Now my answers:

1) I did not find code tags when posting. Maybe I wasn't searching well enough. Anyway, now I'm unable to edit post, but next time I'll try to find the button that inserts code tags. Or is there only textual keyword available (which one?) for that?

2) I usually do check return values, but for simplicity I ommited the relevant code fragments. What matters for the sake of this discussion is that none of the used APIs fail. They all return success values.

3) I find underscores more convenient than "m_" prefix, and I always use qualified names for variables so that collision chance is near zero. Plus this convention is better compatible with my C# coding style. It is only the matter of taste, I think.

4) (pDC->GetDeviceCaps(RASTERCAPS) & RC_STRETCHBLT) is true so with device capabilities everything's all right.

5) No, that code is not called repeatedly. As I said: it belongs to "initialization routine". It has corresponding cleanup routine so there are no memory leaks. The reason I create object on heap is that in some circumstances I might want to delete it before parent object is destructed, so the logic is correct here. Anyway, this is not really relevant for this discussion.

Re: Unable to implement DIB printing with GDI (MFC)

...
Anyway, now I'm unable to edit post, but next time I'll try to find the button that inserts code tags. Or is there only textual keyword available (which one?) for that?

You will be able to edit your posts after about 5-th post.

Originally Posted by TX_

3) I find underscores more convenient than "m_" prefix, and I always use qualified names for variables so that collision chance is near zero. Plus this convention is better compatible with my C# coding style. It is only the matter of taste, I think

Please, reread what Paul wrote you about underscores and C++ compiler. Note that C# compiler is not the same as C++ compiler.

Re: Unable to implement DIB printing with GDI (MFC)

Originally Posted by TX_;20523433)

It is only the matter of taste, I think.

Not in this case. C++ is not C#.

C++ has rules as described by ANSI/ISO. One of those rules specifies that names, variables, macros, etc. that start with underscores are reserved for the compiler implementation. Otherwise if you start your names with underscores, you risk messing up the implementation in some way, either with weird compilation errors, or worse, your program compiles but the program doesn't behave correctly.

Re: Unable to implement DIB printing with GDI (MFC)

I was (and still am) in a hurry because I have to solve this problem ASAP. I registered just now to post this question, and I didn't have the time to read it. I promise I'll do it now.

Originally Posted by VictorN

You will be able to edit your posts after about 5-th post.

Good

Originally Posted by VictorN

Please, reread what Paul wrote you about underscores and C++ compiler. Note that C# compiler is not the same as C++ compiler.

I understand this perfectly clear sir. Maybe more clear than 95% of C++ developers, because I have kinda lowest level understanding of this area. But still I manage to use that convention without much problems, and the readability effect justifies the small risk for me. So, in hands of established developers, such things are really the matter of taste, I believe, rather than hard-coded axiom.

BUT... It does not print on physical printers! Let me start from beginning: In the beginning I used StretchBlt, which worked well for screen drawing, print preview, and printing on virtual (pdf) printers. But it was not working on actual printers. Then I tried to change my code to use StretchDIBits but I was failing until now. As I'm posting this now, I found the solution for StretchDIBits so that it works well for screen drawing and print preview, but oddly, it still is not working for actual printing, just like StretchBlt!

By "not working" I mean the following: it returns success code, but draws incorrect parts of the image buffer: sometimes it prints first few pages repeatedly (not matter what pages I select), sometimes it prints black pages. The strangest thing here is that print preview is working like it should! So if I had messed up coordinate calculation (like one would suspect seeing the results), print preview should be failing as well.

More info:

I have a large backbuffer, one big DIB, say 5000x3000. I divide this to pages, say 4 pages a row, 3 rows - 12 pages in total. Now when I print only 2nd page, it prints well. When I print 5th page only, it prints all black page. When I print, say, 6th page only, it prints 2nd page. And when I select to print whole range (1-12) it repeatedly prints first four pages - the pages that are in first row. I don't know if there is any coincidence, or there is any pattern. Again, anyone would suspect that I calculate page coordinates incorrectly, but how the hell is print preview always working fine!

StretchBlt and now StretchDIBits both fail. Now I tried stretching to another memory bitmap, and then using BitBlt and it succeeded - all pages print like they should. But due to two blitting operations for each page, process is slow (this is noticeable on print preview). Plus additional buffer is required which increases memory consumption. I'd like to avoid this. But I can't get either of StretchBlt and StretchDIBits to print!

Re: Unable to implement DIB printing with GDI (MFC)

I know it's a big favor to ask, but it would be very much appreciated if someone could code for me small example, that creates DIB (with CreateDIBSection), selects it into memory DC, draws something (say single rectangle or circle) on it, and then blits that DIB onto printer page using StretchDIBits, so that it works on actual printers, and with big DIBs. I'd be grateful till death

Re: Unable to implement DIB printing with GDI (MFC)

So, I guess, I can use php tag for C++ too? I find it more pleasing to the eye

We are the ones looking at your code. The least you can do is follow well-established protocol by just using code tags. There is no need to have every odd symbol in C++ lit up like a Christmas tree.

As to your problem with big DIBs -- I remember solving this by implementing something called "banding" or "banded printing", however this was a long time ago, so I can't go into specific details. Banding meant you read one or more raster rows of image data at a time, and send those rows to the printer using StretchDIBits. Then you loop for all the rows. This also allowed you to write your printing routines in a way so that if you sent a large bitmap to the printer, the user can (via your program) stop the print process (in this case, each iteration of the for loop would check if your "stop printing button" or some other indicator was activated).

Here is a link to a book article and source code. Yes the article is old, but this is how I remember doing this type of work (again, many years ago).