ImagerColor24DeviceImpl.mesa
Copyright © 1984 Xerox Corporation. All rights reserved.
Doug Wyatt, November 5, 1984 3:27:35 pm PST
DIRECTORY
Basics USING [bitsPerWord, LongMult],
ImagerColor,
ImagerDevice USING [Class, ClassRep, Device, DeviceRep, HalftoneParameters, RunProc],
ImagerPixelArray,
ImagerPixelMap,
ImagerPixelRow,
ImagerSampler USING [CreateSampler, ObtainInterpolatedSamples, Sampler],
ImagerTransformation USING [Cat, PreRotate, Transformation, Translate],
PrincOps USING [BBTableSpace, BitBltTable, BitBltTablePtr, zBNDCK, zINC],
PrincOpsUtils USING [AlignedBBTable, BITBLT],
Real USING [FixC, RoundC],
Terminal,
Vector2 USING [VEC];
ImagerColor24DeviceImpl: CEDAR PROGRAM
IMPORTS Basics, ImagerColor, ImagerPixelArray, ImagerPixelMap, ImagerPixelRow, ImagerSampler, ImagerTransformation, PrincOpsUtils, Real, Terminal
~ BEGIN
Device: TYPE ~ ImagerDevice.Device;
RunProc: TYPE ~ ImagerDevice.RunProc;
HalftoneParameters: TYPE ~ ImagerDevice.HalftoneParameters;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
VEC: TYPE ~ Vector2.VEC;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Color: TYPE ~ ImagerColor.Color;
ConstantColor: TYPE ~ ImagerColor.ConstantColor;
SampledColor: TYPE ~ ImagerColor.SampledColor;
SpecialColor: TYPE ~ ImagerColor.SpecialColor;
ColorOperator: TYPE ~ ImagerColor.ColorOperator;
ColorOperatorRep: TYPE ~ ImagerColor.ColorOperatorRep;
Case: TYPE ~ {nil, constant, sampled};
Data: TYPE ~ REF DataRep;
DataRep:
TYPE ~
RECORD[
frameA: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL], -- frame buffer for A channel
frameB: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL], -- frame buffer for B channel
pixelsPerInch: REAL, -- declared resolution
case: Case ← nil, -- what type of color
function: ImagerPixelMap.Function ← [null, null], -- bitblt function
pixelA, pixelB: CARDINAL ← 0, -- bitblt gray values
pa: ImagerPixelArray.PixelArray ← NIL, -- pixel array from sampled color
colorOperator: ImagerColor.ColorOperator ← NIL,
paToDevice: Transformation ← NIL, -- transformation from pa coords to display
sourceR: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL], -- source values for red
sourceB: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL], -- source values for green
sourceG: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL], -- source values for blue
paSampler: ImagerSampler.Sampler ← NIL -- for sampling pixel array
];
class: ImagerDevice.Class ~
NEW[ImagerDevice.ClassRep ← [
type: $Color24Display,
SetColor: SetColor,
SetPriority: SetPriority,
SetHalftone: SetHalftone,
MaskRuns: MaskRuns
]];
defaultPixelsPerInch:
REAL ~ 42;
vt: Terminal.Virtual ← Terminal.Current[];
Create:
PUBLIC
PROC[pixelsPerInch:
REAL ← defaultPixelsPerInch]
RETURNS[Device] ~ {
data: Data ~ NEW[DataRep ← [pixelsPerInch: pixelsPerInch]];
fSize, sSize: NAT ← 0;
surfaceToDevice: Transformation ← NIL;
[] ← Terminal.SetColorMode[vt, [TRUE, 0, 0]];
FOR i:
NAT
IN[0..256)
DO
Terminal.SetRedMap[vt, i, i];
Terminal.SetGreenMap[vt, i, i];
Terminal.SetBlueMap[vt, i, i];
ENDLOOP;
Terminal.TurnOnColorDisplay[vt];
fSize ← vt.colorWidth;
sSize ← vt.colorHeight;
TRUSTED {
lines: NAT ~ vt.colorHeight;
rastA: CARDINAL ~ vt.colorWordsPerLineA;
rastB: CARDINAL ~ vt.colorWordsPerLineB;
data.frameA ← ImagerPixelMap.CreateFrameBuffer[pointer: vt.colorBitmapA,
words: INT[rastA]*sSize, lgBitsPerPixel: 4, rast: rastA, lines: lines];
data.frameB ← ImagerPixelMap.CreateFrameBuffer[pointer: vt.colorBitmapB,
words: INT[rastB]*sSize, lgBitsPerPixel: 3, rast: rastB, lines: lines];
};
surfaceToDevice ← ImagerTransformation.Translate[[sSize, 0]];
surfaceToDevice.PreRotate[90];
RETURN[
NEW[ImagerDevice.DeviceRep ← [class: class,
clipBox: [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize],
surfaceToDevice: surfaceToDevice,
surfaceUnitsPerInch: [pixelsPerInch, pixelsPerInch],
surfaceUnitsPerPixel: 1,
data: data]]];
};
Val: TYPE ~ ImagerPixelArray.Val;
Table: TYPE ~ REF TableRep;
TableRep: TYPE ~ RECORD[SEQUENCE size: NAT OF CARDINAL];
BuildTable:
PROC[max: Val, scale:
REAL, sWhite, sBlack:
REAL,
map: ImagerColor.SampleMap ← NIL] RETURNS[Table] ~ {
table: Table ~ NEW[TableRep[max+1]];
FOR s0: Val
IN[0..max]
DO
s: REAL ~ IF map=NIL THEN s0 ELSE map[s0];
v: REAL ~ MIN[MAX[(s-sBlack)/(sWhite-sBlack), 0], 1];
table[s0] ← Real.FixC[scale*v];
ENDLOOP;
RETURN[table];
};
SetColor:
PROC[device: Device, color: Color, viewToDevice: Transformation] ~ {
data: Data ~ NARROW[device.data];
WITH color
SELECT
FROM
color: ConstantColor => {
rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[color.cie];
rPixel: [0..256) ~ Real.RoundC[MIN[MAX[rgb.r, 0], 1]*255];
gPixel: [0..256) ~ Real.RoundC[MIN[MAX[rgb.g, 0], 1]*255];
bPixel: [0..256) ~ Real.RoundC[MIN[MAX[rgb.b, 0], 1]*255];
data.function ← [null, null];
data.pixelA ← rPixel*256+gPixel;
data.pixelB ← bPixel*256+bPixel;
data.case ← constant;
};
color: SampledColor => {
pa: ImagerPixelArray.PixelArray ~ color.pa;
colorOperator: ImagerColor.ColorOperator ~ color.colorOperator;
data.paToDevice ← ImagerTransformation.Cat[pa.m, color.um, viewToDevice];
data.paSampler ← ImagerSampler.CreateSampler[
m: data.paToDevice, x: 0, y: 0, sPixels: pa.sSize, fPixels: pa.fSize];
data.case ← sampled;
IF data.pa#pa
OR data.colorOperator#colorOperator
THEN {
samples: ImagerPixelArray.Row ~ NEW[ImagerPixelArray.RowRep[pa.fSize]];
row: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[
sMin: 0, fMin: 0, fSize: pa.fSize];
data.sourceR ← ImagerPixelMap.Create[lgBitsPerPixel: 3,
bounds: [sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize]];
data.sourceG ← ImagerPixelMap.Create[lgBitsPerPixel: 3,
bounds: [sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize]];
data.sourceB ← ImagerPixelMap.Create[lgBitsPerPixel: 3,
bounds: [sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize]];
WITH colorOperator
SELECT
FROM
op: REF ColorOperatorRep.grayLinear => {
table: Table ← NIL;
IF pa.samplesPerPixel#1 THEN ERROR; -- samplesPerPixel must be 1
table ← BuildTable[max: pa.MaxSampleValue[0], scale: 255,
sWhite: op.sWhite, sBlack: op.sBlack, map: op.map];
FOR s: NAT IN[0..pa.sSize) DO
row.sOrigin ← s;
ImagerPixelArray.GetRow[pa, row, s, 0, 0];
FOR f: NAT IN[0..pa.fSize) DO row[f] ← table[row[f]] ENDLOOP;
ImagerPixelRow.StorePixelRow[row, data.source];
ENDLOOP;
};
op:
REF ColorOperatorRep.separations => {
sum: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[
sMin: 0, fMin: 0, fSize: pa.fSize];
tables: ARRAY[0..4) OF Table ← ALL[NIL];
IF pa.samplesPerPixel#op.samplesPerPixel THEN ERROR; -- samplesPerPixel must match
-- Red
FOR i:
NAT
IN[0..pa.samplesPerPixel)
DO
sep: ImagerColor.Separation ~ op[i];
rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[sep.cie];
tables[i] ← BuildTable[max: pa.MaxSampleValue[i], scale: 255*rgb.r,
sWhite: sep.sMax, sBlack: sep.sMin, map: sep.map];
ENDLOOP;
FOR s:
NAT
IN[0..pa.sSize)
DO
row.sOrigin ← s;
ImagerPixelRow.ClearPixelRow[row];
FOR i:
NAT
IN[0..pa.samplesPerPixel)
DO
table: Table ~ tables[i];
ImagerPixelArray.GetRow[pa, samples, s, 0, i];
FOR f: NAT IN[0..pa.fSize) DO row[f] ← row[f]+table[samples[f]] ENDLOOP;
ENDLOOP;
ImagerPixelRow.StorePixelRow[row, data.sourceR];
ENDLOOP;
-- Green
FOR i:
NAT
IN[0..pa.samplesPerPixel)
DO
sep: ImagerColor.Separation ~ op[i];
rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[sep.cie];
tables[i] ← BuildTable[max: pa.MaxSampleValue[i], scale: 255*rgb.g,
sWhite: sep.sMax, sBlack: sep.sMin, map: sep.map];
ENDLOOP;
FOR s:
NAT
IN[0..pa.sSize)
DO
row.sOrigin ← s;
ImagerPixelRow.ClearPixelRow[row];
FOR i:
NAT
IN[0..pa.samplesPerPixel)
DO
table: Table ~ tables[i];
ImagerPixelArray.GetRow[pa, samples, s, 0, i];
FOR f: NAT IN[0..pa.fSize) DO row[f] ← row[f]+table[samples[f]] ENDLOOP;
ENDLOOP;
ImagerPixelRow.StorePixelRow[row, data.sourceG];
ENDLOOP;
-- Blue
FOR i:
NAT
IN[0..pa.samplesPerPixel)
DO
sep: ImagerColor.Separation ~ op[i];
rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[sep.cie];
tables[i] ← BuildTable[max: pa.MaxSampleValue[i], scale: 255*rgb.b,
sWhite: sep.sMax, sBlack: sep.sMin, map: sep.map];
ENDLOOP;
FOR s:
NAT
IN[0..pa.sSize)
DO
row.sOrigin ← s;
ImagerPixelRow.ClearPixelRow[row];
FOR i:
NAT
IN[0..pa.samplesPerPixel)
DO
table: Table ~ tables[i];
ImagerPixelArray.GetRow[pa, samples, s, 0, i];
FOR f: NAT IN[0..pa.fSize) DO row[f] ← row[f]+table[samples[f]] ENDLOOP;
ENDLOOP;
ImagerPixelRow.StorePixelRow[row, data.sourceB];
ENDLOOP;
};
ENDCASE => ERROR; -- unknown ColorOperator
data.pa ← pa;
data.colorOperator ← colorOperator;
};
};
color: SpecialColor =>
SELECT color.ref
FROM
$XOR => {
data.function ← [xor, null];
data.pixelA ← data.pixelB ← 177777B;
data.case ← constant;
};
ENDCASE => ERROR; -- unknown special color
ENDCASE => ERROR; -- unknown color variant
};
SetPriority:
PROC[device: Device, priorityImportant:
BOOL] ~ {
};
SetHalftone:
PROC[device: Device, halftone: HalftoneParameters] ~ {
};
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
MaskRuns:
PROC[device: Device, runs:
PROC[RunProc]] ~ {
data: Data ~ NARROW[device.data];
frameA: ImagerPixelMap.PixelMap ~ data.frameA;
frameB: ImagerPixelMap.PixelMap ~ data.frameB;
SELECT data.case
FROM
nil => ERROR; -- color not initialized
constant =>
TRUSTED {
bbspaceA: PrincOps.BBTableSpace;
bbA: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspaceA];
bbspaceB: PrincOps.BBTableSpace;
bbB: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspaceB];
baseA: LONG POINTER ~ frameA.refRep.pointer;
baseB: LONG POINTER ~ frameB.refRep.pointer;
rastA: CARDINAL ~ frameA.refRep.rast;
rastB: CARDINAL ~ frameB.refRep.rast;
grayA: LONG POINTER ~ @data.pixelA;
grayB: LONG POINTER ~ @data.pixelB;
run:
PROC[sMin, fMin:
INTEGER, fSize:
NAT] ~
TRUSTED {
f: NAT ~ Check[fMin, frameA.fSize];
s: NAT ~ Check[sMin, frameA.sSize];
bbA.dst.word ← baseA+Basics.LongMult[s, rastA]+f;
bbA.dst.bit ← 0;
bbA.width ← 16*Check[fSize, frameA.fSize-f];
bbA.height ← Check[1, frameA.sSize-s];
PrincOpsUtils.BITBLT[bbA];
bbB.dst.word ← baseB+Basics.LongMult[s, rastB]+f/2;
bbB.dst.bit ← 8*(f MOD 2);
bbB.width ← 8*Check[fSize, frameA.fSize-f];
bbB.height ← Check[1, frameA.sSize-s];
PrincOpsUtils.BITBLT[bbB];
};
bbA^ ← nullBitBltTable;
bbB^ ← nullBitBltTable;
bbA.dstBpl ← rastA*Basics.bitsPerWord;
bbB.dstBpl ← rastB*Basics.bitsPerWord;
bbA.src.word ← grayA;
bbB.src.word ← grayB;
bbA.src.bit ← 0;
bbB.src.bit ← 0;
bbA.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0];
bbB.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0];
bbA.flags ← [direction: forward, disjoint:
TRUE, gray:
TRUE,
srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc];
bbB.flags ← [direction: forward, disjoint:
TRUE, gray:
TRUE,
srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc];
runs[run];
};
sampled => {
rowR: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[
sMin: 0, fMin: 0, fSize: frameA.fSize];
rowG: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[
sMin: 0, fMin: 0, fSize: frameA.fSize];
run:
PROC[sMin, fMin:
INTEGER, fSize:
NAT] ~ {
rowR.sOrigin ← rowG.sOrigin ← Check[sMin, frameA.sSize];
rowR.fOrigin ← rowG.fOrigin ← Check[fMin, frameA.fSize];
rowR.fSize ← rowG.fSize ← Check[fSize, frameA.fSize-fMin];
ImagerSampler.ObtainInterpolatedSamples[sampler: data.paSampler,
pixelRow: rowR, source: data.sourceR];
ImagerSampler.ObtainInterpolatedSamples[sampler: data.paSampler,
pixelRow: rowG, source: data.sourceG];
FOR f:
NAT
IN[0..rowR.fSize)
DO
rowR[f] ← rowR[f]*256+rowG[f];
ENDLOOP;
ImagerPixelRow.StorePixelRow[rowR, frameA];
ImagerSampler.ObtainInterpolatedSamples[sampler: data.paSampler,
pixelRow: rowR, source: data.sourceB];
ImagerPixelRow.StorePixelRow[rowR, frameB];
};
runs[run];
};
ENDCASE => ERROR; -- illegal case
};
END.