[lazarus] Printers unit

andrew johnson acjgenius at earthlink.net
Tue Nov 5 09:24:11 EST 2002

On Tue, 2002-11-05 at 01:38, Tony Maro wrote:
> I've got a basic working printers unit.
> I've tried to make it as ready for real printer support as possible. 
> What I've done is added a TPostScriptCanvas object that handles most of
> the Postscript work - not that there's a lot to do.  Unfortunately part
> of it must be handled at the Printer object level (page separation, etc)
> so I can't encapsulate all of the postscript generation in that object.

Are you certain? I was fairly sure that Postscript supported multiple
pages from the same file... with %%Page

> The plan is to have anything that I can't handle in postscript code to
> pass through to a regular TCanvas object that holds a bitmap.  Then,
> once I figure out how... I can encapsulate the remaining graphics from
> the bitmap into the postscript code.  So, any paint or drawing routines
> the user calls that doesn't directly translate to postscript can still
> be used.

You can handle virtually anything with Postscript calls. Bitmaps are a
Problem, as are More advanced Raster Operations, but even they can be
handled for the most part natively. And for the rest.. Arc/Pie/Ellipse
can use Bezier functions from MathGraph.pp routines and call to Polygon.
Polygon works the same way as Polyline except for the fill params. Easy
enough to handle I think. Obviously Polyline can simply loop through the
points and call to MoveTo LineTo something like this :

procedure TPostScriptCanvas.Polyline(Points: PPoint; NumPts: Integer);
  i : Longint;
  LastPt : TPoint;
  If (NumPts <= 1) or (Points = nil) then exit;
  LastPt := Point(LastX, LastY);
  MoveTo(Points[0].X, Points[0].Y);
  For i := 1 to NumPts - 1 do
    LineTo(Points[i].X, Points[i].Y);
  MoveTo(LastPt.X, LastPt.Y);

RoundRect can be based upon my InterfaceBase RoundRect to Call to the
canvas arc Pie & rectangle instead of Interfaces. Or better we can
convert it into a Polygon Points with Bezier Functions. That will be
easier I think..

Also note you have started single path, this will be hard to handle with
things like rectangle ellipse and so forth which are their own complete
path(not that you can't do it this way.. but it may be difficult).

> Attached is the printers.pas unit and a sample application for testing
> purposes.  I have no font support in it yet, and the only things that
> work on the canvas are moveto, lineto and TextOut.
> I wouldn't bother adding this to the LCL just yet... but I wanted
> feedback to see if anyone thinks I'm headed down the wrong path with
> this.  If I get a green light I'll delve into it deeper.

It's a start. Portions of this would be much easier on the interface
side of things, but that would make things harder for Cross-Platform
support. My Suggestion would be to write a third object. A TPostscript
object encapsulating the Postscript calls. Not a translation, not
anything. Pure Postscript calls. This way it would be easier later on to
separate the Postscript code from your canvas and move it to the
back-end of things. Then your canvas can use it to handle the calls etc.
I can help out some with this, but if you are willing to make it easy
enough to separate the Postscript Engine from the Postscript Canvas it
will make it even easier, because then it would be possible to create
wrappers around it in the interface portion, which would essentially
allows us to phase out the need for a special TCanvas component. But
either way it can be done. So too sum up.. go for it it will work fine
for now, and portions can be re-used later on to design a more
Delphi/all things automated, most of the work hidden, way.

> My questions are these: 
> What is the proper way to tell the Printer object to print to file using
> Delphi?

Its automatic. If the printer is set to start printing immediately the
moment you do a NewPage/EndDoc the prior page will print, otherwise all
pages will start after EndDoc.

> How can I (in Linux) stream the stringlist holding the postscript into
> LPR directly?  Or must I go through a temp file?

I would suggest for now a temp file, but you could probably find a way
to do it via stdin/stdout.

> Another thing I need to do is query lpstat to find out what printers are
> available.  How can I best issue the shell command and grab the output? 
> I know I could output it to a temp file, read that file then delete it. 
> Is there a better way?

Again, if there is an easy way.. stdin/stdout. I know how to do this in
C, but never had a real need in Delphi so.. research. I will see if I
can find anything in my spare time. Also you might look into Corel's old
library its kinda obsolete(though I think its currently being worked on
by Xandros), but it may be a useful reference anyway. Its located at 


(and yes, it's in C).


More information about the Lazarus mailing list