Re: win32lib printing
- Posted by ghaberek (admin) Dec 23, 2014
- 1475 views
I did some testing and I realized that queryDevice() in Win32Lib calls CreateIC to create an information context and returns only 96 DPI for the Printer.
According to the GetDeviceCaps documentation, it appears that 96 DPI is the "default" when it cannot figure out the actual DPI...
Note GetDeviceCaps reports info that the display driver provides. If the display driver declines to report any info, GetDeviceCaps calculates the info based on fixed calculations. If the display driver reports invalid info, GetDeviceCaps returns the invalid info. Also, if the display driver declines to report info, GetDeviceCaps might calculate incorrect info because it assumes either fixed DPI (96 DPI) or a fixed size (depending on the info that the display driver did and didn’t provide).
The trick then, is to just call GetDeviceCaps directly and provide it the proper device context using getDC() instead. Here is a function that will return one or more device values.
public function getDeviceCaps( integer device, object index ) object result atom dc = getDC( device ) if atom( index ) then -- just return one value result = w32Func( xGetDeviceCaps, {dc,index} ) else -- look up each value and return the list result = repeat( 0, length(index) ) for i = 1 to length(index) do result[i] = w32Func( xGetDeviceCaps, {dc,index[i]} ) end for end if return result end function
And now that we can get the DPI for any device, we can scale from one device to another, so an image appears the same size on both.
public function scaleDPI( sequence size, integer fromDevice, integer toDevice, atom factor = 1.0 ) -- use 'factor' to provide additional scaling if required -- get the DPI for each device sequence fromDPI = getDeviceCaps( fromDevice, {LOGPIXELSX,LOGPIXELSY} ) sequence toDPI = getDeviceCaps( toDevice, {LOGPIXELSX,LOGPIXELSY} ) -- calculate the scale ratio sequence scale = (toDPI / fromDPI) -- return the scaled size return floor( size * scale * factor ) end function
Now my click event handler looks like this. Notice I am taking nothing for granted and the bitmap appears the correct size on the page.
procedure myButton_OnClick( integer self, integer event, sequence params ) sequence result = getPrinter() if length( result ) = 0 then -- user cancelled return end if -- get the printer DPI values sequence printerDPI = getDeviceCaps( Printer, {LOGPIXELSX,LOGPIXELSY} ) if startDoc( "Test" ) then if startPage() then atom bmp = loadBitmapFromFile( "space.bmp" ) -- original bitmap size in pixels sequence screenSize = getCtlSize( bmp ) -- scale the bitmap from screen DPI to printer DPI (e.g. 96-to-600) sequence printSize = scaleDPI( screenSize, Screen, Printer ) -- calculate a decent page margin (1/2 inch) sequence margins = floor( printerDPI * 0.5 ) stretchBlt( Printer, -- dest device margins[1], -- dest x margins[2], -- dest y printSize[1], -- dest width printSize[2], -- dest height bmp, -- src bitmap 0, -- src x 0, -- src y screenSize[1], -- src width screenSize[2], -- src height SRCCOPY -- operation ) endPage() end if endDoc() end if releasePrinter() end procedure
-Greg