Printing in SB programs
Posted: Sat Oct 20, 2018 9:40 am
Direct printing in SmartBasic
Summary
SmartBasic ("SB") does not have a facility to print data on a printer. This document describes a method which enables such facilty and contains the software to implement the method.
The method consists of a number of SB functions to reside on an iOS device and a little webserver, written in Python, on a PC with a printer attached to it.
Presently, the method is restricted and tested for use with a Windows PC and a cable attached printer. It should not be too difficult to extent the method to cover using a MAC computer and/or a network printer, by modifying the webserver applet.
Components
The components of the solution are indicated in the sketch hereafter.
There are two "low-level" components:
- a SB function (named eprt(a$) in the scheme), which accepts a string as parameter and sends this string to the PC via WiFi, using a HTTP command with the IP adress of the PC.
- a webserver applet in the PC, currently written in Python, which fetches the string and sends it to the printer with a Notepad command, using the current font setting of Notepad.
Alternatives (MAC instead of PC, network printer instead of cable attached printer) might be realized by modification of the webserver applet. If such modifications are in fact realized, please add them to this document.
One peculiarity exists regarding the IP adress of the PC. It is hardcoded in the SB function. However, it is an adress which may be dynamically changed by the router.
In the current situation, when printing fails, the local IP adress has to be found using the Windows "ipconfig" program and entered into the SB program
No method has been found yet to automatically ensure that the correct IP adress is used in de SB function.
For now one could put ipconfig on a shortcut on the toolbar so that one can quickly fetch the PC's address.
"High-level" components
Those are SB calling programs that make use of the printing functionality.
As a little example serves a code snippet which prints a SB source listing (of course any piece of text can be printed with it).
A more elaborate example is a function suite to print multipage reports of any kind. Initial preparation consists of testing the number of characters per line and the number of lines per page. These are printer and font specification dependent. Using these numbers, large reports may be printed where the functions keep track of jumps to new pages, adding a report title, date/time stamp, and a page number to the new page, and columns headings if they are specified.
Step by step installation
The steps to implement and test this feature are as follows:
1. Install Python on the PC system (free, website "Python.org" -> "Download"), if not already installed.
2. Create or choose a directory where to run the webserver
3. Copy/paste the webserver code into Notepad and save it in the chosen directory giving it a filename with extension .py, for instance "iOS2print.py".
4. Open the command line window (CMD), switch to the webserver directory ("CD \xxxx") and start the server: "python iOS2print.py". The message "Print Server started..." should appear. It may be simplified by making a .bat file:
"CD \xxxx
Python iOS2print.py",
and create a shortcut for it on the desktop.
5. Make a little testprogram, or use the one herafter.
6. Switch the printer on, wait until it is ready and run the testprogram. The content of the string should be printed now. From the output you can deduct the number of caracters/line and lines/page.
7. The webserver may be stopped with CTRL-C.
Software components
The two basic components are the low-level SB function and the Python webserver applet for the PC:
And the webserver applet :
The next component is an utility that prints a test sheet, which may be used to establish the number op characters/line and the number of lines/page of your printing device. These numbers are necessary for the report function suite to function properly.:
The next code snippet may be used to print a listing of an SB progam on paper, oa any text file for that matter. An advantage of this method over other methods is that additional features may be added to the listing. For instance, adding line numbers to the program lines is a peace of cake.
Finally there is the report function suite.
A report is entirely packed into one string. When the report is finished, the built report string is sent to the PC to be printed on the default printed.
There are 3 functions to accomplish this:
"Iprt" - An initialization function, to be used once for each report, prepares the header strings, starts the report string, and does some initializations for the line printing function.
"Prt" - adds one line to the report string, and insets the header info into the report string when a new page is detected.
"Eprt" - sends the report string (or any other string supplied by the calling code) to the printer.
Proper inserts of the heading info on each page depends on the value of the "lpp" (lines per page) value when invoking the "lprt() function. This value, in turn, depends on the settings of the Windows "Notepad" program, with respect to font and font size. The best way is to use the little testprogram already presented.
In addition to the 3 basic functions, there is a demo (main) program which calls the functions, and there are some utilities to take care of date/time and column aligning.
(Main) Demo program:
The 3 basic functions:
And the additional utilities:
Finally, some remarks are included from RBytes, who made some first tests with the printing method:
"
I had a couple of printing glitches this morning that I thought I should share. I had a small program for which I wanted a code printout. I sent it to the printserver a couple of times, with no response. Since I had some internet issues earlier today and had rebooted my modem/router, I suspected that my tablet IP address had been dynamically reassigned. I ran ipconfig and discovered that it had. Only the last of the 4 sets of digits had changed slightly, but since they didn't match the setting in my SB program, nothing could print.
I fixed the IP address in my SB code, then printed the program. The font was huge! It took 4 pages to hold all of the text.
I opened Notepad on my PC tablet and checked the font setting. It was Courier, 24 points! I set it to Arial 12, sent the file to the printserver again and now the printing looked great and required just two pages.
I still don't know why my Notepad's font size setting was so large. I did find that if you open Notepad before you print, set your desired font name and point size, then close it, your text will print with that setting. If you leave Notepad open, the print server will not function.
You may prefer to use a monospaced font if you are printing columns, tables, or anything else that requires horizontal alignment. The only standard Windows monospaced fonts are Courier New (has serifs) and Lucida Sans Typewriter (no serifs).
"
Summary
SmartBasic ("SB") does not have a facility to print data on a printer. This document describes a method which enables such facilty and contains the software to implement the method.
The method consists of a number of SB functions to reside on an iOS device and a little webserver, written in Python, on a PC with a printer attached to it.
Presently, the method is restricted and tested for use with a Windows PC and a cable attached printer. It should not be too difficult to extent the method to cover using a MAC computer and/or a network printer, by modifying the webserver applet.
Components
The components of the solution are indicated in the sketch hereafter.
There are two "low-level" components:
- a SB function (named eprt(a$) in the scheme), which accepts a string as parameter and sends this string to the PC via WiFi, using a HTTP command with the IP adress of the PC.
- a webserver applet in the PC, currently written in Python, which fetches the string and sends it to the printer with a Notepad command, using the current font setting of Notepad.
Alternatives (MAC instead of PC, network printer instead of cable attached printer) might be realized by modification of the webserver applet. If such modifications are in fact realized, please add them to this document.
One peculiarity exists regarding the IP adress of the PC. It is hardcoded in the SB function. However, it is an adress which may be dynamically changed by the router.
In the current situation, when printing fails, the local IP adress has to be found using the Windows "ipconfig" program and entered into the SB program
No method has been found yet to automatically ensure that the correct IP adress is used in de SB function.
For now one could put ipconfig on a shortcut on the toolbar so that one can quickly fetch the PC's address.
"High-level" components
Those are SB calling programs that make use of the printing functionality.
As a little example serves a code snippet which prints a SB source listing (of course any piece of text can be printed with it).
A more elaborate example is a function suite to print multipage reports of any kind. Initial preparation consists of testing the number of characters per line and the number of lines per page. These are printer and font specification dependent. Using these numbers, large reports may be printed where the functions keep track of jumps to new pages, adding a report title, date/time stamp, and a page number to the new page, and columns headings if they are specified.
Step by step installation
The steps to implement and test this feature are as follows:
1. Install Python on the PC system (free, website "Python.org" -> "Download"), if not already installed.
2. Create or choose a directory where to run the webserver
3. Copy/paste the webserver code into Notepad and save it in the chosen directory giving it a filename with extension .py, for instance "iOS2print.py".
4. Open the command line window (CMD), switch to the webserver directory ("CD \xxxx") and start the server: "python iOS2print.py". The message "Print Server started..." should appear. It may be simplified by making a .bat file:
"CD \xxxx
Python iOS2print.py",
and create a shortcut for it on the desktop.
5. Make a little testprogram, or use the one herafter.
6. Switch the printer on, wait until it is ready and run the testprogram. The content of the string should be printed now. From the output you can deduct the number of caracters/line and lines/page.
7. The webserver may be stopped with CTRL-C.
Software components
The two basic components are the low-level SB function and the Python webserver applet for the PC:
Code: Select all
def eprt(t$) ' low-level SB print function
dim h$(3)
h$(1) = "content-type:text/html"
h$(2) = "content-length:"&len(t$)
HTTP "192.168.2.5" HEADER h$ POST t$ ' IP adress of PC
end def
Code: Select all
# Software by Michiel Overtoom, motoom@xs4all.nl
import os
from http.server import BaseHTTPRequestHandler, HTTPServe
class MyPrintService(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers["Content-Length"])
post_data = self.rfile.read(content_length)
with open("report.txt", "wb") as f:
f.write(post_data)
os.system("notepad /p report.txt")
if __name__ == "__main__":
print("Print Server started...")
HTTPServer(("0.0.0.0", 80), MyPrintService).serve_forever()
Code: Select all
option base 1
url$="192.168.2.9" ' the URL of the host PC
dim h$(2)
' construct a string to measure how many caracters per line and
' how many lines fit on one page
'
t$="1234567890"
for i=1 to 80 ! s$&="regel "&i&chr$(13)&chr$(10) ! next i
for i=1 to 10 ! s$&=t$ ! next i
h$(1) = "content-type:text/html" ' make header info
h$(2) = "content-length:" & len(s$)
HTTP URL$ HEADER H$ POST s$ ' send doc to the webserver
end
Code: Select all
' print a SB source file (or any text file)
' mind the current IP adress of the PC !
'
do input "filename ?": f$ ! until file_exists(f$)
do
file f$ readline dt$
t$ &= dt$ & chr$(10)
until file_end(f$)
eprt(t$)
end
A report is entirely packed into one string. When the report is finished, the built report string is sent to the PC to be printed on the default printed.
There are 3 functions to accomplish this:
"Iprt" - An initialization function, to be used once for each report, prepares the header strings, starts the report string, and does some initializations for the line printing function.
"Prt" - adds one line to the report string, and insets the header info into the report string when a new page is detected.
"Eprt" - sends the report string (or any other string supplied by the calling code) to the printer.
Proper inserts of the heading info on each page depends on the value of the "lpp" (lines per page) value when invoking the "lprt() function. This value, in turn, depends on the settings of the Windows "Notepad" program, with respect to font and font size. The best way is to use the little testprogram already presented.
In addition to the 3 basic functions, there is a demo (main) program which calls the functions, and there are some utilities to take care of date/time and column aligning.
(Main) Demo program:
Code: Select all
' Demo program, generates a multipage report with rubbish content
' and demonstrates the use of the three print functions to print
' the report on the default printer of a PC system.
' The three function follow the test program, together with some
' auxiliary functions.
'
dim col_head$(3),lin$(100)
rname$="Spare parts in stock at Newport" ' title of the report
restore to columns
for i=1 to 1 ! read col_head$(i) ! next i ' column headings
columns:
data " Code Description Quantity Price"
data " nr of item in pieces $/pc"
restore to lines
for i=0 to 4 ! read lin$(i) ! next i ' 5 lines with random content
lines:
data " xxx fuhvhijfxd 328 20.45"
data " gyyy fcjkhjk 42 48.00"
data " sde d bmiddg 1523 4.99"
data " sdu hfc hhj 469 3.50"
data " umkj fmoputdsn 5 120.40"
l$ = " cccc ddddddddd nnn nn.nn"
for i=5 to 60 ! lin$(i)=l$ ! next i ' additional lines to exceed
' the length of one sheet
' initialization of header info, # lines per sheet, and
' # characters per line (used to centre the title, and
' cut off the title in case it is too long
'
iprt(rname$,col_head$,58,70)
'
' generate 60 lines, which is enough to exceed one sheet
'
for i=0 to 60 ! prt(lin$(i)) ! next i
'
' print the report on the screen, if desired
'
print prt.t$
'
' print the report on the printer
'
' eprt(prt.t$)
end
Code: Select all
' initialization for printing a report
' rname$ = report title, is printed on each page
' col_head$() = 0, 1 or 2 strings with colomn headers
' lpp = # of lines per page
' cpl = # of characters per line
'
def iprt(rname$,col_head$(),lpp,cpl)
ob=option_base() ! option base 1
set output font size int(1250/cpl)
' make report header
prt.rn$=date_time$() ! ld=len(prt.rn$) ! av=cpl-ld-8
lr=len(rname$)
if lr>av-4 then ! rname$=left$(rname$,av-4)! lr=av-4 ! end if
sp=(av-lr)/2
prt.rn$&=ft$(sp+lr,rname$)&ft$(sp+5,"page ")
' make columns headers
prt.header$=""
h1$=col_head$(2-ob) ! lh1=len(h1$)
h2$=col_head$(3-ob) ! lh2=len(h2$)
if lh1 then prt.header$ &= h1$ & lf$()
if lh2 then prt.header$ &= h2$ & lf$()
' underline the column headers
sp$="" ! ns=min(lh1,lh2)
for i=1 to ns
if asc(mid$(h1$,i,1))+asc(mid$(h2$,i,1))>64 then sp$&="~" else sp$&=" "
next i
if lh1>ns then
for i=ns+1 to lh1
if mid$(h1$,i,1)>" " then sp$&="~" else sp$&=" "
next i
end if
if lh2>ns then
for i=ns+1 to lh2
if mid$(h2$,i,1)>" " then sp$&="~" else sp$&=" "
next i
end if
prt.header$ &= sp$
' initialize some more values for the prt() function
prt.hfix=3+sgn(lh1)+sgn(lh2)
prt.lc=lpp+1 ! prt.lmax=lpp ! prt.page=0 ! prt.t$=""
option base ob
end def
def prt(a$)
if lc>=lmax then
page+=1 ! lc=hfix
t$ &= rn$ & page & lf$ & lf$ & header$ & lf$
end if
lc+=1 ! t$ &= a$ & lf$
end def
def eprt(t$)
dim h$(3)
h$(1) = "content-type:text/html"
h$(2) = "content-length:"&len(t$)
HTTP "192.168.2.9" HEADER h$ POST t$ ' IP adress of PC
end def
Code: Select all
def date_time$()
dim m$(13)
restore to months
for i=1 to 12 ! read m$(i) ! next i
months:
data "january","february","march","april","may","june","july"
data "augustus","september","october","november","december"
y=current_year() ! mo=current_month() ! d=current_date()
h=current_hour() ! mi=current_minute()
dt$=m$(mo)&" "&d&","&y&" "&h&"."&mi&"h"
return dt$
end def
' print formatting of numbers
' n is total fieldwith, -n puts %-sign at end of number
' field starts and ends with one space
' number is right justified if smaller than fieldwith
' number is truncated if larger than fieldwidth
'
def fn$(n,x)
sp$=" "
if n<0 then p=1 else p=0 ! n=abs(n)
v$=x ! lv=len(v$) ! dp=n-lv-p-2
if dp<0 then v$=left$(v$,lv+dp)
ret$=" " ! if dp>0 then ret$&=left$(sp$,dp)
ret$&=v$ ! if p=1 then ret$&="%" ! ret$&=" "
return ret$
end def
' print formatting of texts
'
def ft$(n,v$)
sp$=" "
lv=len(v$) ! dp=n-lv-2
if dp<0 then v$=left$(v$,lv+dp)
ret$=" " ! if dp>0 then ret$&=left$(sp$,dp)
ret$&=v$&" "
return ret$
end def
def lf$ = chr$(13)&chr$(10)
"
I had a couple of printing glitches this morning that I thought I should share. I had a small program for which I wanted a code printout. I sent it to the printserver a couple of times, with no response. Since I had some internet issues earlier today and had rebooted my modem/router, I suspected that my tablet IP address had been dynamically reassigned. I ran ipconfig and discovered that it had. Only the last of the 4 sets of digits had changed slightly, but since they didn't match the setting in my SB program, nothing could print.
I fixed the IP address in my SB code, then printed the program. The font was huge! It took 4 pages to hold all of the text.
I opened Notepad on my PC tablet and checked the font setting. It was Courier, 24 points! I set it to Arial 12, sent the file to the printserver again and now the printing looked great and required just two pages.
I still don't know why my Notepad's font size setting was so large. I did find that if you open Notepad before you print, set your desired font name and point size, then close it, your text will print with that setting. If you leave Notepad open, the print server will not function.
You may prefer to use a monospaced font if you are printing columns, tables, or anything else that requires horizontal alignment. The only standard Windows monospaced fonts are Courier New (has serifs) and Lucida Sans Typewriter (no serifs).
"