|
Hello
Trying to figure out if my POS Epson receipt printer can print bitmaps or not,
using GetDeviceCaps(hDC,RASTERCAPS)on 4 different printers - I get the same result of the returning value = something like 28313
Anything else maybe that I can use?
Cheers
Alex
|
|
|
|
|
Alex,
the function GetDeviceCaps(hDC, RASTERCAPS) does actually not test, if the printer can print bitmaps. It returns an information, that can be tested for certain raster capabilities. So you have to check the return value if the desired bit is set. In my code, i was testing specificly the stretchblit capability with
int iRasterCaps=GetDeviceCaps(pd.hDC,RASTERCAPS);
if ((iRasterCaps&RC_STRETCHBLT)==0) ...
The GetDeviceCaps() function can retrieve diferent device-specific informations, where 'RASTERCAPS' is just one of them.
I think, if you check the TECHNOLOGY feature and then test, if the DT_RASPRINTER bit is set, the printer should be able to print graphics.
So maybe you should try something like:
int iDevCaps=GetDeviceCaps(pd.hDC, TECHNOLOGY);
if (iDevCaps & DT_RASPRINTER)
{
...printer should be able to print graphics
}
I am not 100% shure, maybe you will have to play around a bit with this.
Albert
|
|
|
|
|
Hi Albert
Thanks for that, it seems the right direction. When I tried it however, various printers are reporting back features that are not always delivered...
Thanks again
Alex
|
|
|
|
|
My boss asked me to print the display (which includes a map of North America). Within minutes (using your code)... problem solved.
Thanks for the posting.
Just one thing. I'm printing from a dual screen setup which has a resolution of 1200x3200, so I had to modify the algorithm to print the correct size.
|
|
|
|
|
Thanks for this articol, it's excellent!
I've used it for one application with success.
Now I'm developping another dialog based application and I need to print only a dialog, so I made this change:
.....
wHndle=DialogToPrint->m_hWnd;
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
sizeClient.cx = 400;
sizeClient.cy = 400;
sizeScreen.cx = 400;
sizeScreen.cy = 400;
screenDC.DPtoLP(&sizeScreen);
.....
the problem is the following:
- if the user shift a block of the dialog out of the screen, the application print a piece of dialog with a black column.
I haven't any idea how to print a dialog, can you help me?
Thank in advance
mais
|
|
|
|
|
The only way how i can imagine how to solve this is to force the dialog back to visible area. Here some code which brings back the dialog to the screen center during capture:
I suppose you use "Dialog Capture", so insert into the following section
case 1:
..
..
GetWindowRect(wHndle,&rectClient);
nX = rectClient.left;
nY = rectClient.top;
nX2 = rectClient.right;
nY2 = rectClient.bottom;
<-------insert here the code below!
if (nX < 0) nX = 0;
if (nY < 0) nY = 0;
..
..
the following code:
if ((nX < 0)||(nY < 0)||(nX2 > sizeClient.cx) || (nY2 > sizeClient.cy))
{
HWND hwndOwner;
RECT rc, rcDlg, rcOwner;
hwndOwner = GetDesktopWindow();
GetWindowRect(hwndOwner, &rcOwner);
GetWindowRect(wHndle, &rcDlg);
CopyRect(&rc, &rcOwner);
OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
OffsetRect(&rc, -rc.left, -rc.top);
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
SetWindowPos(wHndle,
HWND_TOP,
rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),
0, 0,
SWP_NOSIZE);
UpdateWindow(wHndle);
GetWindowRect(wHndle,&rectClient);
nX = rectClient.left;
nY = rectClient.top;
nX2 = rectClient.right;
nY2 = rectClient.bottom;
}
Hope that helps,
Albert
|
|
|
|
|
Thanks very much, now my application works correctly!
mais
|
|
|
|
|
When I print the client area in an SDI application I also capture the toolbar, how do I capture the client area without the toolbar?
|
|
|
|
|
The toolbar is part of the client area, so with the this class it is not possible to avoid the capturing of the bar.
It would need a bigger change in the class to implement this, like:
- passing a handle of the toolbar to the DoPrntScreen function (easy)
- retriving the rectangle infos of that window (easy)
- add/subtract point/rectangle coordinates of client and toolbar rectangles, depending orientation of toolbar (tricky)
I can´t look into this for the next 3 months due to project stress, sorry.
Albert
|
|
|
|
|
I have replace the stretchBlt function by the following code ( took from
http://www.codeproject.com/treectrl/prttview.asp )
The DDBToDIB function is defined at http://www.codeguru.com/bitmap/ddb_to_dib.shtml
void CPrntScreen::DoPrntScreen(int fArea, int fOrientation, bool bDialog)
{
CDC screenDC,memDC;
HDC hscreenDC;
HWND wHndle;
CSize sizeClient, sizeScreen;
RECT rectClient;
POINT pt1, pt2;
int nX, nY, nX2, nY2; // coordinates of rectangle to grab
//determine the area of screen to be captured
//-------------------------------------------
switch (fArea)
{
case 0:
//Capture Whole screen
wHndle=NULL;
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
sizeClient.cx = screenDC.GetDeviceCaps(HORZRES);
sizeClient.cy = screenDC.GetDeviceCaps(VERTRES);
sizeScreen.cx = screenDC.GetDeviceCaps(HORZRES);
sizeScreen.cy = screenDC.GetDeviceCaps(VERTRES);
screenDC.DPtoLP(&sizeScreen);
break;
case 1:
//Determine screen size
wHndle=NULL;
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
sizeScreen.cx = screenDC.GetDeviceCaps(HORZRES);
sizeScreen.cy = screenDC.GetDeviceCaps(VERTRES);
screenDC.DPtoLP(&sizeScreen);
screenDC.Detach();
ReleaseDC(wHndle,hscreenDC);
// Get Foreground window
wHndle=GetForegroundWindow();
hscreenDC = ::GetWindowDC(wHndle);
screenDC.Attach(hscreenDC);
// Calculate resolution of capture area (Window)
sizeClient.cx = screenDC.GetDeviceCaps(HORZRES);
sizeClient.cy = screenDC.GetDeviceCaps(VERTRES);
GetWindowRect(wHndle,&rectClient);
nX = rectClient.left;
nY = rectClient.top;
nX2 = rectClient.right;
nY2 = rectClient.bottom;
if (nX < 0) nX = 0;
if (nY < 0) nY = 0;
if (nX2 > sizeClient.cx) nX2 = sizeClient.cx;
if (nY2 > sizeClient.cy) nY2 = sizeClient.cy;
sizeClient.cx = nX2 - nX;
sizeClient.cy = nY2 - nY;
break;
case 2:
//Determine screen size
wHndle=NULL;
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
sizeScreen.cx = screenDC.GetDeviceCaps(HORZRES);
sizeScreen.cy = screenDC.GetDeviceCaps(VERTRES);
screenDC.DPtoLP(&sizeScreen);
screenDC.Detach();
ReleaseDC(wHndle,hscreenDC);
// Get Foreground window - Client area
wHndle=GetForegroundWindow();
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
// Calculate resolution of capture area (Client)
sizeClient.cx = screenDC.GetDeviceCaps(HORZRES);
sizeClient.cy = screenDC.GetDeviceCaps(VERTRES);
GetClientRect(wHndle,&rectClient);
pt1.x = rectClient.left;
pt1.y = rectClient.top;
pt2.x = rectClient.right;
pt2.y = rectClient.bottom;
ClientToScreen(wHndle,&pt1);
ClientToScreen(wHndle,&pt2);
nX = pt1.x;
nY = pt1.y;
nX2 = pt2.x;
nY2 = pt2.y;
if (nX < 0) nX = 0;
if (nY < 0) nY = 0;
if (nX2 > sizeClient.cx) nX2 = sizeClient.cx;
if (nY2 > sizeClient.cy) nY2 = sizeClient.cy;
sizeClient.cx = nX2 - nX;
sizeClient.cy = nY2 - nY;
break;
default:
return;
}
//Screen Capture
CBitmap *oldImage = new CBitmap,srcImage;
memDC.CreateCompatibleDC(&screenDC);
screenDC.DPtoLP(&sizeClient);
srcImage.CreateCompatibleBitmap(&screenDC,sizeClient.cx,sizeClient.cy);
oldImage = memDC.SelectObject(&srcImage);
memDC.PatBlt( 0, 0,sizeClient.cx,sizeClient.cy, WHITENESS);
memDC.BitBlt(0,0,sizeClient.cx,sizeClient.cy,&screenDC,0,0,SRCCOPY);
screenDC.Detach();
ReleaseDC(wHndle,hscreenDC);
// Here starts the printing part
//-------------------------------
PRINTDLG pd;
LPDEVMODE lpDevMode;
CSize sizePrn;
DOCINFO di;
CDC *pDC = new CDC;
memset( &pd, 0, sizeof(PRINTDLG) ) ;
//Fill out PrintDialog structure
pd.lStructSize = sizeof(PRINTDLG);
pd.hDC = NULL;
pd.hwndOwner = NULL;
pd.hInstance = NULL;
pd.nMaxPage = 1;
pd.nMinPage = 1;
pd.nFromPage = 1;
pd.nToPage = 1;
pd.nCopies = 1;
pd.hDevMode = NULL;
pd.hDevNames = NULL;
if (bDialog)
pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
else
pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
//Call PrintDialog
if(PrintDlg(&pd))
{
pDC->Attach(pd.hDC);
//If default printer is used, we adjust orientation
if (!bDialog)
{
//Check Orientation
if ((fOrientation!=DMORIENT_LANDSCAPE)&&(fOrientation!=DMORIENT_PORTRAIT))
fOrientation=DMORIENT_PORTRAIT;
// Adjust desired orientation
lpDevMode = (LPDEVMODE)::GlobalLock(pd.hDevMode);
if(lpDevMode != NULL)
{
lpDevMode->dmOrientation=(short)fOrientation;
pDC->ResetDC(lpDevMode);
::GlobalUnlock(pd.hDevMode);
}
}
// Get page dimensions
sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);
pDC->PatBlt( 0, 0, sizePrn.cx, sizePrn.cy, WHITENESS);
// Set magnitude of stretching (in relation screen to captured area)
// sizePrn.cx = (sizePrn.cx*sizeClient.cx)/sizeScreen.cx;
// sizePrn.cy = (sizePrn.cy*sizeClient.cy)/sizeScreen.cy;
double zoom = sizePrn.cx / sizeClient.cx;
pDC->LPtoDP(&sizePrn);
// Start printing
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "Lizenzen";
di.lpszOutput = (LPTSTR) NULL;
di.lpszDatatype = (LPTSTR) NULL;
di.fwType = 0;
::StartDoc(pd.hDC, &di);
::StartPage(pd.hDC);
//pDC->StretchBlt(0,200,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeClient.cx,sizeClient.cy,SRCCOPY);
// Enlarge and print the Bitmap
//copy the bitmap (Device dependant bitmap or DDB)
//to a Device indepedant bitmap (DIB)
CPalette pal;
HANDLE hDIB = DDBToDIB(srcImage, BI_RGB, &pal );
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER)hDIB;
int nColors = lpbi->biClrUsed ? lpbi->biClrUsed : 1 << lpbi->biBitCount;
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB;
LPVOID lpDIBBits;
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
bmInfo.bmiHeader.biClrUsed) +
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
HDC hDC = pDC->GetSafeHdc();
//copy de DIB to the printer device
//I use DIB rather than DDB because DDB can
//have an unpredicable behavior with network printer !!!!!
StretchDIBits(
hDC, // hDC
0, // DestX
0, // DestY
(int) zoom*sizeClient.cx, // nDestWidth
(int) zoom*sizeClient.cy, // nDestHeight
0, // SrcX
0, // SrcY
sizeClient.cx, // wSrcWidth
sizeClient.cy, // wSrcHeight
lpDIBBits, // lpBits
&bmInfo, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP
::EndPage(pd.hDC);
::EndDoc(pd.hDC);
}
else if ((!bDialog)||(CommDlgExtendedError()!=0))
MessageBox(NULL,_TEXT(sErrortext),_TEXT(sMsgCaption),MB_OK|MB_ICONERROR);
DeleteDC(pd.hDC);
delete pDC;
memDC.SelectObject(oldImage);
}
|
|
|
|
|
Dieter,
Interesting idea. I´m heavily occupied with a project atm, but will look into this as soon as possible. Maybe this can resolve the problem, some of the people are getting with the class.
Thanks
Albert
|
|
|
|
|
Yeah, now it works. No more blank sheets!!!!!!!!
|
|
|
|
|
Thanks for the input.
I had exactly the problem you described. I could print on a couple of local printers, but not on the network printers. After implementing your change everything works as described. I can even print on a large plotter.
Thanks again.
|
|
|
|
|
Hello,
I am sorry that it took so long to react. I have checked and tested Dieter Hammer's code now and it works perfectly on all my available printers. So i am preparing a new, updated version and i will upload it as soon as possible. Huge thanks to Dieter!!!!
This new version will include:
- the code suggested by Dieter Hammer, which should eliminate
that nasty blank page problem
- correct printing dialogs, which were partially pushed out of desktop area
- proportional correct printout, independent of paper orientation
- checking, if printer is actually capable for printing image
Albert
|
|
|
|
|
Hello Albert!
I need realy your help! Send me please (if it is possible) a demo project.
mailto: kaiser@nm.ru
|
|
|
|
|
Demo is on the way, check your mail
Albert
|
|
|
|
|
Just returned on Sunday from my vacancy from Europe and just now (was away
for 6 weeks) i had a chance to see the mess i've created with my last
version. I had uploaded an update/bugfix before i started my trip, but
for some reason, Codeproject doesn´t seem to have received it (maybe mail
probs, who knows). Just sent it yesterday again.
The main problem at the last version was, that the memdc doesn´t
combine with the stretch coordinates. This works on some printers, but not
on all. In the new version (uploaded) i calculate the stretching relation at the printer cap side. That version worked on all printers i had access
(laser and deskjets).
If htere is still a problem i will look into Noels suggestion.
Again, big sorry, hope it works now.
|
|
|
|
|
Maybe the printer isn't capable of performing a StretchBlt(...)
Just test this with:
<code>int iRasterCaps=GetDeviceCaps(pDC,RASTERCAPS)
</code>
|
|
|
|
|
Hi everybody !
I implemented your code to make a hardcopy and it worked - for a moment. At homeOffice (HP Deskjet 930C) it worked 10 time very good.
Now beeing in the Office (HP LaserJet 1200) it works only rarely. Most attemps ends with a blank page.
Is there any Problem with device-depindig bmps ? I would like to print an existing memDC (Mirror-Image to make all drawings, when all is finished it will be displayed to the screen to prevent flickering).
But using this DC and calculationg the size etc. causes a blank sheet too. Are there Problems with sizes etc ? It drives me crazy - I have no idea what to do now
Any help ?
Thanks
Martin L
|
|
|
|
|
I have a Lexmark Optra S 1650, plus a couple of other Lexmark printers I've tried printing on, all I can get so far is just the printers to wind up but I don't even get a blank page, I've also tried every possible print option combination. Any ideas?
I have added the changes you mentioned 2 sizeprn lines and changed the stretchBlt line.
Thanks,
Oscar
|
|
|
|
|
Hi, I'm still a beginner in MFC. I was wandering, where to put the command? Do I have to make another button specially for printing or I can use the default?
I'm trying to understand how to print using MFC.
Thx
|
|
|
|
|
Hi there,
I think it's easy. Below you find that part of my source, that will do what you need.
void OPP::OnRButtonDblClk(UINT nFlags, CPoint point)
{
CPrntScreen * ScrCap;
ScrCap = new CPrntScreen();
ScrCap->DoPrntScreen(2,2,FALSE);
delete ScrCap;
ScrCap = NULL;
COlePropertyPage::OnRButtonDblClk(nFlags, point);
}
As you can see, at my programm I i added an Window-Message for
WM_RBUTTONDBLCK which will call the function above.
Hope that helps,
regrads, Rudolf
|
|
|
|
|
First, I like the simplicity of this. Very good.
I created an MFC Dialog application with a command button to execute the print screen. I used the example code given. Actually I tried both. Everything seems to work, but the page printed is blank. Got any ideas what I am doing wrong?
Jeff Brady
CTO Visual Systems, Inc.
|
|
|
|
|
Sorry, my mail doesn´t work atm, so didn´t see this. No, atm i don´t have an idea, will cross check this tomorrow with the src code from the page, just to be sure. I use this code in two commercial projects without prob, but will see.
til later,
Albert
|
|
|
|
|
Jeff,
you are right, there is a bug in the stretching routine
I didn´t see it, because it does not happen on all printers. I had to go through 7 printers for finding 2 which show the same problem you described.
And it only happens, if dialogs are captured, full screen capture (type 0" work perfectly.
Thanks god, that my application are still in developement and the client didn´t see it either
I think, i found the solution and will upload a revised version.
If you need a quickfix, here is how to:
In the printing section, you will find the following 2 lines:
sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);
add there, just before the
pDC->LPtoDP(&sizePrn);
this two lines:
sizePrn.cx = (sizePrn.cx*sizeClient.cx)/sizeScreen.cx;
sizePrn.cy = (sizePrn.cy*sizeClient.cy)/sizeScreen.cy;
so that you get a:
sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);
sizePrn.cx = (sizePrn.cx*sizeClient.cx)/sizeScreen.cx;
sizePrn.cy = (sizePrn.cy*sizeClient.cy)/sizeScreen.cy;
pDC->LPtoDP(&sizePrn);
Change the line:
pDC->StretchBlt(0,0,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeScreen.cx,sizeScreen.cy,SRCCOPY);
to:
pDC->StretchBlt(0,0,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeClient.cx,sizeClient.cy,SRCCOPY);
That should do it!
|
|
|
|
|