Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to organize multiple devices in PS interpreter? (secrets of banddevice and framedevice)

116 views
Skip to first unread message

luser- -droog

unread,
Jul 17, 2013, 12:21:47 PM7/17/13
to
The Warnock/Wyatt Stencil-Paint Image Model (SIGGRAPH 16(3) 1982)
says

Scan Conversion
Strictly speaking, a given device implementation need supply only
one procedure, DisplayConvexPolygon. This procedure
implements the most general case of scan conversion that the device
must handle: pushing a general mapped scanned image, as a source,
through a mapped mask. The arguments taken by the procedure
are:

1. A convex polygon. This polygon represents either part of a
shape (if no mask is given), or the boundary of a mask (if a
mask is given).

2. A source, which is either a constant value, or:
a. A mapping S from the SCS [Source-Coordinate-System]
to the DCS [Device-Coordinate-System], and
b. A pointer to the source sample array.

3. An optional mask which includes:
a. A mapping M from the mask's SCS to the DCS, and
b. A pointer to the mask sample array.

The operation carried out by this procedure is:

For each pixel position (x, y) in the interior of the convex polygon in
DCS, compute (x_s, y_s) = (x,y)S^-1, and (x_m, y_m) = (x,y)M^-1. If the
value in the mask array at (x_m, y_m) = 1, then interpret the source
value at (x_s, y_s) for the device type and display an appropriate value
at (x, y). Note: in practice, instead of mapping each point in DCS
through two inverse mappings (computationally expensive),
incremental mapping techniques are used; in this way each mapping
is replaced with two add operations. This is dicussed later in the
section on optimizations.

So it all boils down to this amazing DisplayConvexPolygon procedure
that's fully generalized (but case special-case out to optimized
versions where some of the above input is constant).

The PLRM, 1ed, describes some interesting Device setup and output
operators:

matrix width height proc banddevice - install band buffer device
matrix width height proc framedevice - install frame buffer device
- nulldevice - install no-output device
proc renderbands - enumerate bands for output
to device

So each of these device setup operators (at least conceptually) must
install a version of DisplayConvexPolygon which corresponds to the
final actions of fill or eofill.

fill - fill -
paints the area enclosed by the current path with the current color.
Any previous contents of that area on the current page are obscured,
so areas may be erased by filling with color set to white.

Before painting, fill implicitly closes any open subpaths of the
current path. The inside of the current path is determined by the
normal PostScript non-zero winding number rule (see section 4.6).

fill implicitly performs newpath after it has finished filling the
current path. To preserve the current path across a fill operation,
use the sequence: gsave fill grestore.

The banddevice works so: "operations that place marks on the page
accumulate information in a display list. When it comes time to render
the page on the output device (during showpage), the display list
is read and used to construct a sequence of rectangular bands of pixels,
each of which is immediately transmitted to the device." Ignoring the
actual "bands" part, this sort of display list would be the structure
manipulated by a pdfdevice::DisplayConvexPolygon, n'est-ce-pas?

Whereas using a screen window as a canvas would correspond more to
the framedevice archetype: "installs a frame buffer as the raster
memory for an output device and establishes some of the properties
of that device. This operator sets up a full page frame buffer 8 x width
pixels wide by height pixels high; the width and height should be
consistent with the physical properties of the raster output device."


So that's the mess I'm trying to make sense of now.
Questions? Corrections? Stories from the trenches?

--
M. Joshua Ryan
(luser droog)

abeddie

unread,
Jul 17, 2013, 3:18:35 PM7/17/13
to
I believe the banded frame would be used in low memory devices so a full frame
buffer would not have to be allocated. In a multi-threaded device one thread
could be writing display list and another the buffer.

luser- -droog

