Two Years Ago in LBNews
Effective GUI Design
Alternative to Graphics Printing
Liberty Basic Simple Help
New LB Programming Contest
Debugging by Simulating Breakpoints
Multi-Coloured Text Input Boxes
Liberty BASIC allows us to print graphics from graphicboxes or graphics windows. It does no translating between logical units, so a pixel on the screen is mapped to a dot on the printer. While the screen width may be 800 or 1024 pixels, the printer may have thousands of dots across the width of a page. A high resolution printer will then print the graphic very tiny; good if you are creating postage stamp images from your graphics, but not so good otherwise! Also, the graphics printing capabilities native to Liberty BASIC do not allow you to designate the area to be printed. The entire graphics area will be sent to the printer. The syntax for hard-copy printing of graphics is as follows:
print #graphicwin, "print"
There are add-on DLLs to print images. It is also possible to print graphics directly via API calls to the Graphics Device Interface. API calls for printing can get complicated pretty fast, so you might want to try these two very easy alternatives, both of which should give you a properly sized hard-copy printout.
Both methods rely on using another application to print the graphics. Although this may sound clumsy, in fact it is quite easy and the other application can run completely hidden in the background. The first method is to use the ShellExecuteA API call. The second method calls MSPaint directly. The demo program included shows both methods.
PRINTING GRAPHICS WITH THE DEFAULT BITMAP PROGRAM
ShellExecuteA will allow you to print your graphics with the user's default
bitmap application. This may be MSPaint, or an application like PaintShopPro
or PhotoShop. You must first save your graphics to a disk file with BMPSAVE.
This requires you to use GETBMP to capture the part of the graphics desired
and give it an LB name. Use the LB name you have given to your bmp when using
BMPSAVE. This little example draws some graphics and saves them to disk. It
uses GETBMP to get a memory bitmap starting at point 0,0 and 300 pixels wide
by 300 pixels high. Be sure to UNLOADBMP for any bitmaps created with GETBMP.
The bmp in the example is given the name, "test". BMPSAVE then saves
"test" with the filename "atest.bmp" Note that it is EXTREMELY
IMPORTANT to give the disk file the extension "bmp":
open "Graphics Print Test" for graphics_nsb as #1 #1 "trapclose [quit]" #1 "down; fill yellow;color darkblue" #1 "backcolor pink;size 5;place 150 150" #1 "circlefilled 100;flush" #1 "getbmp test 0 0 300 300" bmpsave "test", "atest.bmp"
The API function from Shell32.dll is called ShellExecuteA. It will open or print the file specified in the filename argument. It looks at the extension of the file to consult the Windows registry and determine the default application for this file type. That is why it is very important that the filename of the saved bitmap has the extension "bmp". The arguments for the function are set up before the function is called. The filename argument should match the name you gave the bitmap file on disk. The operation argument should be "print". The directory argument and command line parameters argument are both null. The final (show window) parameter defines the way the called application is displayed. If _SW_HIDE is used, the called application will do its work invisibly in the background. The return from this function will be a number greater than 32 if it is successful.
RunFile$=DefaultDir$+"\atest.bmp" bmpsave "test",RunFile$ lpOperation$ = "print" lpParameters$ = "" lpDirectory$ = "" nShowCmd = _SW_HIDE calldll #shell32, "ShellExecuteA",_ hWin as long,_ 'window handle lpOperation$ as ptr,_ 'open or print RunFile$ as ptr,_ 'name of file on disk lpParameters$ as ptr,_ 'command line parameters lpDirectory$ as ptr,_ 'default directory, can be null nShowCmd as ulong,_ 'show window flag result as long 'result>32=success
PRINTING WITH MSPAINT
It is probably best to use the ShellExecuteA function to call an external
program to do hard-copy printing for us. We can usually count on users having
MSPaint available, though, since it has always been a part of 32-bit Windows.
We can run MSPaint directly and quite easily with Liberty BASIC's RUN command:
run "mspaint"
We can run MSPaint with a file loaded if we include the name of the file in the parameter string for the run command. The tricky bit happens because command line paramters may be parsed at empty spaces. The easiest way to insure that the filename is interpreted properly is to use the function GetShortPathNameA. This function takes a path and filename and returns the DOS short version of the filename. We need to set up a string buffer that will be large enough to contain the returned path string, and we must be sure to end it with a null termination to tell Liberty BASIC to pass this value by reference, so that the API function may modify the contents of the string. The return from this function gives us the length of the short path string returned by the function, so we can use it to truncate the returned string with LEFT$() to remove any junk characters.
lPath$=DefaultDir$+"\atest.bmp" 'filename of bmp file on disk sPath$=Space$(256) 'create string buffer lenPath=Len(sPath$) 'length of buffer CallDLL #kernel32, "GetShortPathNameA",_ lPath$ As ptr,_ 'long pathname sPath$ As ptr,_ 'buffer to receive short path name lenPath As long,_ 'length of buffer r As long 'length of returned string ShortPathName$=Left$(sPath$,r) 'We can easily wrap this API function in a Liberty BASIC function: Function GetShortPathName$(lPath$) sPath$=Space$(256) 'create string buffer lenPath=Len(sPath$) 'length of buffer CallDLL #kernel32, "GetShortPathNameA",_ lPath$ As ptr,_ 'long pathname sPath$ As ptr,_ 'buffer to receive short path name lenPath As long,_ 'length of buffer r As long 'length of returned string GetShortPathName$=Left$(sPath$,r) End FunctionWhen we use Liberty BASIC's RUN command, we can use the "show window" flags as well. After the command string, we place a comma, and then the desired mode for showing the window. In this case, we'll use HIDE so that MSPaint will not display, but will print invisibly in the background.
RunFile$=GetShortPathName$(RunFile$) run "mspaint.exe " + RunFile$, HIDEThe code above won't actually print the bitmap. It will run MSPaint with the bitmap loaded, but we won't see it because we have chosen to hide the application. To cause MSPaint to print a hard-copy of the bitmap, we need to add the " /p" switch to the command line. Here it is:
run "mspaint.exe " + RunFile$ + " /p", HIDEBe sure to include a space when adding the " /p" switch, or those characters will simply get tacked onto the end of the filename and the code won't work.
DEMO
The following small program creates a graphics window, draws some graphics, uses GETBMP to capture a bitmap from the graphics area, then saves it to disk. It then calls on ShellExecuteA to print the bitmap using the default bitmap application on the user's system. It checks the return from this function and if the function failed, it calls on MSPaint to print the bitmap. The demo leaves the graphics window open for five seconds, then closes it, unloads the bitmap and ends.'demo of hard-copy graphics printing 'with an external application nomainwin open "Graphics Print Test" for graphics_nsb as #1 #1 "trapclose [quit]" #1 "down; fill yellow;color darkblue" #1 "backcolor pink;size 5;place 150 150" #1 "circlefilled 100;flush" #1 "getbmp test 0 0 300 300" RunFile$=DefaultDir$+"\atest.bmp" bmpsave "test",RunFile$ lpOperation$ = "print" lpParameters$ = "" lpDirectory$ = "" nShowCmd = _SW_HIDE calldll #shell32, "ShellExecuteA",_ hW as long,_ 'window handle lpOperation$ as ptr,_ 'open or print RunFile$ as ptr,_ 'name of file on disk lpParameters$ as ptr,_ 'command line parameters lpDirectory$ as ptr,_ 'default directory, can be null nShowCmd as ulong,_ 'show window flag result as long 'result>32=success 'if ShellExecuteA didn't work then print with mspaint.exe if result <= 32 then RunFile$=GetShortPathName$(RunFile$) run "mspaint.exe " + RunFile$ + " /p", HIDE end if timer 5000, [quit] wait [quit] close #1:unloadbmp "test" notice "Graphics sent to printer." end Function GetShortPathName$(lPath$) sPath$=Space$(256) 'create string buffer lenPath=Len(sPath$) 'length of buffer CallDLL #kernel32, "GetShortPathNameA",_ lPath$ As ptr,_ 'long pathname sPath$ As ptr,_ 'buffer to receive short path name lenPath As long,_ 'length of buffer r As long 'length of returned string GetShortPathName$=Left$(sPath$,r) End Function