Click here to Skip to main content
15,887,746 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have written following code. It is printing a blank document. I think there is something wrong with image loading or attachment with context

C++
LPTSTR    lpszDevice = TEXT("Datacard Printer");
    HDC hCardDC  = NULL;
    HDC localDC;
    HBITMAP hOld;

    BITMAP  bm;

    LPTSTR szFileName = "C://Front.bmp";
    HBITMAP phBitmap;  

   phBitmap = (HBITMAP)LoadImage( NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );

   if( phBitmap == NULL )
   {   
    DWORD error  = GetLastError();

    return -1;
   } 

    GetObject(phBitmap, sizeof(BITMAP), &bm );  
    hCardDC = CreateDC(NULL, lpszDevice, NULL, NULL);   
    localDC=CreateCompatibleDC(hCardDC);     

    hOld = (HBITMAP)::SelectObject(localDC,phBitmap);
    BOOL qRetBlit = ::BitBlt(hCardDC,0,0,924,624,localDC,0,0,SRCCOPY);


If i replace image loading code with textout("Test String") then it prints well.

Option 2
=========
I tried another option. Here Image is loaded in CBITMAP. but it is not attached to the
HDC.

C++
CImage frontImage;
frontImage.Load(_T("C:\\Front.bmp"));
CBitmap frontBitmap;
frontBitmap.Attach(frontImage.Detach());
HDC memHDC;
memHDC=CreateCompatibleDC(hCardDC);
HGDIOBJ pOldBitmap = SelectObject(memHDC, frontBitmap);
result = BitBlt(hCardDC, 0, 0, 994, 624, memHDC, 0, 0, SRCCOPY)


memHDC is always blank, shows unused. as image is not attached to context that is why printed doc remains blank.
Posted
Updated 24-Nov-14 6:26am
v2
Comments
KarstenK 24-Nov-14 2:46am    
Does GetObject work fine? Can the output be in the "non-printable area"?

Try a black/white image.
Tanveer Asim 24-Nov-14 3:35am    
GetObject has no effect, it do not fetch image. Also LoadImage is returning non null value but it is not valid value and GetLastError returns 0 but. Please view the attached image
Tanveer Asim 24-Nov-14 3:37am    
sorry i think i cannot attach pictures here
Richard MacCutchan 24-Nov-14 5:02am    
I don't think LPTSTR szFileName = "C://Front.bmp"; is a valid pathname. should be: LPTSTR szFileName = "C:\\Front.bmp";
Tanveer Asim 24-Nov-14 5:42am    
i tried with all options like back/ forward slash, single double slash

The LoadImage function returns a bitmap with colors mapped to those of the display device. This can't be used to be selected into a printer compatible device context because the color depth is usually not the same. Use the LR_CREATEDIBSECTION flag when loading the image to get a device independant bitmap.

You should also check if your printer supports raster operations by calling GetDeviceCaps and checking for the RASTERCAPS and RC_BITBLT flags. If the printer does not support raster operations, BitBlt will fail.
 
Share this answer
 
Comments
Tanveer Asim 24-Nov-14 11:46am    
I printed same image with GUI application. Image was displayed on form and then i printed using CDC. I am developing a class library project and don't want to display any GUI.
Jochen Arndt 24-Nov-14 11:59am    
There you used GUI functions to prepare window content for printing. If you don't want to use GUI functions you must perform the preparation yourself. And one essential step is converting the image for the color depth of the printer. But using LoadImage like you do prepares the image for screen display (your call is similar to using LoadBitmap). From the LoadBitmap description in the MSDN:
"LoadBitmap creates a compatible bitmap of the display, which cannot be selected to a printer. To load a bitmap that you can select to a printer, call LoadImage and specify LR_CREATEDIBSECTION to create a DIB section. A DIB section can be selected to any device."
Tanveer Asim 24-Nov-14 12:14pm    
thanks jochen for your help. I tried LoadImage with "LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_DEFAULTSIZE"but every time result is same. is there any other option other than LoadImage. I don't have good enough experience in vc++.
Jochen Arndt 24-Nov-14 12:22pm    
Did you check all return values (CreateDC, SelectObject, BitBlt)?
Tanveer Asim 24-Nov-14 12:30pm    
yes only CreateDC is successfully and creates dc, other two run without any error. IN select object nothing is assigned to dc and same is with BitBlt
As mentioned, LoadImage loads an image ready for output on a screen. You have the alternative already given, or to use GDI+ to load the image. The advantage of using GDI+ is that not only is a DIB created, but you can also load formats including png, jpg and gif.