unread,
Jul 17, 2013, 5:10:08 PM7/17/13
to
On Wednesday, July 17, 2013 2:18:35 PM UTC-5, abeddie wrote:
> On Wednesday, July 17, 2013 12:21:47 PM UTC-4, luser- -droog wrote:
>
>
> > The PLRM, 1ed, describes some interesting Device setup and output
> > operators:
>
> > matrix width height proc banddevice - install band buffer device
> > matrix width height proc framedevice - install frame buffer device
> > - nulldevice - install no-output device
> > proc renderbands - enumerate bands for output
> > to device
[snip]
>
> > The banddevice works so: "operations that place marks on the page
> > accumulate information in a display list. When it comes time to render
> > the page on the output device (during showpage), the display list
> > is read and used to construct a sequence of rectangular bands of pixels,
> > each of which is immediately transmitted to the device." Ignoring the
> > actual "bands" part, this sort of display list would be the structure
> > manipulated by a pdfdevice::DisplayConvexPolygon, n'est-ce-pas?
>
> > Whereas using a screen window as a canvas would correspond more to
> > the framedevice archetype: "installs a frame buffer as the raster
> > memory for an output device and establishes some of the properties
> > of that device. This operator sets up a full page frame buffer 8 x width
> > pixels wide by height pixels high; the width and height should be
> > consistent with the physical properties of the raster output device."
> >

>
> I believe the banded frame would be used in low memory devices so a full frame
>
> buffer would not have to be allocated. In a multi-threaded device one thread
>
> could be writing display list and another the buffer.

I hadn't thought of that. I thought it would mostly be for
spool-fed printers where the output page might have a
variable length (hence no predictable buffer size).


luser- -droog

unread,
Jul 18, 2013, 11:43:33 PM7/18/13
to
So, the really slick way to do devices is going to be hot-loadable dll-modules, right? So they can be loaded and unloaded by a running instance of the program (appropriate for the planned 'server'-mode).

I did some work on this a few years ago, but I've misplaced the sd-card salvaged from the XO-1, so my code-base is down to what I written since December on this new computer, a few versions of xpost I copied over from the sd-card, and all the stuff I've shared on the internet. Fortunately for me, I share a lot. :D

luser- -droog

unread,
Jul 21, 2013, 2:23:12 AM7/21/13
to
On Thursday, July 18, 2013 10:43:33 PM UTC-5, luser- -droog wrote:
> So, the really slick way to do devices is going to be hot-loadable dll-modules, right? So they can be loaded and unloaded by a running instance of the program (appropriate for the planned 'server'-mode).
>
>
>
> I did some work on this a few years ago, but I've misplaced the
> sd card salvaged from the XO-1, so my code-base is down to what I
> written since December on this new computer, a few versions of
> xpost I copied over from the sd-card, and all the stuff I've
> shared on the internet. Fortunately for me, I share a lot. :D

