ImagerRasterLFImpl.mesa
Copyright © 1984 Xerox Corporation. All rights reserved.
Michael Plass, June 19, 1984 1:19:53 pm PDT
Doug Wyatt, October 16, 1984 6:05:35 pm PDT
DIRECTORY
Basics USING [bitsPerWord, LongMult],
ImagerColor USING [Color, ConstantColor, SampledColor, SpecialColor],
ImagerRaster USING [Device, DeviceRep, RectangleProc, RunProc],
ImagerPixelMap USING [DeviceRectangle, Function, PixelMap],
ImagerTransformation USING [PreRotate, Transformation, Translate],
PrincOps USING [BBTableSpace, BitBltTable, BitBltTablePtr, zBNDCK, zINC],
PrincOpsUtils USING [AlignedBBTable, BITBLT];
ImagerRasterLFImpl: CEDAR PROGRAM
IMPORTS Basics, ImagerTransformation, PrincOpsUtils
~ BEGIN
Device: TYPE ~ ImagerRaster.Device;
RunProc: TYPE ~ ImagerRaster.RunProc;
RectangleProc: TYPE ~ ImagerRaster.RectangleProc;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Color: TYPE ~ ImagerColor.Color;
ConstantColor: TYPE ~ ImagerColor.ConstantColor;
SampledColor: TYPE ~ ImagerColor.SampledColor;
SpecialColor: TYPE ~ ImagerColor.SpecialColor;
GrayArray: TYPE ~ ARRAY [0..16) OF CARDINAL;
grayHeight: NAT ~ 16; -- must not exceed 16, should be a power of 2
checkeredGray: GrayArray ~ [
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH, -- @ . @ . @ . @ . @ . @ . @ . @ .
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH, -- @ . @ . @ . @ . @ . @ . @ . @ .
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH, -- @ . @ . @ . @ . @ . @ . @ . @ .
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH, -- @ . @ . @ . @ . @ . @ . @ . @ .
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH, -- @ . @ . @ . @ . @ . @ . @ . @ .
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH, -- @ . @ . @ . @ . @ . @ . @ . @ .
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH, -- @ . @ . @ . @ . @ . @ . @ . @ .
05555H, -- . @ . @ . @ . @ . @ . @ . @ . @
0AAAAH -- @ . @ . @ . @ . @ . @ . @ . @ .
];
desktopGray: GrayArray ~ [
01111H, -- . . . @ . . . @ . . . @ . . . @
01111H, -- . . . @ . . . @ . . . @ . . . @
04444H, -- . @ . . . @ . . . @ . . . @ . .
04444H, -- . @ . . . @ . . . @ . . . @ . .
01111H, -- . . . @ . . . @ . . . @ . . . @
01111H, -- . . . @ . . . @ . . . @ . . . @
04444H, -- . @ . . . @ . . . @ . . . @ . .
04444H, -- . @ . . . @ . . . @ . . . @ . .
01111H, -- . . . @ . . . @ . . . @ . . . @
01111H, -- . . . @ . . . @ . . . @ . . . @
04444H, -- . @ . . . @ . . . @ . . . @ . .
04444H, -- . @ . . . @ . . . @ . . . @ . .
01111H, -- . . . @ . . . @ . . . @ . . . @
01111H, -- . . . @ . . . @ . . . @ . . . @
04444H, -- . @ . . . @ . . . @ . . . @ . .
04444H -- . @ . . . @ . . . @ . . . @ . .
];
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD[
frame: ImagerPixelMap.PixelMap, -- the bitmap
function: ImagerPixelMap.Function, -- for Constant or Gray
gray: GrayArray -- for Constant or Gray
];
defaultPixelsPerInch: REAL ~ 72;
metersPerInch: REAL ~ 0.0254;
Create: PROC[frame: ImagerPixelMap.PixelMap, pixelsPerInch: REAL ← defaultPixelsPerInch]
RETURNS[Device] ~ {
data: Data ~ NEW[DataRep ← [frame: frame, function: [null, null], gray: ALL[177777B]]];
pixelsPerMeter: REAL ~ pixelsPerInch/metersPerInch;
surfaceToDevice: Transformation ~ ImagerTransformation.Translate[[frame.sSize, 0]];
surfaceToDevice.PreRotate[90];
RETURN[NEW[ImagerRaster.DeviceRep ← [type: $LFDisplay,
setColor: SetColor, setPriorityImportant: SetPriorityImportant,
maskRuns: MaskRunsConst, maskRectangles: MaskRectanglesConst,
surfaceToDevice: surfaceToDevice,
clipBox: [sMin: 0, fMin: 0, sSize: frame.sSize, fSize: frame.fSize],
metersToSurface: [pixelsPerMeter, pixelsPerMeter],
viewUnitsPerPixel: 1,
data: data]]];
};
SetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ {
data: Data ~ NARROW[device.data];
const: BOOLFALSE;
WITH color SELECT FROM
color: ConstantColor => {
data.function ← [null, null];
SELECT color.f FROM
1 => { data.gray ← ALL[177777B]; const ← TRUE };
0 => { data.gray ← ALL[0]; const ← TRUE };
ENDCASE => data.gray ← checkeredGray;
IF const THEN {
device.maskRuns ← MaskRunsConst;
device.maskRectangles ← MaskRectanglesConst;
}
ELSE {
device.maskRuns ← MaskRunsGray;
device.maskRectangles ← MaskRectanglesGray;
};
};
color: SampledColor => {
ERROR; -- not yet implemented
};
color: SpecialColor => SELECT color.ref FROM
$XOR => {
data.function ← [xor, null];
data.gray ← ALL[177777B];
device.maskRuns ← MaskRunsConst;
device.maskRectangles ← MaskRectanglesConst;
};
ENDCASE => ERROR; -- unknown special color
ENDCASE => ERROR; -- unknown color variant
};
SetPriorityImportant: PROC[device: Device, priorityImportant: BOOL] ~ {
};
nullBitBltTable: PrincOps.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: []];
Check: PROC[x: INTEGER, max: NAT] RETURNS[NAT] ~
TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK };
IF x IN[0..max] THEN RETURN[x] ELSE ERROR RuntimeError.BoundsFault
MaskRectanglesGray: PROC[device: Device, rectangles: PROC[RectangleProc]] ~ TRUSTED {
data: Data ~ NARROW[device.data];
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
gray: LONG POINTER ~ @data.gray;
base: LONG POINTER ~ data.frame.refRep.pointer;
rast: CARDINAL ~ data.frame.refRep.rast;
fSizeDevice: NAT ~ data.frame.fSize;
sSizeDevice: NAT ~ data.frame.sSize;
rectangle: PROC[r: DeviceRectangle] ~ TRUSTED {
f: NAT ~ Check[r.fMin, fSizeDevice];
s: NAT ~ Check[r.sMin, sSizeDevice];
bb.dst.word ← base+Basics.LongMult[s, rast]+f/Basics.bitsPerWord;
bb.dst.bit ← bb.src.bit ← f MOD Basics.bitsPerWord;
bb.src.word ← gray+(bb.srcDesc.gray.yOffset ← s MOD grayHeight);
bb.width ← Check[r.fSize, fSizeDevice-f];
bb.height ← Check[r.sSize, sSizeDevice-s];
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← rast*Basics.bitsPerWord;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: grayHeight-1];
bb.flags ← [direction: forward, disjoint: TRUE, gray: TRUE,
srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc];
rectangles[rectangle];
};
MaskRectanglesConst: PROC[device: Device, rectangles: PROC[RectangleProc]] ~ TRUSTED {
data: Data ~ NARROW[device.data];
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
gray: LONG POINTER ~ @data.gray;
base: LONG POINTER ~ data.frame.refRep.pointer;
rast: CARDINAL ~ data.frame.refRep.rast;
fSizeDevice: NAT ~ data.frame.fSize;
sSizeDevice: NAT ~ data.frame.sSize;
rectangle: PROC[r: DeviceRectangle] ~ TRUSTED {
f: NAT ~ Check[r.fMin, fSizeDevice];
s: NAT ~ Check[r.sMin, sSizeDevice];
bb.dst.word ← base+Basics.LongMult[s, rast]+f/Basics.bitsPerWord;
bb.dst.bit ← f MOD Basics.bitsPerWord;
bb.width ← Check[r.fSize, fSizeDevice-f];
bb.height ← Check[r.sSize, sSizeDevice-s];
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← rast*Basics.bitsPerWord;
bb.src.word ← gray;
bb.src.bit ← 0;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: grayHeight-1];
bb.flags ← [direction: forward, disjoint: TRUE, gray: TRUE,
srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc];
rectangles[rectangle];
};
MaskRunsGray: PROC[device: Device, runs: PROC[RunProc]] ~ TRUSTED {
data: Data ~ NARROW[device.data];
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
gray: LONG POINTER ~ @data.gray;
base: LONG POINTER ~ data.frame.refRep.pointer;
rast: CARDINAL ~ data.frame.refRep.rast;
fSizeDevice: NAT ~ data.frame.fSize;
sSizeDevice: NAT ~ data.frame.sSize;
run: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED {
f: NAT ~ Check[fMin, fSizeDevice];
s: NAT ~ Check[sMin, sSizeDevice];
bb.dst.word ← base+Basics.LongMult[s, rast]+f/Basics.bitsPerWord;
bb.dst.bit ← bb.src.bit ← f MOD Basics.bitsPerWord;
bb.src.word ← gray+(bb.srcDesc.gray.yOffset ← s MOD grayHeight);
bb.width ← Check[fSize, fSizeDevice-f];
bb.height ← Check[1, sSizeDevice-s];
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← rast*Basics.bitsPerWord;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: grayHeight-1];
bb.flags ← [direction: forward, disjoint: TRUE, gray: TRUE,
srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc];
runs[run];
};
MaskRunsConst: PROC[device: Device, runs: PROC[RunProc]] ~ TRUSTED {
data: Data ~ NARROW[device.data];
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
gray: LONG POINTER ~ @data.gray;
base: LONG POINTER ~ data.frame.refRep.pointer;
rast: CARDINAL ~ data.frame.refRep.rast;
fSizeDevice: NAT ~ data.frame.fSize;
sSizeDevice: NAT ~ data.frame.sSize;
run: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED {
f: NAT ~ Check[fMin, fSizeDevice];
s: NAT ~ Check[sMin, sSizeDevice];
bb.dst.word ← base+Basics.LongMult[s, rast]+f/Basics.bitsPerWord;
bb.dst.bit ← f MOD Basics.bitsPerWord;
bb.width ← Check[fSize, fSizeDevice-f];
bb.height ← Check[1, sSizeDevice-s];
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← rast*Basics.bitsPerWord;
bb.src.word ← gray;
bb.src.bit ← 0;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: grayHeight-1];
bb.flags ← [direction: forward, disjoint: TRUE, gray: TRUE,
srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc];
runs[run];
};
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD[
value: CARDINAL, -- for ApplyMaskConstant
tile: ImagerPixelMap.Tile, -- for ApplyMaskTile
tileSamples: ImagerColor.SampledColor, -- for ApplyMaskTile
function: ImagerMask.Function, -- for ApplyMaskConstant or ApplyMaskTile
invertOutput, transparent: BOOL, -- for ApplyMaskHalftone
source: PixelArray, -- for ApplyMaskHalftone
transformation: Transformation, -- for ApplyMaskHalftone
deviceBrick: ImagerHalftone.DeviceBrick ← NIL, -- for ApplyMaskHalftone
deviceBrickMaxSampleValue: INT ← -1,
frame: ImagerPixelMap.PixelMap -- the bitmap
];
SetColor: PROC[device: Display, color: Color, vx, vy: INTEGER] ~ {
data: Data ~ NARROW[device.data];
WITH color SELECT FROM
color: ConstantColor => {
tile: ImagerPixelMap.Tile ~ data.tile;
Runs: PROC[run: PROC[sMin, fMin: INTEGER, fSize: NAT]] ~ {
FOR s: INTEGER IN [tile.sOrigin..tile.sOrigin + tile.sSize) DO
run[s, tile.fOrigin, tile.fSize];
ENDLOOP;
};
SetTileSamples[data.tileSamples, Real.RoundC[IntensityFromColor[color]*255]];
ImagerHalftone.Halftone[
dest: [sOrigin: tile.sOrigin, fOrigin: tile.fOrigin,
sMin: 0, fMin: 0, sSize: tile.sSize, fSize: tile.fSize, refRep: tile.refRep],
runs: Runs,
source: data.tileSamples.pa,
transformation: ImagerTransformation.Rotate[0],
deviceBrick: lfBrick
];
tile.sOrigin ← tile.sOrigin + SurfaceOriginS[data]-vy;
tile.fOrigin ← tile.fOrigin + vx;
data.function ← [null, null];
device.ApplyMask ← ApplyMaskTile;
};
color: SampledColor => {
pa: PixelArray ~ color.pa;
data.source ← pa;
data.transformation^ ← device.surfaceToDevice^;
data.transformation.PreTranslate[vx, vy]; -- view to device
data.transformation.PreMultiply[color.m]; -- color to device
data.transformation.PreMultiply[pa.m]; -- pa to device
IF data.deviceBrickMaxSampleValue#pa.maxSampleValue THEN {
data.deviceBrickMaxSampleValue ← pa.maxSampleValue;
data.deviceBrick ← ImagerHalftone.MakeSquareBrick[4, 3, 2, 1, 1, pa.maxSampleValue];
};
SELECT color.colorOperator FROM
$SampledBlack => data.invertOutput ← TRUE;
$Intensity => data.invertOutput ← FALSE;
ENDCASE => Imager.Error[$UnknownColorModel];
data.transparent ← color.transparent;
device.ApplyMask ← ApplyMaskHalftone;
};
color: SpecialColor => {
WITH color.ref SELECT FROM
stipple: REF CARDINAL => {
data.tile ← ImagerPixelMaps.TileFromStipple[stipple: stipple^, scratch: data.tile.refRep];
data.function ← [null, null];
device.ApplyMask ← ApplyMaskTile;
};
ENDCASE => ERROR Imager.Error[$UnknownSpecialColor];
};
ENDCASE => Imager.Error[$Bug];
};
lfBrick: ImagerHalftone.DeviceBrick ← ImagerHalftone.MakeSquareBrick[4, 3, 2, 1, 1, 255];
IntensityFromColor: PROC[c: ConstantColor] RETURNS[REAL] ~ {
WITH c SELECT FROM
c: REF ImagerColor.ColorRep[constant][gray] => RETURN[c.f];
c: REF ImagerColor.ColorRep[constant][cie] => RETURN[c.Y];
ENDCASE => ERROR;
};
SetTileSamples: PROC [tileSamples: SampledColor, intensity: [0..255]] ~ {
WITH tileSamples.pa.data SELECT FROM
n: REF NAT => n^ ← intensity;
ENDCASE => ERROR;
};
ApplyMaskConstant: PROC[device: Display,
mask, clipper: Mask, sTranslate, fTranslate: INTEGER] ~ {
data: Data ~ NARROW[device.data];
ImagerMask.ApplyConstant[mask: mask, clipper: clipper, dest: data.frame,
value: data.value, function: data.function, sTranslate: sTranslate, fTranslate: fTranslate];
};
ApplyMaskTile: PROC[device: Display,
mask, clipper: Mask, sTranslate, fTranslate: INTEGER] ~ {
data: Data ~ NARROW[device.data];
USING [frame, tile, function]
ImagerMask.ApplyTile[mask: mask, clipper: clipper, dest: data.frame,
tile: data.tile, function: data.function, sTranslate: sTranslate, fTranslate: fTranslate];
};
ApplyMaskHalftone: PROC[device: Display,
mask, clipper: Mask, sTranslate, fTranslate: INTEGER] ~ {
data: Data ~ NARROW[device.data];
USING [frame, source, transformation, deviceBrick, invertOutput, transparent]
Runs: PROC[run: PROC[sMin, fMin: INTEGER, fSize: NAT]] ~ {
ImagerMask.GenerateRuns[mask, clipper, run, sTranslate, fTranslate];
};
ImagerHalftone.Halftone[dest: data.frame, runs: Runs, source: data.source,
transformation: data.transformation, deviceBrick: data.deviceBrick,
invertOutput: data.invertOutput, transparent: data.transparent];
};
ImagerPrivate.RegisterDevice[LFDisplayClass];
END.