~
BEGIN
ROPE: TYPE ~ Rope.ROPE;
Context: TYPE ~ Imager.Context;
Toner: TYPE ~ ImagerPDPublic.Toner;
Toners: TYPE ~ LIST OF ImagerPDPublic.Toner;
PrinterType: TYPE ~ ImagerPD.PrinterType;
Color: TYPE ~ ImagerColor.Color;
Transformation: TYPE ~ ImagerTransformation.Transformation;
ConstantColor: TYPE ~ ImagerColor.ConstantColor;
SampledColor: TYPE ~ ImagerColor.SampledColor;
SampledBlack: TYPE ~ ImagerColor.SampledBlack;
ColorOperator: TYPE ~ ImagerColor.ColorOperator;
SampleMap: TYPE ~ ImagerSample.SampleMap;
PixelArray: TYPE ~ ImagerPixelArray.PixelArray;
Tile: TYPE ~ ImagerPD.Tile;
TileEntry:
TYPE ~ ImagerPDPrivate.TileEntry;
ColorKind:
TYPE ~ ImagerPDPrivate.ColorKind;
PD: TYPE ~ REF PDRep;
PDRep:
PUBLIC
TYPE ~ ImagerPDPrivate.PDRep;
DeviceData: TYPE ~ ImagerPDPrivate.DeviceData;
DeviceDataRep: TYPE ~ ImagerPDPrivate.DeviceDataRep;
CMYK: TYPE ~ ImagerColorFns.CMYK;
RGB: TYPE ~ ImagerColor.RGB;
ColorPDBrick:
TYPE ~ ColorRegistry.ColorPDBrick;
Sample: TYPE ~ ImagerSample.Sample;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
SetColor:
PUBLIC PROC [context: Context, color: Color, viewToDevice: Transformation]
RETURNS [ImagerDevice.AllowedMasks] ~ {
deviceData: DeviceData ~ NARROW[context.data];
writer: PDFileWriter.PDState ~ deviceData.writer;
setColorFromCMYK:
PROC[val:
CMYK] = {
SELECT deviceData.toner
FROM
cyan => SetColorFromFraction[deviceData, val.C];
magenta => SetColorFromFraction[deviceData,val.M];
yellow => SetColorFromFraction[deviceData,val.Y];
black => SetColorFromFraction[deviceData,val.K];
ENDCASE => SetColorUniform[deviceData, noInk];
};
deviceData.colorKind ← nil;
deviceData.sampledSource ← NIL;
WITH color
SELECT
FROM
color: ImagerColor.SpecialColor => {
defaultColor:
PROC ={
IF color.substitute #
NIL
THEN { [] ← SetColor[context, color.substitute, viewToDevice] }
ELSE { ERROR Imager.Error[[code: $unknownSpecialColor, explanation: "Unknown special color has no substitute value"]] };
};
SELECT color.type
FROM
$Distinct => {
-- the distinct named colors
nameData: ColorRegistry.Data ← NARROW[color.data];
deviceIndex: NAT ← IndexFromAtom[deviceData.deviceType, $Distinct];
ColorRegistryProcs.InitPrinterColors[deviceType: deviceData.deviceType, colorType: $Distinct]; --won't do any work if already initialized
SELECT deviceData.deviceType
FROM
$color400, $colorversatec => {
--find CMYK
value: CMYK ← NARROW[ nameData.deviceValues[deviceIndex], REF CMYK]^;
setColorFromCMYK[value];
};
$bw400, $versatec, $raven384 => {
--find a Tile
value: ImagerPD.Tile ← NARROW[nameData.deviceValues[deviceIndex], REF ImagerPD.Tile]^;
SetColorFromTile[deviceData, value, FALSE, TRUE]
};
ENDCASE => defaultColor[];
};
$ChipNDale => {
-- the
ChipNDale
named colors
nameData: ColorRegistry.Data ← NARROW[color.data];
deviceIndex: NAT ← IndexFromAtom[deviceData.deviceType, $Distinct];
ColorRegistryProcs.InitPrinterColors[deviceType: deviceData.deviceType, colorType: $ChipNDale]; --won't do any work if already initialized
SELECT deviceData.deviceType
FROM
$color400, $colorversatec => {
--find LIST of ColorRegistry.ColorPDBrick
tiles: LIST OF REF ColorPDBrick ← NARROW[ nameData.deviceValues[deviceIndex]];
SetColorUniform[deviceData, off]; --have to have some color set
IF tiles
#NIL THEN
{
FOR l:
LIST
OF
REF ColorPDBrick ← tiles, l.rest
UNTIL l=
NIL
DO
IF l.first.toner=
LOOPHOLE[deviceData.toner, ImagerPDPublic.Toner]
THEN
SetColorFromTile[deviceData, l.first.tile, TRUE, TRUE];
ENDLOOP;
};
};
ENDCASE => defaultColor[];
};
ENDCASE => defaultColor[];
};
color: ImagerColor.OpConstantColor => {
Check here for different color operators
IF ImagerColorPrivate.SupportsOutput[color.colorOperator, $CMYK]
THEN {
set primaries directly, no color correction
cmyk: CMYK;
pixelIn: ImagerColorPrivate.PixelProc ~ { RETURN[color.pixel[i]] };
tupleAction:
PROC [tupleOut: ImagerColorPrivate.TupleProc] ~ {
cmyk ← [C: tupleOut[0], M: tupleOut[1], Y: tupleOut[2], K: tupleOut[3]];
};
ImagerColorPrivate.TupleFromPixel[color.colorOperator,
[type: $CMYK, samplesPerPixelOut: 4], pixelIn, tupleAction];
setColorFromCMYK[cmyk];
}
ELSE {
rgb: RGB ~ ImagerColorPrivate.RGBFromColor[color];
SetColorFromRGB may do color correction
SetColorFromRGB[deviceData, rgb, ImagerColorPrivate.IntensityFromColor[color]];
};
};
color: ImagerColor.SampledColor => {
pa: PixelArray ~ color.pa;
um: Transformation ~ color.um;
colorOperator: ColorOperator ~ color.colorOperator;
ImagerTransformation.ApplyCat[deviceData.paToDevice, pa.m, color.um, viewToDevice];
deviceData.sampledSource ← GetCachedSource[deviceData, color];
IF deviceData.sampledSource =
NIL
THEN { SetColorUniform[deviceData, noInk] }
ELSE {
deviceData.colorKind ← sampled;
PDFileWriter.NewPriorityLevel[pdState: deviceData.writer, toner: deviceData.toner];
};
};
color: ImagerColor.SampledBlack => {
pa: PixelArray ~ color.pa;
um: Transformation ~ color.um;
SetColorFromSampledBlack[context, pa, color.clear];
PDFileWriter.NewPriorityLevel[pdState: deviceData.writer, toner: deviceData.toner];
};
ENDCASE => ERROR;
SELECT deviceData.colorKind
FROM
constant => RETURN [[unorderedBoxes: TRUE, multipleCoverage: TRUE, regionFill: FALSE, bitmap: TRUE, rawBitmaps: FALSE, runGroupChar: TRUE, rasterChar: TRUE]];
ENDCASE => RETURN [[unorderedBoxes: FALSE, multipleCoverage: FALSE, regionFill: FALSE, bitmap: FALSE, rawBitmaps: FALSE, runGroupChar: FALSE, rasterChar: FALSE]];
};
The color name scheme requires each device to have an index understood by it an
ColorRegistryImpl. This is the cnIndex in the DeviceRec.
Any of the devices not in this list will end up using the color's substitute value
nDevices: NAT = 5;
deviceList:
ARRAY [0..nDevices)
OF DeviceRec ← [
--devices we have implemented names for
[8,$color400],
[9,$colorversatec],
[10,$raven384],
[11,$bw400],
[12,$versatec]];
DeviceRec: TYPE = RECORD[cnIndex: NAT, type: ATOM];
lastPair: DeviceRec ← [0, NIL]; --cheap cache
IndexFromAtom:
PROC [deviceType:
ATOM, colorType:
ATOM]
RETURNS [cnIndex:
NAT] ~ {
FOR i:
NAT
IN [0..nDevices)
DO
IF deviceList[i].type = deviceType
THEN {
cnIndex ← deviceList[i].cnIndex;
lastPair ← deviceList[i];
RETURN[cnIndex]};
ENDLOOP;
ERROR;
};
SetHalftoneProperties:
PUBLIC
PROC [pd:
PD, toner: ImagerPD.Toner, brick: Tile] ~ {
IF brick.maxSample#BYTE.LAST THEN ERROR; -- restrict this for now.
pd.deviceData.halftoneBrick[VAL[ORD[toner]]] ← NEW[Tile ← brick];
};
SetColorCorrection:
PUBLIC
PROC [pd:
PD, correctionProc: ImagerPD.CorrectionProc, data:
REF] = {
Sets the color correction proc, which will be called once per pixel for each sampled color, and once for each constant color.
pd.deviceData.correctionProc ← correctionProc;
pd.deviceData.colorCorrectionData ← data;
[] ← FunctionCache.Obtain[x: FunctionCache.GlobalCache[], compare: FunctionCache.Any, limit: INT.LAST, clientID: pd.deviceData]; -- Flush our stuff from the cache.
};
TileShape: TYPE ~ RECORD [box: SF.Box, phase: INTEGER];
GetGoodShape:
PROC [box:
SF.Box, phase:
INTEGER]
RETURNS [TileShape] ~ {
size: SF.Vec ~ SF.Size[box];
IF size.s <= 0 OR size.f <= 0 THEN ERROR;
WHILE phase < 0 DO phase ← phase + size.f ENDLOOP;
IF (16
MOD
NAT[size.s] = 0)
AND (16
MOD
NAT[size.f] = 0)
AND ((
NAT[phase]*(16/
NAT[size.s]))
MOD 16 = 0)
THEN {
Can turn this to a 16 by 16 brick.
RETURN [[box: [max: [16, 16]], phase: 0]]
};
RETURN [[box: [max: size], phase: phase]];
};
CreateTile:
PUBLIC
PROC [maxSample:
CARDINAL, sampleMap: SampleMap, phase:
INTEGER ← 0, copy:
BOOL ←
TRUE]
RETURNS [Tile] ~ {
boxIn: SF.Box ~ ImagerSample.GetBox[sampleMap];
shape: TileShape ~ GetGoodShape[boxIn, phase];
raster: ImagerSample.RasterSampleMap ← WITH sampleMap SELECT FROM r: ImagerSample.RasterSampleMap => r ENDCASE => NIL;
IF copy
OR raster=
NIL
OR shape#[boxIn, phase]
THEN {
raster ← ImagerSample.NewSampleMap[box: shape.box, bitsPerSample: ImagerSample.GetBitsPerSample[sampleMap]];
ImagerSample.Clear[raster];
ImagerSample.Tile[map: raster, tile: sampleMap, phase: phase];
};
RETURN [[maxSample: maxSample, sampleMap: raster, phase: shape.phase]]
};
CopyTile:
PROC [tile: Tile]
RETURNS [Tile] ~ {
RETURN [CreateTile[tile.maxSample, tile.sampleMap, tile.phase, TRUE]];
};
TileHash:
PROC [tile: Tile]
RETURNS [hash:
CARDINAL] ~
TRUSTED {
box: SF.Box ~ ImagerSample.GetBox[tile.sampleMap];
bps: NAT ~ ImagerSample.GetBitsPerSample[tile.sampleMap];
r: ImagerSample.RasterSampleMap ~ ImagerSample.ObtainScratchMap[box: box, bitsPerSample: bps, bitsPerLine: SF.SizeF[box]*bps];
unsafeBlock: Basics.UnsafeBlock ~ ImagerSample.GetUnsafeBlock[r];
zero: [0..0] ~ unsafeBlock.startIndex;
p: LONG POINTER ← unsafeBlock.base;
count: CARD ← CARD[unsafeBlock.count+Basics.bytesPerWord]/Basics.bytesPerWord;
ImagerSample.Clear[r];
ImagerSample.Transfer[dst: r, src: tile.sampleMap];
hash ← 0;
UNTIL count = 0
DO
nWords: CARDINAL ~ MIN[count, NAT.LAST];
hash ← Checksum.ComputeChecksum[cs: hash, nWords: nWords, p: p];
p ← p + nWords;
count ← count - nWords;
ENDLOOP;
ImagerSample.ReleaseScratchMap[r]
};
TileEqual:
PROC [a, b: Tile]
RETURNS [
BOOL] ~ {
IF a.maxSample # b.maxSample THEN RETURN [FALSE];
IF a.phase # b.phase THEN RETURN [FALSE];
RETURN [ImagerSample.Equal[a.sampleMap, b.sampleMap]];
};
PutTileIntoLoad:
PROC [writer: PDFileWriter.PDState, tile: Tile]
RETURNS [
CARD] ~
TRUSTED {
box: SF.Box ~ ImagerSample.GetBox[tile.sampleMap];
base: LONG POINTER ~ ImagerSample.GetBase[tile.sampleMap].word;
bitsPerLine: NAT ~ ImagerSample.GetBitsPerLine[tile.sampleMap];
IF bitsPerLine MOD 16 # 0 OR (bitsPerLine-SF.SizeF[box]) NOT IN [0..15) THEN ERROR;
RETURN [PDFileWriter.LoadContiguousColorTile[pdState: writer, phase: tile.phase, sMin: box.min.s, fMin: box.min.f, sSize: SF.SizeS[box], fSize: SF.SizeF[box], bitsPtr: base]];
};
TileLoadWords:
PROC [tile: Tile]
RETURNS [
INT] ~ {
RETURN [SIZE[PDFileFormat.Tile] + ImagerSample.WordsForMap[ImagerSample.GetSize[tile.sampleMap]]];
};
SetColorFromTile:
PROC [deviceData: DeviceData, tile: Tile, clear:
BOOL, copy:
BOOL] ~ {
hash: CARDINAL ~ TileHash[tile];
bucket: NAT ~ hash MOD deviceData.tileTable.mod;
loadIndex: LONG CARDINAL ← 0;
found: BOOL ← FALSE;
FOR t:
LIST
OF TileEntry ← deviceData.tileTable[bucket], t.rest
UNTIL (found
OR t =
NIL)
DO
IF t.first.hash = hash
AND TileEqual[tile, t.first.tile]
THEN {
found ← TRUE;
loadIndex ← t.first.loadIndex;
};
ENDLOOP;
IF
NOT found
AND TileLoadWords[tile] <= PDFileWriter.RemainingLoadSize[deviceData.writer]
THEN {
loadIndex ← PutTileIntoLoad[deviceData.writer, tile];
deviceData.tileTable[bucket] ← CONS[[loadIndex, hash, IF copy THEN CopyTile[tile] ELSE tile], deviceData.tileTable[bucket]];
found ← TRUE;
};
IF found
THEN {
PDFileWriter.SetColorTile[pdState: deviceData.writer, toner: deviceData.toner, tileRef: loadIndex, tFlag: (IF clear THEN transparent ELSE opaque)];
deviceData.colorKind ← constant;
}
ELSE {
deviceData.colorTile ← (IF copy THEN CopyTile[tile] ELSE tile);
deviceData.colorClear ← clear;
deviceData.colorKind ← tile;
IF clear THEN PDFileWriter.SetColorInk[deviceData.writer, deviceData.toner]
ELSE PDFileWriter.NewPriorityLevel[pdState: deviceData.writer, toner: deviceData.toner];
};
};
UniformColor: TYPE ~ {ink, noInk, off};
SetColorUniform:
PROC [deviceData: DeviceData, u: UniformColor] ~ {
SELECT u
FROM
ink => PDFileWriter.SetColorInk[deviceData.writer, deviceData.toner];
noInk => {
IF deviceData.priorityImportant
THEN PDFileWriter.SetColorClear[deviceData.writer, deviceData.toner]
ELSE PDFileWriter.SetColorOff[deviceData.writer, deviceData.toner];
};
off => PDFileWriter.SetColorOff[deviceData.writer, deviceData.toner];
ENDCASE => NULL;
deviceData.colorKind ← constant;
};
SetColorFromFraction:
PROC [deviceData: DeviceData, f:
REAL] ~ {
SELECT f
FROM
>= 0.9999 => {
-- all toner
SetColorUniform[deviceData, ink]
};
<= 0.0001 => {
-- no toner
SetColorUniform[deviceData, noInk]
};
ENDCASE => {
brick: Tile ~ deviceData.halftoneBrick[deviceData.toner]^;
shape: TileShape ~ GetGoodShape[ImagerSample.GetBox[brick.sampleMap], brick.phase];
bitmap: ImagerSample.RasterSampleMap ~ ImagerSample.ObtainScratchMap[shape.box];
b: ImagerSample.SampleBuffer ~ ImagerSample.ObtainScratchSamples[SF.SizeF[shape.box]];
sample: CARDINAL ~ Real.InlineRoundC[f*brick.maxSample];
ImagerSample.Clear[bitmap];
FOR s:
INTEGER
IN [shape.box.min.s..shape.box.max.s)
DO
ImagerSample.GetTileSamples[tile: brick.sampleMap, phase: brick.phase, initIndex: [s, shape.box.min.f], buffer: b];
FOR j:
INTEGER
IN [0..b.length)
DO
b[j] ← IF sample > b[j] THEN 1 ELSE 0;
ENDLOOP;
ImagerSample.PutSamples[map: bitmap, initIndex: [s, shape.box.min.f], buffer: b];
ENDLOOP;
SetColorFromTile[deviceData: deviceData, tile: [maxSample: 1, sampleMap: bitmap, phase: shape.phase], clear: FALSE, copy: TRUE];
ImagerSample.ReleaseScratchSamples[b];
ImagerSample.ReleaseScratchMap[bitmap];
};
};
brickFraction: REAL ← 0.5; --for experimenting
SetColorFromBrick:
PROC [deviceData: DeviceData, brick: Tile] ~ {
shape: TileShape ~ GetGoodShape[ImagerSample.GetBox[brick.sampleMap], brick.phase];
bitmap: ImagerSample.RasterSampleMap ~ ImagerSample.ObtainScratchMap[shape.box];
b: ImagerSample.SampleBuffer ~ ImagerSample.ObtainScratchSamples[SF.SizeF[shape.box]];
sample: CARDINAL ~ Real.InlineRoundC[brickFraction*brick.maxSample];
ImagerSample.Clear[bitmap];
FOR s:
INTEGER
IN [shape.box.min.s..shape.box.max.s)
DO
ImagerSample.GetTileSamples[tile: brick.sampleMap, phase: brick.phase, initIndex: [s, shape.box.min.f], buffer: b];
FOR j:
INTEGER
IN [0..b.length)
DO
b[j] ← IF sample > b[j] THEN 1 ELSE 0;
ENDLOOP;
ImagerSample.PutSamples[map: bitmap, initIndex: [s, shape.box.min.f], buffer: b];
ENDLOOP;
SetColorFromTile[deviceData: deviceData, tile: [maxSample: 1, sampleMap: bitmap, phase: shape.phase], clear: FALSE, copy: TRUE];
ImagerSample.ReleaseScratchSamples[b];
ImagerSample.ReleaseScratchMap[bitmap];
};
SetColorFromRGB:
PROC [deviceData: DeviceData, rgb: RGB,
Y:
REAL] ~ {
IF deviceData.tonerUniverseSet[cyan]
AND deviceData.tonerUniverseSet[magenta]
AND deviceData.tonerUniverseSet[yellow]
THEN {
IF deviceData.correctionProc #
NIL
THEN {
deviceData.pixelsRGB[0][0] ← Real.InlineRoundC[rgb.R*255];
deviceData.pixelsRGB[1][0] ← Real.InlineRoundC[rgb.G*255];
deviceData.pixelsRGB[2][0] ← Real.InlineRoundC[rgb.B*255];
deviceData.correctionProc[
deviceData.pixelsRGB, deviceData.pixelsCMYK,
deviceData.colorCorrectionData, LOOPHOLE[deviceData.toner] --toner is actually ignored. Will return all 4 separations, so we could be more efficient here if we wanted to implement a cache.
];
SELECT deviceData.toner
FROM
cyan => SetColorFromFraction[deviceData, deviceData.pixelsCMYK[0][0]/255.0];
magenta => SetColorFromFraction[deviceData,deviceData.pixelsCMYK[1][0]/255.0];
yellow => SetColorFromFraction[deviceData,deviceData.pixelsCMYK[2][0]/255.0];
black => SetColorFromFraction[deviceData,deviceData.pixelsCMYK[3][0]/255.0];
ENDCASE => SetColorUniform[deviceData, noInk];
}
ELSE
SELECT deviceData.toner
FROM
cyan => SetColorFromFraction[deviceData, 1.0 - rgb.R];
magenta => SetColorFromFraction[deviceData, 1.0 - rgb.G];
yellow => SetColorFromFraction[deviceData, 1.0 - rgb.B];
ENDCASE => SetColorUniform[deviceData, noInk];
}
ELSE
IF deviceData.tonerUniverseSet[black]
THEN {
SetColorFromFraction[deviceData, 1.0 - Y];
}
ELSE ERROR;
};
UnimplementedColor:
PUBLIC
SIGNAL [color: Color] ~
CODE;
SetColorFromSampledBlack:
PROC [context: Context, pa: PixelArray, clear:
BOOL] ~ {
deviceData: DeviceData ~ NARROW[context.data];
IF deviceData.tonerUniverseSet[black]
AND deviceData.toner # black
THEN { SetColorUniform[deviceData, IF clear THEN off ELSE noInk] }
ELSE {
cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[];
compare: FunctionCache.CompareProc ~ {RETURN [argument=pa]};
scd: ImagerPixel.PixelMap ← NARROW[FunctionCache.Lookup[cache, compare, deviceData].value];
IF scd =
NIL
THEN
TRUSTED {
sampleMap: ImagerSample.RasterSampleMap ~ ImagerSample.NewSampleMap[box: [max: [pa.sSize, pa.fSize]]];
ImagerSample.Clear[sampleMap];
ImagerPixelArray.Transfer[pa: pa, dst: sampleMap];
scd ← ImagerPixel.MakePixelMap[sampleMap];
IF pa.immutable THEN FunctionCache.Insert[cache, pa, scd, PixelMapWords[scd], deviceData];
};
deviceData.sampledSource ← scd;
IF deviceData.paToDevice.form = 3
AND deviceData.paToDevice.integerTrans
THEN {
SetColorFromTile[deviceData, CreateTile[1, ImagerSample.Shift[scd[0], [deviceData.paToDevice.tx, deviceData.paToDevice.ty]], 0], clear, FALSE];
}
ELSE {
deviceData.colorKind ← sampledBlack;
deviceData.colorClear ← clear;
PDFileWriter.SetColorInk[deviceData.writer, deviceData.toner];
};
};
};
SampledColorData: TYPE ~ REF SampledColorDataRep;
SampledColorDataRep:
TYPE ~
RECORD [
pa: PixelArray,
colorOperator: ColorOperator,
source: ImagerPixel.PixelMap
];
PixelMapWords:
PROC [pixelMap: ImagerPixel.PixelMap]
RETURNS [
INT] ~ {
words: INT ← 0;
FOR i:
NAT
IN [0..pixelMap.samplesPerPixel)
DO
words ← words + ImagerSample.WordsForMap[size: ImagerSample.GetSize[pixelMap[i]], bitsPerSample: ImagerSample.GetBitsPerSample[pixelMap[i]]]
ENDLOOP;
RETURN [words];
};
GetCachedSource:
PROC [deviceData: DeviceData, sampledColor: ImagerColor.SampledColor]
RETURNS [ImagerPixel.PixelMap] ~ {
cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[];
pa: ImagerPixelArray.PixelArray ~ sampledColor.pa;
colorOperator: ImagerColor.ColorOperator ~ sampledColor.colorOperator;
Compare: FunctionCache.CompareProc ~ {
WITH argument
SELECT
FROM
scd: SampledColorData => RETURN [scd.pa = pa AND scd.colorOperator = colorOperator];
ENDCASE => RETURN [FALSE]
};
scd: SampledColorData ← NARROW[FunctionCache.Lookup[cache, Compare, deviceData].value];
fullColor: BOOL ~ colorOperator.chromatic AND deviceData.tonerUniverseSet[cyan] AND deviceData.tonerUniverseSet[magenta] AND deviceData.tonerUniverseSet[yellow];
index: NAT ~ IF fullColor THEN (SELECT deviceData.toner FROM black => 3, cyan => 0, magenta => 1, yellow => 2, ENDCASE => 0) ELSE 0;
IF scd =
NIL
THEN {
pixelMap: ImagerPixel.PixelMap ~ ComputeSource[deviceData, sampledColor];
scd ← NEW [SampledColorDataRep ← [pa: pa, colorOperator: colorOperator, source: pixelMap]];
IF pa.immutable THEN FunctionCache.Insert[x: cache, argument: scd, value: scd, size: PixelMapWords[pixelMap], clientID: deviceData];
};
IF index >= scd.source.samplesPerPixel THEN RETURN [NIL] ELSE RETURN [ImagerPixel.MakePixelMap[scd.source[index]]];
};
ComputeSource:
PROC [deviceData: DeviceData, sampledColor: ImagerColor.SampledColor]
RETURNS [ImagerPixel.PixelMap] ~ {
pa: ImagerPixelArray.PixelArray ~ sampledColor.pa;
colorOperator: ImagerColor.ColorOperator ~ sampledColor.colorOperator;
fullColor: BOOL ~ colorOperator.chromatic AND deviceData.tonerUniverseSet[cyan] AND deviceData.tonerUniverseSet[magenta] AND deviceData.tonerUniverseSet[yellow];
cmyk: BOOL ~ ImagerColorPrivate.SupportsOutput[colorOperator, $CMYK];
size: SF.Vec ~ [s: NAT[pa.sSize], f: NAT[pa.fSize]];
samplesPerPixelOut:
NAT ~
SELECT
TRUE
FROM
fullColor AND deviceData.tonerUniverseSet[black] AND (deviceData.correctionProc#NIL OR cmyk) => 4, -- CMYK
fullColor => 3, -- CMY
ENDCASE => 1; -- Intensity
type: ATOM ~ IF samplesPerPixelOut = 4 AND cmyk THEN $CMYK ELSE IF samplesPerPixelOut = 1 THEN $Y ELSE IF ImagerColorPrivate.SupportsOutput[colorOperator, $CMY] THEN $CMY ELSE $RGB;
maxIn: ImagerPixel.PixelProc ~ { RETURN[pa.MaxSampleValue[i]] };
maxOut: ImagerPixel.PixelProc ~ { RETURN[BYTE.LAST] };
pixelMap: ImagerPixel.PixelMap ~ ImagerPixel.NewPixelMap[samplesPerPixel: samplesPerPixelOut, box: [max: size], maxSample: maxOut];
translateAction:
PROC [translate: ImagerColorPrivate.TranslateProc] ~ {
pixelsIn: ImagerPixel.PixelBuffer ~ ImagerPixel.ObtainScratchPixels[pa.samplesPerPixel, size.f];
pixelsRGB: ImagerPixel.PixelBuffer ~ ImagerPixel.ObtainScratchPixels[3, size.f];
pixelsOut: ImagerPixel.PixelBuffer ~ ImagerPixel.ObtainScratchPixels[samplesPerPixelOut, size.f];
FOR i:
NAT
IN [0..samplesPerPixelOut)
DO
ImagerSample.ClearSamples[pixelsOut[i]]
ENDLOOP;
FOR s:
NAT
IN [0..size.s)
DO
pa.GetPixels[s: s, f: 0, pixels: pixelsIn];
SELECT type
FROM
$CMYK, $CMY => translate[pixelsIn: pixelsIn, pixelsOut: pixelsOut];
$RGB => {
Correction: ImagerPD.CorrectionProc ~ deviceData.correctionProc;
correctionData: REF ~ deviceData.colorCorrectionData;
translate[pixelsIn: pixelsIn, pixelsOut: pixelsRGB];
IF Correction #
NIL
THEN
Computed the corrected pixels for all four separations
Correction[pixelsRGB, pixelsOut, correctionData, black] --toner field is ignored
ELSE
TRUSTED {
FOR i:
NAT
IN [0..3)
DO
a: LONG POINTER TO Basics.RawWords ~ ImagerSample.PointerToSamples[buffer: pixelsRGB[i], start: 0, count: size.f];
b: LONG POINTER TO Basics.RawWords ~ ImagerSample.PointerToSamples[buffer: pixelsOut[i], start: 0, count: size.f];
FOR j: NAT IN [0..size.f) DO b[j] ← BYTE.LAST-a[j] ENDLOOP; -- convert to fraction of ink
ENDLOOP;
};
};
$Y => {
buf: LONG POINTER TO Basics.RawWords ~ ImagerSample.PointerToSamples[buffer: pixelsOut[0], start: 0, count: size.f];
translate[pixelsIn: pixelsIn, pixelsOut: pixelsOut];
TRUSTED {
FOR i: NAT IN [0..size.f) DO buf[i] ← BYTE.LAST-buf[i] ENDLOOP; -- convert to fraction of ink
};
};
ENDCASE => ERROR;
pixelMap.PutPixels[initIndex: [s, 0], pixels: pixelsOut, count: size.f];
ENDLOOP;
ImagerPixel.ReleaseScratchPixels[pixelsOut];
ImagerPixel.ReleaseScratchPixels[pixelsIn];
};
ImagerColorPrivate.TranslatePixels[colorOperator: colorOperator, output: [type: type, samplesPerPixelOut: samplesPerPixelOut], maxIn: maxIn, maxOut: maxOut, translateAction: translateAction];
RETURN [pixelMap];
};
END.