{Begin SubSec Implementation of Image Streams}
{Title Implementation of Image Streams}
{Text

{Index *PRIMARY* Device-independent graphics}
{Index *PRIMARY* DIG (Device-Independent Graphics) Term}

Interlisp does all image creation through a set of functions and data structures for device-independent graphics, known popularly as DIG.  DIG is implemented through the use of a special type of stream, known as an image stream.

An image stream, by convention, is any stream that has its {lisp IMAGEOPS} field (described in detail below) set to a vector of meaningful graphical operations.  Using image streams, you can write programs that draw and print on an output stream without regard to the underlying device, be it a window, a disk, or a printer.

To define a new image stream type, it is necessary to put information on the variable {var IMAGESTREAMTYPES}:

{VarDef {Name IMAGESTREAMTYPES}
{Text
This variable describes how to create a stream for a given image stream type.  The value of {var IMAGESTREAMTYPES} is an association list, indexed by the image stream type (e.g., {lisp DISPLAY}, {lisp INTERPRESS}, etc.).  The format of a single association list item is:

{lispcode 
({arg IMAGETYPE}
   (OPENSTREAM {arg OPENSTREAMFN})
   (FONTCREATE {arg FONTCREATEFN})
   (FONTSAVAILABLE {arg FONTSAVAILABLEFN}))}

{arg OPENSTREAMFN}, {arg FONTCREATEFN}, and {arg FONTSAVAILABLEFN} are "image stream methods," device-dependent functions used to implement generic image stream operations.  For Interpress image streams, the association list entry is:

{lispcode 
(INTERPRESS
   (OPENSTREAM OPENIPSTREAM)
   (FONTCREATE \CREATEINTERPRESSFONT)
   (FONTSAVAILABLE \SEARCHINTERPRESSFONTS))}
}}


{Def {Type (Image Stream Method)}
{Name OPENSTREAMFN} {Args FILE OPTIONS}
{Text
{arg FILE} is the file name as it was passed to {fn OPENIMAGESTREAM}, and {arg OPTIONS} is the {arg OPTIONS} property list passed to {fn OPENIMAGESTREAM}.  The result must be a stream of the appropriate image type.
}}


{Def {Type (Image Stream Method)}
{Name FONTCREATEFN} {Args FAMILY SIZE FACE ROTATION DEVICE}
{Text
{arg FAMILY} is the family name for the font, e.g., {lisp MODERN}.  {arg SIZE} is the body size of the font, in printer's points.  {arg FACE} is a three-element list describing the weight, slope, and expansion of the face desired, e.g., {lisp (MEDIUM ITALIC EXPANDED)}.  {arg ROTATION} is how much the font is to be rotated from the normal orientation, in minutes of arc.  For example, to print a landscape page, fonts have the rotation 5400 (90 degrees).  The function's result must be a {lisp FONTDESCRIPTOR} with the fields filled in appropriately.
}}

{Def {Type (Image Stream Method)}
{Name FONTSAVAILABLEFN} {Args FAMILY SIZE FACE ROTATION DEVICE}
{Text
This function returns a list of all fonts agreeing with the {arg FAMILY}, {arg SIZE}, {arg FACE}, and {arg ROTATION} arguments; any of them may be wild-carded (i.e., equal to {lisp *}, which means any value is acceptable).  Each element of the list should be a quintuple of the form {lisp ({arg FAMILY} {arg SIZE} {arg FACE} {arg ROTATION} {arg DEVICE})}.

Where the function looks is an implementation decision: the {arg FONTSAVAILABLEFN} for the display device looks at {var DISPLAYFONTDIRECTORIES}, the Interpress code looks on {var INTERPRESSFONTDIRECTORIES}, and implementors of new devices should feel free to introduce new search path variables.
}}


As indicated above, image streams use a field that no other stream uses: {lisp IMAGEOPS}.{index IMAGEOPS (Stream Field)}  {lisp IMAGEOPS} is an instance of the {lisp IMAGEOPS}{index IMAGEOPS (Data type)} data type and contains a vector of the stream's graphical methods.  The methods contained in the {lisp IMAGEOPS} object can make arbitrary use of the stream's {lisp IMAGEDATA}{index IMAGEDATA (Stream Field)} field, which is provided for their use, and may contain any data needed.

The {lisp IMAGEOPS} data type has the following fields:

{Def {Type (IMAGEOPS Field)} {Name IMAGETYPE}
{Text
Value is the name of an image type.  Monochrome display streams have an {lisp IMAGETYPE} of {lisp DISPLAY}; color display streams are identified as {lisp (COLOR DISPLAY)}.  The {lisp IMAGETYPE} field is informational and can be set to anything you choose.
}}

{Def {Type (IMAGEOPS Field)} {Name IMFONTCREATE}
{Text
Value is the device name to pass to {fn FONTCREATE} when fonts are created for the stream.
}}


The remaining fields are all image stream methods, whose value should be a device-dependent function that implements the generic operation.  Most methods are called by a similarly-named function, e.g. the function {fn DRAWLINE} calls the {lisp IMDRAWLINE} method.  All coordinates that refer to points in a display device's space are measured in the device's units.  (The {lisp IMSCALE}{index IMSCALE (Image Stream Method)} method provides access to a device's scale.)  For arguments that have defaults (such as the {arg BRUSH} argument of {fn DRAWCURVE}), the default is substituted for the {lisp NIL} argument before it is passed to the image stream method.  Therefore, image stream methods do not have to handle defaults.


{Def {Type (Image Stream Method)}
{Name IMCLOSEFN} {Args STREAM}
{Text
Called before a stream is closed with {fn CLOSEF}.  This method should flush buffers, write header or trailer information, etc.
}}


{Def {Type (Image Stream Method)}
{Name IMDRAWLINE} {Args STREAM X{sub 1} Y{sub 1} X{sub 2} Y{sub 2} WIDTH OPERATION COLOR DASHING}
{Text
Draws a line of width {arg WIDTH} from {lisp ({arg X{sub 1}}, {arg Y{sub 1}})} to {lisp ({arg X{sub 2}}, Y{sub 2})}.  See {fn DRAWLINE}, {PageRef Fn DRAWLINE}.
}}


{Def {Type (Image Stream Method)}
{Name IMDRAWCURVE} {Args STREAM KNOTS CLOSED BRUSH DASHING}
{Text
Draws a curve through {arg KNOTS}.  See {fn DRAWCURVE}, {PageRef Fn DRAWCURVE}.
}}


{Def {Type (Image Stream Method)}
{Name IMDRAWCIRCLE} {Args STREAM CENTERX CENTERY RADIUS BRUSH DASHING}
{Text
Draws a circle of radius {arg RADIUS} around {lisp ({arg CENTERX}, {arg CENTERY})}.  See {fn DRAWCIRCLE}, {PageRef Fn DRAWCIRCLE}.
}}


{Def {Type (Image Stream Method)}
{Name IMDRAWELLIPSE} {Args STREAM CENTERX CENTERY SEMIMINORRADIUS SEMIMAJORRADIUS ORIENTATION BRUSH DASHING}
{Text
Draws an ellipse around {lisp ({arg CENTERX}, {arg CENTERY})}.  See {fn DRAWELLIPSE}, {PageRef Fn DRAWELLIPSE}.
}}


{Def {Type (Image Stream Method)}
{Name IMFILLPOLYGON} {Args STREAM POINTS TEXTURE}
{Text
Fills in the {index Polygons}polygon outlined by {arg POINTS} on the image stream {arg STREAM}, using the texture {arg TEXTURE}.  See {fn FILLPOLYGON}, {PageRef Fn FILLPOLYGON}.
}}


{Def {Type (Image Stream Method)}
{Name IMFILLCIRCLE} {Args STREAM CENTERX CENTERY RADIUS TEXTURE}
{Text
Draws a circle filled with texture {arg TEXTURE} around {lisp ({arg CENTERX}, {arg CENTERY})}.  See {fn FILLCIRCLE}, {PageRef Fn FILLCIRCLE}.
}}


{Def {Type (Image Stream Method)}
{Name IMBLTSHADE} {Args TEXTURE STREAM DESTINATIONLEFT DESTINATIONBOTTOM WIDTH HEIGHT OPERATION CLIPPINGREGION}
{Text
The texture-source case of {fn BITBLT} ({PageRef Fn BITBLT}).  {arg DESTINATIONLEFT}, {arg DESTINATIONBOTTOM}, {arg WIDTH}, {arg HEIGHT}, and {arg CLIPPINGREGION} are measured in {arg STREAM}'s units.  This method is invoked by the functions {fn BITBLT} and {fn BLTSHADE} ({PageRef Fn BLTSHADE}).
}}


{Def {Type (Image Stream Method)}
{Name IMBITBLT} {Args SOURCEBITMAP SOURCELEFT SOURCEBOTTOM STREAM DESTINATIONLEFT DESTINATIONBOTTOM WIDTH HEIGHT SOURCETYPE OPERATION TEXTURE CLIPPINGREGION CLIPPEDSOURCELEFT CLIPPEDSOURCEBOTTOM SCALE}
{Text
Contains the bit-map-source cases of {fn BITBLT} ({PageRef Fn BITBLT}).  {arg SOURCELEFT}, {arg SOURCEBOTTOM}, {arg CLIPPEDSOURCELEFT}, {arg CLIPPEDSOURCEBOTTOM}, {arg WIDTH}, and {arg HEIGHT} are measured in pixels; {arg DESTINATIONLEFT}, {arg DESTINATIONBOTTOM}, and {arg CLIPPINGREGION} are in the units of the destination stream.
}}


{Def {Type (Image Stream Method)}
{Name IMSCALEDBITBLT} {Args SOURCEBITMAP SOURCELEFT SOURCEBOTTOM STREAM DESTINATIONLEFT DESTINATIONBOTTOM WIDTH HEIGHT SOURCETYPE OPERATION TEXTURE CLIPPINGREGION  CLIPPEDSOURCELEFT CLIPPEDSOURCEBOTTOM SCALE}
{Text
A scaled version of {lisp IMBITBLT}.  Each pixel in {arg SOURCEBITMAP} is replicated {arg SCALE} times in the X and Y directions; currently, {arg SCALE} must be an integer.
}}


{Def {Type (Image Stream Method)}
{Name IMMOVETO} {Args STREAM X Y}
{Text
Moves to {lisp ({arg X},{arg Y})}.  This method is invoked by the function {fn MOVETO} ({PageRef Fn MOVETO}).  If {lisp IMMOVETO} is not supplied, a default method composed of calls to the {lisp IMXPOSITION} and {lisp IMYPOSITION} methods is used.
}}


{Def {Type (Image Stream Method)}
{Name IMSTRINGWIDTH} {Args STREAM STR RDTBL}
{Text
Returns the width of string {arg STR} in {arg STREAM}'s units, using {arg STREAM}'s current font.  This is envoked when {fn STRINGWIDTH} ({PageRef Fn STRINGWIDTH}) is passed a stream as its {arg FONT} argument.  If {lisp IMSTRINGWIDTH} is not supplied, it defaults to calling {fn STRINGWIDTH} on the default font of {arg STREAM}.
}}


{Def {Type (Image Stream Method)}
{Name IMCHARWIDTH} {Args STREAM CHARCODE}
{Text
Returns the width of character {arg CHARCODE} in {arg STREAM}'s units, using {arg STREAM}'s current font.  This is invoked when {fn CHARWIDTH} ({PageRef Fn CHARWIDTH}) is passed a stream as its {arg FONT} argument.  If {lisp IMCHARWIDTH} is not supplied, it defaults to calling {fn CHARWIDTH} on the default font of {arg STREAM}.
}}


{Def {Type (Image Stream Method)}
{Name IMCHARWIDTHY} {Args STREAM CHARCODE}
{Text
Returns the Y componant of the width of character {arg CHARCODE} in {arg STREAM}'s units, using {arg STREAM}'s current font.  This is envoked when {fn CHARWIDTHY} ({PageRef Fn CHARWIDTHY}) is passed a stream as its {arg FONT} argument.  If {lisp IMCHARWIDTHY} is not supplied, it defaults to calling {fn CHARWIDTHY} on the default font of {arg STREAM}.
}}


{Def {Type (Image Stream Method)}
{Name IMBITMAPSIZE} {Args STREAM BITMAP DIMENSION}
{Text
Returns the size that {arg BITMAP} will be when {fn BITBLT}ed to {arg STREAM}, in {arg STREAM}'s units.  {arg DIMENSION} can be one of {lisp WIDTH}, {lisp HEIGHT}, or {lisp NIL}, in which case the dotted pair {lisp ({arg WIDTH} . {arg HEIGHT})} will be returned.

This is envoked by {fn BITMAPIMAGESIZE} ({PageRef Fn BITMAPIMAGESIZE}).  If {lisp IMBITMAPSIZE} is not supplied, it defaults to a method that multiplies the bitmap height and width by the scale of {arg STREAM}.
}}

{Def {Type (Image Stream Method)}
{Name IMNEWPAGE} {Args STREAM}
{Text
Causes a new page to be started.  The X position is set to the left margin, and the Y position is set to the top margin plus the linefeed.  If not supplied, defaults to {lisp (\OUTCHAR {arg STREAM} (CHARCODE ↑L))}.  Envoked by {fn DSPNEWPAGE} ({PageRef Fn DSPNEWPAGE}).
}}

{Def {Type (Image Stream Method)}
{Name IMTERPRI} {Args STREAM}
{Text
Causes a new line to be started.  The X position is set to the left margin, and the Y position is set to the current Y position plus the linefeed.  If not supplied, defaults to {lisp (\OUTCHAR {arg STREAM} (CHARCODE EOL))}.  Envoked by {fn TERPRI} ({PageRef Fn TERPRI}).
}}

{Def {Type (Image Stream Method)}
{Name IMRESET} {Args STREAM}
{Text
Resets the X and Y position of {arg STREAM}.  The X coordinate is set to its left margin; the Y coordinate is set to the top of the clipping region minus the font ascent.  Envoked by {fn DSPRESET}, {PageRef Fn DSPRESET}.
}}

The following methods all have corresponding {lisp DSP{arg xx}} functions (e.g., {lisp IMYPOSITION} corresponds to {fn DSPYPOSITION}) that invoke them.  They also have the property of returning their previous value; when called with {lisp NIL} they return the old value without changing it.


{Def {Type (Image Stream Method)}
{Name IMCLIPPINGREGION} {Args STREAM REGION}
{Text
Sets a new clipping region on {arg STREAM}.
}}

{Def {Type (Image Stream Method)}
{Name IMXPOSITION} {Args STREAM XPOSITION}
{Text
Sets the X-position on {arg STREAM}.
}}


{Def {Type (Image Stream Method)}
{Name IMYPOSITION} {Args STREAM YPOSITION}
{Text
Sets a new Y-position on {arg STREAM}.
}}


{Def {Type (Image Stream Method)}
{Name IMFONT} {Args STREAM FONT}
{Text
Sets {arg STREAM}'s font to be {arg FONT}.
}}


{Def {Type (Image Stream Method)}
{Name IMLEFTMARGIN} {Args STREAM LEFTMARGIN}
{Text
Sets {arg STREAM}'s left margin to be {arg LEFTMARGIN}.  The left margin is defined as the X-position set after the new line.
}}


{Def {Type (Image Stream Method)}
{Name IMRIGHTMARGIN} {Args STREAM RIGHTMARGIN}
{Text
Sets {arg STREAM}'s right margin to be {arg RIGHTMARGIN}.  The right margin is defined as the maximum X-position at which characters are printed; printing beyond it causes a new line.
}}

{Def {Type (Image Stream Method)}
{Name IMTOPMARGIN} {Args STREAM YPOSITION}
{Text
Sets {arg STREAM}'s top margin (the Y-position of the tops of characters that is set after a new page) to be {arg YPOSITION}.
}}


{Def {Type (Image Stream Method)}
{Name IMBOTTOMMARGIN} {Args STREAM YPOSITION}
{Text
Sets {arg STREAM}'s bottom margin (the Y-position beyond which any printing causes a new page) to be {arg YPOSITION}.
}}


{Def {Type (Image Stream Method)}
{Name IMLINEFEED} {Args STREAM DELTA}
{Text
Sets {arg STREAM}'s line feed distance (distance to move vertically after a new line) to be {arg DELTA}.
}}


{Def {Type (Image Stream Method)}
{Name IMSCALE} {Args STREAM SCALE}
{Text
Returns the number of device points per screen point (a screen point being ~1/72 inch).  {arg SCALE} is ignored.
}}



{Def {Type (Image Stream Method)}
{Name IMSPACEFACTOR} {Args STREAM FACTOR}
{Text
Sets the amount by which to multiply the natural width of all following space characters on {arg STREAM}; this can be used for the justification of text.  The default value is 1.  For example, if the natural width of a space in {arg STREAM}'s current font is 12 units, and the space factor is set to two, spaces appear 24 units wide.  The values returned by {fn STRINGWIDTH} and {fn CHARWIDTH} are also affected.
}}


{Def {Type (Image Stream Method)}
{Name IMOPERATION} {Args STREAM OPERATION}
{Text
Sets the default {fn BITBLT} {arg OPERATION} argument (see {PageRef (BITBLT argument) OPERATION}).
}}


{Def {Type (Image Stream Method)}
{Name IMBACKCOLOR} {Args STREAM COLOR}
{Text
Sets the background color of {arg STREAM}.
}}


{Def {Type (Image Stream Method)}
{Name IMCOLOR} {Args STREAM COLOR}
{Text
Sets the default color of {arg STREAM}.
}}


In addition to the {lisp IMAGEOPS} methods described above, there are two other important methods, which are contained in the stream itself.  These fields can be installed using a form like {lisp (replace (STREAM OUTCHARFN) of STREAM with (FUNCTION MYOUTCHARFN))}.  Note:  You need to have loaded the Interlisp-D system declarations to manipulate the fields of {lisp STREAM}s.  The declarations can be loaded by loading the Lisp Library package {lisp SYSEDIT}.


{Def {Type (Stream Method)}
{Name STRMBOUTFN} {Args STREAM CHARCODE}
{Text
The function called by {fn BOUT}.
}}

{Def {Type (Stream Method)}
{Name OUTCHARFN} {Args STREAM CHARCODE}
{Text
The function that is called to output a single byte.  This is like {lisp STRMBOUTFN}, except for being one level higher: it is intended for text output.  Hence, this function should convert {lisp (CHARCODE EOL)} into the stream's actual end-of-line sequence and should adjust the stream's {lisp CHARPOSITION} appropriately before invoking the stream's {lisp STRMBOUTFN} (by calling {fn BOUT}) to actually put the character.  Defaults to {index *PRIMARY* \FILEOUTCHARFN Fn}{indexx {Name FILEOUTCHARFN} {Type Function} {Text {lisp \FILEOUTCHARFN}} }{fn \FILEOUTCHARFN}, which is probably incorrect for an image stream.
}}



}{End Subsec Implementation of Image Streams}