GraphicsToPressImpl.mesa
Last changed by Doug Wyatt, April 21, 1982 3:59 pm
Last changed by Warnock June 4, 1982 1:38 pm
Last changed by Michael Plass December 6, 1982 12:22 pm
Last Edited by: Lamming, December 16, 1982 9:57 am
DIRECTORY
FileIO,
GraphicsBasic,
CGArea USING [Empty, Ref, Remove],
GraphicsToPress,
GraphicsToPressPrivate,
CGContext USING [Ref],
CGDevice USING [Ref, Rep],
CGMatrix USING [Inv, InvRel, Make, Ref],
CGSource USING [Mode, Ref, Type],
CGStorage USING [qZone],
IO,
SirPress,
Inline,
Graphics,
GraphicsColor USING [Color, ColorToHSV],
Rope,
Real USING [Fix, FixC, RoundLI];
GraphicsToPressImpl: CEDAR MONITOR
IMPORTS
FileIO, CGArea, CGMatrix, CGStorage, Inline, Real, SirPress, GraphicsColor, Graphics
EXPORTS GraphicsBasic, GraphicsToPress, GraphicsToPressPrivate = {
ROPE: TYPE = Rope.ROPE;
DeviceObject: PUBLIC TYPE = CGDevice.Rep;
dataZone: ZONE = CGStorage.qZone;
repZone: ZONE = CGStorage.qZone;
Error: SIGNAL = CODE;
Data: TYPE = REF DataRep;
DataRep: TYPE = RECORD [
ph:SirPress.PressHandle,
unit: INT,
fatness: REAL,
halftoneSubsamplingFactor: REAL,
matrix: CGMatrix.Ref -- base transformation matrix
];
NewContext: PUBLIC PROCEDURE [fileName: ROPE, resolution: REAL]
RETURNS [Graphics.Context] =
{RETURN[NewContextFromStream[FileIO.Open[fileName, overwrite], fileName, resolution]]};
NewContextFromStream: PUBLIC PROC [
outputStream: IO.STREAM,
fileNameForHeaderPage: ROPENIL,
resolution: REAL ← 384 -- in bits per inch
] RETURNS [Graphics.Context] = {
RETURN[NewContextFromSirPressHandle[
SirPress.Create[outputStream, fileNameForHeaderPage],
resolution
]];
};
NewContextFromSirPressHandle: PUBLIC PROC [
pressHandle: SirPress.PressHandle,
resolution: REAL -- in bits per inch
] RETURNS [Graphics.Context] = {
s: REAL ← resolution/72.0;
data: Data ← dataZone.NEW[DataRep ← [
ph: pressHandle,
unit: Real.RoundLI[SirPress.pt/s],
fatness: 0.2,
halftoneSubsamplingFactor: 5,
matrix: CGMatrix.Make[[s,0,0,s,0,0]]
]];
context: Graphics.Context ← Graphics.NewContext[repZone.NEW[CGDevice.Rep ← [
GetMatrix: GetMatrix,
GetBounds: GetBounds,
Show: Show,
GetRaster: GetRaster,
data: data
]]];
SirPress.SetColor[pressHandle,0,0,0];
RETURN[context];
};
SirPressHandle: PUBLIC PROC [context: Graphics.Context] RETURNS [SirPress.PressHandle] = {
contextRef: CGContext.Ref ← NARROW[context.data];
deviceRef: CGDevice.Ref ← contextRef.device;
data: Data ← NARROW[deviceRef.data];
RETURN[data.ph];
};
Close: PUBLIC PROC [context: Graphics.Context] = {
SirPressHandle[context].ClosePress[];
};
SetPageSize: PUBLIC PROC [context: Graphics.Context, width: REAL, height: REAL] = {
SirPressHandle[context].SetPageSize[
height: Real.RoundLI[height*SirPress.pt],
width: Real.RoundLI[width*SirPress.pt],
unit: 1
];
};
GetMatrix: SAFE PROC[self: CGDevice.Ref] RETURNS [CGMatrix.Ref] = CHECKED {
data: Data ← NARROW[self.data];
RETURN[data.matrix];
};
GetBounds: SAFE PROC[self: CGDevice.Ref] RETURNS [GraphicsBasic.Box] = CHECKED {
data: Data ← NARROW[self.data];
e: REAL = 0.1; -- small fudge factor
RETURN[[xmin: e, ymin: e, xmax: 17*SirPress.in/(2*data.unit)-e, ymax: 11*SirPress.in/data.unit-e]];
};
GetRaster: SAFE PROC[self: CGDevice.Ref] RETURNS [LONG POINTER,CARDINAL] = CHECKED {
RETURN[NIL,0];
};
Show: SAFE PROC[self: CGDevice.Ref, area: CGArea.Ref, src: CGSource.Ref, map: CGMatrix.Ref] = TRUSTED {
data: Data ← NARROW[self.data];
SetColor[data.ph,src.color];
UNTIL CGArea.Empty[area] DO
trap: GraphicsBasic.Trap ← CGArea.Remove[area];
ShowTrap[data,trap,src,map];
ENDLOOP;
};
SetColor: PROC[pressHandle: SirPress.PressHandle, color: GraphicsColor.Color] = {
h,s,v: REAL;
[h,s,v] ← GraphicsColor.ColorToHSV[color];
SirPress.SetColor[pressHandle,Real.RoundLI[h*240],Real.RoundLI[s*255],Real.RoundLI[v*255]];
};
ScreenAngle: PROC[color: GraphicsColor.Color] RETURNS [INTEGER] = {
h,s,v: REAL;
[h,s,v] ← GraphicsColor.ColorToHSV[color];
RETURN[RndI[105 - 90*h] MOD 90];
};
Store: PROC [scanLine: REF SirPress.ScanLine, index: NAT, sample: CARDINAL] = {
WITH scanLine: scanLine SELECT FROM
bitMap => scanLine[index] ← sample;
bitSampled => scanLine[index] ← sample;
bitBitSampled => scanLine[index] ← sample;
nybbleSampled => scanLine[index] ← sample;
byteSampled => scanLine[index] ← sample;
ENDCASE => ERROR;
};
Bot: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r]] };
Top: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r]+1] };
Fix: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r]] };
Rnd: PROC[r: REAL] RETURNS [CARDINAL] = INLINE { RETURN[Real.FixC[r+.5]] };
RndI: PROC[r: REAL] RETURNS [INTEGER] = INLINE {
RETURN[Real.FixC[r+(LAST [INTEGER]+.5)]-LAST[INTEGER]] };
RndUp: PROC[c, m: CARDINAL] RETURNS [CARDINAL] = INLINE {RETURN[(c+(m-1))/m*m]};
White: PROC[bitsPerSample: [0..16]] RETURNS [intensity: CARDINAL] = {
intensity ← Inline.BITSHIFT[1, bitsPerSample];
intensity ← intensity-1;
};
Line1: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..1B]];
Line2: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..3B]];
Line4: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..17B]];
Line8: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..377B]];
AGet: PROC[src: CGSource.Ref, x,y: CARDINAL] RETURNS[CARDINAL] = TRUSTED INLINE {
xline: LONG POINTER ← src.xbase + Inline.LongMult[y,src.xrast];
SELECT src.bps FROM
0,1 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line1][x]];
2 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line2][x]];
4 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line4][x]];
8 => RETURN[LOOPHOLE[xline, LONG POINTER TO Line8][x]];
ENDCASE => ERROR;
};
Frac: TYPE = Inline.LongNumber;
fscl: Frac = [num[lowbits: 0, highbits: 1]];
FixF: PROC[r: REAL] RETURNS[Frac] = INLINE {
RETURN[[li[Real.Fix[r*fscl.li]]]] };
FltF: PROC[f: Frac] RETURNS[REAL] = INLINE {
r: REAL ← f.li; RETURN[r/fscl.li] };
AddF: PROC[a,b: Frac] RETURNS[Frac] = INLINE {
RETURN[[li[a.li+b.li]]] };
IntF: PROC[f: Frac] RETURNS[INTEGER] = INLINE {
RETURN[LOOPHOLE[f.highbits, INTEGER]] };
ShowTrap: ENTRY PROC[data: Data, trap: GraphicsBasic.Trap, src: CGSource.Ref, map: CGMatrix.Ref] = TRUSTED {
type: CGSource.Type ← src.type;
easy: BOOLEAN ← (SELECT type FROM
const => TRUE, -- always easy
array, tile => FALSE, -- Not easy
proc => FALSE, -- never easy
ENDCASE => ERROR);
fat: BOOLEAN ← src.fat;
yb, yt, yl, xl, xr: CARDINAL ← 0;
rdxl, rdxr: REAL ← 0; -- left and right x increments
rsdx, rsdy: REAL ← 0; -- increments for source position
fsdx, fsdy: Frac;
mode: CGSource.Mode ← src.mode;
white: CARDINAL ← White[src.bps];
PutTrap: PROC[xbotL, xtopL, xtopR, xbotR, ybot, ytop: INT] = TRUSTED {
IF xbotL=xtopL AND xbotR=xtopR THEN
SirPress.PutRectangle[data.ph, xbotL, ybot, xbotR-xbotL, ytop-ybot, data.unit]
ELSE {
SirPress.StartOutline[data.ph];
SirPress.PutMoveTo[data.ph, xbotL, ybot, data.unit];
SirPress.PutDrawTo[data.ph, xtopL, ytop, data.unit];
SirPress.PutDrawTo[data.ph, xtopR, ytop, data.unit];
SirPress.PutDrawTo[data.ph, xbotR, ybot, data.unit];
SirPress.EndOutline[data.ph];
}
};
main code for ShowTrap starts here
compute yb (bottom of first scanline) and yt (top of last scanline)
IF fat THEN { yb𡤋ot[trap.ybot]; yt←Top[trap.ytop] }
ELSE { yb←Rnd[trap.ybot]; yt←Rnd[trap.ytop] };
IF yb<yt THEN yl←yt-1 -- yl is last line
ELSE { IF yb>yt OR fat THEN SIGNAL Error; RETURN };
IF easy THEN { --constant color trapezoid
IF fat THEN
PutTrap[
xbotL: Bot[trap.xbotL],
xtopL: Bot[trap.xtopL],
xtopR: Top[trap.xtopR],
xbotR: Top[trap.xbotR],
ybot: yb,
ytop: yt
]
ELSE PutTrap[
xbotL: Rnd[trap.xbotL],
xtopL: Rnd[trap.xtopL],
xtopR: Rnd[trap.xtopR],
xbotR: Rnd[trap.xbotR],
ybot: yb,
ytop: yt
]
}
ELSE { --going to put out a showbits command with carefully placed 0's
scanLine: REF SirPress.ScanLine;
allocate storage for a scan line.
scanLineOrigin: CARDINAL ← Bot[MIN[trap.xbotL, trap.xtopL]];
scanLineEnd: CARDINAL ← Top[MAX[trap.xbotR, trap.xtopR]];
scanLineLength: CARDINALSELECT src.bps FROM
0 => RndUp[scanLineEnd - scanLineOrigin, 16],
1 => RndUp[scanLineEnd - scanLineOrigin, 16],
2 => RndUp[scanLineEnd - scanLineOrigin, 8],
4 => RndUp[scanLineEnd - scanLineOrigin, 4],
8 => RndUp[scanLineEnd - scanLineOrigin, 2],
ENDCASE => ERROR;
DoLine: PROC[xmin, xmax, y: CARDINAL] = TRUSTED {
rsx, rsy: REAL; -- current source position
fsx, fsy: Frac;
sx, sy: CARDINAL; -- truncated source position
s: CARDINAL; -- sample value from source
FOR x: CARDINAL IN [scanLineOrigin..xmin) DO
Store[scanLine, x-scanLineOrigin, white]
ENDLOOP;
FOR x: CARDINAL IN [xmin..xmax) DO --put in the rest of the samples
IF x=xmin THEN {
[[rsx,rsy]] ← CGMatrix.Inv[map,[x+0.5,y+0.5]];
fsx ← FixF[rsx]; fsy ← FixF[rsy];
}
ELSE { fsx ← AddF[fsx,fsdx]; fsy ← AddF[fsy,fsdy]};
Get a sample from the source
IF type=proc THEN s ← src.Get[FltF[fsx], FltF[fsy]]
ELSE { sx ← IntF[fsx]; sy ← IntF[fsy]; s ← AGet[src, sx, sy] };
Store[scanLine, x-scanLineOrigin, s]
ENDLOOP;
FOR x: CARDINAL IN [xmax..scanLineEnd) DO
Store[scanLine, x-scanLineOrigin, white]
ENDLOOP;
SirPress.ShowLine[data.ph, scanLine];
};
SELECT src.bps FROM
0 => scanLine ← NEW[SirPress.ScanLine[bitMap][scanLineLength]];
1 => scanLine ← NEW[SirPress.ScanLine[bitSampled][scanLineLength]];
2 => scanLine ← NEW[SirPress.ScanLine[bitBitSampled][scanLineLength]];
4 => scanLine ← NEW[SirPress.ScanLine[nybbleSampled][scanLineLength]];
8 => scanLine ← NEW[SirPress.ScanLine[byteSampled][scanLineLength]];
ENDCASE => ERROR;
FOR i: NAT IN [scanLineEnd-scanLineOrigin..scanLineLength) DO Store[scanLine, i, white] ENDLOOP;
if opaque, then blot out the trapezoidal region
IF src.mode=opaque THEN {
SirPress.SetColor[data.ph, 0, 0, 255];
PutTrap[
xbotL: Rnd[trap.xbotL],
xtopL: Rnd[trap.xtopL],
xtopR: Rnd[trap.xtopR],
xbotR: Rnd[trap.xbotR],
ybot: yb,
ytop: yt
];
SetColor[data.ph, src.color];
};
SirPress.BeginScannedRectangle[
p: data.ph,
x: scanLineOrigin,
y: yb,
dotsPerLine: scanLineLength,
numberOfLines: yt-yb,
width: scanLineLength,
height: yt-yb,
unit: data.unit,
nextLineDirection: up,
nextDotDirection: right,
coding: scanLine.coding,
samplingProperties: [screenAngle: ScreenAngle[src.color]]
];
set up for getting samples out of a sampled source
[[rsdx, rsdy]] ← CGMatrix.InvRel[map,[1,0]];
rsdx ← rsdx;
rsdy ← rsdy;
fsdx ← FixF[rsdx]; fsdy ← FixF[rsdy];
set up for the scan converter
rdxl←(trap.xtopL-trap.xbotL); -- delta x, left
rdxr←(trap.xtopR-trap.xbotR); -- delta x, right
IF NOT(fat AND yb=yl) THEN {
rdy: REAL←trap.ytop-trap.ybot; -- delta y
rdxl←rdxl/rdy; rdxr←rdxr/rdy; -- dx/dy, left right
};
IF fat THEN {
rxlb, rxrb, rxlt, rxrt: REAL ← 0; -- x at bottom and top of current line
ltop: BOOLEAN ← rdxl<0; -- TRUE means leftmost x is at top of line
rtop: BOOLEAN ← rdxr>0; -- TRUE means rightmost x is at top of line
FOR y: CARDINAL IN[yb..yl] DO -- for each scan line
IF y=yb THEN { rxlb←trap.xbotL; rxrb←trap.xbotR } -- first line
ELSE { rxlb←rxlt; rxrb←rxrt }; -- successive lines
IF y=yl THEN { rxlt←trap.xtopL; rxrt←trap.xtopR } -- last line
ELSE IF y=yb THEN { -- first line, if yl>yb
d: REAL←(yb+1)-trap.ybot; -- distance to top of line
rxlt←rxlb+d*rdxl; rxrt←rxrb+d*rdxr }
ELSE { rxlt←rxlb+rdxl; rxrt←rxrb+rdxr }; -- middle lines
xl𡤋ot[IF ltop THEN rxlt ELSE rxlb];
xr←Top[IF rtop THEN rxrt ELSE rxrb];
DoLine[xmin: xl, xmax: xr, y: y];
ENDLOOP;
}
ELSE {
rxl, rxr: REAL ← 0; -- left and right x at middle of current line
FOR y: CARDINAL IN[yb..yl] DO -- for each scan line
IF y=yb THEN { -- first line
d: REAL←(yb+0.5)-trap.ybot; -- distance to middle of line
rxl←trap.xbotL+d*rdxl; rxr←trap.xbotR+d*rdxr }
ELSE { rxl←rxl+rdxl; rxr←rxr+rdxr }; -- successive lines
xl←Rnd[rxl]; xr←Rnd[rxr];
DoLine[xl,xr,y];
ENDLOOP;
};
SirPress.EndScannedRectangle[data.ph];
};
};
}.