I am having a heck of a time getting a GDI+ bitmap to print to a printer in Freebasic. I have been trying to adapt some of Jose's Powerbasic code but I am in over my head. Could anyone give me a pointer on the code below. I can get the bitmap to print to the screen OK (but only after hours of trial and error) but no luck on the printer. Thanks
FUNCTION EZP_DrawBitmap (BYVAL MyDC as hDC,BYVAL hbmp AS HBITMAP,MyAngle as single, BYVAL x AS SINGLE = 0, BYVAL y AS SINGLE = 0, _
BYVAL nRight AS SINGLE = 0, BYVAL nBottom AS SINGLE = 0, AspectFlag as integer = 0) AS GpStatus
DIM nStatus AS GpStatus, pGraphics AS GpGraphics PTR, pBitmap AS GpBitmap PTR
DIM nWidth AS DWORD, nHeight AS DWORD
DIM StartupInput AS GdiplusStartupInput
DIM token AS ULONG_PTR
Dim pixelColor As COLORREF
dim TempDC1 as hDC
dim TempDC2 as hDC
dim hbit as HBITMAP
dim xxx as LONG
Dim frameCount AS integer
DIM pageGuid AS GUID => ( &H86DC6274, &H8061, &H7E4C, {&H8E ,&H3F, &HEE, &H73, &H33, &HA7, &HA4, &H8 })
Dim nCount AS LONG
'$FrameDimensionPage = GUID$("{7462DC86-6180-4C7E-8E3F-EE7333A7A483}")
' // Initialize GDI+
StartupInput.GdiplusVersion = 1
GdiplusStartup(@token, @StartupInput, NULL)
DO
nStatus = GdipCreateBitmapFromHBITMAP (hbmp, NULL, @pBitmap)
IF pBitmap = NULL THEN EXIT DO
GdipGetImageWidth(cast(GpImage PTR, pBitmap), @nWidth)
GdipGetImageHeight(cast(GpImage PTR, pBitmap), @nHeight)
'Full Picture
if nRight = 0 and nBottom = 0 THEN
nRight = nWidth
nBottom = nHeight
end if
if AspectFlag <> 0 THEN
if nRight = 0 and nBottom = 0 THEN
'Nothing for now
else
nBottom = nBottom *(nHeight/nWidth)
end if
end if
MyAngle = MyAngle + 180
GdipImageRotateFlip(cast(any ptr,pBitmap),6)
nStatus = GdipCreateFromHDC(MyDC, @pGraphics)
if EZP.SorP = 1 THEN
nStatus = GdipImageGetFrameDimensionsCount(cast(any ptr,pBitmap), @nCount)
IF nCount THEN
' // Get the list of frame dimensions from the Image object.
REDIM dimensionIDs(nCount - 1) AS GUID
nStatus = GdipImageGetFrameDimensionsList(cast(any ptr,pBitmap), @dimensionIDs(0), nCount)
' // Get the number of frames in the first (and only) frame dimension.
nStatus = GdipImageGetFrameCount(cast(any ptr,pBitmap), @dimensionIDs(0), @frameCount)
IF frameCount = 0 THEN GOTO LExit
END IF
END IF
IF nStatus <> S_OK OR pGraphics = 0 THEN Print "Problem with Graphic DC"
nStatus = GdipBitmapGetPixel(pBitmap, 1, 1, @pixelColor)
IF pGraphics = NULL THEN EXIT DO
GdipSetSmoothingMode(pGraphics, SmoothingModeAntiAlias)
GdipSetInterpolationMode(pGraphics, InterpolationModeHighQualityBicubic)
GdipRotateWorldTransform(pGraphics,MyAngle,MatrixOrderAppend)
GdipTranslateWorldTransform(pGraphics,x+(nRight/2), y +(nBottom/2),MatrixOrderAppend)
if EZP.SorP = 0 THEN
GdipDrawImageRectI(pGraphics,cast(any ptr, pBitmap),nRight/2,nBottom/2,-nRight,-nBottom)
else
FOR xxx = 0 TO frameCount - 1
nStatus = GdipImageSelectActiveFrame(cast(any ptr, pBitmap), @pageGuid, xxx)
GdipDrawImageRectI(pGraphics,cast(any ptr, pBitmap),nRight/2,nBottom/2,-nRight,-nBottom)
next xxx
end if
GdipResetWorldTransform(pGraphics)
EXIT DO
LOOP
LExit:
IF pBitmap THEN GdipDisposeImage(cast(GpImage PTR, pBitmap))
IF pGraphics THEN GdipDeleteGraphics(pGraphics)
' // Shutdown GDI+
GdiplusShutdown token
RETURN nStatus
END FUNCTION
In the above code I don't see any printer instruction.
Have you tried the AfxGdipPrintHBITMAP function in AfxGdiPlus.inc?
Thanks Jose. Yeah, I looked through all of it and it was my first "go by". Your code is very helpful. I am still stumped - I have spent days on this. Attached is a printer project that I am working on for a couple of months and I guess it is coming along OK. I have spent a good chunk of time on the GDI+ stuff which I still don't feel comfortable with. This is sort of a DDOC / Virtual Print Engine clone.
This file has 1 graphic called "It's time to review" which is on page 2. In the code the function that controls printing is EZP_DrawBitmap (on line 1238) This example just has a bunch of scattered objects on page to test ideas. The print button is hard-wired to print page 2 and points to EZP_PrintDoc. The graphic shows on the print preview just fine but for the life of me I can't get it to print.
If someone would be kind enough to look at this I would be grateful. At this point I am blind to my problem. By the way, I will be writing docs for this project when it is done.
Thanks
nStatus = GdipDrawImageRectI(pGraphics,cast(any ptr, pBitmap),nRight/2,nBottom/2,-nRight,-nBottom)
Negative width and height?
BTW I prefer to use GdiPlus only, e.g.
#define UNICODE
#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/AfxPrinter.inc"
#INCLUDE ONCE "Afx/CGdiPlus/CGdiPlus.inc"
USING Afx
DIM docInfo AS DOCINFOW
docInfo.cbSize = sizeof(DOCINFOW)
DIM wszDocName AS WSTRING * 260 = "GdiplusPrint"
docInfo.lpszDocName = cast(LPWSTR, @wszDocName)
DIM hdcPrint AS HDC = CreateDCW(NULL, AfxGetDefaultPrinter, NULL, NULL)
IF hdcPrint THEN
StartDoc(hdcPrint, @docInfo)
StartPage(hdcPrint)
DIM graphics AS CGpGraphics = hdcPrint
' // Get the DPIs of the printer
DIM dpiX AS SINGLE = graphics.GetDpiX
DIM dpiY AS SINGLE = graphics.GetDpiY
' // Calculate the width and height according to the DPIs of the printer
DIM cx AS LONG = GetDeviceCaps(hdcPrint, HORZRES) / (dpiX / 100)
DIM cy AS LONG = GetDeviceCaps(hdcPrint, VERTRES) / (dpiY / 100)
' // ---------------------------------------------------
DIM pen AS CGpPen = CGpPen(GDIP_ARGB(255, 0, 0, 0))
graphics.DrawLine(@pen, 50, 50, 350, 550)
graphics.DrawRectangle(@pen, 50, 50, 300, 500)
graphics.DrawEllipse(@pen, 50, 50, 300, 500)
' // ---------------------------------------------------
EndPage(hdcPrint)
EndDoc(hdcPrint)
DeleteDC(hdcPrint)
END IF
I saw the negative width and height on quite a few examples on the internet that rotated objects (which I want to do) and I don't understand it. I tried positive numbers but no luck when I rotated and modified the world. This is why I said I don't understand GDI+. The way I have it works fine to a screen DC to display a bitmap but printers seem to fail on it. There has to be a way to rotate a bitmap map that works on both screen and a printer. The code I have fails at home printers and on the networked printers at work.
Thanks for looking at it.
Well I found my bitmap printing problem and programmed a kludge to fix it. It turns out the when printing in GDI+, even though the device context may be a printer with 600 dpi, GDI+ expects the location to be is SCREEN RESOLUTION (or something close to that). I was always printing off the page. The below code prints the bitmap in the middle of the page whereas a GDI printer device context would be in the upper left hand corner. Wow, I used a ream of paper to figure this out. Jim
'hDC is a printer DC
GdipCreateFromHDC(hDC, @pGraphics)
GdipCreateBitmapFromHBITMAP(hbmp, NULL, @pBitmap)
GdipDrawImage(pGraphics, CAST(GpImage PTR, pBitmap), 400, 600)
I think that, by default, GDI+ uses UnitDisplay as the unit of measurement. If the display device is a monitor, then the unit is 1 pixel, but for printers it uses 100 of inches (see DIM cx AS LONG = GetDeviceCaps(hdcPrint, HORZRES) / (dpiX / 100) in my AfxGdipPrintHBITMAP function). To use the same coordinates, call the GdipSetPageUnit function (see http://www.jose.it-berater.org/gdiplus/reference/flatapi/graphics/gdipsetpageunit.htm ) passing the constant UnitPixel (see https://msdn.microsoft.com/en-us/library/windows/desktop/ms534405(v=vs.85).aspx ).
Thanks Jose