NectarineImpl.mesa
Copyright Ó 1986, 1987, 1988 by Xerox Corporation. All rights reserved.
Giordano Bruno Beretta, April 11, 1986 7:57:41 pm PST
gbb October 14, 1988 11:46:38 am PDT
Jean-Marc Frailong December 12, 1988 12:04:38 pm PST
Implements an alternate way to produce Interpress masters from ChipNDale drawings. The difference is in the user interface. It is similar to the one in programs by Imaging Folks, and it is simpler to use for casual users.
Fuzzless and sweeter than peaches (S. Williams)
DIRECTORY
Args USING [Arg, ArgsGet, Error, NArgs],
Atom USING [MakeAtom],
BasicTime USING [GMT, Now, OutOfRange, Period, ToNSTime, Update],
CD USING [commentLayer, ContextColors, CreateDrawRef, Design, DrawProc, DrawContextProc, DrawRectProc, DrawRef, Instance, InstanceList, Layer, Number, Object, Position, Rect, undefLayer],
CDBasics USING [BaseOfRect, ImagerTransform, Intersection, NonEmpty, SizeOfRect],
CDDirectory USING [EachEntryAction, Enumerate],
CDCurves USING [CurveSpecific],
CDOps USING [DrawDesign, InstList],
CDProperties USING [GetListProp],
CDTexts USING [TextSpecific],
CDValue USING [Fetch],
Commander USING [CommandProc, Register],
CStitching USING [all, Area, ChangeEnumerateArea, ChangeRect, DumpCache, EnumerateArea, EnumerateNeighborhood, NewTesselation, RectProc, Region, ResetTesselation, Tesselation, Tile, TileProc],
D2Orient USING [Orientation],
FS USING [ComponentPositions, Error, ExpandName, FileInfo, Position],
Imager USING [ClipRectangle, ColorOperator, ConcatT, Context, ConstantColor, DoSave, Font, MaskBitmap, MaskDashedStrokeTrajectory, MaskFillTrajectory, MaskRectangle, MaskStrokeTrajectory, MaskVector, MaskVectorI, PutProp, Rectangle, ScaleT, SetColor, SetFont, SetPriorityImportant, SetStrokeEnd, SetStrokeJoint, SetStrokeWidth, SetXY, ShowRope, StrokeEnd, StrokeJoint, TranslateT, VEC],
ImagerColor USING [ColorOperator, ConstantColor, NewColorOperatorRGB, RGB],
ImagerColorFns USING [NewColorOperatorCMYK],
ImagerColorPrivate USING [RGBFromColor],
ImagerFont USING [Find, FontBoundingBox, Modify, RopeBoundingBox, RopeEscapement, Scale, Substitution, Typeface, TypefaceRep],
ImagerInterpress USING [Close, Create, DeclareColorOperator, DeclareFont, DoPage, Ref],
ImagerPath USING [LineToX, LineToY, MoveTo, Trajectory],
ImagerSample USING [Box, Clear, Fill, NewSampleMap, RasterSampleMap, Trim],
ImagerTransformation USING [Cat, Create, Invert, Rotate, Scale2, Transformation, Translate],
ImagerTypeface USING [TypefaceRep],
Interpress USING [classAppearanceError, classAppearanceWarning, classComment, classMasterError, classMasterWarning, Close, DoPage, LogProc, Master, Open],
IO USING [bool, card, int, PutFR, PutFR1, real, rope, time],
MessageWindow USING [Append, Blink, Clear],
Nectarine,
NectarineAids USING [ComposeRegisterMarks],
NectarineColors USING [Bitset, blackBlack, Blend, BlendTileColours, BlendRec, ResetColourStatistics, Color, NumberOfColours, ColourTile, colSubDef, DeclareColours, IthColour, LayerColour, ListColourStatistics, orableBackground, ReadMap, ResetLayerColourTable, SetLayerColourTable, traceColourInferences, unColour],
NectarinePd USING [field, PdPrintProcess],
NodeStyle USING [FontFace],
NodeStyleFont USING [FontFromStyleParams],
PrincOpsUtils USING [],
Process USING [CheckForAbort, Detach, priorityBackground, SetPriority],
Real USING [Fix, Float, Round],
RefTab USING [Create, Delete, EachPairAction, Fetch, GetSize, Insert, Pairs, Ref],
Rope USING [Cat, Concat, Equal, Fetch, IsEmpty, Length, Replace, ROPE, SkipTo, Substr],
SafeStorage USING [ReclaimCollectibleObjects],
SimpleMailer USING [SendMessage, SendMessageInfo],
TerminalIO USING [PutF, PutRope],
UserCredentials USING [Get],
UserProfile USING [Boolean, CallWhenProfileChanges, ProfileChangedProc, Token],
XNSPrint USING [Context, Error, GetDefaults, PrintFromFile];
NectarineImpl: CEDAR PROGRAM
IMPORTS Args, Atom, BasicTime, CD, CDBasics, CDDirectory, CDOps, CDProperties, CDValue, Commander, CStitching, FS, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, ImagerFont, ImagerInterpress, ImagerPath, ImagerSample, ImagerTransformation, IO, MessageWindow, NectarineAids, NectarineColors, NectarinePd, NodeStyleFont, Process, Real, RefTab, Rope, SafeStorage, TerminalIO, UserProfile, UserCredentials, XNSPrint
EXPORTS ImagerFont, Nectarine ~ BEGIN
OPEN NectarineColors, NectarinePd, Real;
Implementation note on clipping: If bands have to be created because of the size of the design, true clipping to bands must be done when traversing the design. The penalty on the corner stitched data structure may be swallowed, since it is an overnight job anyway. However, leaving clipping to the Imager, you will have all those rectangles in the Interpress master with their multiciplity. A large disk can hold only about 90% of a thing like the Cross-RAM, and every single file on your disk will have been flushed off when you come in in the morning.
If you insist on leaving the clipping to the imager, then you must be very careful deciding where to place it. The reason is that clipping in the Imager is relative, and therefore the window must be specified inside Do-Save-Simple-Body, in order not to disturb the global clipping window. The places would be EnumerateGeometry and EnumerateTextInDesign.
break: SIGNAL ~ CODE;  -- for debugging
invalidPrinter: PUBLIC SIGNAL ~ CODE;
communicationsFailure: PUBLIC SIGNAL ~ CODE;
tooComplex: PUBLIC SIGNAL ~ CODE;
layout, showTesselation, ignoreAnnotation, imageRegions: BOOLFALSE;
letChipndaleCallTheImager, centerSignalNames: BOOLTRUE;
signalNameFont: Font ← NIL;
outline: REAL ← -1.0;
risk: INT ← 2; -- decrease if Nectarine runs out of VM. More risk mean much more speed. Geometric interpretation: consider a horizontal straight line through the design; you state that you have a rectangle only each risk l. At zero risk, Nectarine uses only 14 MB of memory in the worst case.
Font: TYPE ~ Imager.Font;
Typeface: TYPE ~ REF TypefaceRep;
TypefaceRep: PUBLIC TYPE ~ ImagerTypeface.TypefaceRep;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Hyperplane: TYPE ~ RECORD [used: BOOLFALSE, hyp: ImagerSample.RasterSampleMap];
ColorRegion: TYPE ~ REF ColorRegionRep;
ColorRegionRep: TYPE ~ RECORD [SEQUENCE size: NAT OF Hyperplane];
ROPE: TYPE ~ Rope.ROPE;
Box: TYPE ~ ImagerSample.Box;
State: TYPE ~ REF StateRec;
StateRec: TYPE ~ RECORD [
previousColour: Color ← NIL,
previousStrokeWidth: REAL ← -1.0,
previousFont: Font ← NIL,
previousTextOrientation: D2Orient.Orientation ← original,
cardTile: CARD ← 0, -- |{tile}|
startTime: BasicTime.GMT,
context: Imager.Context,
ipName: ROPE,
design: CD.Design,
interpress: ImagerInterpress.Ref,
tess: Tess,
abort: REF BOOL,
clip: BOOLFALSE, -- Wysiwyg or selectedOnly
cdClip: CD.Rect, -- Wysiwyg or selectedOnly
selectedOnly: BOOL,
singleLayer: BOOLFALSE, -- only the layer of interset will be printed
layerOfInterest: CD.Layer ← CD.undefLayer,
isFirstPage, isLastPage: BOOLTRUE,
substituteColor: BOOL ← colSubDef,
band: REF CD.Rect ← NIL,
bitmapScale: REAL ← 0.0, -- Versatec hack only
colorRegion: ColorRegion ← NIL];
statistics: BOOLFALSE;
debug: BOOLFALSE;
remindFontConventions: BOOLTRUE;
minInteger: INT ~ INTEGER.FIRST;
maxInteger: INT ~ INTEGER.LAST;
regionShrink: INT ← 4;
mmXin: REAL ~ 25.4;
versatecWidth: REAL ~ 8000; -- 40 inches at 200 bits per inch
versatecLength: REAL ~ 32600; -- 163 inches at 200 bits per inch
versatecWidthInMM: REAL ~ 40 * mmXin; versatecLengthInMM: REAL ~ 163 * mmXin;
versatecResolution: REAL ~ 0.001 / 200 * mmXin;
Geometry
Region: TYPE ~ LIST OF REF CStitching.Region;
Tess: TYPE ~ CStitching.Tesselation;
Tile: TYPE ~ CStitching.Tile;
TileAndContext: TYPE ~ REF TcRec;
TcRec: TYPE ~ RECORD [tile: Tile, context: Imager.Context];
empty: REF ~ NIL;
nothing: REF INT ~ NEW [INT];
StartDecomposition: PROC [state: State] RETURNS [dec: Tess] ~
{RETURN [CStitching.NewTesselation[stopFlag: state.abort]]};
FlushDecomposition: PROC [dec: Tess] ~ BEGIN
Does what FreeTesselation supposedly did once upon a time.
CStitching.ResetTesselation [dec]
END; -- FlushDecomposition
FastMaskVector: PROC [context: Imager.Context, x1, y1, x2, y2: INT] ~ BEGIN
Probably for speed reasons the Imager uses 16 bit integers.
IF ((x1 >= minInteger) AND (y1 >= minInteger) AND (x2 <= maxInteger) AND (y2 <= maxInteger)) THEN context.MaskVectorI [x1, y1, x2, y2]
ELSE context.MaskVector [[Float[x1], Float[y1]], [Float[x2], Float[y2]]]
END; -- FastMaskVector
SouthRim: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
tc: TileAndContext ~ NARROW [data];
IF (tile.value # tc.tile.value) THEN BEGIN
tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area;
x1: INT ~ MAX [tr.x1, nr.x1]; x2: INT ~ MIN [tr.x2, nr.x2];
b: Blend ~ NARROW [tile.value];
IF (x1 < x2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN
FastMaskVector [tc.context, x1, tr.y1, x2, tr.y1]
END
END; -- SouthRim
EastRim: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
tc: TileAndContext ~ NARROW [data];
IF (tile.value # tc.tile.value) THEN BEGIN
tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area;
y1: INT ~ MAX [tr.y1, nr.y1]; y2: INT ~ MIN [tr.y2, nr.y2];
b: Blend ~ NARROW [tile.value];
IF (y1 < y2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN
FastMaskVector [tc.context, tr.x2, y1, tr.x2, y2]
END
END; -- EastRim
NorthRim: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
tc: TileAndContext ~ NARROW [data];
IF (tile.value # tc.tile.value) THEN BEGIN
tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area;
x1: INT ~ MAX [tr.x1, nr.x1]; x2: INT ~ MIN [tr.x2, nr.x2];
b: Blend ~ NARROW [tile.value];
IF (x1 < x2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN
FastMaskVector [tc.context, x1, tr.y2, x2, tr.y2]
END
END; -- NorthRim
WestRim: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
tc: TileAndContext ~ NARROW [data];
IF (tile.value # tc.tile.value) THEN BEGIN
tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area;
y1: INT ~ MAX [tr.y1, nr.y1]; y2: INT ~ MIN [tr.y2, nr.y2];
b: Blend ~ NARROW [tile.value];
IF (y1 < y2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN
FastMaskVector [tc.context, tr.x1, y1, tr.x1, y2]
END
END; -- WestRim
PrintAlignedTile: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
This version is much slower than PrintTile. It uses 4 additional operations and 12 additional bytes. This buys that all rectangles get aligned to pixels. This makes that all wires in schematics are printed with the same width.
state: State ~ NARROW [data];
b: Blend ~ NARROW [tile.value];
r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle !
ir: Imager.Rectangle ~ ImagerRect [r];
MaskAlignedRectangle: PROC ~ BEGIN
state.context.SetXY [[ir.x, ir.y]]; state.context.Trans [];
state.context.MaskRectangle [[0, 0, ir.w, ir.h]]
END; -- MaskAlignedRectangle
ChangeColour [state, b.blend];
state.context.DoSave [MaskAlignedRectangle];
IF state.abort^ THEN ERROR ABORTED;
IF (outline >= 0.0) AND (b.blend # blackBlack) THEN BEGIN
tc: TileAndContext ~ NEW [TcRec ← [tile, state.context]];
ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline];
state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing]
END;
IF statistics THEN BEGIN
l: CD.Number ~ state.design.technology.lambda;
b.area ← b.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l);
state.cardTile ← SUCC [state.cardTile]
END
END; -- PrintAlignedTile
PrintTile: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
state: State ~ NARROW [data];
colour: Blend ~ NARROW [tile.value];
r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle !
ChangeColour [state, colour.blend];
state.context.MaskRectangle [ImagerRect [r]];
IF state.abort^ THEN ERROR ABORTED;
IF (outline >= 0.0) AND (colour.blend # blackBlack) THEN BEGIN
ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline];
IF showTesselation THEN BEGIN
FastMaskVector [state.context, r.x1, r.y1, r.x2, r.y1]; -- South
FastMaskVector [state.context, r.x2, r.y1, r.x2, r.y2]; -- East
FastMaskVector [state.context, r.x2, r.y2, r.x1, r.y2]; -- North
FastMaskVector [state.context, r.x1, r.y2, r.x1, r.y1] -- West
END
ELSE BEGIN
tc: TileAndContext ~ NEW [TcRec ← [tile, state.context]];
state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing]
END
END;
IF statistics THEN BEGIN
l: CD.Number ~ state.design.technology.lambda;
colour.area ← colour.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l);
state.cardTile ← SUCC [state.cardTile]
END
END; -- PrintTile
NewPrintTile: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
This is an experiment for Cedar 7.0. Michael Plass has changed the implementation of MaskVector so that it gives the result of PrintAlignedTile at the cost of PrintTile.
state: State ~ NARROW [data];
b: Blend ~ NARROW [tile.value];
r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle !
ir: Imager.Rectangle ~ ImagerRect [r];
median: INT;
ChangeColour [state, b.blend];
IF (ir.w > ir.h) THEN BEGIN
ChangeStrokeWidth [state, ir.h]; median ← (r.y1 + r.y2) / 2;
FastMaskVector [state.context, r.x1, median, r.x2, median]
END
ELSE BEGIN
ChangeStrokeWidth [state, ir.w]; median ← (r.x1 + r.x2) / 2;
FastMaskVector [state.context, median, r.y1, median, r.y2]
END;
IF state.abort^ THEN ERROR ABORTED;
IF (outline >= 0.0) AND (b.blend # blackBlack) THEN BEGIN
ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline];
IF showTesselation THEN BEGIN
FastMaskVector [state.context, r.x1, r.y1, r.x2, r.y1]; -- South
FastMaskVector [state.context, r.x2, r.y1, r.x2, r.y2]; -- East
FastMaskVector [state.context, r.x2, r.y2, r.x1, r.y2]; -- North
FastMaskVector [state.context, r.x1, r.y2, r.x1, r.y1] -- West
END
ELSE BEGIN
tc: TileAndContext ~ NEW [TcRec ← [tile, state.context]];
state.context.SetStrokeEnd [square];
state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing];
state.context.SetStrokeEnd [butt]
END
END;
IF statistics THEN BEGIN
l: CD.Number ~ state.design.technology.lambda;
b.area ← b.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l);
state.cardTile ← SUCC [state.cardTile]
END
END; -- NewPrintTile
AddTile: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
state: State ~ NARROW [data];
colour: Blend ~ NARROW [tile.value];
band: CD.Rect ~ IF (state.band = NIL) THEN state.cdClip
ELSE CDBasics.Intersection [state.cdClip, state.band^];
r: Box ~ BoxFromRect [tile.Area, band];
state.colorRegion[colour.index.ABS - 1].used ← TRUE;
state.colorRegion[colour.index.ABS - 1].hyp.Fill [r]
END; -- AddTile
AddTile: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
state: State ~ NARROW [data];
colour: Blend ~ NARROW [tile.value];
band: CD.Rect ~ QuickTransf [IF (state.band = NIL) THEN state.cdClip
ELSE CDBasics.Intersection [state.cdClip, state.band^], state];
r: Box ~ BoxFromRect [QuickTransf [tile.Area, state], band];
i: INT ← colour.index.ABS - 1;
IF (i < 0) OR (i > 30) THEN i ← 0; -- Cheap hack for seldom layer combinations (e.g. pads)
state.colorRegion[i].used ← TRUE; state.colorRegion[i].hyp.Fill [r]
END; -- AddTile
PrintStippledTile: CStitching.TileProc ~ BEGIN
PROC [tile: REF Tile, data: REF]
state: State ~ NARROW [data];
b: Blend ~ NARROW [tile.value];
r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle !
FOR i: CD.Layer IN CD.Layer DO
IF b.flavours[i] THEN BEGIN
ChangeColour [state, LayerColour [i]]; state.context.MaskRectangle [ImagerRect [r]]
END
ENDLOOP;
IF state.abort^ THEN ERROR ABORTED;
IF (outline >= 0.0) AND (b.blend # blackBlack) THEN BEGIN
ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline];
IF showTesselation THEN BEGIN
FastMaskVector [state.context, r.x1, r.y1, r.x2, r.y1]; -- South
FastMaskVector [state.context, r.x2, r.y1, r.x2, r.y2]; -- East
FastMaskVector [state.context, r.x2, r.y2, r.x1, r.y2]; -- North
FastMaskVector [state.context, r.x1, r.y2, r.x1, r.y1] -- West
END
ELSE BEGIN
tc: TileAndContext ~ NEW [TcRec ← [tile, state.context]];
state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing]
END
END;
IF statistics THEN BEGIN
l: CD.Number ~ state.design.technology.lambda;
b.area ← b.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l);
state.cardTile ← SUCC [state.cardTile]
END
END; -- PrintStippledTile
PrintBand: PROC [state: State] ~ BEGIN
Prints a band. If there is only one band and no clipping is necessary, setting clip to false will make it faster.
gdr: CD.DrawRef ~ CD.CreateDrawRef [[]];
smp: Imager.VEC; -- sample map position
deviceBand: CD.Rect; box: Box;
EnumerateGeometry: PROC ~ BEGIN
state.context.SetStrokeEnd [IF layout THEN square ELSE butt];
state.context.SetStrokeJoint [miter]; -- I hope that's faster for rectangles
IF (state.colorRegion # NIL) THEN BEGIN
state.tess.EnumerateArea [rect: CStitching.all, eachTile: AddTile, data: state, skip: empty]
END
ELSE BEGIN
IF state.substituteColor THEN BEGIN
IF layout THEN state.tess.EnumerateArea [rect: CStitching.all, eachTile: PrintTile, data: state, skip: empty]
ELSE state.tess.EnumerateArea [rect: CStitching.all, eachTile: NewPrintTile, data: state, skip: empty]
END
ELSE state.tess.EnumerateArea [rect: CStitching.all, eachTile: PrintStippledTile, data: state, skip: empty]
END
END; -- EnumerateGeometry
Process.CheckForAbort []; IF state.abort^ THEN ERROR ABORTED;
gdr.interestClip ← IF (state.band = NIL) THEN state.cdClip
ELSE CDBasics.Intersection [state.cdClip, state.band^];
state.tess ← StartDecomposition [state];
gdr.drawRect ← NewRect;
gdr.drawContext ← DoNotDrawContext; gdr.devicePrivate ← state;
IF state.abort^ THEN ERROR ABORTED;
IF state.selectedOnly THEN DrawSelection [state.design, gdr]
ELSE CDOps.DrawDesign [state.design, gdr]; -- pass 2
TerminalIO.PutRope ["."]; IF state.abort^ THEN ERROR ABORTED;
IF state.substituteColor THEN BlendTileColours []; TerminalIO.PutRope ["."]; -- pass 3
state.previousColour ← NIL; state.previousStrokeWidth ← -1.0;
state.previousFont ← NIL; state.previousTextOrientation ← original;
IF (state.colorRegion # NIL) THEN BEGIN
deviceBand ← QuickTransf [gdr.interestClip, state];
box ← BoxFromRect [deviceBand, deviceBand];
smp ← [x: 0, y: deviceBand.y2];
FOR p: INT IN [0 .. state.colorRegion.size) DO
state.colorRegion[p].used ← FALSE;
IF state.abort^ THEN ERROR ABORTED;
state.colorRegion[p].hyp ← ImagerSample.NewSampleMap [box];
state.colorRegion[p].hyp.Clear
ENDLOOP;
gdr.drawRect ← NewRect; SafeStorage.ReclaimCollectibleObjects
END;
state.context.DoSave [EnumerateGeometry]; -- pass 4
FlushDecomposition [state.tess]; SafeStorage.ReclaimCollectibleObjects;
IF (state.colorRegion # NIL) THEN BEGIN
FOR p: INT IN [0 .. state.colorRegion.size) DO
IF state.colorRegion[p].used THEN BEGIN
state.context.SetColor [IthColour [p+1]];
IF debug THEN [] ← state.colorRegion[p].hyp.Trim [box];
state.context.MaskBitmap [bitmap: state.colorRegion[p].hyp, position: smp];
state.colorRegion[p].used ← FALSE;
state.colorRegion[p].hyp ← NIL; SafeStorage.ReclaimCollectibleObjects;
IF state.abort^ THEN ERROR ABORTED
END;
ENDLOOP;
END;
TerminalIO.PutRope [". "]
END; -- PrintBand
NewRect: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
state: State ~ NARROW [pr.devicePrivate, State];
rect: CD.Rect;
IF (state.singleLayer AND (l # state.layerOfInterest)) THEN RETURN;
rect ← IF (state.band = NIL) THEN r ELSE CDBasics.Intersection [r, state.band^];
IF (CDBasics.NonEmpty [rect]) THEN BEGIN
Note that merging works correctly because of the use of the colour table.
dec: Tess ~ state.tess;
InsertRect: CStitching.RectProc = BEGIN
[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]
WITH oldValue SELECT FROM
b: Blend => IF NOT b.flavours[l] THEN dec.ChangeRect [rect: rect, new: ColourTile [b, l]];
ENDCASE => BEGIN
b: Blend ← NEW [BlendRec];
dec.ChangeRect [rect: rect, new: ColourTile [b, l]]
END
END; -- InsertRect
dec.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing];
IF state.abort^ THEN ERROR ABORTED
END
END; -- NewRect
NewScaledRect: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
state: State ~ NARROW [pr.devicePrivate, State];
rect: CD.Rect ← [r.x1/regionShrink, r.y1/regionShrink, r.x2/regionShrink, r.y2/regionShrink];
rect ← IF (state.band = NIL) THEN rect ELSE CDBasics.Intersection [rect, state.band^];
IF (CDBasics.NonEmpty [rect]) THEN BEGIN
Note that merging works correctly because of the use of the colour table.
dec: Tess ~ state.tess;
InsertRect: CStitching.RectProc = BEGIN
[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]
WITH oldValue SELECT FROM
b: Blend => IF NOT b.flavours[l] THEN dec.ChangeRect [rect: rect, new: ColourTile [b, l]];
ENDCASE => BEGIN
b: Blend ← NEW [BlendRec];
dec.ChangeRect [rect: rect, new: ColourTile [b, l]]
END
END; -- InsertRect
dec.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing];
END
END; -- NewScaledRect
Annotation
mirrorY: Transformation ~ ImagerTransformation.Scale2 [[-1, 1]];
rot180: Transformation ~ ImagerTransformation.Rotate [180];
SpecialHack: PROC [obj: CD.Object, or: D2Orient.Orientation] RETURNS [t: Transformation] ~ BEGIN
This is a special temporary hack that hacks out the transformation required to print the same thing as ChipNDale displays in the class $FlipText. Do not try to understand it from a geometrical point of view, it is brain-dammaged.
adjustX: Transformation ~ ImagerTransformation.Translate [[-(obj.bbox.x2 - obj.bbox.x1), 0]];
adjustY: Transformation ~ ImagerTransformation.Translate [[0, +(obj.bbox.x2 - obj.bbox.x1)]];
adjustXY: Transformation ~ ImagerTransformation.Translate [[-(obj.bbox.x2 - obj.bbox.x1), -(obj.bbox.y2 - obj.bbox.y1)]];
adjustXhalfY: Transformation ~ ImagerTransformation.Translate [[-(obj.bbox.x2 - obj.bbox.x1), -(obj.bbox.y2 - obj.bbox.y1) / 2]];
IF (obj.class.objectType # $FlipText) THEN ERROR; -- tocca ferro
t ← SELECT or FROM
The transformation sequences in comment are what has been reconstructed using the Interpreter as what ChipNDale does.
mirrorX, rotate90X => adjustX.Cat [mirrorY], -- TxSxSy
rotate180X, rotate270X => adjustXY.Cat [rot180, adjustX, mirrorY], -- TxySxyRTxSxSy
rotate180, rotate90 => adjustXY.Cat [rot180], -- TxySxyR
rotate180, rotate90 => adjustXY.Cat [adjustY, rot180], -- TxyTySxyR
rotate180, rotate90 => adjustXhalfY.Cat [rot180], -- Txy/2SxyR
ENDCASE => ImagerTransformation.Create [1, 0, 0, 0, 1, 0] -- plain vanilla Identity
END; -- SpecialHack
DrawText: CD.DrawProc ~ BEGIN
[pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL]
state: State ~ NARROW [pr.devicePrivate];
context: Imager.Context ~ state.context;
text: CDTexts.TextSpecific ~ NARROW [ob.specific];
offset: Imager.VEC ← text.cdFont.xy;
transf, invTransf: Transformation;
IF (state.singleLayer AND (ob.layer # state.layerOfInterest)) THEN RETURN;
IF state.abort^ THEN ERROR ABORTED;
ChangeColour [state, LayerColour [ob.layer]];
ChangeFont [state, text.cdFont.font]; -- order of statements important !
transf ← CDBasics.ImagerTransform [trans];
IF (ob.class.objectType = $FlipText) THEN BEGIN
transf ← ImagerTransformation.Cat [SpecialHack [ob, trans.orient], transf];
SELECT trans.orient FROM
mirrorX, rotate90, rotate180, rotate90X => BEGIN
Obviously it is bogus to use the bounding box of the bits instead of the font metrics. However, ChipNDale uses the bits, and therefore the rope will be off and the user will manually shift it in place. Since the user corrects manually this error, Nectarine has to intentionally introduce this error to make things look the same on the screen and on paper.
In particular, if text is changed from rigid to flipped, or vice versa, it will be off by the difference between the font metrics and the bit approximation. However, also what the user seen on the screen is off, because ChipNDale uses the bit approximation. Since he will ``fix'' it manually, Nectarine must introduce the same error.
offset.x ← offset.x + (ImagerFont.RopeBoundingBox [font: text.cdFont.font, rope: text.text].rightExtent) - (ImagerFont.RopeBoundingBox [font: state.previousFont, rope: text.text].rightExtent);
Correct offset:
offset.x ← offset.x + (ImagerFont.RopeEscapement [font: text.cdFont.font, rope: text.text].x) - (ImagerFont.RopeEscapement [font: state.previousFont, rope: text.text].x);
offset.y ← 0; -- that's what's in ChipNDale release 25
IF (trans.orient = rotate90) OR (trans.orient = rotate180) THEN
A wild guess that is closer to the above.
offset.y ← offset.y - ImagerFont.FontBoundingBox [state.previousFont].descent / 2.0
END
ENDCASE => offset ← [0, 0]; -- that's what's in ChipNDale release 25
END
ELSE offset.y ← 0; -- different from CD but a closer approximation
invTransf ← ImagerTransformation.Invert [transf];
context.ConcatT [transf]; context.SetXY [offset];
context.ShowRope [text.text]; context.ConcatT [invTransf]
END; -- DrawText
DrawPath: CD.DrawProc ~ BEGIN
[pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL]
state: State ~ NARROW [pr.devicePrivate];
context: Imager.Context ~ state.context;
curve: CDCurves.CurveSpecific ~ NARROW [ob.specific];
transf: Transformation ~ CDBasics.ImagerTransform [trans];
invTransf: Transformation ~ ImagerTransformation.Invert [transf];
IF (state.singleLayer AND (ob.layer # state.layerOfInterest)) THEN RETURN;
IF state.abort^ THEN ERROR ABORTED;
context.ConcatT [transf]; -- context.SetXY [offset];
ChangeColour [state, LayerColour [ob.layer]];
ChangeStrokeWidth [state, Float [curve.w]];
context.MaskStrokeTrajectory [curve.path]; context.ConcatT [invTransf]
END; -- DrawPath
DrawArea: CD.DrawProc ~ BEGIN
[pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL]
state: State ~ NARROW [pr.devicePrivate];
context: Imager.Context ~ state.context;
curve: CDCurves.CurveSpecific ~ NARROW [ob.specific];
transf: Transformation ~ CDBasics.ImagerTransform [trans];
invTransf: Transformation ~ ImagerTransformation.Invert [transf];
IF (state.singleLayer AND (ob.layer # state.layerOfInterest)) THEN RETURN;
IF state.abort^ THEN ERROR ABORTED;
context.ConcatT [transf]; -- context.SetXY [offset];
ChangeColour [state, LayerColour [ob.layer]];
ChangeStrokeWidth [state, Float [curve.w]];
context.MaskFillTrajectory [curve.path, TRUE]; context.ConcatT [invTransf]
END; -- DrawArea
DrawObjectBorder: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
The border is drawn outside the cell, since this is the way they are used by Rick Barth, currently the only creator of documents using boxes.
state: State ~ NARROW [pr.devicePrivate, State];
pen: REAL ~ Float [state.design.technology.lambda];
halfPen: REAL ~ pen / 2.0;
object: Imager.Rectangle ~ ImagerRect [r];
border: ImagerPath.Trajectory;
IF state.abort^ THEN ERROR ABORTED;
ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, pen];
Convert the object border into an Imager trajectory.
border ← ImagerPath.MoveTo [[object.x - halfPen, object.y - halfPen]];
border ← border.LineToX [object.x + object.w + halfPen]; -- South
border ← border.LineToY [object.y + object.h + halfPen]; -- East
border ← border.LineToX [object.x - halfPen];  -- North
border ← border.LineToY [object.y - halfPen];  -- West
Draw it !
Note that the stroke ends and joints are round.
state.context.MaskStrokeTrajectory [trajectory: border]
END; -- DrawObjectBorder
DrawDashedObjectBorder: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
The border is drawn outside the cell, since this is the way they are used by Rick Barth, currently the only creator of documents using boxes.
state: State ~ NARROW [pr.devicePrivate, State];
pen: REAL ~ Float [state.design.technology.lambda / 2];
halfPen: REAL ~ pen / 2.0;
object: Imager.Rectangle ~ ImagerRect [r];
border: ImagerPath.Trajectory;
patternElements: NAT ~ 8;
DotDotDotDash: PROC [i: NAT] RETURNS [REAL] ~ BEGIN
pattern: ARRAY [0 .. patternElements) OF REAL ~ [0, 5*pen, 0, 5*pen, 0, 10*pen, 30*pen, 10*pen];
RETURN [pattern[i]]
END; -- DotDotDotDash
IF state.abort^ THEN ERROR ABORTED;
ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, pen];
Convert the object border into an Imager trajectory.
border ← ImagerPath.MoveTo [[object.x - halfPen, object.y - halfPen]];
border ← border.LineToX [object.x + object.w + halfPen]; -- South
border ← border.LineToY [object.y + object.h + halfPen]; -- East
border ← border.LineToX [object.x - halfPen];  -- North
border ← border.LineToY [object.y - halfPen];  -- West
Draw it !
Note that the stroke ends and joints are round.
Imager.MaskDashedStrokeTrajectory [context: state.context, trajectory: border, offset: 0, length: 2*(object.w+object.h), patternLen: patternElements, pattern: DotDotDotDash]
END; -- DrawDashedObjectBorder
DrawObjectBorder: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
The border is drawn outside the cell, since this is the way they are used by Rick Barth, currently the only creator of documents using boxes.
state: State ~ NARROW [pr.devicePrivate, State];
pen: REAL ~ Float [state.design.technology.lambda / 2];
object, border: Imager.Rectangle;
Process.CheckForAbort []; IF state.abort^ THEN ERROR ABORTED;
ChangeColour [state, blackBlack];
object ← ImagerRect [r];
South:
object.x ← object.x - pen; object.y ← object.y - pen;
object.w ← object.w + 2 * pen; object.h ← object.h + 2 * pen;
border ← [x: object.x, y: object.y, w: object.w , h: pen];
state.context.MaskRectangle [border];
West:
border ← [x: object.x, y: object.y, w: pen, h: object.h];
state.context.MaskRectangle [border];
East:
border ← [x: object.x + object.w - pen, y: object.y, w: pen, h: object.h];
state.context.MaskRectangle [border];
North:
border ← [x: object.x, y: object.y + object.h - pen, w: object.w, h: pen];
state.context.MaskRectangle [border]
END; -- DrawObjectBorder
DrawObject: CD.DrawProc ~ BEGIN
[pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL]
Process.CheckForAbort [];
SELECT ob.class.objectType FROM
$Text, $RigidText, $FlipText => DrawText [pr, ob, trans, readOnlyInstProps];
$Spline0, $Line0 => DrawPath [pr, ob, trans, readOnlyInstProps];
$FilledCurve0, $Polygon0 => DrawArea [pr, ob, trans, readOnlyInstProps];
The procedure for rectangles is called through the recursion step.
ENDCASE => ob.class.drawMe [pr, ob, trans, readOnlyInstProps]
END; -- DrawObject
DrawObjectWithSignalNames: CD.DrawProc ~ BEGIN
[pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL]
Process.CheckForAbort [];
IF (readOnlyInstProps # NIL) THEN BEGIN
name: ROPE ~ NARROW [CDProperties.GetListProp [readOnlyInstProps, $SignalName]];
IF NOT name.IsEmpty THEN BEGIN
state: State ~ NARROW [pr.devicePrivate];
transf: Transformation ~ CDBasics.ImagerTransform [trans];
invTransf: Transformation ~ ImagerTransformation.Invert [transf];
offset: Imager.VEC ← [0, 0];
IF state.abort^ THEN ERROR ABORTED;
ChangeColour [state, LayerColour [CD.commentLayer]];
ChangeFont [state, signalNameFont]; -- order of statements important !
IF (ob.class.objectType = $Rect) AND centerSignalNames THEN BEGIN
esc: Imager.VEC ~ ImagerFont.RopeEscapement [signalNameFont, name];
offset.x ← ob.bbox.x1 + ((ob.bbox.x2 - ob.bbox.x1) - esc.x) / 2.0;
offset.y ← ob.bbox.y1 + ((ob.bbox.y2 - ob.bbox.y1) - esc.y) / 2.0
END;
state.context.ConcatT [transf]; state.context.SetXY [offset];
state.context.ShowRope [name]; state.context.ConcatT [invTransf]
END
END;
SELECT ob.class.objectType FROM
$Text, $RigidText, $FlipText => DrawText [pr, ob, trans, readOnlyInstProps];
$Spline0, $Line0 => DrawPath [pr, ob, trans, readOnlyInstProps];
$FilledCurve0, $Polygon0 => DrawArea [pr, ob, trans, readOnlyInstProps];
The procedure for rectangles is called through the recursion step.
ENDCASE => ob.class.drawMe [pr, ob, trans, readOnlyInstProps]
END; -- DrawObjectWithSignalNames
Interpress
multipageHack: State;
rgbLinear: Imager.ColorOperator ~ ImagerColor.NewColorOperatorRGB [255];
cmyk: Imager.ColorOperator ~ ImagerColorFns.NewColorOperatorCMYK [255];
DoInterpress: PUBLIC PROC [design: CD.Design, chipNDaleWindow: CD.Rect, clip, onlySel, singleLayer, register: BOOLFALSE, layer: CD.Layer ← CD.undefLayer, lambda: REAL ← 0.0, firstPage, lastPage: BOOLTRUE, abortFlag: REF BOOL] RETURNS [masterName: Rope.ROPE, usedField: Imager.Rectangle] ~ BEGIN
Produces an Interpress master of the design. The master is scaled such that it fits a whole page. chipNDaleWindow is either the bounding box of the design or a window in it. In the latter case, clip must be set to TRUE, and objects completetly outside the window will be ommitted from the Interpress master (because of things like mitering, actual clipping can be performed only when a bitmap is created).
The usedField is specified in millimetres. It is useful for subsequent processing of the Interpress master as long as this field cannot be specified in the preamble of Interpress masters themselves.
If onlySel is true, only the selected object are included in the Interpress master.
If singleLayer is true, only objects in the layer layer are included in the Interpress master.
If lambda = 0 then scale such that the window fills the field, else scale such that 1  will be lambda mm in the Interpress master.
If not last page, the Interpress master is not closed, hence the next call of this procedure will add a page to the same master instead of creating a new document.
May return signal tooComplex if it is believed that there might be too many rectangles in a horizontal cross section. The used criterion is the width of the design; if you do not agree, use the Interpreter to increase the risk.
state: State;
OpenIPMaster: PROC [] RETURNS [ImagerInterpress.Ref] ~ BEGIN
Creates the interpress master.
ENABLE {FS.Error => GOTO failure};
subDir: ROPE ~ "[]<>Temp>Nectarine>"; -- follows the religion
pos: FS.ComponentPositions;
ext: ROPE ← ".dummy";
Version number alone are not sufficient to allow for different files with the same name. In fact, independently of the version numbers, some tools have the property to get notified if a new version of a file is created, replacing the file they are working on in favour of the new version.
ext ← IO.PutFR ["-NS%g%g", IO.card [BasicTime.ToNSTime [BasicTime.Now[]]], IO.rope [ext]];
IF NOT design.name.IsEmpty[] THEN masterName ← design.name.Cat [ext]
ELSE BEGIN
cdName: ROPE ~ NARROW [CDValue.Fetch [design, $CDxLastFile]];
IF cdName.IsEmpty[] THEN masterName ← Rope.Cat ["UnnamedMaster", ext]
ELSE BEGIN
shortFName: ROPE;
[fullFName: masterName, cp: pos] ← FS.ExpandName [cdName, subDir];
shortFName ← masterName.Substr [start: pos.base.start, len: pos.base.length];
masterName ← shortFName.Cat [ext]
END
END;
[fullFName: masterName, cp: pos] ← FS.ExpandName [masterName, subDir];
masterName ← masterName.Replace [pos.ext.start, pos.ext.length, "Interpress"];
RETURN [ImagerInterpress.Create [masterName]];
EXITS
failure => BEGIN
masterName ← IO.PutFR ["[]<>Temp>Nectarine>UnnamedMaster-NS%g.%g", IO.card [BasicTime.ToNSTime [BasicTime.Now[]]], IO.rope ["Interpress"]];
RETURN [ImagerInterpress.Create [masterName]]
END
END; -- OpenIPMaster
DrawToIP: PROC [context: Imager.Context] ~ BEGIN
Called back by the Interpress machinery.
tdr: CD.DrawRef ~ CD.CreateDrawRef [[]];
window: Imager.Rectangle; -- in the CG sense
ratioW, ratioH, y0: REAL;
iterations, bandSize: INT; -- number and size of bands
chronos: BOOL;
lap, end: BasicTime.GMT;
EnumerateTextInDesign: PROC ~ BEGIN
state.context.SetPriorityImportant [TRUE]; -- see EnumerateGeometry
IF state.selectedOnly THEN DrawSelection [state.design, tdr]
ELSE CDOps.DrawDesign [state.design, tdr]
END; -- EnumerateTextInDesign
state.context ← context;
window ← ImagerRect [chipNDaleWindow];
IF imageRegions THEN BEGIN
width, heigth: REAL;
state.bitmapScale ← versatecWidth / window.w;
width ← versatecWidthInMM; heigth ← window.h*state.bitmapScale/200*mmXin;
IF (heigth > versatecWidthInMM) THEN BEGIN
state.bitmapScale ← versatecLength / window.h;
width ← window.w*state.bitmapScale/200*mmXin;
heigth ← versatecLengthInMM
END;
usedField ← [x: 0.0, y: 0.0, w: width, h: heigth];
state.colorRegion ← NEW [ColorRegionRep[NumberOfColours[]]]
END
ELSE BEGIN
ratioW ← field.w / window.w; ratioH ← field.h / window.h;
usedField.x ← field.x; usedField.y ← field.y; -- in mm
IF ratioH < ratioW THEN
{usedField.w ← window.w * ratioH; usedField.h ← field.h}
ELSE {usedField.w ← field.w; usedField.h ← window.h * ratioW};
Preview considers the top of the page to be most important, because we write text from top to bottom. Also designers want have images to be flush to the top of the field, so they can use the bottom of the medium for hand-annotations. Unfortunately, this causes a severe problem when producing a PD file. In fact there is said to be a hack fixing a hard bug in the Peach software. This hack is said to be a white rectangle at the lower left corner of the medium. On the Versatec this means that with every image in landscape format you would get metres of white paper. This is why images are positioned in the lower left corner of the field.
y0 ← IF ratioH < ratioW THEN 0.0 ELSE field.h - shrunkWindow.h * ratioW;
y0 ← 0.0;
IF register THEN BEGIN
pos: FS.ComponentPositions; fName: ROPE;
[fullFName: fName, cp: pos] ← FS.ExpandName [masterName, NIL];
context.PutProp [$separationLabel, fName.Substr [pos.base.start, pos.base.length]];
NectarineAids.ComposeRegisterMarks ["Nectarine", UseProcessColors[], context]
END;
IF (ratioH < ratioW) THEN usedField.x ← (field.w - usedField.w) / 2.0;
context.TranslateT [[usedField.x, y0 + field.y]];
IF (lambda = 0.0) THEN context.ScaleT [MIN [ratioW, ratioH]]
ELSE context.ScaleT [lambda / Float [design.technology.lambda]];
context.TranslateT [[-window.x, -window.y]];
IF clip THEN context.ClipRectangle [window] -- global to context !!!
END;
IF NOT SetLayerColourTable[] THEN TerminalIO.PutRope ["\nSome layers are not in the Color Registry.\n"];
context.SetPriorityImportant [NOT (ignoreAnnotation OR (NOT state.substituteColor) OR DoLineArt[] OR imageRegions)];
IF (NOT state.substituteColor) AND (NOT DoLineArt[]) THEN BEGIN
This hack is necessary because colours will be OR-ed.
ChangeColour [state, orableBackground];
state.context.MaskRectangle [window]
END;
Rectangles:
IF state.substituteColor AND (NOT DoLineArt []) THEN BEGIN
IF imageRegions THEN BEGIN
Magic numbers: 1000 bytes per line, cylinder holds 64 lines. There are 27 bitmaps. You also need space for finding the intersections.
bandSizeR: REAL ~ MIN [320.0, window.h * state.bitmapScale];
bandSize ← Fix [bandSizeR / state.bitmapScale]; -- translate into ChipNDale units
iterations ← Fix [window.h] / bandSize -- "zero relative" !
END
ELSE BEGIN
Magic numbers: Assume 14 MB of memory may be used. Each tile requires 16 words of storage (14 words for the tile and 2 words Cedar overhead), hence 106 tiles can be stored. In the current worst case, a die is 10 mm wide. If a gate can be 2 mm long, in the worst case there is a rectangle each mm. In the average there are as many space tiles as there are colored tiles.
bandSize ← Fix [(1000000.0 * (risk+1)) / window.w];
IF bandSize < 4 * design.technology.lambda THEN SIGNAL tooComplex;
iterations ← Fix [window.h] / bandSize; -- "zero relative" !
END;
IF (iterations > 5) THEN
TerminalIO.PutF [" There will be %g sets of 3 dots ", IO.int [iterations]]
ELSE {IF debug THEN TerminalIO.PutF [v1: IO.int [iterations]]};
IF ((iterations = 0) AND (NOT state.clip)) THEN PrintBand [state] -- shortcut
ELSE BEGIN
halftime: INT ~ iterations / 2;
currentBand: REF CD.Rect ~ NEW [CD.Rect ← chipNDaleWindow];
The intersection of the current band with the clipping window is performed by PrintBand. The field state.cdClip is assigned earlier.
state.band ← currentBand;
chronos ← iterations > 5;
FOR b: INT DECREASING IN [0 .. iterations] DO
Produce bands from high to low y-coordinate values in order to avoid paging in succeeding software.
currentBand.y1 ← chipNDaleWindow.y1 + b * bandSize;
currentBand.y2 ← MIN [chipNDaleWindow.y2, currentBand.y1 + bandSize + 1];
IF chronos THEN BEGIN
The first bands are not typical, because they are not dense.
fudge: INT ~ 8;
IF (b = iterations - 3) THEN lap ← BasicTime.Now [];
IF (b = iterations - 4) AND state.isLastPage THEN BEGIN
duration: INT ~ BasicTime.Period [lap, BasicTime.Now[]];
end ← BasicTime.Update [lap, fudge * duration * (b + 2) !
BasicTime.OutOfRange => GOTO endless];
TerminalIO.PutF ["\nInterpress page will be ready ca. %g (this is only an educated guess)\n", IO.time [end]];
chronos ← FALSE
END
END;
PrintBand [state];
IF (b = halftime) AND (iterations > 10) AND state.isLastPage THEN BEGIN
fudge: INT ~ 3; -- more than 2 because of memory fragmentation
duration: INT ~ BasicTime.Period [state.startTime, BasicTime.Now[]];
end ← BasicTime.Update [state.startTime, fudge * duration !
BasicTime.OutOfRange => GOTO endless];
TerminalIO.PutF ["\nRevised duration inference: Interpress master will be ready ca. %g\n", IO.time [end]]
END
ENDLOOP;
state.band ← NIL
END;
IF (state.tess # NIL) THEN {CStitching.DumpCache []; state.tess ← NIL};
state.colorRegion ← NIL; SafeStorage.ReclaimCollectibleObjects
END-- IF state.substituteColor
ELSE BEGIN
gdr: CD.DrawRef ~ CD.CreateDrawRef [[]];
gdr.interestClip ← state.cdClip; gdr.devicePrivate ← state;
gdr.drawRect ← IF DoLineArt [] THEN LineRect ELSE OrRect;
gdr.drawContext ← DoNotDrawContext;
CDOps.DrawDesign [state.design, gdr]
END;
IF ignoreAnnotation OR (DoLineArt []) THEN RETURN;
IF imageRegions THEN RETURN; -- because it does not work yet
Text:
context.SetStrokeEnd [round]; context.SetStrokeJoint [round];
The stroke joint must be round, because a ChipNDale staightline segment [a, b] is made out of a spline [a, b, a'], where d (a, a') < e.
The end must also be round because polygons are drawn as polylines with common endpoints.
IF clip THEN tdr.interestClip ← chipNDaleWindow;
tdr.drawRect ← DoNotDrawRect;
IF letChipndaleCallTheImager THEN BEGIN
tdr.deviceContext ← context; tdr.fontSubstitution ← TRUE;
Now you think that's all and zip. Wrong, you darn sucker. Of course Chipndale does not use the Color Registry, but uses an own hack of it. So here we go to consult the Color Hyper Registry (I should have trade marked this) to build a a fourth color registry and give it to Chipndale.
tdr.contextColors ← NEW [CD.ContextColors];
FOR c: CD.Layer IN CD.Layer DO
tdr.contextColors[c] ← LayerColour [c]
ENDLOOP
END
ELSE BEGIN
tdr.drawContext ← DoNotDrawContext;
tdr.drawChild ← IF (signalNameFont = NIL) THEN DrawObject ELSE DrawObjectWithSignalNames
END;
tdr.drawOutLine ← DrawObjectBorder; tdr.borders ← TRUE; tdr.selections ← FALSE;
tdr.devicePrivate ← state;
state.previousColour ← NIL; -- needed by Interpress
state.previousStrokeWidth ← -1.0; -- needed by Interpress
context.DoSave [EnumerateTextInDesign]; TerminalIO.PutRope [". "]; -- pass 5
EXITS
endless => BEGIN
ImportantMessage [" Nectarine would not terminate before 2036"];
SIGNAL tooComplex
END
END; -- DrawToIP
Action: PROC [] ~ BEGIN
Does it at background priority.
DeclareFonts: RefTab.EachPairAction ~
{state.interpress.DeclareFont [NARROW [val,Font]]; RETURN [FALSE]};
ListFonts: RefTab.EachPairAction ~ BEGIN
t: Typeface ~ NARROW [val, Font].typeface;
TerminalIO.PutF ["%g\n", IO.rope [t.name]];
RETURN [FALSE]
END; -- ListFonts
IF state.isFirstPage THEN BEGIN
state.interpress ← OpenIPMaster []; state.ipName ← masterName;
TerminalIO.PutRope [Rope.Cat ["Producing Interpress master ", masterName, "\n"]];
IF DoLineArt [] THEN BEGIN
TerminalIO.PutRope ["Line art (overrides halftoning and cross-hatching). "];
IF UseProcessColors [] THEN TerminalIO.PutRope ["Requires process colors to print.\n"]
ELSE TerminalIO.PutRope ["Requires custom colors to print.\n"]
END
ELSE TerminalIO.PutRope ["Halftoned art. Requires process colors to print.\n"];
IF NOT state.substituteColor THEN TerminalIO.PutRope ["No color substitution.\n"];
Produce preamble.
IF (SubColours [] OR DoLineArt []) THEN
state.interpress.DeclareColorOperator [IF UserProfile.Boolean [key: "Nectarine.ContinuousTone", default: FALSE] THEN rgbLinear ELSE cmyk]
ELSE NULL;
It is not possible to declare all colours in the preamble, because the size of the Interpress frame is 50 entries (this is defined in the Standard).
IF (NumberOfColours[] + fontMap.GetSize[] < 50) THEN DeclareColours [state.interpress];
This is a terrible hack, since the colours in the table are those from the previuos run. Unfortunately the Imager does not permit to define the preamble when all the data has been processed.
Create a table of the fonts and them in the preamble.
UpdateFontMap [state];
IF (NOT ignoreAnnotation) AND (fontMap.GetSize[] < 50) THEN
[] ← fontMap.Pairs [DeclareFonts];
IF (signalNameFont # NIL) THEN state.interpress.DeclareFont [signalNameFont];
TerminalIO.PutRope [". "]; -- pass 1
IF debug THEN BEGIN
TerminalIO.PutRope ["\nThe following fonts are in the preamble:\n"];
[] ← fontMap.Pairs [ListFonts]
END
END;
Produce the page. All coordinates will be in millimetres.
TRUSTED {Process.SetPriority [Process.priorityBackground]};
state.interpress.DoPage [action: DrawToIP, scale: IF imageRegions THEN versatecResolution ELSE 0.001];
Close.
IF state.isLastPage THEN BEGIN
state.interpress.Close []; multipageHack ← NIL;
TerminalIO.PutRope [TimeToRope [state.startTime, BasicTime.Now[]]];
TerminalIO.PutRope ["\n"];
IF (statistics OR debug) THEN ListColourStatistics [state.cardTile];
TerminalIO.PutRope [Rope.Cat ["Interpress master ", state.ipName, " is ready.\n"]]
END
END; -- Action
Main of DoInterpress
IF firstPage THEN BEGIN
IF (multipageHack # NIL) THEN BEGIN
TerminalIO.PutRope [Rope.Cat ["Interpress master ", multipageHack.ipName, " was orphaned and is being salvaged.\n"]];
multipageHack.interpress.Close []; multipageHack ← NIL
END;
multipageHack ← state ← NEW [StateRec]; state.design ← design;
IF singleLayer THEN {state.singleLayer ← TRUE; state.layerOfInterest ← layer};
state.substituteColor ← SubColours [];
IF statistics THEN {ResetColourStatistics; state.cardTile ← 0};
state.abort ← IF abortFlag # NIL THEN abortFlag ELSE NEW [BOOLFALSE];
state.startTime ← BasicTime.Now []
END
ELSE BEGIN
state ← multipageHack; masterName ← state.ipName;
state.previousColour ← NIL; state.previousStrokeWidth ← -1.0;
state.previousFont ← NIL; state.previousTextOrientation ← original
END;
state.isLastPage ← lastPage; state.isFirstPage ← firstPage;
state.clip ← clip;state.cdClip ← chipNDaleWindow;
state.selectedOnly ← onlySel;
Action []
END; -- DoInterpress
DrawSelection: PROC [design: CD.Design, d: CD.DrawRef] ~ BEGIN
Same as CDOps.DrawDesign, but visits only the selected objects.
FOR all: CD.InstanceList ← CDOps.InstList [design], all.rest WHILE all # NIL DO
IF all.first.selected THEN d.drawChild [d, all.first.ob, all.first.trans, all.first.properties]
ENDLOOP
END; -- DrawSelection
EnumerateObjects: PROC [design: CD.Design, d: CD.DrawRef] ~ BEGIN
Same as CDOps.DrawDesign, but visits objects only once.
DoObject: CDDirectory.EachEntryAction ~ BEGIN
PROC [name: ROPE, ob: CD.Object] RETURNS [quit: BOOLFALSE]
d.drawChild [d, ob, [[0,0], original], NIL]
END; -- DoObject
[] ← CDDirectory.Enumerate [design, DoObject]
END; -- EnumerateObjects
ChangeColour: PROC [state: State, colour: Color] ~ INLINE BEGIN
At this point we know that only one colour representation is used. Must be fast as a bullet.
context: Imager.Context ~ state.context;
IF (colour # state.previousColour) THEN BEGIN
context.SetColor [colour]; state.previousColour ← colour
END
END; -- ChangeColour
ChangeColour: PROC [state: State, colour: Color] ~ INLINE BEGIN
At this point we know that only one colour representation is used. Must be fast as a bullet.
context: Imager.Context ~ state.context;
a: ImagerColor.RGB ~ RGBFromColour [colour];
b: ImagerColor.RGB ~ RGBFromColour [state.previousColour];
IF (a.R # b.R) OR (a.G # b.G) OR (a.B # b.B) OR (state.previousColour = NIL) THEN BEGIN
context.SetColor [colour]; state.previousColour ← colour
END
END; -- ChangeColour
ChangeStrokeWidth: PROC [state: State, w: REAL] ~ INLINE BEGIN
w < 0 means that it has not yet been set in this body. Must be fast as a bullet.
context: Imager.Context ~ state.context;
IF (w < 0) OR (w # state.previousStrokeWidth) THEN BEGIN
context.SetStrokeWidth [w]; state.previousStrokeWidth ← w
END
END; -- ChangeStrokeWidth
ChangeFont: PROC [state: State, skFont: Font] ~ INLINE BEGIN
Must be fast as a bullet
context: Imager.Context ~ state.context;
IF (skFont # state.previousFont) THEN BEGIN
prFont: Font ← NARROW [fontMap.Fetch[skFont].val];
IF (prFont = NIL) THEN BEGIN
This is nasty code. The trade off was between sort of a hack, 20 minutes of CPU on full chips, and this fix here. I wanted to find all fonts appearing in the design in order to declare them in the preamble. The most stupid thing somebody could do, would be to use a ChipNDale drawProc to visit all text objects [this can take 20 minutes of CPU]. In fact you only need to visit once every object. In ChipNDale you do this by enumerating the directory. Unfortunately ChipNDale has one object which is never in the directory, namely the root cell. In order to avoid the unesthetic special code for the root, the fonts used in the root object are not cached. In the normal case, no fonts are missed, because if there are non-cell objects in the root then usually they have some buddy inside an official cell. So all this was to justify why the print font can be L and has to be handled here at this stange place. All in all I don't care, so if you want to do something different just go ahead (the quickest would be to bypass the ChipNDale directory enumeration procedure and to do your own; this is easy if you use my table called visitedCells).
prFont ← Mapping [skFont]; [] ← fontMap.Insert [skFont, prFont]
END;
context.SetFont [prFont]; state.previousFont ← skFont
END
END; -- ChangeFont
Conversions
Data is global
fontMap: RefTab.Ref ~ RefTab.Create []; -- global
fontPrefix: ATOM ~ Atom.MakeAtom ["xerox/pressfonts/"];
visitedCells: RefTab.Ref;
DrawFilter: CD.DrawProc ~ BEGIN
[pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL]
SELECT ob.class.objectType FROM
$Text, $RigidText, $FlipText => FindFont [pr, ob, trans, readOnlyInstProps];
$Cell =>
There is no facility offered by ChipNDale to visit only a cell without recursing to its subcells, so here is a homebrew hack.
IF visitedCells.Insert [ob, $hack] THEN ob.class.drawMe [pr, ob, trans, readOnlyInstProps];
ENDCASE => NULL
END; -- DrawFilter
FindFont: CD.DrawProc ~ BEGIN
[pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL]
text: CDTexts.TextSpecific ~ NARROW [ob.specific];
font: Font ~ text.cdFont.font;
IF NOT fontMap.Fetch[font].found THEN [] ← fontMap.Insert [font, Mapping [font]]
END; -- FindFont
UpdateFontMap: PROC [state: State] ~ BEGIN
The map is global, because fonts rarely change across designs.
tdr: CD.DrawRef ~ CD.CreateDrawRef [[]];
Evict: RefTab.EachPairAction ~ {[] ← visitedCells.Delete [key]; RETURN [FALSE]};
remindFontConventions ← TRUE;
tdr.drawChild ← DrawFilter; tdr.drawRect ← DoNotDrawRect;
tdr.drawContext ← DoNotDrawContext; tdr.devicePrivate ← state;
visitedCells ← RefTab.Create [557];
IF state.selectedOnly THEN DrawSelection [state.design, tdr]
ELSE EnumerateObjects [state.design, tdr];
DrawDesign is an overkill, which easily takes 20 minutes on the CrossRAM. There is no facility offered by ChipNDale to visit only a cell without recursing to its subcells, so here is a homebrew hack.
[] ← visitedCells.Pairs [Evict]; visitedCells ← NIL
END; -- UpdateFontMap
Mapping: PROC [sk: Font] RETURNS [mr: Font] ~ BEGIN
Translates from strike to spline fonts.
fontVendor, fontClass, fullName, shortName, family, attributes: ROPE;
slashPos1, slashPos2, sizePos, facePos: INTEGER;
isXerox: BOOL;
face: NodeStyle.FontFace ← Regular;
typeface: Typeface ← sk.typeface;
size: REAL;
fullName ← typeface.name;
slashPos1 ← fullName.SkipTo [0, "/"];
fontVendor ← fullName.Substr [0, slashPos1]; isXerox ← fontVendor.Equal ["Xerox", FALSE];
slashPos1 ← slashPos1.SUCC; slashPos2 ← fullName.SkipTo [slashPos1, "/"];
fontClass ← fullName.Substr [slashPos1, slashPos2-slashPos1];
shortName ← fullName.Substr [slashPos2+1];
SELECT TRUE FROM
isXerox AND fontClass.Equal ["PressFonts", FALSE] => BEGIN
IF remindFontConventions THEN BEGIN
TerminalIO.PutRope ["Nectarine takes care of all the font substitutions. You can use the strike fonts for the layout.\n"];
remindFontConventions ← FALSE
END;
mr ← sk
END;
isXerox AND fontClass.Equal ["TiogaFonts", FALSE] => BEGIN
Find the size and face from the old style name:
sizePos ← shortName.SkipTo [0, "0123456789"];
attributes ← shortName.Substr [sizePos, shortName.Length[]-sizePos];
facePos ← attributes.SkipTo [0, "bBiI"];
Compute the size (assume: there always is a size):
size ← (ORD [attributes.Fetch[0]] - ORD ['0]);
FOR i: INT IN [1 .. facePos) DO
size ← size * 10.0 + (ORD [attributes.Fetch[i]] - ORD ['0])
ENDLOOP;
Determine the face:
IF (facePos # attributes.Length[]) THEN BEGIN
it: BOOL ~ (attributes.SkipTo [0, "iI"] # attributes.Length[]);
b: BOOL ~ (attributes.SkipTo [0, "bB"] # attributes.Length[]);
SELECT TRUE FROM
it AND b => face ← BoldItalic;
it AND NOT b => face ← Italic;
NOT it AND b => face ← Bold;
ENDCASE => ERROR
END;
family ← shortName.Substr [0, sizePos];
mr ← NodeStyleFont.FontFromStyleParams [prefix: fontPrefix, family: Atom.MakeAtom[family], face: face, size: size, alphabets: CapsAndLower];
mr ← ImagerFont.Modify [mr, sk.charToClient]
END;
ENDCASE => BEGIN
IF isXerox THEN
TerminalIO.PutRope [fullName.Cat [": font class", fontClass, " unknown, not substituted.\n"]]
ELSE TerminalIO.PutRope [fullName.Cat [": vendor", fontVendor, " unknown, not substituted.\n"]];
mr ← sk
END
END; -- Mapping
ImagerRect: PROC [r: CD.Rect] RETURNS [Imager.Rectangle] ~ BEGIN
base: CD.Position ~ CDBasics.BaseOfRect [r];
size: CD.Position ~ CDBasics.SizeOfRect [r];
RETURN [[Float[base.x], Float[base.y], Float[size.x], Float[size.y]]]
END; -- ImagerRect
ImagerVec: PROC [p: CD.Position] RETURNS [Imager.VEC] ~ BEGIN
RETURN [[Float[p.x], Float[p.y]]]
END; -- ImagerVec
BoxFromRect: PROC [r, viewport: CD.Rect] RETURNS [Box] ~ BEGIN
Box: TYPE ~ RECORD [min, max: Vec ← zeroVec];
b: Box denotes all v: Vec that satisfy v.s IN[b.min.s..b.max.s) AND v.f IN[b.min.f..b.max.f)
RETURN [[min: [f: r.x1, s: viewport.y2-r.y2], max: [f: r.x2, s: viewport.y2-r.y1]]]
RETURN [[min: [f: r.x1-viewport.x1, s: viewport.y2-r.y2],
max: [f: r.x2-viewport.x1, s: viewport.y2-r.y1]]]
END; -- BoxFromRect
QuickTransf: PROC [r: CD.Rect, state: State] RETURNS [CD.Rect] ~ BEGIN
PointX: PROC [p: INT] RETURNS [INT] ~ INLINE BEGIN
RETURN [Round [Float [p-state.cdClip.x1] * state.bitmapScale]]
END; -- PointX
PointY: PROC [p: INT] RETURNS [INT] ~ INLINE BEGIN
RETURN [Round [Float [p-state.cdClip.y1] * state.bitmapScale]]
END; -- PointY
RETURN [[PointX [r.x1], PointY [r.y1], PointX [r.x2], PointY [r.y2]]]
END; -- QuickTransf
CdPos: PROC [v: Imager.VEC] RETURNS [CD.Position] ~ BEGIN
RETURN [[InlineRound[v.x], InlineRound[v.y]]]
END; -- CdPos
RGBFromColour: PROC [c: Color] RETURNS [rgb: ImagerColor.RGB] ~ INLINE BEGIN
Assume that LayerColour had previously been called.
WITH c SELECT FROM
constant: Imager.ConstantColor => rgb ← ImagerColorPrivate.RGBFromColor [constant];
ENDCASE => rgb ← unColour;
RETURN [rgb]
END; -- RGBFromColour
SubColours: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [UserProfile.Boolean [key: "Nectarine.SubstituteColors", default: colSubDef]]
END; -- SubColours
DoLineArt: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [UserProfile.Boolean [key: "Nectarine.LineArt", default: FALSE]]
END; -- DoLineArt
UseProcessColors: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [UserProfile.Boolean [key: "Nectarine.ProcessColors", default: TRUE]]
END; -- UseProcessColors
ImportantMessage: PROC [msg: ROPE] ~ BEGIN
Writes a message in the ChipNDale terminal viewer and in the Message Window at the top of the LF screen and makes it blink.
TerminalIO.PutRope [msg]; TerminalIO.PutRope ["\n"];
MessageWindow.Clear []; MessageWindow.Append [msg]; MessageWindow.Blink []
END; -- ImportantMessage
DoNotDrawContext: CD.DrawContextProc ~ {};
DoNotDrawObject: CD.DrawProc ~ {};
DoNotDrawRect: CD.DrawRectProc ~ {};
OrRect: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
state: State ~ NARROW [pr.devicePrivate, State];
IF (state.singleLayer AND (l # state.layerOfInterest)) THEN RETURN;
IF (CDBasics.NonEmpty [r]) THEN BEGIN
IF state.abort^ THEN ERROR ABORTED;
ChangeColour [state, LayerColour [l]];
state.context.MaskRectangle [ImagerRect [r]]
END
END; -- OrRect
LineRect: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
state: State ~ NARROW [pr.devicePrivate, State];
IF (state.singleLayer AND (l # state.layerOfInterest)) THEN RETURN;
IF (CDBasics.NonEmpty [r]) AND (LayerColour [l] # NIL) THEN BEGIN
IF state.abort^ THEN ERROR ABORTED;
ChangeColour [state, LayerColour [l]]; state.context.MaskRectangle [ImagerRect [r]]
END
END; -- LineRect
Printing
Print: PUBLIC PROC [masterName: Rope.ROPE, printerKey: ATOM, copies: INT ← 1, doNotScale: BOOLFALSE, mergeRegister: BOOLTRUE, sizeHint: REF Imager.Rectangle ← NIL, abortFlag: REF BOOL] RETURNS [peachName: ROPE] ~ BEGIN
Produces (if necessary) a PD file from an Interpress master and ships it to the printer. Valid printer keys are $NVersatec, $NColorVersatec, $NPeachExpand, $NBw400, $NColor400, $NPlateMaker, $NRaven300, $C2700, $NRaven384. May return signals invalidPrinter.
If the image is in portrait format and the printer uses roll paper, the rectangle usedField from DoInterpress can be specified as a sizeHint to increase the scale so a to use the full roll width.
If doNotScale then Print does not fit the field to the medium.
errorCause: ROPE;
pos: FS.ComponentPositions;
{ENABLE BEGIN
XNSPrint.Error => {errorCause ← explanation; GOTO xnsFailure};
END;
IF masterName.IsEmpty THEN BEGIN
TerminalIO.PutRope ["Produce an Interpress master first.\n"]; RETURN [NIL]
END;
IF (abortFlag = NIL) THEN abortFlag ← NEW [BOOLFALSE];
IF abortFlag^ THEN ERROR ABORTED; Process.CheckForAbort;
Process.CheckForAbort has to be called because of the Redo command.
pos ← FS.ExpandName[masterName].cp;
SELECT printerKey FROM
$NVersatec, $NColorVersatec, $NBw400, $NColor400, $NPeachExpand, $NRaven384 => BEGIN
peachName ← masterName.Replace [pos.ext.start, pos.ext.length, "PD"];
TRUSTED BEGIN
Process.Detach [FORK PdPrintProcess [masterName, peachName, printerKey, copies, doNotScale, FALSE, sizeHint, abortFlag]]
END;
TerminalIO.PutRope ["Printing process forked off.\n"]
END;
$NRaven300, $C2700 => BEGIN
serverName: ROPE;
fullName: ROPE; -- with version number
c: XNSPrint.Context ~ XNSPrint.GetDefaults [];
fullName ← FS.FileInfo [name: masterName, remoteCheck: FALSE].fullFName;
pos ← FS.ExpandName [fullName].cp;
c.printObjectName ← fullName.Substr[start: pos.base.start, len: pos.base.length].Cat["!",fullName.Substr[start: pos.ver.start, len: pos.ver.length]]; -- Sorry !
SELECT printerKey FROM
$NRaven300 => serverName ← UserProfile.Token ["Nectarine.Raven300", "Quoth"];
$C2700 => serverName ← UserProfile.Token ["Nectarine.C2700", "TimsToy"];
ENDCASE => SIGNAL invalidPrinter;
c.printerName ← serverName;
c.printObjectCreateDate ← FS.FileInfo [name: fullName, remoteCheck: FALSE].created;
c.copyCount ← copies;
c.senderName ← UserCredentials.Get[].name;
c.message ← Rope.Cat ["Nectarine for ", c.senderName];
IF abortFlag^ THEN ERROR ABORTED; Process.CheckForAbort;
[] ← XNSPrint.PrintFromFile [fullName, c];
TerminalIO.PutF ["%g submitted to %g.\n", IO.rope [c.printObjectName], IO.rope [serverName]];
peachName ← masterName
END;
$NPlateMaker => BEGIN
Note: the Interpress decomposer shifts to the right by 7.9375 mm and up by 12.7 mm.
sent: BOOL; info: SimpleMailer.SendMessageInfo;
user: ROPE ~ UserCredentials.Get[].name;
erieSeparations: ROPE ← UserProfile.Token ["Nectarine.PlatemakerSeparations"];
Following statement is wrong: need to call MergeRegisterMarks first.
gName: ROPE ~ FS.Copy [from: masterName, to: Rope.Cat ["[Cyan]<DATools7.0>Platemaker>", user, ">", masterName.Substr [pos.base.start, pos.base.length], ".Interpress"]];
IF erieSeparations.IsEmpty THEN break;
peachName ← masterName.Substr [pos.base.start, pos.base.length];
TRUSTED BEGIN
Process.Detach [FORK PdPrintProcess [masterName, peachName, printerKey, copies, doNotScale, mergeRegister, sizeHint, abortFlag]]
END;
TerminalIO.PutRope ["Printing process forked off.\n"];
IF abortFlag^ THEN ERROR ABORTED; Process.CheckForAbort;
[sent, info] ← SimpleMailer.SendMessage [from: "Nectarine", to: LIST ["Scamporrino.PA"], cc: LIST [user], subject: "Platemaker Print Request", body: Rope.Cat ["Dear Bridget,\n\nHow are you today ?\nPlease print for me the file ", gName, ".\n\nThe Interpress master is in A size with a margin of 1 cm on each side.\n\nThis master is for your convenience to preview the picture on a monitor. In a while, you will also find there the required separations ready to be printed. I will send you a message with the names as soon as I will have produced them.\n\nThank you,\n", user]];
IF NOT sent THEN ImportantMessage [Rope.Cat ["Ask Bridget Scamporrino to print ", gName, " for you."]];
SELECT info FROM
ok => TerminalIO.PutRope ["Your job will be printed as fast as possible.\n"];
invalidRecipient => TerminalIO.PutRope ["The person in charge of Platemaker has changed. Please consult a wizard.\n"];
noValidRecipients => TerminalIO.PutRope ["Nectarine can no longer handle printing on Platemaker. Please consult a wizard.\n"];
badPwd => TerminalIO.PutF ["Your password is invalid. May be you just changed it and did not roll-back. Ask Bridget Scamporrino to print %g for you.\n", IO.rope [gName]];
badSender => TerminalIO.PutF ["You need a Grapevine account to print on Platemaker with no hands. Ask Bridget Scamporrino to print %g for you.\n", IO.rope [gName]];
badReturnTo => TerminalIO.PutRope ["Implementation problem.\n"];
allDown => TerminalIO.PutF ["The mail system is down. Ask Bridget Scamporrino to print %g for you.\n", IO.rope [gName]];
ENDCASE => ERROR
END;
ENDCASE => SIGNAL invalidPrinter;
EXITS
xnsFailure => BEGIN
ImportantMessage [errorCause.Cat [" File saved on ", peachName, " for manual retry."]]
END
}
END; -- Print
Statistics
previousColorSubEntry: BOOL ← SubColours [];
previousLineArtEntry: BOOL ← DoLineArt [];
previousInkEntry: BOOL ← UseProcessColors [];
GetStatisticsToggle: UserProfile.ProfileChangedProc ~ BEGIN
colorSub: BOOL ~ SubColours [];
lineArt: BOOL ~ DoLineArt [];
processColors: BOOL ~ UseProcessColors [];
statistics ← UserProfile.Boolean [key: "Nectarine.Statistics"];
IF (colorSub # previousColorSubEntry) THEN BEGIN
previousColorSubEntry ← colorSub;
IF (reason = edit) OR (reason = newUser) THEN BEGIN
TerminalIO.PutRope ["\nOption for color substitution changed.\n"];
IF colorSub THEN BEGIN
ReadMap ["[DATools7.0]<Nectarine>Discriminable.ColorMap"];
[] ← ResetLayerColourTable []; BlendTileColours
END
ELSE [] ← ResetLayerColourTable []
END
END;
IF (lineArt # previousLineArtEntry) THEN BEGIN
previousLineArtEntry ← lineArt;
IF (reason = edit) OR (reason = newUser) THEN BEGIN
TerminalIO.PutRope ["\nOption for line art changed.\n"];
IF NOT lineArt THEN BEGIN
ReadMap ["[DATools7.0]<Nectarine>Discriminable.ColorMap"];
[] ← ResetLayerColourTable []; BlendTileColours
END
ELSE [] ← ResetLayerColourTable []
END
END;
IF (processColors # previousInkEntry) THEN BEGIN
previousInkEntry ← processColors;
IF (reason = edit) OR (reason = newUser) THEN BEGIN
TerminalIO.PutRope ["\nOption for line art ink changed.\n"];
[] ← ResetLayerColourTable []
END
END
END; -- GetStatisticsToggle
TimeToRope: PROC [from, to: BasicTime.GMT] RETURNS [time: ROPE] ~ BEGIN
Although the INT returned BasicTime.Period is the same as GMT and might hence be loopholed to use IO.time from Conversions, the latter uses BasicTime.Unpack which allows only values that give a valid date.
TwoPosInt: PROC [i: INT] RETURNS [ROPE] ~ BEGIN
RETURN [SELECT i FROM
= 0 => "00",
< 10 => Rope.Cat ["0", IO.PutFR1 [value: IO.int [i]]],
ENDCASE => IO.PutFR1 [value: IO.int [i]]]
END;
s: INT ← BasicTime.Period [from, to];
m: INT ← s / 60; h: INT ← m / 60; d: INT ~ h / 24;
s ← s MOD 60; m ← m MOD 60; h ← h MOD 24;
IF (d > 0) THEN time ← Rope.Cat ["d:h:m:s ", TwoPosInt[d], ":"]
ELSE time ← "h:m:s ";
time ← time.Cat [TwoPosInt[h], ":"];
RETURN [time.Cat [TwoPosInt[m], ":", TwoPosInt[s]]]
END; -- TimeToRope
Initialization
doc: ROPE ~ "tunes the parameters of Nectarine.\n\t-a do not align rectangles to pixels (schematics)\n\t-b outline regions\n\t\t-1: no outline\n\t\t 0: one pixel outline\n\t\t 1: unit width outline\n\t-c do not use (reveal tess.)\n\t-d <1/density> controls the size of bands (risk)\n\t-e do not trace color inferences\n\t-f do not use ChipNDale to image annotation\n\t-g ignore annotation (image only rectangles)\n\t-h do rectangles\nIf a boolean switch is absent, it is set to TRUE.\n[Additional commands: NCount, NRedo, NQuery, NWriteColors, NReadColors, NOldColors, PrintDesignOnVersatec, NectarineField, NSetMaxField, NectarineSignal].";
fieldDoc: ROPE ~ "explicitly set the field size to perform image ganging. Specify the field in mm\n\t-x lower left corner x\n\t-y lower left corner y\n\t-w width\n\t-h height\nDefaults: x: medium.x + 10.0, y: medium.y + 10.0, w: medium.w - 20.0, h: medium.h - 20.0; where medium = [x: 0.0, y: 0.0, w: 215.9, h: 279.4]\n[Additional commands: NCount, NRedo, NQuery, NWriteColors, NReadColors, NOldColors, PrintDesignOnVersatec, Nectarine, NSetMaxField, NectarineSignal].";
signalDoc: ROPE ~ "controls the rendering of signal names. If no parameter is specified, they will rendered with a 5 CMOS-lambda font. If a positive value is specified with the -a switch, this values is used as the font size, otherwise the rendering of signal names is disabled. If switch -b is not specified or positive, the names are centered, otherwise they start at the origin. Side-effect: Nectarine's -f switch is set.\n[Additional commands: NCount, NRedo, NQuery, NWriteColors, NReadColors, NOldColors, PrintDesignOnVersatec, NectarineField, NSetMaxField, Nectarine].";
argError: ROPE;
SetSwitches: Commander.CommandProc ~ BEGIN
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
Sets the switches which control the tuning of Nectarine.
align, outlineType, tess, density, inferenceTrace, ann, skipAnn, hyp: Args.Arg;
prevTraceValue: BOOL ~ traceColourInferences;
IF (Args.NArgs [cmd] # 0) THEN BEGIN
[align, outlineType, tess, density, inferenceTrace, ann, skipAnn, hyp] ← Args.ArgsGet [cmd, "-a%b-b%i-c%b-d%i-e%b-f%b-g%b-h%b" ! Args.Error => {argError ← reason; GOTO failure}];
layout ← (align.ok AND align.bool);
IF outlineType.ok THEN outline ← SELECT outlineType.int FROM < 0 => -1.0, > 0 => 1.0, ENDCASE => 0.0;
showTesselation ← (tess.ok AND tess.bool);
IF density.ok THEN risk ← density.int;
traceColourInferences ← (inferenceTrace.ok AND inferenceTrace.bool);
letChipndaleCallTheImager ← NOT (ann.ok AND ann.bool);
ignoreAnnotation ← (skipAnn.ok AND skipAnn.bool);
IF debug THEN imageRegions ← (hyp.ok AND hyp.bool)
END;
msg ← IO.PutFR ["Nectarine parametrisation: layout = %g, outline = %g, risk = %g, annotation via cd = %g, ignore annotation = %g\nYou typed: Nectarine", IO.bool [layout], IO.real [outline], IO.int [risk], IO.bool [letChipndaleCallTheImager], IO.bool [ignoreAnnotation]];
IF layout THEN msg ← msg.Concat [" -a"];
msg ← IO.PutFR ["%g -b %g -d %g", IO.rope [msg], IO.int [Round [outline]], IO.int [risk]];
IF traceColourInferences THEN msg ← msg.Concat [" -e"];
IF NOT letChipndaleCallTheImager THEN msg ← msg.Concat [" -f"];
IF ignoreAnnotation THEN msg ← msg.Concat [" -g"];
IF imageRegions THEN msg ← msg.Concat [" -h"];
IF (traceColourInferences # prevTraceValue) THEN BEGIN
[] ← ResetLayerColourTable [];
IF SubColours [] THEN BlendTileColours []
END;
EXITS
failure => RETURN [$Failure, argError.Cat ["\n", doc]]
END; -- SetSwitches
SignalNames: Commander.CommandProc ~ BEGIN
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
size, alignement: Args.Arg;
[size, alignement] ← Args.ArgsGet [cmd, "-a%i-b%i" ! Args.Error => {argError ← reason; GOTO failure}];
IF (Args.NArgs [cmd] = 0) OR (NOT size.ok) THEN size.int ← 5; -- in l
IF (size.int <= 0) THEN size.int ← 0;
IF size.int > 0 THEN BEGIN
regularFace: Font ~ ImagerFont.Find ["Xerox/PressFonts/Modern-MRR", substituteQuietly];
signalNameFont ← regularFace.Scale [8 * size.int];
msg ← IO.PutFR ["Signal names will be imaged and their size will be %g CMOS-lambdas.", IO.int [size.int]];
letChipndaleCallTheImager ← FALSE
END
ELSE {signalNameFont ← NIL; msg ← "Signal names will not be imaged"};
IF alignement.ok THEN centerSignalNames ← (alignement.int > 0);
msg ← IO.PutFR ["%g Centered signal names = %g.", IO.rope [msg], IO.bool [centerSignalNames]];
EXITS
failure => RETURN [$Failure, argError.Cat ["\n", signalDoc]]
END; -- SignalNames
UserProfile.CallWhenProfileChanges [GetStatisticsToggle];
Commander.Register [key: "Nectarine", proc: SetSwitches, doc: doc];
Commander.Register [key: "NectarineSignals", proc: SignalNames, doc: signalDoc]
END.
gbb September 4, 1986 1:49:44 pm PDT
Made a change to avoid anti-aliasing. All rectangles are now printed with the lower left corner starting on a pixel.
changes to: DIRECTORY, PrintAlignedTile, MaskAlignedRectangle (local of PrintAlignedTile), PrintTile, PrintBand, EnumerateGeometry (local of PrintBand)
gbb September 4, 1986 5:51:47 pm PDT
Changed the border of cells from a sequence of rectangles to a trajectory.
changes to: DIRECTORY, IMPORTS, DrawObjectBorder, DotDotDotSpace (local of DrawObjectBorder), DrawObject
gbb September 5, 1986 11:09:19 am PDT
Added the parameter sizeHint to the print procedure.
changes to: PeachProcess, Print
gbb September 19, 1986 7:14:38 pm PDT
Black toner for color Versatec had gone lost somewhen.
changes to: PeachProcess
gbb September 22, 1986 3:26:33 pm PDT
Added capability to produce tone separations for PlateMaker.
changes to: DIRECTORY, PeachProcess, Print
gbb September 23, 1986 6:04:17 pm PDT
Addded filled trajectories.
changes to: DIRECTORY, DrawArea, DrawObjectBorder, DrawObject
gbb September 24, 1986 3:47:17 pm PDT
Fixed scaling for devices with cut paper. Changed colour model used to print black. Added 1 to the height of bands.
changes to: DIRECTORY, DrawToIP (local of DoInterpress), black, unColour, BlendColours, PeachProcess.
gbb September 25, 1986 8:00:34 pm PDT
Bypassed an arcane bug in the compiler.
changes to: PeachProcess: see implementation note.
gbb October 2, 1986 1:01:19 pm PDT
Introduced a mild temporary hack to fix a server locking problem until the new print server software becomes available in about three to four weeks.
Finished adjusting and testing all the little details to print on Platemaker at 1200 lines per inch resolution. Instructions are written in the Terminal viewer. When submitting the separations, please advise the operator that the separations make use of the full device size.
changes to: Action (local of DoInterpress), PeachProcess
gbb October 7, 1986 3:36:11 pm PDT
Tweeking the rendition of colours on the Versatec.
changes to: PeachProcess
gbb October 9, 1986 1:47:12 pm PDT
Handle gracefully the limit of 50 entries in the Interpress frame.
changes to: DIRECTORY, Action (local of DoInterpress)
gbb December 5, 1986 1:48:47 pm PST
Added Raven 384 printer
changes to: PeachProcess, Print.
gbb December 18, 1986 4:52:55 pm PST
In ChipNdale 23 cut (cut-2) was always black (blue), but in rel. 24 was displayed black (blue) and printed blue (green).
changes to: SetLayerColourTable: cut is forced to black and cut-2 to blue.
gbb December 18, 1986 7:52:00 pm PST
In mid-december 1986, the Interpress to PD software has changed, and the speed-up trick of turning off the Interpress imaging model for the tesselated geometry does no longer work. The new regime is: the imager priority is always set to important, but setting NectarineImpl.layout ← TRUE in the interpreter, the priority is turned off. In addition rectangles are no longer aligned to pixels, avoiding the white strikes.
changes to: OPEN, EnumerateGeometry (local of PrintBand), EnumerateTextInDesign (local of DrawToIP, local of DoInterpress), DrawToIP (local of DoInterpress), BlendRec, BlendColours, SetLayerColourTable
gbb December 24, 1986 10:33:00 am PST
Since gates are very important, they are given double weight.
changes to: doubleYellowRGB: doubled, BlendColours: double weight for gates.
gbb February 2, 1987 6:02:40 pm PST
Added the capability to print at a given scale, i.e., to define  in millimetres
changes to: DoInterpress added parameter lambda, DrawToIP (local of DoInterpress): fixed scaling, Print: added parameter doNotScale.
gbb February 6, 1987 1:20:30 pm PST
Added XNS printing service.
changes to: DIRECTORY, IMPORTS, submittedPrintRequests: interim, XNSwatch:interim, PdPrintProcess, Print.
gbb February 7, 1987 6:56:46 pm PST
Added queueing for XNS printing service.
changes to: DIRECTORY, XNSinfo, PrintRequest, PrintRequestRec, pendingRequests, AnalyzeSubmitted (local of ReportXNSprintingStatus), Resubmit (local of ReportXNSprintingStatus), ReportXNSprintingStatus, PdPrintProcess
gbb February 9, 1987 1:59:04 pm PST
Added a watcher because this stuff does not work in the Cedar 6.1 version of XNS printing.
changes to: DIRECTORY, PrintRequestRec, niceGuyQueueSize, XNSfinalisation, XNSwatcher, ReportXNSprintingStatus, Resubmit (local of ReportXNSprintingStatus), PdPrintProcess, UserProfile, TRUSTED
gbb February 10, 1987 2:56:47 pm PST
Added the ability to print only a single layer.
changes to: OPEN, StateRec, NewRect, DrawText, DrawPath, DrawArea, DrawObjectBorder, DrawDashedObjectBorder, DoInterpress, DrawToIP (local of DoInterpress), Action (local of DoInterpress), DrawSelection, niceGuyQueueSize
gbb March 16, 1987 3:22:03 pm PST
Added capability to print multi-page documents for the Dragon documentation.
changes to: StateRec, DoInterpress, DrawToIP (local of DoInterpress), Action (local of DoInterpress), PdPrintProcess
gbb March 25, 1987 3:26:43 pm PST
Changed scaling for Platemaker to be fixed to 1.0 instead of using Platemaker's device size.
changes to: PdPrintProcess
gbb March 31, 1987 4:12:04 pm PST
Took out pending queue, because did never get notification from printer, hence locking up the transfer. Now everything is just shipped off to the printer.
changes to: PrintRequestRec, submittedRequests, XNSfinalisation, AnalyzeSubmitted (local of ReportXNSprintingStatus), ReportXNSprintingStatus, PdPrintProcess, UserProfile
gbb April 14, 1987 4:16:31 pm PDT
Implemented new user profile option to substitute named colors. Imager error is caught and bogus colors are replaced by black.
changes to: DIRECTORY, DrawToIP (local of DoInterpress), SetLayerColourTable
gbb April 17, 1987 3:25:52 pm PDT
Radically changed printing on Platemaker.
changes to: DIRECTORY, IMPORTS, Print
gbb May 19, 1987 1:22:59 pm PDT
Optimized main data space storage requirements for the case of Interpress printers.
changes to: PdPrintProcess, Print
gbb May 19, 1987 5:42:42 pm PDT
Added a command that allows to parametrize Nectarine via straight commands instead of using the Interpreter.
changes to: DIRECTORY, IMPORTS, OPEN, StateRec, OpenIPMaster (local of DoInterpress), DoObject (local of EnumerateObjects), Mapping, ImportantMessage, ResetColourStatistics, doc, SetSwitches, UserProfile, Commander.
gbb May 26, 1987 4:27:06 pm PDT
Added capability to draw borders of regions (rims).
changes to: DIRECTORY, Tile, TileAndContext, TcRec, FlushDecomposition, SouthRim, EastRim, NorthRim, WestRim, PrintAlignedTile, PrintTile, PrintBand, EnumerateGeometry (local of PrintBand)
gbb June 5, 1987 1:08:47 pm PDT
Added color corection for PD devices.
changes to: FillSample (local of PdPrintProcess), PdPrintProcess
gbb June 5, 1987 5:49:44 pm PDT
Added some redundant consistency checks because of a spurious problem in printing very large multi-page Interpress masters.
Michael Plass has changed the implementation of MaskVector so that it gives the result of PrintAlignedTile at the cost of PrintTile.
changes to: DIRECTORY, OPEN, FastMaskVector, SouthRim, EastRim, NorthRim, WestRim, NewPrintTile, PrintBand, EnumerateGeometry (local of PrintBand), multipageHack, DoInterpress, Action (local of DoInterpress), Set (local of FillSample, local of PdPrintProcess), PdPrintProcess
gbb June 8, 1987 4:37:40 pm PDT
Added grey balance.
changes to: PdPrintProcess
gbb June 12, 1987 4:14:04 pm PDT
Changed the layer $yellow to print as n-well and $blue as metal-1, because that's what you see on the screen.
Up to Cedar 6.1, Imager.black was printed on the black separation. Starting from 7.0, it is printed on all layers except black because of the 3-dimensionality of the thermal transfer printing process. Since this in not wanted for schematics, black is now taken from the CMYK color model instead of RGB linear.
changes to: DIRECTORY, DoInterpress, Action (local of DoInterpress), blackBlack, SetLayerColourTable, DrawText
gbb June 16, 1987 3:02:24 pm PDT
A new procedure PrintStippledTile has been introduced, that paints every tile once for every layer intersecting in it. If no colour substitution is performed, this allows to produce exactly the same output as with the checkplot software, except that outlines can be drawn around regions if the user wishes so.
changes to: StateRec, OPEN, SouthRim, EastRim, NorthRim, WestRim, PrintStippledTile, PrintBand, EnumerateGeometry (local of PrintBand), OpenIPMaster (local of DoInterpress), DoInterpress
gbb June 16, 1987 4:35:04 pm PDT
Optimized outiles for named colours.
Maureen Stone will be notified by mail every time an Interpress master with named colours is used.
changes to: SouthRim, EastRim, NorthRim, WestRim, Action (local of DoInterpress), DoInterpress, Print
gbb June 17, 1987 11:21:25 am PDT
Implemented a concertated change with the Imager that speeds-up the raster-scan conversion of a factor 3.
changes to: PrintTile, PrintStippledTile
gbb June 17, 1987 5:38:22 pm PDT
CDColors changed to CDColorsExtras with different semantics.
changes to: DIRECTORY, IMPORTS, SetLayerColourTable
gbb June 18, 1987 10:01:52 am PDT
1000 details for ChipNDale's special colors.
changes to: DIRECTORY, PrintBand, DrawObjectBorder, DrawDashedObjectBorder, DrawToIP (local of DoInterpress), cyan, red, SetLayerColourTable, previousColorSubEntry, GetStatisticsToggle
gbb June 22, 1987 1:12:14 pm PDT
Following an expert advice, colours are taken from the Imager instead from ChipNDale.
changes to: DIRECTORY, SetLayerColourTable
gbb June 23, 1987 3:26:58 pm PDT
The inheritance scheme for the colour registries turned out to be unsafe. Hence, it has been substituted by a rule based inference engine.
changes to: OPEN, undefColour, SetLayerColourTable, MakeConstant (local of SetLayerColourTable), ColourName (local of SetLayerColourTable), InferenceStatus (local of SetLayerColourTable), Decide (local of SetLayerColourTable), One (local of SetLayerColourTable), Two (local of SetLayerColourTable), Three (local of SetLayerColourTable), Four (local of SetLayerColourTable), Five (local of SetLayerColourTable), Six (local of SetLayerColourTable), Seven (local of SetLayerColourTable), Nine (local of SetLayerColourTable), Ten (local of SetLayerColourTable), doc, SetSwitches
gbb June 24, 1987 10:36:28 am PDT
Put colour registry inference engine in a separate module because a limit in the code generation part of the compiler was blown.
changes to: DIRECTORY, IMPORTS, OPEN, colourTable, ColourTile, BlendColours, GetStatisticsToggle, SetSwitches
gbb June 30, 1987 5:33:12 pm PDT
Introduced a fourth color registry so that ChipNDale can be used to draw the annotation. This was necessary for some undiscovered spurious side-effect lurking somewhere deep in its guts. Since ChipNDale does not use the Color Registry, we have to put him up one.
changes to: DIRECTORY, OPEN, DrawToIP (local of DoInterpress)
gbb September 16, 1987 11:06:27 am PDT
Changed the font name parser to be independent of an eventual working directory in which ChipNDale might have been forked as a process.
changes to: Mapping.
gbb October 28, 1987 3:20:46 pm PST
Added creation and automatic submission of separations for printing on Platemeker.
changes to: PdPrintProcess, Print
gbb November 10, 1987 11:19:23 am PST
Standardization of Cromalin pigments to SOP-Cyan, SOP-Magenta, and SOP-Yellow.
changes to: PdPrintProcess.
gbb November 16, 1987 1:35:44 pm PST
Another attempt to simulate what happened from 24 to 25 with the font offset.
changes to: DrawText, DIRECTORY
gbb November 25, 1987 5:11:22 pm PST
Merged colour blending into NectarineHyperRegistryImpl and renamed it into NectarineColourImpl.
changes to: DIRECTORY, IMPORTS, EXPORTS, OPEN, Action (local of DoInterpress), DoInterpress, ProgressLog, previousColorSubEntry, GetStatisticsToggle
gbb December 3, 1987 11:01:23 am PST
Changed the default for grey balancing to TRUE. Made printing abortable from the ChipNDale viewer.
changes to: PdPrintProcess, Print.
gbb December 5, 1987 3:50:23 pm PST
Added alignement marks to the separations for Platemaker.
changes to: DIRECTORY, IMPORTS, MergeAlignementMarks, DoIt (local of MergeAlignementMarks), PdPrintProcess, Print.
gbb December 9, 1987 5:01:01 pm PST
New switch to image only rectangles
changes to: doc.
gbb December 14, 1987 2:16:55 pm PST
Peach printing is now forked off.
changes to: PdPrintProcess.
gbb December 15, 1987 4:32:40 pm PST
The Interpress masters for Platemaker are now being merged with the alignment marks. This means, that it is no longer possible to translate or scale during the InterpressToPD conversion; the user has to live with the 1 cm margin.
changes to: PdPrintProcess: eliminated tx, ty, and scale in the Platemaker case.
gbb December 22, 1987 11:23:18 am PST
Tweaked screening for Versatec.
changes to: DrawToIP (local of DoInterpress), Action (local of DoInterpress), PdPrintProcess.
gbb December 31, 1987 3:57:54 pm PST
New user profile option Nectarine.ContinuousTone: BOOLFALSE. Set to TRUE when separations are created by an electronic color scanner or by photographic halftoning.
changes to: Action (local of DoInterpress).
gbb January 4, 1988 4:11:58 pm PST
Added a command to explicitly set the field size to perform image ganging.
changes to: OPEN, doc, fieldDoc, SetSwitches, SetField, Commander, Commander
gbb January 5, 1988 5:59:25 pm PST
Introduced line art.
changes to: DrawToIP (local of DoInterpress), Action (local of DoInterpress), DoLineArt, ImportantMessage, LineRect, previousColorSubEntry, previousLineArtEntry, GetStatisticsToggle
gbb January 9, 1988 4:00:17 pm PST
Re-implemented high resolution high speed halftoning.
changes to: PdPrintProcess
gbb January 12, 1988 11:32:22 am PST
Trying to reduce local disk sace requirements by 75% in the case of platemaker output.
changes to: DIRECTORY, IMPORTS, ForcedDelete, MergeRegisterMarks, PdPrintProcess
gbb January 29, 1988 7:51:09 pm PST
Dusted off an old algorithm for finding multiple connected regions.
changes to: DIRECTORY, OPEN, StateRec, AddTile, PrintStippledTile, EnumerateGeometry (local of PrintBand), PrintBand, NewScaledRect, DrawToIP (local of DoInterpress), ChangeFont, BoxFromRect, doc, SetSwitches, Commander
gbb February 10, 1988 4:26:09 pm PST
Tuned the algortihm with respect to the Cedar Imager
changes to: OPEN, AddTile, DrawToIP (local of DoInterpress)
gbb August 12, 1988 11:32:43 am PDT
Added the capability to render signal names (for debugging routers, requested by Bryan Preas)
changes to: DIRECTORY, IMPORTS, OPEN, DrawObject, DrawObjectWithSignalNames, DrawToIP (local of DoInterpress), Action (local of DoInterpress), fieldDoc, signalDoc, SignalNames, Commander, Commander
gbb September 19, 1988 10:07:15 am PDT
Added Versatec C2700
changes to: Print
gbb October 13, 1988 2:50:17 pm PDT
When ratioH < ratioW the image is centered.
changes to: DrawToIP (local of DoInterpress)