Alternative to Graphics Printing
by Alyce Watson

Home

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 Function

When 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$, HIDE

The 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", HIDE

Be 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