Create a PDF Service with Samba
Use GhostScript to create a
PDF document out of any PostScript printer job
14 November 2001
Copyright 2001 John Bright (jbright@winfordeng.com)
Introduction
PDF documents provide a great way to pass around documents on the
Internet. They have many uses, such as sending quotes and invoices to
business clients. Two of the main reasons the PDF format is so
popular is that it preserves all of the document's formatting exactly
and it is easily viewable on almost all platforms. For many computer
users stuck in the Windows paradigm, creating PDF documents means
forking over precious cash to the folks at Adobe. However, this
article will show you how to use Linux, Samba, and GhostScript to
provide a PDF-creation service to both Windows and Linux users. Of
course, all of this can be obtained for free.
First, let's take a look at the overall scheme of operation. We will
use Samba to provide a "pseudo-printer" service (it will look like a
standard printer to clients) that will use GhostScript to create a
PDF document out of any PostScript printer job that is queued onto
it. We will then configure the Windows machines to use this shared
printer and send jobs to it in PostScript form.
Samba
Samba (www.samba.org) is a great piece of software that runs on
Linux/UNIX and allows you to share files and printers with Windows
machines. Samba provides services that are compatible with the
standard "Windows Networking" services provided by Windows
95/98/NT/etc computers. Before we get into configuring Samba for our
purposes, you'll need to make sure that the Samba server is installed
on your Linux system. As always, you can download the Samba source, but generally the easiest way to install it on your system is by installing the "samba" package provided by Debian, Red Hat, or whoever.
If this is your first time installing Samba, you will want to
review/edit some of the basic configuration options in the smb.conf
(look in /etc or /etc/samba) configuration file. The main things to
watch in order to get your services up and running are the security
policy (security=share or security=user) and the "guest account"
setting. For details of configuring Samba, refer to the Samba
documentation or the
SMB HOWTO. A complete
sample (low-security) configuration file will be shown later.
It is probably advisable to test your connection and authentication
method (if any) by creating a simple file share for your clients. In
any event, once your clients are able to connect to your Samba
server, we are ready to create the PDF "pseudo-printer". First,
though, let's make sure we have the right utilities to actually
produce the PDF documents.
TOP
GhostScript
GhostScript is another great application that can be used on a Linux
system. GhostScript is often used to convert Postscript into the
correct raw format for a printer, but it can also be used to convert
between Postscript and PDF formats. GhostScript comes installed on
many distributions in order to provide printer support. If the "gs"
command is available on your system, then GhostScript is probably
already installed. Otherwise, you can install your distribution's
package (ghostscript on Red Hat, gs or gs-aladdin on Debian) or
download the
source if
you're feeling adventurous.
The GhostScript package includes a script called ps2pdf that makes
the conversion of PostScript to PDF quite easy. Now that we have this
utility available, we can begin the creation of our PDF service on
Samba.
Bringing It Together
First, let's review a typical bare-bones printer share in Samba (from
the smb.conf file):
[hpdeskjet]
path = /tmp
printable = yes
writeable = no
create mask = 0700
guest ok = yes
printer name = lp
(Note the silent "e" in writeable. The configuration file has
it even though the ordinary word doesn't. The same applies to
browseable below. Actually, Samba accepts it either way, but
Samba's manpages use writeable.)
Normally, when a print job is spooled to this share, a command such
as lpr is run to transfer the job to the Linux printing system. Our
method here is to use the excellent configurability of Samba to
specify an alternate printing command in place of lpr. Specifically,
the configuration variable is called "print command". The specified
command is executed, and any occurrence of %f or %s in the "print
command" variable will be replaced by the name of the printer spool
file that was sent in by the windows client. For example, to simply
discard any print jobs, this line could be placed in the above
printer configuration:
print command = /bin/rm %f
This brings up another important point: whatever print command is
specified must delete the spool files, or else they will eventually
pile up and fill your disk.
TOP
Print Script
Our print script will accept one command-line argument: the name of
the print spool file, which is assumed to be in PostScript format. It
will then convert this into the PDF document and place it in an
accessible location. Clients will be able to retrieve the finished
product by using the file sharing services of Samba. For example, if
a directory named "/shr" is shared by Samba, we could place finished
PDF documents in /shr/pdfdropbox/. Be sure to mkdir whatever
directory you choose. Also, you must be sure that you give write
permission to the Samba user (the nobody user in this example) or it
will not be able to create any PDFs. In this example, you would want
to:
chown nobody /shr/pdfdropbox
chmod u+rwx /shr/pdfdropbox
Here is the complete, yet simple print script, called printpdf, also
available in
text
format. On our Linux system, we'll place the script at
/usr/bin/printpdf
#!/bin/sh
# Simple script to convert a specified postscript file into a PDF
document # and place it in a location that is shared by the Samba
server. #
# Arguments:
# 1st - The name of the spool file
#
# John Bright, 2001, jbright@winfordeng.com
# We will create the pdf into a temporary file based upon the current
date and time. # After we are finished, we'll rename it to a file
with the same date, but ending # in .pdf. We do this because if a
user tries to open a PDF that is still being written, # they will get
a message that it is corrupt, when it is actually just not done yet.
DATE=`date +%b%d-%H%M%S`
# Directory in which to place the output # Be sure this directory
exists and is writable by the user that Samba # is running as (for
example, the nobody user) OUTDIR=/shr/pdfdropbox
ps2pdf $1 $OUTDIR/$DATE.temp
mv $OUTDIR/$DATE.temp $OUTDIR/$DATE.pdf
rm $1
I said it was simple, right? There's really not much to it once we
have all of the tools together.
TOP
Finish the Samba Setup
Now that we have seen everything that goes into the PDF service on
the Linux side, we can finish the Samba configuration file. Here is
an example smb.conf file that gets the job done. It is a little low
on security, but that keeps everything simple. You can download
smb.conf.1.txt.
[global]
guest account = nobody
invalid users = root
; Tighten security just a little: only allow local access interfaces
= 127.0.0.1 eth0
bind interfaces only = Yes
; This assumes you are on a local network with 192.168.x.x IP
addresses hosts allow = 192.168.
; Share-level security is generally easier, although not as secure
security=share
workgroup=WORKGROUP
; Set up a public share, this will be used to retrieve PDFs ; The
name of the share will be seen as "shr" by Windows users [shr]
path = /shr
browseable = yes
writeable = yes
guest ok = yes
force user = nobody
; Set up our PDF-creation print service
[pdf]
path = /tmp
printable = yes
guest ok = yes
print command = /usr/bin/printpdf %s
; There is no need to support listing or removing print jobs, ; since
the server begins to process them as soon as they arrive. ; So, we
set the lpq (list queued jobs) and lprm (remove jobs in queue) ;
commands to be empty.
lpq command =
lprm command =
Of course, you will need to start/restart Samba after you have
created/edited the smb.conf configuration file to your liking.
TOP
Setting Up a Windows Client
You should now be able to go ahead and install the shared PDF printer
as a network printer on your Windows client machine. To do this, find
the printer share under Network Neighborhood, right-click, and select
Install. During installation, you will be asked to pick a printer
driver. Just select some PostScript printer driver, for example, the
HP LaserJet 5P/5MP PostScript.
To briefly explain how this is fitting together, the PDF service on
your Linux machine is expecting to receive input in PostScript
format. Since our printpdf script receives the print job exactly as
it was sent by the Windows client, this means we need to have the
Windows clients send print jobs in PostScript form. As described
above, this is done by selecting a driver for any Postscript printer
on the Windows client when the PDF network printer is installed. I
generally select some variety of HP Laserjet PS printer from Windows'
printer driver list (such as the HP LaserJet 5P/5MP PostScript, as
noted above) although it doesn't matter a whole lot because all of
the Microsoft-supplied PostScript drivers use the same core driver to
generate the PostScript.
Once you have the PDF network printer installed on your Windows
machine, simply print anything from any program to your new network
printer, and you should have a PDF document waiting for you shortly.
TOP
Streamlining
If you have an office full of non-computer-savvy folks, it would
probably be more trouble than it's worth to try to have them go
through the installation process and select an appropriate printer
driver. If you have ever installed a network printer from another
Windows machine, you have probably noticed how the printer driver is
automagically copied to your machine so that you are never even
prompted for a driver. We can do the same thing with Samba. First,
you should set up a file share on your Linux machine named "printer$"
(without the quotes). We'll make the path for the printer$ share be
/etc/samba/printdrivers/ (you'll have to mkdir the directory). The
clients will simply use this share to obtain the printer driver files
during installation.
Now we need to find out which driver files must be copied into the
printer$ share directory. We also need to give Samba a printer
definition so it can tell the client which driver files it needs. It
turns out all this is taken care of in one step thanks to a Samba
utility called make_printerdef. This utility requires you to have the
Windows INF file that defines your printer and know the full title,
such as "HP LaserJet 5P/5MP PostScript". You will need to find which
INF file your printer is defined in. For example, this LaserJet is
defined in C:\WINDOWS\INF\MSPRINT3.INF. Note that C:\WINDOWS\INF is a
hidden directory. Copy this file onto your Linux machine and use the
make_printerdef utility to create a local printer definition file
that Samba will read. For example:
make_printerdef MSPRINT3.INF "HP LaserJet 5P/5MP PostScript" >> /etc/samba/printers.def
TOP
Here we redirected standard output to the printers.def file to create
the printer configuration. The make_printerdef program also outputs
some explanation on standard error which you will see. It should tell
you which driver files you need. You can find these in
C:\WINDOWS\SYSTEM or C:\WINDOWS and you should copy them into the
path of your printer$ share on the Linux machine (in our case,
/etc/samba/printerdrivers/). The printers.def file that we have
created (or appended to) here does not need to be shared to the
Windows machines, it is only read by Samba. Now we just have to tell
Samba about the printers.def file and our driver files. This is done
with the "printer driver file" setting in the global section and the
"printer driver" and "printer driver location" settings in each
printer section of smb.conf. The following revised smb.conf file
shows how these settings are used, and also shows an example of a
printer$ share. You can download this
configuration file.
[global]
guest account = nobody
invalid users = root
; Tighten security just a little: only allow local access
interfaces = 127.0.0.1 eth0
bind interfaces only = Yes
; This assumes you are on a local network with 192.168.x.x IP addresses
hosts allow = 192.168.
; Share-level security is generally easier, although not as secure
security=share
workgroup=WORKGROUP
printer driver file = /etc/samba/printers.def
; Set up a public share, this will be used to retrieve PDFs
; The name of the share will be seen as "shr" by Windows users
[shr]
path = /shr
browseable = yes
writeable = yes
guest ok = yes
force user = nobody
; Set up our PDF-creation print service
[pdf]
path = /tmp
printable = yes
guest ok = yes
print command = /usr/bin/printpdf %s
; There is no need to support listing or removing print jobs,
; since the server begins to process them as soon as they arrive.
; So, we set the lpq (list queued jobs) and lprm (remove jobs in queue)
; commands to be empty.
lpq command =
lprm command =
; We already defined the printer driver definition file above.
; Here we need to specify the entry in that file that should be used
; for this printer.
printer driver = HP LaserJet 5P/5MP PostScript
printer driver location = \\%h\printer$
; File share to allow clients to download printer drivers
[printer$]
path = /etc/samba/printdrivers
guest ok = yes
read only = yes
TOP
Setting Up a Linux Client
This section isn't necessary for providing a PDF service to Windows
clients. This section describes the procedure for using the PDF
service from Linux clients. The service probably isn't quite as
useful for the Linux clients, since they can more easily install all
the necessary tools on their own machines, but it still might be
useful to have a centralized PDF creation service. (Side note:
Ghostscript is available for the Windows platform, but most users
would probably find it quite difficult compared to the printer
service-based technique described here.) Also, the technique used to
print to the PDF service can be used to print to any other printer
service shared by Samba or Windows, so it is good information to
cover.
There are numerous ways that you can print to a Windows printer share
from Linux. Probably the best is to list the smbprint script (which
uses smbclient) as a filter in an /etc/printcap entry. When this
method is used, a Windows shared printer can be used with the
standard lpr command that Linux users and applications are accustomed
to. You will need to make sure you have both the smbprint and
smbclient programs on your computer. The smbclient program is in the
"smbclient" package on Debian systems and the "samba-client" package
on Red Hat systems. On Red Hat, the smbprint script is included with
the "samba-client" package. On Debian, it is included with the
"samba-doc" package as well as a different version in the
"printfilters-ppd" package and "lprngtool". There are so many
different versions floating around that I thought it best to include
a copy here. You can download
smbprint.sh.txt. In any event, I'll assume that you have a working smbprint at
/usr/bin/smbprint and that it is executable (chmod +x
/usr/bin/smbprint).
Here is the smbprint script:
#!/bin/sh
# This script is an input filter for printcap printing on a UNIX machine. It
# uses the smbclient program to print the file to the specified smb-based
# server and service.
# For example you could have a printcap entry like this
#
# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
#
# which would create a UNIX printer called "smb" that will print via this
# script. You will need to create the spool directory /usr/spool/smb with
# appropriate permissions and ownerships for your system.
# Set these to the server and service you wish to print to
# In this example I have a Windows for Workgroups PC called "lapland" that has
# a printer exported called "printer" with no password.
#
# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
# so that the server, service, and password can be read from
# a /usr/var/spool/lpd/PRINTNAME/.config file.
#
# In order for this to work the /etc/printcap entry must include an
# accounting file (af=...):
#
# cdcolour:\
# :cm=CD IBM Colorjet on 6th:\
# :sd=/var/spool/lpd/cdcolour:\
# :af=/var/spool/lpd/cdcolour/acct:\
# :if=/usr/local/etc/smbprint:\
# :mx=0:\
# :lp=/dev/null:
#
# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
# share=PC_SERVER
# user="user"
# password="password"
#
# Please, do not modify the order in the file.
# Example:
# share=\\server\deskjet
# user="fred"
# password=""
#
# The last parameter to the filter is the accounting file name.
# Extract the directory name from the file name.
# Concatenate this with /.config to get the config file.
#
eval acct_file=\$$#
spool_dir=`dirname $acct_file`
config_file=$spool_dir/.config
# Should read the following variables set in the config file:
# share
# hostip
# user
# password
eval `cat $config_file`
share=`echo $share | sed "s/[\]/\//g"`
if [ "$user" != "" ]; then
usercmd="-U"
else
usercmd=""
fi
if [ "$workgroup" != "" ]; then
workgroupcmd="-W"
else
workgroupcmd=""
fi
if [ "$translate" = "yes" ]; then
command="translate ; print -"
else
command="print -"
fi
#echo $share $password $translate $x_command > /tmp/smbprint.log
cat | /usr/bin/smbclient "$share" "$password" -E ${hostip:+-I} \
$hostip -N -P $usercmd "$user" $workgroupcmd "$workgroup" \
-c "$command" 2>/dev/null
TOP
The next step is to add a new /etc/printcap entry and list the
smbprint script as a filter. Here is an example printcap entry (or
complete file), also available as a
text
file:
# PDF Service entry
lp|pdf|PDF Printer:\
:lp=/dev/null:sh:\
:sd=/var/spool/lpd/pdf:\
:af=/var/spool/lpd/pdf/acct:\
:mx#0:sh:\
:if=/usr/bin/smbprint:
You will need to create the spool directory /var/spool/lpd/pdf/ (or
if you have LPRng, run checkpc -f). Be sure to keep the accounting
file line in the printcap entry, and be sure the accounting file is
located in the same directory as your .config file, as this is how
the smbprint script finds the .config file. Also, it is standard
procedure to have the system's default printer named "lp" as shown
above. If you already have a /etc/printcap file and would like to
retain your existing default printer, you should remove the leading
"lp|" from the entry shown above. Next, you need to create a
configuration file named ".config". You should create this at
/var/spool/lpd/pdf/.config . The .config file defines which server
the print job should be sent to. Here is an example:
share=//yourserver/pdf
user=""
password=""
Here, yourserver should be replaced by the name of the computer
providing the PDF service. If you have any trouble with this, make
sure that the smbprint script has permission to read the .config
file, or you may be scratching your head for a while. Probably the
safest way, at least at first, is to give read permission to all, for
example: chmod a+r /var/spool/lpd/pdf/.config
Finally, to print to the PDF service from Linux, invoke the command:
lpr -Ppdf file_to_print.ps
on a PostScript file. This can also be used from within most
applications. For example, listing "lpr -Ppdf" as the print command
in Netscape will allow you to create a PDF document from a Web page.
TOP
Viewing PDF Documents
The final topic to be covered deals with how to view PDF documents.
Everybody knows the standard on Windows is Adobe Acrobat Reader, but
there are many more options on Linux. Unfortunately, none of the
current options on Linux seem to be quite as dependable as Reader on
Windows, but they are still very workable. The main options are:
- acroread - Adobe has a nice version of Acrobat Reader (currently v. 4.05) for Linux
- gv - Viewer that uses GhostScript to interpret the PDF
- gnome-gv - Also uses GhostScript, but has a nicer user interface
- xpdf - A nice lean PDF viewer, but not a fancy interface
In my opinion, gnome-gv has the nicest user interface. It is based on
GTK+, so things like the mouse scroll wheel work without any special
consideration. Unfortunately, it will fail to read some PDF documents
and display a nasty-looking error from ghostscript. From my
experience, acroread is very good about being able to interpret
documents. In the past I have had some trouble with it crashing, but
I think it has gotten better since then. I have rarely used gv, but I
imagine it has the same problem as gnome-gv since they are both based
on ghostscript. Finally, xpdf is a very stable PDF reader. I don't
recall every having it crash, and it usually has no problem
interpreting documents. Still, there is an occasional problem, and
the displayed quality of the document often isn't quite up to par. It
doesn't have a full feature list, but it is a good viewer to keep
around. All this may sound scary, but be assured that on average, PDF
viewing on Linux is not a problem.
Have fun and good luck!
John Bright is a partner in Winford
Engineering and flawlessly performs his assigned programming and
Linux administration duties :). He also administers several
Linux/UNIX computers at a local university and always has several
Linux-related projects to keep him busy.
This article appeared originally in
Issue 72 of Linux Gazette, November 2001 and is republished with the author's expressed permission.
TOP