ImagerPressImpl:
CEDAR
PROGRAM
IMPORTS FS, Imager, ImagerBackdoor, ImagerColor, ImagerFont, ImagerFontPrivate, ImagerPath, ImagerPressFontSubst, ImagerState, ImagerTransformation, Real, RealFns, RefTab, SirPress, Vector2
EXPORTS Imager, ImagerColorDefs, ImagerFont, ImagerPress
Rectangle: TYPE ~ ImagerTransformation.Rectangle;
PixelArray: TYPE ~ ImagerPixelArray.PixelArray;
RealKey: TYPE ~ ImagerBackdoor.RealKey;
IntKey: TYPE ~ ImagerBackdoor.IntKey;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Font: TYPE ~ ImagerFont.Font;
Color: TYPE ~ ImagerColorDefs.Color;
VEC: TYPE ~ Vector2.VEC;
PathProc: TYPE ~ ImagerPath.PathProc;
ColorOperator: TYPE ~ ImagerColorDefs.ColorOperator;
Context: TYPE ~ Imager.Context;
PrinterType:
TYPE ~ ImagerPress.PrinterType;
Class: TYPE ~ ImagerPrivate.Class;
ClassRep:
PUBLIC
TYPE ~ ImagerPrivate.ClassRep;
-- export to Imager.ClassRep
State: TYPE ~ ImagerState.State;
StateRep:
PUBLIC
TYPE ~ ImagerState.StateRep;
-- export to Imager.StateRep
FontImpl: TYPE ~ REF FontImplRep;
FontImplRep:
PUBLIC
TYPE ~ ImagerFontPrivate.FontImplRep;
-- export to ImagerFont.FontImplRep
ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl;
ConstantColorImplRep:
PUBLIC
TYPE ~ ImagerColorPrivate.ConstantColorImplRep;
-- export to ImagerColorDefs.ConstantColorImplRep
Data: TYPE ~ REF DataRep;
DataRep:
TYPE ~
RECORD [
sirpress: SirPress.PressHandle,
printerType: PrinterType,
wantWarnings: INT ← 0,
pageWidth: NAT,
pageHeight: NAT,
page: INT ← 1,
cpValid: BOOL ← FALSE,
hue, sat, val: [0..255] ← 0,
fontTable: RefTab.Ref,
scratchT: Transformation,
scratchText: REF TEXT,
lastPFD: REF ← NIL
];
Create:
PUBLIC
PROC [outputStream:
IO.
STREAM, fileNameForHeaderPage:
ROPE, creatorName:
ROPE, printerType: PrinterType, printingMode: ImagerPress.PrintingMode, pageWidthMicas:
INT, pageHeightMicas:
INT]
RETURNS [context: Context] ~ {
data: Data ~
NEW[DataRep ← [
sirpress: SirPress.Create[outputStream, fileNameForHeaderPage, creatorName, (SELECT printingMode FROM normal => normal, reverse => reverse, solid => solid, transparent => transparent, ENDCASE => ERROR)],
printerType: printerType,
pageWidth: MAX[MIN[pageWidthMicas, NAT.LAST], 0],
pageHeight: MAX[MIN[pageHeightMicas, NAT.LAST], 0],
fontTable: RefTab.Create[],
scratchT: ImagerTransformation.Scale[0],
scratchText: NEW[TEXT[80]]
]];
state: State ~ NEW[StateRep ← []];
state.T ← ImagerTransformation.Scale[100000];
state.color ← Imager.MakeGray[1];
context ← NEW[Imager.ContextRep ← [class: class, state: state, data: data, propList: NIL]];
};
SimpleCreate:
PUBLIC
PROC [fileName:
ROPE, printerType: PrinterType ← press]
RETURNS [context: Context] ~ {
outputStream: IO.STREAM ~ FS.StreamOpen[fileName, $create];
context ← Create[outputStream, fileName, NIL, printerType, normal, 21590, 27940];
};
DoWithWarnings:
PUBLIC
PROC [context: Context, action:
PROC] ~ {
data: Data ~ NARROW[context.data];
data.wantWarnings ← data.wantWarnings + 1;
action[! UNWIND => data.wantWarnings ← data.wantWarnings - 1];
data.wantWarnings ← data.wantWarnings - 1;
};
Warning:
PUBLIC
SIGNAL [code:
ATOM, explanation:
ROPE, page, micaX, micaY:
INT] ~
CODE;
nullVec: VEC ~ [Real.LargestNumber, Real.LargestNumber];
Warn:
PROC [context: Context, code:
ATOM, explanation:
ROPE, position:
VEC ← nullVec] ~ {
data: Data ~ NARROW[context.data];
state: State ~ context.state;
IF data.wantWarnings > 0
THEN {
IF position = nullVec THEN position ← ImagerBackdoor.GetCP[context];
position ← ImagerTransformation.Transform[state.T, position];
SIGNAL Warning[code, explanation, data.page, CRound[position.x, data.pageWidth], CRound[position.y, data.pageHeight]];
};
};
NewPage:
PUBLIC
PROC [context: Context] ~ {
data: Data ~ NARROW[context.data];
state: State ~ context.state;
SirPress.WritePage[data.sirpress];
state^ ← [];
state.T ← ImagerTransformation.Scale[100000];
state.color ← Imager.MakeGray[1];
data.page ← data.page + 1;
data.cpValid ← FALSE;
data.hue ← data.sat ← data.val ← 0;
data.lastPFD ← NIL;
};
ValidateConstantColor:
PUBLIC
PROC [context: Context, pos:
VEC ← nullVec] ~ {
data: Data ~ NARROW[context.data];
state: State ~ context.state;
sirpress: SirPress.PressHandle ~ data.sirpress;
WITH state.color
SELECT
FROM
c: ImagerColorDefs.ConstantColor => {
impl: ConstantColorImpl ~ c.impl;
hsv: ImagerColor.HSV ← [H: 0, S: 0, V: impl.Y];
h, s, v: [0..255] ← 0;
WITH impl: impl
SELECT
FROM
stipple => Warn[context,
$SpecialColorNotAllowed, "Special color replaced by gray", pos];
gray => NULL;
rgb => hsv ← ImagerColor.HSVFromRGB[impl.val];
cie => hsv ← ImagerColor.HSVFromRGB[ImagerColor.RGBFromCIE[impl.val]];
ENDCASE => Warn[context,
$UnknownConstantColor, "Unknown constant color replaced by gray", pos];
h ← CRound[hsv.H*240, 240];
s ← CRound[hsv.S*255, 255];
v ← CRound[hsv.V*255, 255];
IF h#data.hue
THEN {
SirPress.SetHue[sirpress, data.hue ← h];
};
IF s#data.sat
THEN {
SirPress.SetSaturation[sirpress, data.sat ← s];
};
IF v#data.val
THEN {
SirPress.SetBrightness[sirpress, data.val ← v];
};
};
ENDCASE => {
Warn[context, $SampledColorNotAllowed, "Sampled color not allowed for this mask", pos];
data.hue ← data.sat ← data.val ← 0;
SirPress.SetColor[sirpress, 0, 0, 0];
};
};
SetSamplingProperties:
PUBLIC
PROC [context: Context, screenAngle:
INT, screenAmplitude:
INT, screenFrequency:
INT, minIntensity:
INT, maxIntensity:
INT] ~ {
refSamplingProperties: REF SirPress.SamplingProperties ← NEW[SirPress.SamplingProperties ← [omitted: FALSE, screenAngle: screenAngle, screenAmplitude: screenAmplitude, screenFrequency: screenAmplitude, minIntensity: minIntensity, maxIntensity: maxIntensity]];
Imager.PutProp[context, $PressSamplingProperties, refSamplingProperties];
};
Close:
PUBLIC
PROC [context: Context] ~ {
WITH context.data
SELECT
FROM
data: Data => {
SirPress.ClosePress[data.sirpress];
};
ENDCASE => NULL;
};
MyShow:
PROC [context: Context, string: ImagerFont.XStringProc, xrel:
BOOL] ~ {
data: Data ~ NARROW[context.data];
xmax: REAL ~ data.pageWidth;
ymax: REAL ~ data.pageHeight;
sirpress: SirPress.PressHandle ~ data.sirpress;
state: State ~ context.state;
font: Font ~ state.font;
fontImpl: FontImpl ~ font.impl;
fontName: ROPE ~ fontImpl.typeface.name;
offset: VEC ← [0,0];
composite: Transformation ~ CompositeT[];
CompositeT:
PROC
RETURNS [Transformation] ~
INLINE {
t: Transformation ~ data.scratchT;
t^ ← state.T^;
t.c ← t.f ← 0;
ImagerTransformation.ApplyPreConcat[t, font.charToClient];
offset ← [t.c, t.f];
t.c ← t.f ← 0;
RETURN [t];
};
pfd: ImagerPressFontSubst.PressFontDescription ~ ImagerPressFontSubst.FindSubstitute[fontName, composite, data.printerType];
amplifySpace: REAL ~ state.np.amplifySpace;
testAmplified: BOOL ~ amplifySpace#1;
testCorrection: BOOL ~ state.np.correctPass#0;
odd: BOOL ← FALSE;
startCP: VEC ← nullVec;
text: REF TEXT ~ data.scratchText;
pressCP: VEC ← nullVec;
pressSpace: VEC ← nullVec;
Flush:
PROC ~ {
IF text.length > 0
THEN {
IF startCP#nullVec
THEN
TRUSTED {
SirPress.PutText[sirpress, LOOPHOLE[text], Real.Round[startCP.x], Real.Round[startCP.y]];
}
ELSE
TRUSTED {
SirPress.PutTextHere[sirpress, LOOPHOLE[text]];
};
text.length ← 0;
};
startCP ← nullVec;
};
charAction:
PROC [char: ImagerFont.XChar] ~ {
IF odd THEN {Imager.SetXRel[context, CARDINAL[char.code]+256*CARDINAL[char.set]]}
ELSE {
width: VEC ← font.Width[char];
didPutChar: BOOL ← FALSE;
IF testAmplified AND font.Amplified[char] THEN width ← width.Mul[amplifySpace];
Imager.Trans[context];
IF state.np.noImage=0
THEN {
IF char.set = 0
AND pfd#
NIL
THEN {
IF pressCP # state.p.cp
THEN {
Flush[];
pressCP ← state.p.cp;
startCP ← Vector2.Add[pressCP, offset];
};
IF pressCP.x
IN [0.0..xmax)
AND pressCP.y
IN [0.0..ymax)
THEN {
i: NAT ~ text.length;
IF text.length = text.maxLength THEN Flush[];
text[text.length] ← VAL[char.code];
text.length ← text.length + 1;
didPutChar ← TRUE;
};
}
ELSE {
Flush[];
ImagerFontPrivate.MaskChar[font, char, context];
};
};
Imager.SetXYRel[context, width];
pressCP ← IF didPutChar AND pfd.veryClose THEN state.p.cp ELSE nullVec;
IF testCorrection
THEN
SELECT ImagerFont.Correction[font, char]
FROM
none => NULL;
space => Imager.CorrectSpace[context, width];
mask => Imager.CorrectMask[context];
ENDCASE => ERROR;
};
odd ← xrel AND NOT odd;
};
saveAction:
PROC ~ {
text.length ← 0;
ValidateConstantColor[context];
string[charAction];
Flush[];
};
IF pfd #
NIL
AND pfd # data.lastPFD
THEN {
refCode: REF NAT ← NARROW[RefTab.Fetch[data.fontTable, pfd].val];
IF refCode =
NIL
THEN {
refCode ← NEW[NAT ← SirPress.GetFontCode[sirpress, pfd.family, pfd.size, pfd.face, pfd.rotation, SirPress.mica]];
[] ← RefTab.Store[data.fontTable, pfd, refCode];
};
SirPress.SetFontFromCode[sirpress, refCode^];
data.lastPFD ← pfd;
};
IF testAmplified
THEN {
w: VEC ← state.T.TransformVec[font.Width[[0, 40B]].Mul[amplifySpace]];
SirPress.SetSpace[sirpress, Real.Round[w.x], Real.Round[w.y]];
}
ELSE SirPress.ResetSpace[sirpress];
Imager.DoSave[context, saveAction];
};
MyShowText:
PROC [context: Context, text:
REF
READONLY
TEXT, start, len:
NAT, xrel:
BOOL] ~ {
string: ImagerFont.XStringProc ~ { ImagerFont.MapText[text, start, len, charAction] };
MyShow[context, string, xrel];
};
BezierToCoeffs:
PROC [b0, b1, b2, b3: Vector2.
VEC]
RETURNS [c0, c1, c2, c3: Vector2.
VEC] = {
t: Vector2.VEC ← b2.Sub[b1].Mul[3];
c0 ← b0;
c1 ← b1.Sub[b0].Mul[3];
c2 ← t.Sub[c1];
c3 ← b3.Sub[b0.Add[t]];
};
Bezier:
TYPE ~
RECORD [b0, b1, b2, b3:
VEC];
Add: PROC[a: VEC, b: VEC] RETURNS[VEC] = INLINE { RETURN[[a.x+b.x,a.y+b.y]] };
Sub: PROC[a: VEC, b: VEC] RETURNS[VEC] = INLINE { RETURN[[a.x-b.x,a.y-b.y]] };
In: PROC[a: VEC, b: VEC, c: VEC] RETURNS[BOOLEAN] = INLINE { RETURN[a.x IN[b.x..c.x] AND a.y IN[b.y..c.y]] };
Min: PROC[a: VEC, b: VEC] RETURNS[VEC] = INLINE { RETURN[[MIN[a.x,b.x],MIN[a.y,b.y]]] };
Max:
PROC[a:
VEC, b:
VEC]
RETURNS[
VEC] =
INLINE {
RETURN[[
MAX[a.x,b.x],
MAX[a.y,b.y]]] };
FlatBezier:
PROC[bezier: Bezier, epsilon:
REAL]
RETURNS[
BOOLEAN] ~ {
dx,dy: REAL;
d1,d2,d,bl,bh: VEC;
oh: VEC=[0.5,0.5];
bh ← Add[Max[bezier.b0,bezier.b3],oh];
bl ← Sub[Min[bezier.b0,bezier.b3],oh];
IF NOT In[bezier.b1,bl,bh] OR NOT In[bezier.b2,bl,bh] THEN RETURN[FALSE];
d1 ← Sub[bezier.b1,bezier.b0];
d2 ← Sub[bezier.b2,bezier.b0];
d ← Sub[bezier.b3,bezier.b0];
dx ← ABS[d.x]; dy ← ABS[d.y];
IF dx+dy < 1 THEN RETURN[TRUE];
IF dy < dx
THEN {
dydx: REAL ← d.y/d.x;
RETURN[ABS[d2.y-d2.x*dydx]<epsilon AND ABS[d1.y-d1.x*dydx]<epsilon]
}
ELSE {
dxdy: REAL ← d.x/d.y;
RETURN[ABS[d2.x-d2.y*dxdy]<epsilon AND ABS[d1.x-d1.y*dxdy]<epsilon]
}
};
Split:
PROC [bezier: Bezier]
RETURNS [firstHalf, secondHalf: Bezier] ~ {
a,b,c,ab,bc,p: VEC;
Mid: PROC[u,v: VEC] RETURNS[VEC] = INLINE { RETURN[[(u.x+v.x)/2,(u.y+v.y)/2]] };
a ← Mid[bezier.b0,bezier.b1];
b ← Mid[bezier.b1,bezier.b2];
c ← Mid[bezier.b2,bezier.b3];
ab ← Mid[a,b];
bc ← Mid[b,c];
p ← Mid[ab,bc];
RETURN[[bezier.b0, a, ab, p],[p, bc, c, bezier.b3]];
};
Intersection:
PROC [p0, p1:
VEC, a, b, c:
REAL]
RETURNS [
VEC] ~ {
Intersection of line through p0 and p1 with the line ax+by=c.
delta: VEC ~ Vector2.Sub[p1, p0];
denom: REAL ~ Vector2.Dot[[a,b], delta];
num: REAL ~ c-Vector2.Dot[[a,b], p0];
t: REAL ~ num/denom;
RETURN [Vector2.Add[p0, Vector2.Mul[delta, t]]];
};
PressPath:
PROC [context: Context, path: PathProc]
RETURNS [
VEC] ~ {
data: Data ~ NARROW[context.data];
sirpress: SirPress.PressHandle ~ data.sirpress;
state: State ~ context.state;
t: Transformation ~ state.T;
lp: VEC ← [0.0, 0.0];
xmax: REAL ~ data.pageWidth;
ymax: REAL ~ data.pageHeight;
moveTo: ImagerPath.MoveToProc ~ {
SirPress.PutMoveTo[sirpress, CRound[p.x, data.pageWidth], CRound[p.y, data.pageHeight]];
lp ← p;
};
curse: NAT ← 4;
lineTo: ImagerPath.LineToProc ~ {
cross: VEC;
SELECT
TRUE
FROM
lp.x < 0.0 AND p1.x > 0.0,
lp.x > 0.0 AND p1.x < 0.0 => cross ← Intersection[lp, p1, 1, 0, 0];
lp.y < 0.0 AND p1.y > 0.0,
lp.y > 0.0 AND p1.y < 0.0 => cross ← Intersection[lp, p1, 0, 1, 0];
lp.x < xmax AND p1.x > xmax,
lp.x > xmax AND p1.x < xmax => cross ← Intersection[lp, p1, 1, 0, xmax];
lp.y < ymax AND p1.y > ymax,
lp.y > ymax AND p1.y < ymax => cross ← Intersection[lp, p1, 0, 1, ymax];
ENDCASE => {
SirPress.PutDrawTo[sirpress, CRound[p1.x, data.pageWidth], CRound[p1.y, data.pageHeight]];
lp ← p1;
RETURN;
};
curse ← curse-1;
lineTo[cross];
lineTo[p1];
curse ← curse+1;
};
curveTo: ImagerPath.CurveToProc ~ {
IF MIN[lp.x, lp.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y] < 0.0
OR MAX[lp.x, p1.x, p2.x, p3.x] > xmax
OR MAX[lp.y, p1.y, p2.y, p3.y] > ymax
THEN {
IF FlatBezier[[lp, p1, p2, p3], 1]
OR MIN[lp.x, p1.x, p2.x, p3.x] > xmax
OR MAX[lp.x, lp.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y] < 0.0
OR MIN[lp.y, p1.y, p2.y, p3.y] > ymax
THEN {
SirPress.PutDrawTo[sirpress, CRound[p3.x, data.pageWidth], CRound[p3.y, data.pageHeight]];
lp ← p3;
}
ELSE {
a, b: Bezier;
[a, b] ← Split[[lp, p1, p2, p3]];
curveTo[a.b1, a.b2, a.b3];
curveTo[b.b1, b.b2, b.b3];
};
}
ELSE {
c0, c1, c2, c3: Vector2.VEC;
[c0, c1, c2, c3] ← BezierToCoeffs[lp, p1, p2, p3];
SirPress.PutCubic[sirpress, c1.x, c1.y, c2.x, c2.y, c3.x, c3.y];
lp ← p3;
};
};
ImagerPath.Transform[path, t, moveTo, lineTo, curveTo];
RETURN [lp];
};
MyMaskFill:
PROC [context: Context, path: PathProc, parity:
BOOL] ~ {
data: Data ~ NARROW[context.data];
lp: VEC;
ValidateConstantColor[context];
SirPress.StartOutline[data.sirpress];
lp ← PressPath[context, path];
SirPress.EndOutline[data.sirpress];
IF data.printerType = spruce THEN Warn[context, $MaskFillNotImplemented, "Spruce will not like MaskFill", lp];
IF NOT parity THEN Warn[context, $WrapFillNotImplemented, "Press will use parity fill", lp];
};
CRound:
PROC [real:
REAL, bound:
NAT]
RETURNS [
NAT] ~ {
IF real <= 0 THEN RETURN [0]
ELSE IF real >= bound THEN RETURN [bound]
ELSE RETURN [Real.RoundC[real]]
};
MyMaskRectangle:
PROC [context: Context, r: Rectangle] ~ {
data: Data ~ NARROW[context.data];
sirpress: SirPress.PressHandle ~ data.sirpress;
state: State ~ context.state;
t: Transformation ~ state.T;
p0: VEC ~ ImagerTransformation.Transform[t, [r.x, r.y]];
v1: VEC ~ ImagerTransformation.TransformVec[t, [r.w, 0]];
v2: VEC ~ ImagerTransformation.TransformVec[t, [0.0, r.h]];
IF (v1.x = 0.0
AND v2.y = 0.0)
OR (v1.y = 0.0
AND v2.x = 0.0)
THEN {
x0: REAL ← p0.x;
y0: REAL ← p0.y;
x1: REAL ← p0.x + v1.x + v2.x;
y1: REAL ← p0.y + v1.y + v2.y;
ox, oy, ow, oh: NAT;
IF x0 > x1 THEN {t: REAL ← x0; x0 ← x1; x1 ← t};
IF y0 > y1 THEN {t: REAL ← y0; y0 ← y1; y1 ← t};
ox ← CRound[x0, data.pageWidth];
oy ← CRound[y0, data.pageHeight];
ow ← CRound[x1, data.pageWidth]-ox;
oh ← CRound[y1, data.pageHeight]-oy;
WITH state.color
SELECT
FROM
c: ImagerColorDefs.ConstantColor => {
ValidateConstantColor[context, [r.x, r.y]];
SirPress.PutRectangle[sirpress, ox, oy, ow, oh];
data.cpValid ← FALSE;
};
c: ImagerColorDefs.SampledColor => {
ValidateConstantColor[context, [r.x, r.y]]; -- will want to do scanned rectangle instead someday
SirPress.PutRectangle[sirpress, ox, oy, ow, oh]; data.cpValid ← FALSE;
};
ENDCASE => ERROR;
}
ELSE {
pathProc: PathProc ~ {
moveTo[[r.x, r.y]];
lineTo[[r.x+r.w, r.y]];
lineTo[[r.x+r.w, r.y+r.h]];
lineTo[[r.x, r.y+r.h]];
};
IF data.printerType=spruce
THEN {
Warn[context, $HardTransformation, "Unaligned rectangle", p0];
};
Imager.MaskFill[context: context, path: pathProc, parity: TRUE];
};
};
MyMaskRectangleI:
PROC [context: Context, x, y, w, h:
INTEGER] ~ {
MyMaskRectangle[context, [x, y, w, h]];
};
MyMaskStroke:
PROC [context: Context, path: PathProc, closed:
BOOL] ~ {
data: Data ~ NARROW[context.data];
Warn[context, $Unimplemented, "MaskStroke not implemented"];
};
MyMaskVector:
PROC [context: Context, p1, p2:
VEC] ~ {
data: Data ~ NARROW[context.data];
state: State ~ context.state;
strokeWidth: REAL ~ state.np.strokeWidth;
strokeEnd: Imager.StrokeEnd ~ VAL[NAT[state.np.strokeEnd]];
r: REAL ~ strokeWidth*0.5;
proc:
PROC ~ {
pathProc: PathProc ~ {
moveTo[[s, -r]];
arcTo[[s+r, 0], [s, r]];
lineTo[[0, r]];
arcTo[[-r, 0], [0, -r]];
};
v: VEC ~ Vector2.Sub[p2, p1];
s: REAL ~ RealFns.SqRt[v.x*v.x+v.y*v.y];
sin: REAL ~ IF s=0 THEN 0.0 ELSE v.y/s;
cos: REAL ~ IF s=0 THEN 1.0 ELSE v.x/s;
m: Transformation ~ data.scratchT;
m.a ← m.e ← cos;
m.b ← -sin; m.d ← sin;
m.c ← m.f ← 0;
m.form ← 0;
m.integerTrans ← FALSE;
Imager.TranslateT[context, p1];
Imager.ConcatT[context, m];
SELECT strokeEnd
FROM
square => {MyMaskRectangle[context, [-r, -r, s+2*r, strokeWidth]]};
butt => {MyMaskRectangle[context, [0, -r, s, strokeWidth]]};
round => {MyMaskFill[context, pathProc, TRUE]};
ENDCASE => ERROR;
};
IF strokeWidth >= 0 THEN Imager.DoSaveAll[context, proc];
};
MyMaskPixel:
PROC [context: Context, pa: PixelArray] ~ {
data: Data ~ NARROW[context.data];
Warn[context, $Unimplemented, "MaskPixel not implemented"];
};
MyMaskBits:
PROC [context: Context, base:
LONG
POINTER, wordsPerLine:
NAT,
sMin, fMin, sSize, fSize:
NAT, tx, ty:
INTEGER] ~ {
data: Data ~ NARROW[context.data];
Warn[context, $Unimplemented, "MaskBits not implemented"];
};
MyGetBoundingRectangle:
PROC [context: Context]
RETURNS [Rectangle] ~ {
state: State ~ context.state;
data: Data ~ NARROW[context.data];
RETURN[state.T.InverseTransformRectangle[[x: 0, y: 0, w: data.pageWidth, h: data.pageHeight]]];
};
class: Class ~
NEW [ClassRep ← [
type: $Press,
DoSave: ImagerState.StateDoSave,
SetInt: ImagerState.StateSetInt,
SetReal: ImagerState.StateSetReal,
SetT: ImagerState.StateSetT,
SetFont: ImagerState.StateSetFont,
SetColor: ImagerState.StateSetColor,
SetClipper: ImagerState.StateSetClipper,
SetStrokeDashes: ImagerState.StateSetStrokeDashes,
GetInt: ImagerState.StateGetInt,
GetReal: ImagerState.StateGetReal,
GetT: ImagerState.StateGetT,
GetFont: ImagerState.StateGetFont,
GetColor: ImagerState.StateGetColor,
GetClipper: ImagerState.StateGetClipper,
GetStrokeDashes: ImagerState.StateGetStrokeDashes,
ConcatT: ImagerState.StateConcatT,
Scale2T: ImagerState.StateScale2T,
RotateT: ImagerState.StateRotateT,
TranslateT: ImagerState.StateTranslateT,
Move: ImagerState.StateMove,
SetXY: ImagerState.StateSetXY,
SetXYRel: ImagerState.StateSetXYRel,
Show: MyShow,
ShowText: MyShowText,
StartUnderline: ImagerState.StateStartUnderline,
MaskUnderline: ImagerState.StateMaskUnderline,
CorrectMask: ImagerState.StateCorrectMask,
CorrectSpace: ImagerState.StateCorrectSpace,
Space: ImagerState.StateSpace,
SetCorrectMeasure: ImagerState.StateSetCorrectMeasure,
SetCorrectTolerance: ImagerState.StateSetCorrectTolerance,
Correct: ImagerState.StateCorrect,
DontCorrect: ImagerState.StateDontCorrect,
SetGray: ImagerState.StateSetGray,
SetSampledColor: ImagerState.StateSetSampledColor,
SetSampledBlack: ImagerState.StateSetSampledBlack,
MaskFill: MyMaskFill,
MaskStroke: MyMaskStroke,
MaskRectangle: MyMaskRectangle,
MaskRectangleI: MyMaskRectangleI,
MaskVector: MyMaskVector,
MaskPixel: MyMaskPixel,
MaskBits: MyMaskBits,
Clip: ImagerState.StateClip,
ClipRectangle: ImagerState.StateClipRectangle,
ClipRectangleI: ImagerState.StateClipRectangleI,
GetCP: ImagerState.StateGetCP,
GetBoundingRectangle: MyGetBoundingRectangle,
propList: NIL
]];
END.