Provided you have already intialized GDI+, the following function will load an image ready for screen or print.

C++
// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
HBITMAP mLoadImageFile(wchar_t *filename)
{
    HBITMAP result = NULL;
    Bitmap bitmap(filename, false);
    bitmap.GetHBITMAP(0, &result);
    return result;
}



Failing the use of GDI+, you can use the dib section flag with LoadImage.
The following code creates a 1 page pdf, loading a copy of the CP logo that's been converted from gif to bmp.

Just:
(a) change the name of the loaded image in the drawPage function
(b) change the name of the printer in the 1st line of main

Note: Link against the gdi32 and winspool libraries.

C++
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>


void drawPage(HDC hdc)
{
    HBITMAP logo = (HBITMAP)LoadImage(NULL, "logo.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);

    int pageWidth, pageHeight;
    pageWidth = GetDeviceCaps( hdc, HORZRES ),
    pageHeight = GetDeviceCaps( hdc, VERTRES );
    int dpiX, dpiY;

    dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
    dpiY = GetDeviceCaps(hdc, LOGPIXELSY);

    double dpiMmX, dpiMmY;

    dpiMmX = dpiX / 25.4;
    dpiMmY = dpiY / 25.4;

    HBRUSH redBrush = CreateSolidBrush( RGB(255,0,0) );
    RECT pageRect = {0,0,pageWidth,pageHeight};

    int borderWidth = dpiMmX * 10;
    int borderHeight = dpiMmY * 10;

    RECT borderRect = {borderWidth, borderHeight, pageWidth-1-borderWidth, pageHeight-1-borderHeight};

    FrameRect(hdc, &pageRect, redBrush);
    int i;
    for (i=0; i<5; i++)
    {
        FrameRect(hdc, &borderRect, redBrush);
        InflateRect(&borderRect, -1, -1);
    }

    HDC memDC = CreateCompatibleDC(hdc);
    HBITMAP old = (HBITMAP)SelectObject(memDC, logo);
    StretchBlt(hdc, 100,100, 1000,540, memDC, 0,0, 250,125, SRCCOPY);
    SelectObject(memDC, old);
    DeleteObject(logo);
    DeleteDC(memDC);

    DeleteObject(redBrush);
}


void testPrint(char *szPrinterName)
{
    DOCINFO diDocInfo = {0};
    diDocInfo.cbSize = sizeof( DOCINFO );
    diDocInfo.lpszDocName = "printTest";

    HANDLE printerHandle;
    if (OpenPrinter(szPrinterName, &printerHandle, NULL) != 0)
    {
        HDC pDC2 = CreateDC("", szPrinterName, NULL, NULL);

        if( StartDoc( pDC2, &diDocInfo ) > 0 )
        {
            if( StartPage( pDC2 ) > 0 )
            {
                drawPage(pDC2);
                EndPage(pDC2);
            }
            EndDoc( pDC2 );
        }
        ClosePrinter(printerHandle);
    }
}

int main()
{
    testPrint("CutePDF Writer");
    return 0;
}



EDIT: MFC code added

C++
// CdcTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "CdcTest.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// The one and only application object

CWinApp theApp;

using namespace std;

void drawPage(HDC hdc)
{
    HBITMAP logo = (HBITMAP)LoadImage(NULL, L"c:/logo.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);

    int pageWidth, pageHeight;
    pageWidth = GetDeviceCaps( hdc, HORZRES ),
    pageHeight = GetDeviceCaps( hdc, VERTRES );
    int dpiX, dpiY;

    dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
    dpiY = GetDeviceCaps(hdc, LOGPIXELSY);

    double dpiMmX, dpiMmY;

    dpiMmX = dpiX / 25.4;
    dpiMmY = dpiY / 25.4;

    HBRUSH redBrush = CreateSolidBrush( RGB(255,0,0) );
    RECT pageRect = {0,0,pageWidth,pageHeight};

    int borderWidth = dpiMmX * 10;
    int borderHeight = dpiMmY * 10;

    RECT borderRect = {borderWidth, borderHeight, pageWidth-1-borderWidth, pageHeight-1-borderHeight};

    FrameRect(hdc, &pageRect, redBrush);
    int i;
    for (i=0; i<5; i++)
    {
        FrameRect(hdc, &borderRect, redBrush);
        InflateRect(&borderRect, -1, -1);
    }

    HDC memDC = CreateCompatibleDC(hdc);
    HBITMAP old = (HBITMAP)SelectObject(memDC, logo);
    StretchBlt(hdc, 100,100, 1000,540, memDC, 0,0, 250,125, SRCCOPY);
    SelectObject(memDC, old);
    DeleteObject(logo);
    DeleteDC(memDC);

    DeleteObject(redBrush);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	HMODULE hModule = ::GetModuleHandle(NULL);

	if (hModule != NULL)
	{
		// initialize MFC and print and error on failure
		if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
		{
			// TODO: change error code to suit your needs
			_tprintf(_T("Fatal Error: MFC initialization failed\n"));
			nRetCode = 1;
		}
		else
		{
			// TODO: code your application's behavior here.
			CDC memDC;
			memDC.CreateDCW(NULL, L"CutePDF Writer", NULL, NULL);

			DOCINFO diDocInfo = {0};
			diDocInfo.cbSize = sizeof( DOCINFO );
			diDocInfo.lpszDocName = L"printTest";

			if( StartDoc( memDC.GetSafeHdc(), &diDocInfo ) > 0 )
			{
				if( StartPage( memDC.GetSafeHdc() ) > 0 )
				{
					drawPage(memDC.GetSafeHdc());
					EndPage(memDC.GetSafeHdc());
				}
				EndDoc( memDC.GetSafeHdc() );
			}

		}
	}
	else
	{
		// TODO: change error code to suit your needs
		_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
		nRetCode = 1;
	}

	return nRetCode;
}
 
Share this answer
 
v2
Comments
Tanveer Asim 25-Nov-14 2:06am    
Thanks a lot, i am trying both options
Tanveer Asim 25-Nov-14 4:44am    
@enhzflep i tried both solutions, in first with gdiplus it is printing blank. Then i tried 2nd, here it is printing red border but no image. i tried to check error by GetLastError() but it is 0 every time. can i check at any place that image is loaded to hbitmap or no and is attached to hdc as well?
enhzflep 25-Nov-14 5:16am    
Oh. :( I assume you called GdiplusStartup before trying to load the image (I get nothing where the image should be if I dont)

Hmm. I find it interesting that you've been able to print an image to this printer with existing software, but are having trouble doing so yourself. Some times I really hate hardware/software interactions!

The only thing I can think of is to find some code that will write a HBITMAP to a file. If you do that to the loaded image, you can check to see if it loads or not.

Though, on further reflection - a far easier way would be to create a 'throw-away' project that has a picture control on a dialog. You could then call LoadImage in the WM_INITDIALOG message handler before sending a STM_SETIMAGE to the picture control. That would show you if the image is loaded correctly or not.

However, unless you get NULL as the return from LoadImage, you know it has succeeded, rendering both methods described above entirely redundant.

As for determining if the HBITMAP has been successfully selected into the HDC, this should be very easy.

1. Load the bmp
2. Select the bmp into the hdc
3. Call GetCurrentObject(hdc, OBJ_BITMAP) and check to see if the result is the same as the handle you already have for the image from step 1. If it is, you know that the currently selected bitmap of that HDC is indeed the one that you've tried to select into it.

Something that may also prove fruitful, is to try images with different formats. I.e indexed, 24 bit colour, 1-bit black & white
Tanveer Asim 25-Nov-14 5:06am    
Following is my code and logo is always null and file is available on specified location

HBITMAP logo = (HBITMAP)LoadImage(NULL, szFileName, IMAGE_BITMAP, 0,0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
enhzflep 25-Nov-14 5:20am    
Something else I wonder - is the ability to test with different printers. If you have a win7 system, you can choose to 'print' documents to a printer called "Microsoft XPS Document Writer" - I also have the (free) CutePDF printer driver installed as a cheap (free) and easy way to test print-output.

This would help determine if the difficulty was related to the "Datacard Printer" or to the code itself.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900