It looks like I never posted it. :( It wasn't much.
It had an ascii-art device, an x-window device, an xbm device.
It accepted moveto, lineto, curveto, closepath;
did a flattenpath with recursive deCasteljau,
Then, I had some stupid flood-fills and bresenham-plotter
functions that were called through function-pointers in the
device object. I fizzled-out looking for info on Weiler-Atherton.

But the real question is Multi-platform or Cross-platform.

The xpost2 slap-shod graphics capability was Cairo coupled
with X1ib. Which is kinda/sorta portable-ish. The Xlib window
part could be supplemented with a Windows equivalent (I think).
This is what I would call "Multiplatform". Where the portability
is relatively isolated to 1 or 2 OS- or GUI- specific files.

On the other hand, there's SDL... Abstracts the whole GUI, right?
That leaves just One OS-dependent file. And maybe some POSIX
support, if needed. But that can be supplied without a full
Cygwin install, right? SDL seems like the stuff.

I suppose OpenGL would sort-of qualify, too. But it's really bad
match-up of abstractions. I tried, years ago, with the F.S. Hill
textbook, but Mayura-draw did a better job than my OpenGl-mess
ever did. :D

--
Design teacher said a print-out was not acceptable for the assignment.
I said, "But I wrote an OpenGl program to produce the coordinates,
then tweaked each triangle numerically to get the nicest pattern
on the magpie's wing."
She insisted I re=do it with cut-paper and rubber-cement.
Years later, it still hangs, framed and mounted in my mother's
livingroom. But the triangles have fallen like winter leaves.
And the magpie is no more.

luser- -droog

unread,
Jul 21, 2013, 4:06:17 PM7/21/13
to
> that's fully generalized (but [can] special-case out to optimized
A little more cribbing from SIGGRAPH 82 (Warnock/Wyatt).
Concise stencil/paint API.

display_context {
interface_to_device;
current position (cpx, cpy) in DCS;
transformation matrix T;
clipping_region CR;
}

Device NewXXXDevice (<optional params>);
Image NewXXXImage (<optional params>);

DisplayContext NewDisplayContext (Device device);

(x,y) GetCurrentPosition (DisplayContext dc);
void SetCurrentPosition (DisplayContext dc, x, y);
Trajectory NewTrajectory (x, y);
Trajectory LineTo (Trajectory t, x, y);
Trajectory CurveTo (Trajectory t, x1, y1, x2, y2, x3, y3);
Trajectory Close (Trajectory t);
Trajectory Rectangle (xl, yl, xu, yu);

Shape NewShape ();
Shape AddToShape (Shape s, Trajectory t);
Shape MakeLineShape (Shape brush, Trajectory t);

Source MakeColorSource (hue, sat, bright);
Source MakeImageSource (Image image);

void DrawShape (DisplayContext dc, Shape shape, Source source);
void DrawMask (DisplayContext dc, Image mask, Source source);

void SetClipShape (DisplayContext dc, Shape shape);

void Translate (DisplayContext dc, x, y);
void Rotate (DisplayContext dc, angle);
void Scale (DisplayContext dc, sx, sy);
void Concatenate (DisplayContext dc, Matrix m);
Matrix GetMatrix (DisplayContext dc);

FontId MakeFont (<font name>);
void DisplayChar (Char c, FontId f);
void DisplayText (String s, FontId f);
<metrics> GetCharMetrics (Char c, FontId f);

_________Internal _ Operations________________________
PS ___________ Warnock/Wyatt _____ Algorithm _________
(automatic) Shape Mapping (Matrix Transforms)
flattenpath Shape Approximation (deCasteljau)
Shape Reduction
clip clippath Shape Clipping (Weiler/Atherton)

luser- -droog

unread,
Sep 7, 2013, 1:46:15 AM9/7/13
to
On Thursday, July 18, 2013 10:43:33 PM UTC-5, luser- -droog wrote:
> So, the really slick way to do devices is going to be hot-loadable dll-modules, right? So they can be loaded and unloaded by a running instance of the program (appropriate for the planned 'server'-mode).
>
>
>
> I did some work on this a few years ago, but I've misplaced the sd-card salvaged from the XO-1, so my code-base is down to what I written since December on this new computer, a few versions of xpost I copied over from the sd-card, and all the stuff I've shared on the internet. Fortunately for me, I share a lot. :D

I found a short manual that describes a system for multiple output devices,
that appears to be just the model I'm looking for. Geared toward pen-plotters,
but it even includes a PS device.

Technical manual for a UNIX-based device-independent vector graphic system
1991, Evenden, G. I.
USGS Open-File Report: 91-2
http://pubs.er.usgs.gov/publication/ofr912 (pdf available)

luser- -droog

unread,
Sep 7, 2013, 3:02:15 PM9/7/13
to
The author, Mr. Evenden, no longer has a copy of the software. So don't anybody else go bothering him about it. :)

luser- -droog

unread,
Sep 14, 2013, 1:11:24 AM9/14/13
to
On Thursday, July 18, 2013 10:43:33 PM UTC-5, luser- -droog wrote:
> So, the really slick way to do devices is going to be hot-loadable dll-modules, right? So they can be loaded and unloaded by a running instance of the program (appropriate for the planned 'server'-mode).
>
>
>
> I did some work on this a few years ago, but I've misplaced the sd-card salvaged from the XO-1, so my code-base is down to what I written since December on this new computer, a few versions of xpost I copied over from the sd-card, and all the stuff I've shared on the internet. Fortunately for me, I share a lot. :D

At long last, I think the correct way to build this is finally clear
to me. It starts with filenameforall, ie. filename globbing. ?a*.exe
etc. With that I can efficiently implement named resources loaded from predictable file-system locations. With named resources, I can
conveniently store the various device-dictionaries in a user-transparent
way.

The file-name globbing presents a small challenge. I could either disregard
the memory-saving behavior of having the user pass a string buffer for
filenames, and having filenameforall construct an array and call regular
forall. Ptooey. Or, I think I need to make a new globtype object to pass
the list of filenames from one iteration to the next. It'll also need an
internal continuation operator, which I've avoided with the other loops.
This because the globtype object itself is only generated once at the start.
This internal operator would only be user-visible if execstack were called
during the execution of proc inside the loop. So, meh. Everybody else does it.

Moral: don't mess with the execstack unless you know what you're doing.
Theyre be thinges thar with no name!

luser- -droog

unread,
Sep 19, 2013, 4:52:03 AM9/19/13
to
I think I've got the glob-loop written. But I can't verify it. I can't even read it. My brain isn't working.
:(

cf. http://code.google.com/p/xpost/source/browse/opf.c#225

sleep, maybe...

luser- -droog

unread,
Sep 19, 2013, 4:58:35 AM9/19/13
to
Dammit! NO. There's something very wrong there.
That is not a good way to treat a pointer.
I haven't asserted that it's 32bits anywhere!

And this won't work if the server session is hibernated
and restored from the mfile image. Raw pointers! :-(

It would fit the pattern of the rest of the code better,
if I go ahead and copy the whole list into vm.

global or local?
lexically at least, glob clearly belongs with global.

luser- -droog

unread,
Sep 19, 2013, 5:59:22 AM9/19/13
to
On Thursday, September 19, 2013 3:58:35 AM UTC-5, luser- -droog wrote:
> On Thursday, September 19, 2013 3:52:03 AM UTC-5, luser- -droog wrote:
>
> > On Saturday, September 14, 2013 12:11:24 AM UTC-5, luser- -droog wrote:
>
> > > On Thursday, July 18, 2013 10:43:33 PM UTC-5, luser- -droog wrote:
>
> > > > So, the really slick way to do devices is going to be hot-loadable dll-modules, right? So they can be loaded and unloaded by a running instance of the program (appropriate for the planned 'server'-mode).
>
> > > > I did some work on this a few years ago, but I've misplaced the sd-card salvaged from the XO-1, so my code-base is down to what I written since December on this new computer, a few versions of xpost I copied over from the sd-card, and all the stuff I've shared on the internet. Fortunately for me, I share a lot. :D
>
> > > At long last, I think the correct way to build this is finally clear
> > > to me. It starts with filenameforall, ie. filename globbing. ?a*.exe
> > > etc. With that I can efficiently implement named resources loaded from predictable file-system locations. With named resources, I can
> > > conveniently store the various device-dictionaries in a user-transparent
>
> > > The file-name globbing presents a small challenge. I could either disregard
> > > the memory-saving behavior of having the user pass a string buffer for
> > > filenames, and having filenameforall construct an array and call regular
> > > forall. Ptooey. Or, I think I need to make a new globtype object to pass
> > > the list of filenames from one iteration to the next. It'll also need an
> > > internal continuation operator, which I've avoided with the other loops.
> > > This because the globtype object itself is only generated once at the start.
> > > This internal operator would only be user-visible if execstack were called
> > > during the execution of proc inside the loop. So, meh. Everybody else does it.
> > > Moral: don't mess with the execstack unless you know what you're doing.
> > > Theyre be thinges thar with no name!
>
> > I think I've got the glob-loop written. But I can't verify it. I can't even read it. My brain isn't working.
> > :(
>
> > cf. http://code.google.com/p/xpost/source/browse/opf.c#225
>
> > sleep, maybe...
>
> Dammit! NO. There's something very wrong there.
> That is not a good way to treat a pointer.
> I haven't asserted that it's 32bits anywhere!
>
> And this won't work if the server session is hibernated
> and restored from the mfile image. Raw pointers! :-(
>
> It would fit the pattern of the rest of the code better,
> if I go ahead and copy the whole list into vm.
>
> global or local?
>
> lexically at least, glob clearly belongs with global.

Holy crap! it works!

$ ./itp

^test itp.c
loading init.ps...
loading err.ps...
$error
Xpost3 version 0.0
PS>(*.c){=}128 string filenameforall
ar.c
di.c
err.c
f.c
gc.c
itp.c
m.c
nm.c
ob.c
op.c
opar.c
opb.c
opc.c
opdi.c
opf.c
opm.c
oppa.c
ops.c
opst.c
opt.c
optok.c
opv.c
opx.c
osunix.c
s.c
st.c
v.c
PS>
0 new messages