DIRECTORY Basics, Checksum, ColorRegistry, ColorRegistryProcs, --FontTune,-- FunctionCache, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, ImagerDevice, ImagerPD, ImagerPDPrivate, ImagerPixelArray, ImagerSample, ImagerPixel, ImagerTransformation, ImagerPDPublic, PDFileFormat, PDFileWriter, PrincOps, PrincOpsUtils, Real, Rope, Vector2, SF, ImagerPrivate; ImagerPDColorImpl: CEDAR PROGRAM IMPORTS Checksum, ColorRegistryProcs, --FontTune,-- FunctionCache, Imager, ImagerColorPrivate, ImagerPixelArray, ImagerSample, ImagerPixel, ImagerTransformation, PDFileWriter, Real, SF EXPORTS ImagerPDPrivate, ImagerPD ~ 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 => { IF ImagerColorPrivate.SupportsOutput[color.colorOperator, $CMYK] THEN { 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[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]]; }; 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] = { 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 { 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 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. ΐImagerPDColorImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Maureen Stone, June 11, 1987 6:28:23 pm PDT Check here for different color operators set primaries directly, no color correction SetColorFromRGB may do color correction 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 Sets the color correction proc, which will be called once per pixel for each sampled color, and once for each constant color. Can turn this to a 16 by 16 brick. Computed the corrected pixels for all four separations ΚM˜codešœ™Kšœ Οmœ7™BK™+—šΟk ˜ Jšœ5Οc œžœ˜γ—K˜KšΡblnœžœž˜ KšžœŸ œƒž˜ΈKšžœ˜!šœž˜Kšžœžœžœ˜Kšœ žœ˜Kšœžœ˜#Kšœžœžœžœ˜,Kšœ žœ˜)Kšœžœ˜ Kšœžœ'˜;Kšœžœ˜0Kšœžœ˜.Kšœžœ˜.Kšœžœ˜0Kšœ žœ˜)Kšœ žœ˜/Kšœžœ˜šœ žœ˜,K˜—šœ žœ˜,K˜—Kšžœžœžœ˜šœžœžœ˜+K˜—Kšœ žœ˜.Kšœžœ!˜4Kšžœžœžœ˜!Kšžœžœžœ˜K˜šœžœ˜0K˜—Kšœžœ˜#Kšœžœ˜/K˜šΟnœž œ@žœ ˜|Kšœžœ˜.Kšœ1˜1šΟbœžœžœ˜%šžœž˜Kšœ0˜0Kšœ2˜2Kšœ1˜1Kšœ0˜0Kšžœ'˜.—K˜—Kšœ˜Kšœžœ˜šžœžœž˜šœ$˜$š’ œžœ˜šžœž˜Kšžœ;˜?Kšžœžœl˜x—Kšœ˜—šžœ ž˜šœŸ˜-Kšœžœ ˜2Kšœ žœ3˜CKšœ_Ÿ*˜‰šžœž˜!šœŸ ˜*Kš œžœžœ&žœžœ˜EKšœ˜K˜—šœ"Ÿ ˜/Kšœžœ%žœ˜VKšœ$žœžœ˜0K˜—Kšžœ˜—K˜—šœŸΟi Ÿ ˜-Kšœžœ ˜2Kšœ žœ3˜CKšœaŸ*˜‹šžœžœ˜#šœŸ*˜IKš œžœžœžœžœ&˜NKšœ"Ÿ˜?šžœž œž˜š žœžœžœžœžœžœž˜>šžœžœ)ž˜FKšœ+žœžœ˜7—Kšžœ˜—K˜—K˜——Kšžœ˜K˜—Kšžœ˜—K˜—Kšœ'˜'™(šžœ?žœ˜GKšœ+™+Kšœžœ˜ Kšœ*žœ˜Cšœ žœ-˜>KšœH˜HKšœ˜—Kšœs˜sK˜K˜—šžœ˜Kšœ2˜2Kšœ'™'KšœO˜OK˜—Kšœ˜—šœ$˜$Kšœ˜Kšœ˜Kšœ3˜3KšœS˜SKšœ>˜>šžœž˜!Kšžœ'˜+šžœ˜Kšœ˜KšœS˜SKšœ˜——Kšœ˜—šœ$˜$Kšœ˜Kšœ˜Kšœ3˜3KšœS˜SKšœ˜—Kšžœžœ˜—šžœž˜ Kšœ žœžœžœžœ žœžœžœžœ˜žKšžœžœžœžœžœ žœžœžœžœ˜’—Kšœ˜K˜—K™OK™9K™RKšœ žœ˜šœ žœžœŸ'˜XKšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—Kš œ žœžœ žœžœ˜3KšœžœŸ ˜-š ‘ œžœžœ žœžœ žœ˜Ršžœžœžœž˜šžœ!žœ˜)Kšœ ˜ Kšœ˜Kšžœ ˜—Kšžœ˜—Kšžœ˜K˜—K˜K˜š‘œžœžœžœ)˜SKš žœžœžœžœžœŸ˜BKšœžœžœ žœ˜AKšœ˜K˜—š ‘œžœžœžœ1žœ˜`K™}Kšœ.˜.Kšœ)˜)K•StartOfExpansion|[x: FunctionCache.Cache, compare: FunctionCache.CompareProc, limit: INT _ 1, clientID: FunctionCache.ClientID _ NIL]šœ]žœžœŸ"˜£K˜K™—Kš œ žœžœžœ žœ˜7š ‘ œžœžœ žœžœ˜HKšœžœžœ ˜Kšžœ žœ žœžœ˜)Kšžœ žœžœ˜2šžœžœžœžœžœžœžœžœ žœ žœ žœ˜nK™"K–D[lgBitsPerPixel: [0..4], bounds: ImagerPixelMap.DeviceRectangle]šžœ#˜)Kšœ˜—Kšžœ$˜*Kšœ˜K˜—š‘ œžœžœ žœžœ žœžœžœ ˜}Kšœžœ&˜/Kšœ.˜.Kš œ'žœ žœžœ&žœžœ˜vš žœžœžœžœžœ˜4K–X[box: SF.Box, bitsPerSample: ImagerSample.BitsPerSample _ 1, bitsPerLine: INT _ 0]šœl˜lK–ο[map: ImagerSample.SampleMap, box: SF.Box _ [min: [s: -32768, f: -32768], max: [s: 32767, f: 32767]], tile: ImagerSample.SampleMap, phase: NAT _ 0, function: ImagerSample.Function _ [dstFunc: null, srcFunc: null]]šœ˜Kšœ>˜>Kšœ˜—Kšžœ@˜FKšœ˜K˜—š‘œžœžœ ˜.Kšžœ9žœ˜FJšœ˜K˜—š ‘œžœžœžœžœ˜@Kšœžœ+˜2K–X[box: SF.Box, bitsPerSample: ImagerSample.BitsPerSample _ 1, bitsPerLine: INT _ 0]šœžœ1˜9Kšœkžœ˜~K–C -- [base: LONG POINTER _ NIL, startIndex: INT _ 0, count: INT _ 0]šœA˜AKšœ&˜&Kšœžœžœ˜#Kšœžœžœ<˜NKšœ˜K–ͺ[dst: ImagerSample.SampleMap, src: ImagerSample.SampleMap, delta: SF.Vec _ [s: 0, f: 0], function: ImagerSample.Function _ [dstFunc: null, srcFunc: null]]šœ3˜3Kšœ ˜ šžœ ž˜Kš œžœžœžœžœ˜(Kšœ@˜@Kšœ˜Kšœ˜Kšžœ˜—Kšœ!˜!Kšœ˜K˜—š‘ œžœžœžœ˜/Kšžœžœžœžœ˜1Kšžœžœžœžœ˜)Kšžœ0˜6Kšœ˜K˜—š ‘œžœ,žœžœžœ˜[Kšœžœ+˜2Kšœžœžœ-˜?Kšœ žœ/˜?Kšžœ žœžœžœ žœžœ žœžœ˜SKšžœtžœžœ˜―K˜K˜—š‘ œžœžœžœ˜2K–Y[size: SF.Vec, bitsPerSample: ImagerSample.BitsPerSample _ 1, bitsPerLine: INT _ 0]šžœžœV˜bK˜K˜—š‘œžœ-žœžœ˜XKšœžœ˜ Kšœžœžœ˜0Kšœ žœžœ˜Kšœžœžœ˜š žœžœžœ2žœžœžœž˜[šžœžœžœ˜?Kšœžœ˜ Kšœ˜Kšœ˜—Kšžœ˜—šžœžœžœJžœ˜`Kšœ5˜5Kš œžœžœžœžœ&˜|Kšœžœ˜ Kšœ˜—–‹[pdState: PDFileWriter.PDState, toner: PDFileFormat.Toner, tileRef: PDFileWriter.LoadReference, tFlag: PDFileWriter.TFlag _ opaque]šžœ˜šžœ˜Kšœkžœžœ žœ ˜“Kšœ ˜ Kšœ˜—šžœ˜Kšœžœžœžœ˜?Kšœ˜Kšœ˜Kšžœžœ>˜KKšžœT˜XKšœ˜——K˜K˜—Kšœžœ˜'š‘œžœ.˜Cšžœž˜ KšœE˜Ešœ ˜ šžœ˜Kšžœ@˜DKšžœ?˜C—Kšœ˜—KšœE˜EKšžœžœ˜—Kšœ ˜ K˜K˜—š‘œžœžœ˜@šžœž˜ šœŸ ˜Kšœ ˜ Kšœ˜—šœŸ ˜Kšœ"˜"Kšœ˜—šžœ˜ Kšœ:˜:KšœS˜SKšœP˜PKšœAžœ˜VKšœžœ(˜8Kšœ˜šžœžœžœ$ž˜7Kšœs˜sšžœžœžœž˜"Kšœžœžœžœ˜&Kšžœ˜—KšœQ˜QKšžœ˜—Kšœmžœžœ˜€Kšœ&˜&Kšœ'˜'Kšœ˜——K˜K˜—KšœžœŸ˜.š‘œžœ*˜AKšœS˜SKšœP˜PKšœAžœ˜VKšœžœ4˜DKšœ˜šžœžœžœ$ž˜7Kšœs˜sšžœžœžœž˜"Kšœžœžœžœ˜&Kšžœ˜—KšœQ˜QKšžœ˜—Kšœmžœžœ˜€Kšœ&˜&Kšœ'˜'K˜K˜—š‘œžœ$‘œžœ˜Ešžœ#žœ&žœ%žœ˜|šžœžœžœ˜)Kšœ:˜:Kšœ:˜:Kšœ:˜:šœ˜Kšœ,˜,Kšœ žœŸ‚˜½Kšœ˜—šžœž˜KšœL˜LKšœN˜NKšœM˜MKšœL˜LKšžœ'˜.—K˜—šžœžœž˜!Kšœ6˜6Kšœ9˜9Kšœ8˜8Kšžœ'˜.—Kšœ˜—šžœžœ$žœ˜1Kšœ*˜*Kšœ˜—Kšžœžœ˜ K˜K˜—š‘œžœžœžœ˜8K˜—š‘œžœ+žœ˜RKšœžœ˜.šžœ$žœ˜BKšžœžœžœžœ ˜Bšžœ˜Kšœ9˜9Kšœ&žœ˜˜>Kšœ˜——Kšœ˜——K˜K˜—Kšœžœžœ˜1šœžœžœ˜$Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—š‘ œžœ"žœžœ˜FKšœžœ˜šžœžœžœž˜.KšœŒ˜ŒKšžœ˜—Kšžœ ˜Kšœ˜K˜—š‘œžœBžœ˜yKšœ9˜9Kšœ2˜2KšœF˜Fš‘œ˜&šžœ žœž˜Kšœžœžœ$˜TKšžœžœžœ˜—Kšœ˜—Kšœžœ9˜WKš œ žœžœ#žœ&žœ%˜‘Kšœžœžœ žœžœžœ3žœžœ˜„šžœžœžœ˜KšœI˜IKšœžœR˜[K–U[size: SF.Vec, bitsPerSample: IISample.BitsPerSample _ 1, bitsPerLine: NAT _ 0]šžœžœp˜„Kšœ˜—Kš žœ%žœžœžœžœžœ/˜sK˜K˜—š‘ œžœBžœ˜wKšœ2˜2KšœF˜FKš œ žœžœ#žœ&žœ%˜‘Kšœžœ;˜EKšœžœ žœžœ ˜4šœžœ˜šžœžœž˜Kš œ žœ$žœžœžœ Ÿ˜jKšœŸ˜KšžœŸ ˜——Kšœžœžœžœžœžœžœžœžœžœ8žœžœ˜΅Kšœ!žœ˜@Kšœ"žœžœžœ˜6Kšœƒ˜ƒšœžœ2˜GKšœ`˜`KšœP˜PKšœa˜ašžœžœžœž˜(Kšœ'˜'Kšžœ˜—šžœžœžœ ž˜K˜+šžœž˜KšœC˜Cšœ ˜ Kš‘ œ6˜@Kšœžœ"˜5Kšœ4˜4šžœžœž˜K™6Kšœ9Ÿ˜Q—šžœžœ˜šžœžœžœž˜Kšœžœžœžœ`˜rKšœžœžœžœ`˜rKšžœžœžœ žœžœžœžœŸ˜YKšžœ˜—Kšœ˜—Kšœ˜—šœ˜Kšœžœžœžœ`˜tKšœ4˜4šžœ˜ Kšžœžœžœ žœ žœžœžœŸ˜]Kšœ˜—Kšœ˜—Kšžœžœ˜—KšœH˜HKšžœ˜—Kšœ,˜,Kšœ+˜+K˜—KšœΏ˜ΏK–΄[s0: ImagerSample.SampleMap _ NIL, s1: ImagerSample.SampleMap _ NIL, s2: ImagerSample.SampleMap _ NIL, s3: ImagerSample.SampleMap _ NIL, s4: ImagerSample.SampleMap _ NIL]šžœ ˜Kšœ˜K˜—Jšžœ˜——…—Sβpο