Home > Archive > Unix Programming > December 2005 > printing
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
|
|
| Simon Elliott 2005-11-24, 6:58 pm |
| What's the current wisdom on printing from a reasonably portable unix
app? I've looked at these options:
1/ popen lpr,fprintf, pclose. This seems simple, portable and familiar,
as long as I'm only printing line by line with no graphics or special
effects. I'm not clear what would happen to the app if the printer were
to be switched off, run out of paper, user pulls the lead out, etc.(*)
2/ CUPS. I'm not sure this gives us what we need, and all users would
need to install it.
3/ Postscript. This seems like a lot of work just to get the odd bit of
bold or italic text, and AIUI we'd need to install ghostscript if
(when) we need to use a non postscript printer.
Are there any other options we're missing here?
The target printers will likely be pretty basic dot matrix parallel
printers, and ideally we'd like to be able to get at the paper-out and
offline status that we would read direct from the parallel port back in
the olden days of MS DOS. Any thoughts on this?
(*) What I _want_ to happen is for the app to continue as normal, but
to notify the user _exactly_ what has happened and how to fix it.
--
Simon Elliott http://www.ctsn.co.uk
| |
| Lew Pitcher 2005-11-24, 6:58 pm |
| -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Simon Elliott wrote:
> What's the current wisdom on printing from a reasonably portable unix
> app? I've looked at these options:
>
> 1/ popen lpr,fprintf, pclose. This seems simple, portable and familiar,
> as long as I'm only printing line by line with no graphics or special
> effects. I'm not clear what would happen to the app if the printer were
> to be switched off, run out of paper, user pulls the lead out, etc.(*)
Should work for graphics, etc, so long as you encapsulate them in the
appropriate metalanguage (pcl, postscript, or whatever your spooler recognizes
as graphics). As far as app impacts when printer fails, there are none. lpr is
a spooler, not a direct connect to the printer. Your app talks to lpr, not the
printer.
> 2/ CUPS. I'm not sure this gives us what we need, and all users would
> need to install it.
As far as this goes, CUPS is just another spooler, and you'd spool to it in
the same way as you spool to lpr/lpd (your alternative #1 above). Same
concerns about graphics coming out of your app, same non-concerns about it
failing to print.
> 3/ Postscript. This seems like a lot of work just to get the odd bit of
> bold or italic text, and AIUI we'd need to install ghostscript if
> (when) we need to use a non postscript printer.
Postscript is a print control language. You still have to direct it to a
printer, and you'd do that through a print spooler or direct I/O. You still
have all the concerns of #1, #2 above.
> Are there any other options we're missing here?
>
> The target printers will likely be pretty basic dot matrix parallel
> printers, and ideally we'd like to be able to get at the paper-out and
> offline status that we would read direct from the parallel port back in
> the olden days of MS DOS. Any thoughts on this?
You can either drive these directly from your application (open the printer
device in O_RDWR mode, and manipulate it directly) or you can let the print
spooler manage it for you. Some basic dot matrix printers still have a print
control language that the spooler understands. The spooler would transform
your printer-independant pcl (i.e. postscript) into the PCL that the printer
understands, or pass the printer-dependant pcl (i.e. ESC/P2) directly to the
printer.
> (*) What I _want_ to happen is for the app to continue as normal, but
> to notify the user _exactly_ what has happened and how to fix it.
- --
Lew Pitcher
Master Codewright & JOAT-in-training | GPG public key available on request
Registered Linux User #112576 (http://counter.li.org/)
Slackware - Because I know what I'm doing.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.7 (GNU/Linux)
iD8DBQFDhgMIagVFX4UWr64RAhPCAKCckVKbiTC+
kchnnY//HNPzZnMsIACfcyFJ
DSkFy8syr6jhzdsvR6AzZ7k=
=wX8m
-----END PGP SIGNATURE-----
| |
| Roger Leigh 2005-11-24, 6:58 pm |
| "Simon Elliott" <Simon at ctsn.co.uk> writes:
> What's the current wisdom on printing from a reasonably portable unix
> app? I've looked at these options:
>
> 3/ Postscript. This seems like a lot of work just to get the odd bit of
> bold or italic text, and AIUI we'd need to install ghostscript if
> (when) we need to use a non postscript printer.
>
> Are there any other options we're missing here?
Everything Lew Pitcher said is good advice.
If all you want is simple text formatting, consider piping the output
through groff. For example:
.TL
Troff test page
.PP
Here's some
.I italic
and some \fBbold\fP text.
And here's some \f[CR]courier text\fP.
Pipe this through groff:
groff -T ps -ms < test.ms > test.ps
and inspect the output.
Your application can spool this directly using e.g. popen:
FILE *print = popen("tbl | groff -T ps -ms | lpr -P myprinter", "w");
You just need to allow the user to specify a command for the "lpr -P
myprinter" bit, so that they can use the spooler of their choice. The
above would work with either LPR(ng) or CUPS.
You can do very nice tables (see tbl(1)), and simple graphics as well
(pic(1)). groff is designed to be piped, and works in a single pass.
It's very efficient. If it's not good enough, LaTeX is also worth
considering, but it may require multiple passes, and leaves a pile of
temporary files that need cleaning up. It's much slower, and can't be
piped.
> The target printers will likely be pretty basic dot matrix parallel
> printers, and ideally we'd like to be able to get at the paper-out and
> offline status that we would read direct from the parallel port back in
> the olden days of MS DOS. Any thoughts on this?
That would require direct hardware access. You can certainly do this,
if you open /dev/lpn, and use the ioctls in <linux/lp.h> (in the case
of using Linux). But what about USB printers, network printers etc.?
> (*) What I _want_ to happen is for the app to continue as normal, but
> to notify the user _exactly_ what has happened and how to fix it.
Is this the application's responsibility? It can be, but note that
you forego the flexibility of using a proper spooling system: you'll
have to handle that yourself (queuing jobs, non-blocking I/O if you
want to print while handling user interaction, multiuser
considerations if you want more than one program to print at once,
etc.). I would advise against it, but this may be appropriate for a
very specialised single-user application. If the application ever
grows, you may find this a liability, however.
Regards,
Roger
--
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
| |
| Simon Elliott 2005-11-25, 7:57 am |
| On 24/11/2005, Lew Pitcher wrote:
> Simon Elliott wrote:
>
> Should work for graphics, etc, so long as you encapsulate them in the
> appropriate metalanguage (pcl, postscript, or whatever your spooler
> recognizes as graphics).
Would this be printer specific or would the spooler convert the
graphics to the correct format for the printer which happened to be
attached?
>As far as app impacts when printer fails,
> there are none. lpr is a spooler, not a direct connect to the
> printer. Your app talks to lpr, not the printer.
OK. Is there any way of asking lpr how it's getting on - how many pages
it's printed, whether it's printing my print job yet, whether the
printer is still OK?
>
> As far as this goes, CUPS is just another spooler, and you'd spool to
> it in the same way as you spool to lpr/lpd (your alternative #1
> above). Same concerns about graphics coming out of your app, same
> non-concerns about it failing to print.
Thanks for this - I'm not at all familiar with CUPS and it looks as if
you may have saved me the time needed to evaluate it!
>
> Postscript is a print control language. You still have to direct it
> to a printer, and you'd do that through a print spooler or direct
> I/O. You still have all the concerns of #1, #2 above.
A while ago I did some X windows development, and some photon
development with QNX, which is vaguely similar. There were various
utilities which allowed the developer to output a region as a
postscript file. (I get the impression that Xprint has made all this a
bit easier now, but haven't worked with X windows for a while now and
haven't really been following this.) Many of our users didn't much want
to spend the money on a postscript printer, so we used ghostscript to
take the postscript files and print them.
But this particular app won't necessarily be running with X windows so
generating postscript may be more of a challenge.
> You can either drive these directly from your application (open the
> printer device in O_RDWR mode, and manipulate it directly) or you can
> let the print spooler manage it for you. Some basic dot matrix
> printers still have a print control language that the spooler
> understands. The spooler would transform your printer-independant pcl
> (i.e. postscript) into the PCL that the printer understands, or pass
> the printer-dependant pcl (i.e. ESC/P2) directly to the printer.
So if I put together a postscript file, the spooler will automagically
print that for me on whatever printer is attached?
--
Simon Elliott http://www.ctsn.co.uk
| |
| Simon Elliott 2005-11-25, 7:00 pm |
| On 24/11/2005, Roger Leigh wrote:
> Everything Lew Pitcher said is good advice.
>
> If all you want is simple text formatting, consider piping the output
> through groff. For example:
>
> .TL
> Troff test page
> .PP
> Here's some
> .I italic
> and some \fBbold\fP text.
> And here's some \f[CR]courier text\fP.
>
> Pipe this through groff:
>
> groff -T ps -ms < test.ms > test.ps
>
> and inspect the output.
>
> Your application can spool this directly using e.g. popen:
>
> FILE *print = popen("tbl | groff -T ps -ms | lpr -P myprinter",
> "w");
I like this idea. I'm sort of familiar with troff but hadn't heard of
groff.
> You just need to allow the user to specify a command for the "lpr -P
> myprinter" bit, so that they can use the spooler of their choice. The
> above would work with either LPR(ng) or CUPS.
And presumably switch between troff and groff depending on what's
installed.
> You can do very nice tables (see tbl(1)), and simple graphics as well
> (pic(1)). groff is designed to be piped, and works in a single pass.
> It's very efficient. If it's not good enough, LaTeX is also worth
> considering, but it may require multiple passes, and leaves a pile of
> temporary files that need cleaning up. It's much slower, and can't be
> piped.
Thanks. I'm not that familiar with LaTeX, so this is useful info.
>
> That would require direct hardware access. You can certainly do this,
> if you open /dev/lpn, and use the ioctls in <linux/lp.h> (in the case
> of using Linux). But what about USB printers, network printers etc.?
All a minefield when we port the software to freeBSD, Solaris etc...
>
> Is this the application's responsibility? It can be, but note that
> you forego the flexibility of using a proper spooling system: you'll
> have to handle that yourself (queuing jobs, non-blocking I/O if you
> want to print while handling user interaction, multiuser
> considerations if you want more than one program to print at once,
> etc.). I would advise against it, but this may be appropriate for a
> very specialised single-user application. If the application ever
> grows, you may find this a liability, however.
Most of the time, users be will using our app on a box dedicated for
the task. However, I like the idea of using groff/troff as well, so
looks like it's tradeoff time.
Thanks again for all the useful info and advice.
--
Simon Elliott http://www.ctsn.co.uk
| |
| Lew Pitcher 2005-11-25, 9:56 pm |
| -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Simon Elliott wrote:
> On 24/11/2005, Lew Pitcher wrote:
>
>
>
>
> Would this be printer specific or would the spooler convert the
> graphics to the correct format for the printer which happened to be
> attached?
Your best bet is to use a standard graphics format. A format like postscript
would be the ideal way to generate more than just basic text, but (depending
on the backends supported by your print system) you can also try formats like
png, gif or jpeg.
>
>
>
> OK. Is there any way of asking lpr how it's getting on - how many pages
> it's printed, whether it's printing my print job yet, whether the
> printer is still OK?
popen("lpq") and read the status line
>
>
> Thanks for this - I'm not at all familiar with CUPS and it looks as if
> you may have saved me the time needed to evaluate it!
>
>
>
>
> A while ago I did some X windows development, and some photon
> development with QNX, which is vaguely similar. There were various
> utilities which allowed the developer to output a region as a
> postscript file. (I get the impression that Xprint has made all this a
> bit easier now, but haven't worked with X windows for a while now and
> haven't really been following this.) Many of our users didn't much want
> to spend the money on a postscript printer, so we used ghostscript to
> take the postscript files and print them.
>
> But this particular app won't necessarily be running with X windows so
> generating postscript may be more of a challenge.
Postscript doesn't have to be a challenge to generate. Your output is likely
going to consist of a fixed content portion containing the 'pre-printed' part
of your data, and a variable content portion containing your application data.
You can pre-build the fixed content portion, and store it as program constants
or a configuration/macro substitution file. The variable content portion you
would handle a bit differently, wrapping the variable content in minimal
postscript commands to position it correctly within the end result, and give
it the proper formatting. Most of that could likely be handled with printf()
format strings. Output the fixed content and then the variable content to your
popen()ed lpr, then pclose() the file.
>
>
> So if I put together a postscript file, the spooler will automagically
> print that for me on whatever printer is attached?
Essentially, yes.
You can add logic to permit the user to select the printer (vary the lpr
command options in your popen() - popen("lpr -Pprinter1","w") vs popen("lpr
- -Pprinter2","w") for instance), and just write your output. lpr will take care
of managing the printer, and you (or your user) can use the standard tools and
commands to manipulate the printer and its print.
- --
Lew Pitcher
Master Codewright & JOAT-in-training | GPG public key available on request
Registered Linux User #112576 (http://counter.li.org/)
Slackware - Because I know what I'm doing.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.7 (GNU/Linux)
iD8DBQFDh7Z7agVFX4UWr64RAuqcAJ9u7/wQ9QRmpvrayoHjtCE0WIZnggCglPij
zM2v+mdqxenlZ+pGnzZWZCM=
=/978
-----END PGP SIGNATURE-----
| |
| Simon Elliott 2005-12-07, 7:04 pm |
| On 26/11/2005, Lew Pitcher wrote:
>
> Your best bet is to use a standard graphics format. A format like
> postscript would be the ideal way to generate more than just basic
> text, but (depending on the backends supported by your print system)
> you can also try formats like png, gif or jpeg.
Unless my png/gif/jpeg was the size of the page - which would tie me
down to a specific paper size - I'd still have the problem of
positioning the graphic on the page. Or am I missing something here?
>
> popen("lpq") and read the status line
Seems reasonable!
> Postscript doesn't have to be a challenge to generate. Your output is
> likely going to consist of a fixed content portion containing the
> 'pre-printed' part of your data, and a variable content portion
> containing your application data. You can pre-build the fixed
> content portion, and store it as program constants or a
> configuration/macro substitution file. The variable content portion
> you would handle a bit differently, wrapping the variable content in
> minimal postscript commands to position it correctly within the end
> result, and give it the proper formatting. Most of that could likely
> be handled with printf() format strings. Output the fixed content and
> then the variable content to your popen()ed lpr, then pclose() the
> file.
Interesting idea, as it makes the output configurable without changing
any code.
>
> Essentially, yes.
>
> You can add logic to permit the user to select the printer (vary the
> lpr command options in your popen() - popen("lpr -Pprinter1","w") vs
> popen("lpr - -Pprinter2","w") for instance), and just write your
> output. lpr will take care of managing the printer, and you (or your
> user) can use the standard tools and commands to manipulate the
> printer and its print.
Just to make sure I've understood this: I can have a clunky old Epson
dot matrix printer as printer2, which uses escape codes for bold and so
on, do a popen("lpr -Pprinter2","w") and write a postscript file, and
an appropriately formatted (as far as possible) set of pages will be
printed?
--
Simon Elliott http://www.ctsn.co.uk
| |
| Roger Leigh 2005-12-07, 7:04 pm |
| -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
"Simon Elliott" <Simon at ctsn.co.uk> writes:
> On 26/11/2005, Lew Pitcher wrote:
>
>
> Unless my png/gif/jpeg was the size of the page - which would tie me
> down to a specific paper size - I'd still have the problem of
> positioning the graphic on the page. Or am I missing something here?
You could wrap it in PostScript and have the raster image scaled and
positioned appropriately. Unless the data you are printing is a
photograph or other raster image, this is not ideal (you will lose in
both print quality, print job size and print speed due to the
processing overhead of rescaling the raster image).
> Just to make sure I've understood this: I can have a clunky old Epson
> dot matrix printer as printer2, which uses escape codes for bold and so
> on, do a popen("lpr -Pprinter2","w") and write a postscript file, and
> an appropriately formatted (as far as possible) set of pages will be
> printed?
Sort of. The PostScript will be rasterised, and this will be printed
on the printer in its native raster graphics mode. For an Epson dot
matrix, this equates to the single-, double- or quad-density bit-image
modes. These modes are progressively slower as you increase the
density, and will all be less readable than the built-in fonts which
are designed for legibility and fast printing. If you use PostScript,
you will forego the ability to use the built-in fonts and
escape-sequence formatting (for bold, italic, underline, etc.).
Regards,
Roger
- --
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8+ <http://mailcrypt.sourceforge.net/>
iD8DBQFDl1gKVcFcaSW/ uEgRAt3TAJ48xixWWnoUYGvrd1DkdNsOEb2BAwCf
Two2
vtOPLcEeGD3Uqm3XZwD2KmM=
=6uFb
-----END PGP SIGNATURE-----
| |
| Simon Elliott 2005-12-09, 4:15 am |
| On 07/12/2005, Roger Leigh wrote:
>
> Sort of. The PostScript will be rasterised, and this will be printed
> on the printer in its native raster graphics mode. For an Epson dot
> matrix, this equates to the single-, double- or quad-density bit-image
> modes. These modes are progressively slower as you increase the
> density, and will all be less readable than the built-in fonts which
> are designed for legibility and fast printing. If you use PostScript,
> you will forego the ability to use the built-in fonts and
> escape-sequence formatting (for bold, italic, underline, etc.).
Would I need CUPS or ghostscript to be installed to make this happen,
or is the basic spooler enough?
--
Simon Elliott http://www.ctsn.co.uk
| |
| Roger Leigh 2005-12-09, 8:14 am |
| -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
"Simon Elliott" <Simon at ctsn.co.uk> writes:
> On 07/12/2005, Roger Leigh wrote:
>
>
> Would I need CUPS or ghostscript to be installed to make this happen,
> or is the basic spooler enough?
You need Ghostscript to do the rasterisation, and CUPS or LPRng for
spooling. CUPS requires ESPgs, a customised version of Ghostscript
which includes extra drivers. In Debian, you would install the
"cupsys" and "gs-esp" packages; CUPS comes with basic 9- and 24-pin
drivers.
Regards,
Roger
- --
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8+ <http://mailcrypt.sourceforge.net/>
iD8DBQFDmVoYVcFcaSW/uEgRAnwCAKC0AGSNeh7gC/9j4lPlaWvH26JRawCggC+Q
x8D3TeJLjNQbhcxekxODjRA=
=YR51
-----END PGP SIGNATURE-----
| |
| Simon Elliott 2005-12-09, 7:18 pm |
| On 09/12/2005, Roger Leigh wrote:
>
> You need Ghostscript to do the rasterisation, and CUPS or LPRng for
> spooling. CUPS requires ESPgs, a customised version of Ghostscript
> which includes extra drivers. In Debian, you would install the
> "cupsys" and "gs-esp" packages; CUPS comes with basic 9- and 24-pin
> drivers.
OK. Many thanks for all your input. I think given your and Lew
Pitcher's advice, my first pass will be groff/troff, with postscript
held in reserve if the requirement gets more involved.
--
Simon Elliott http://www.ctsn.co.uk
|
|
|
|
|