<> <> <> <> <> <> <> <> <<>> DIRECTORY ColorRegistry, FunctionCache, Imager, ImagerBackdoor, ImagerBox, ImagerBrick, ImagerRavenBitmapContext, ImagerColor, ImagerColorPrivate, ImagerDevice, ImagerFont, ImagerMaskCache, ImagerPath, ImagerPixel, ImagerPixelArray, ImagerPrivate, ImagerRaster, ImagerSample, ImagerState, ImagerTransformation, Real, SF, Vector2; ImagerRavenBitmapContextImpl: CEDAR PROGRAM IMPORTS FunctionCache, Imager, ImagerBackdoor, ImagerColor, ImagerColorPrivate, ImagerDevice, ImagerMaskCache, ImagerPixel, ImagerPixelArray, ImagerRaster, ImagerSample, ImagerState, ImagerTransformation, Real, SF, Vector2 EXPORTS ImagerRavenBitmapContext, Imager SHARES ImagerSample ~ BEGIN <> Color: TYPE ~ ImagerColor.Color; ColorOperator: TYPE ~ ImagerColor.ColorOperator; Context: TYPE ~ Imager.Context; Device: TYPE ~ ImagerDevice.Device; Object: TYPE ~ Imager.Object; PixelMap: TYPE ~ ImagerPixel.PixelMap; PixelArray: TYPE ~ ImagerPixelArray.PixelArray; RasterSampleMap: TYPE ~ ImagerSample.RasterSampleMap; Rectangle: TYPE ~ ImagerBox.Rectangle; SampleMap: TYPE ~ ImagerSample.SampleMap; ScanMode: TYPE ~ ImagerTransformation.ScanMode; Transformation: TYPE ~ ImagerTransformation.Transformation; VEC: TYPE ~ Vector2.VEC; classCode: PUBLIC ATOM ¬ $Bitmap; Case: TYPE ~ {constant, tile, sampled, sampledBlack}; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ bitmap: SampleMap ¬ NIL, savedBuffer: ImagerSample.SampleMap ¬ NIL, case: Case ¬ constant, constant: [0..1] ¬ 1, function: ImagerSample.Function ¬ [null, null], maskBitmapFunction: ImagerSample.Function ¬ [null, null], tile: ImagerBrick.Brick ¬ [0, NIL, 0], -- bitmap for case=tile separation: ATOM, brick: ImagerBrick.Brick ¬ [0, NIL, 0], -- thresholds paToDevice: Transformation, source: ImagerPixel.PixelMap ¬ NIL, scratchSampleMapThatIsInUse: SampleMap ¬ NIL, -- SampleMap that should go back to the scratch pool at the next SetColor scratchStippleMap: SampleMap ¬ NIL, -- scratch storage for stipple case scratchPixelMap: PixelMap ¬ NIL, -- scratch descriptor for AccessBuffer scratchBitmapContext: Imager.Context ¬ NIL -- for making fancy tiles ]; <> Create: PUBLIC PROC [deviceSpaceSize: SF.Vec, scanMode: ScanMode, surfaceUnitsPerInch: VEC, pixelUnits: BOOL, fontCacheName: ATOM, deviceCode: ATOM ¬ $Raven300] RETURNS [Context] ~ { data: Data ~ NEW[DataRep ¬ [paToDevice: ImagerTransformation.Scale[1]]]; deviceParm: ImagerDevice.DeviceParm ¬ ImagerDevice.MakeDeviceParm[ class: deviceClass, sSize: deviceSpaceSize.s, fSize: deviceSpaceSize.f, scanMode: scanMode, surfaceUnitsPerInch: surfaceUnitsPerInch, surfaceUnitsPerPixel: 1, fontCache: IF fontCacheName = NIL THEN NIL ELSE ImagerMaskCache.GetNamedCache[fontCacheName] ]; context: Context ~ ImagerRaster.Create[class: contextClass, deviceClass: deviceClass, deviceParm: deviceParm, data: data, pixelUnits: pixelUnits]; <<>> <> black: ImagerColor.Color ¬ ImagerColor.Find["Xerox/Research/Distinct/Black"]; white: ImagerColor.Color ¬ ImagerColor.Find["Xerox/Research/Distinct/White"]; oldClass: REF ClassRep ¬ context.class; --crack the opaque type newClass: REF ClassRep ¬ NEW[ClassRep ¬ oldClass­]; ImagerRasterMaskVector ¬ oldClass.MaskVector; ImagerRasterMaskStroke ¬ oldClass.MaskStroke; newClass.MaskStroke ¬ MyMaskStroke; newClass.MaskVector ¬ MyMaskVector; Imager.PutProp[context, $DistinctBlack, black]; Imager.PutProp[context, $DistinctWhite, white]; Imager.PutProp[context, $DeviceCode, deviceCode]; Imager.PutProp[context, $DeviceIndex, NEW[NAT ¬ (SELECT deviceCode FROM $Raven300 => 7, $BWPlatemaker => 6, ENDCASE => 7)] ]; --from ColorRegistryImpl context.class ¬ newClass; --replace the class with our local subclass data.brick ¬ defaultBrick; ImagerRaster.SetDeviceClipBox[context, [[0,0], [0,0]]]; RETURN [context]; }; SetBitmap: PUBLIC PROC [context: Context, bitmap: SampleMap] ~ { data: Data ~ NARROW[ImagerRaster.GetDevice[context].data]; data.bitmap ¬ bitmap; ImagerRaster.SetDeviceClipBox[context, IF bitmap = NIL THEN [] ELSE ImagerSample.GetBox[bitmap]]; }; GetBitmap: PUBLIC PROC [context: Context] RETURNS [SampleMap] ~ { data: Data ~ NARROW[ImagerRaster.GetDevice[context].data]; RETURN [data.bitmap]; }; <> ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; PathProc: TYPE = ImagerPath.PathProc; <> ImagerRasterMaskVector: PROC [context: Context, p1, p2: VEC] ¬ NIL; ImagerRasterMaskStroke: PROC [context: Context, path: PathProc, closed: BOOL] ¬ NIL; DoDash: PROC[context: Context] RETURNS[BOOLEAN] = { WITH ImagerBackdoor.GetColor[context] SELECT FROM color: ImagerColor.SpecialColor => IF color.type=$Distinct THEN { nameData: ColorRegistry.Data ¬ NARROW[color.data]; IF nameData.id#$Black AND nameData.id#$White AND nameData.id#$Gray THEN { widthInPixels: REAL ¬ Vector2.Length[ImagerBackdoor.TransformVec[context: context, v: [ImagerBackdoor.GetReal[context, strokeWidth], 0], from: client, to: device]]; IF widthInPixels < 10 THEN RETURN[TRUE]; --define 10 device pixels as ok for texture }}; ENDCASE; RETURN[FALSE]; }; MyMaskVector: PROC [context: Context, p1, p2: VEC] = { IF DoDash[context] THEN { black: ImagerColor.Color ¬ NARROW[Imager.GetProp[context, $DistinctBlack]]; white: ImagerColor.Color ¬ NARROW[Imager.GetProp[context, $DistinctWhite]]; path: ImagerPath.PathProc = {moveTo[p1]; lineTo[p2]}; color: ImagerColor.SpecialColor ¬ NARROW[ImagerState.StateGetColor[context]]; ImagerState.StateSetColor[context, white]; ImagerRasterMaskVector[context, p1, p2]; ImagerState.StateSetColor[context, black]; IRBMaskDashedStroke[context, color, path, FALSE]; ImagerState.StateSetColor[context, color]; } ELSE ImagerRasterMaskVector[context, p1, p2]; }; MyMaskStroke: PROC [context: Context, path: PathProc, closed: BOOL] = { IF DoDash[context] THEN { black: ImagerColor.Color ¬ NARROW[Imager.GetProp[context, $DistinctBlack]]; white: ImagerColor.Color ¬ NARROW[Imager.GetProp[context, $DistinctWhite]]; color: ImagerColor.SpecialColor ¬ NARROW[ImagerState.StateGetColor[context]]; ImagerState.StateSetColor[context, white]; ImagerRasterMaskStroke[context, path, closed]; ImagerState.StateSetColor[context, black]; IRBMaskDashedStroke[context, color, path, closed]; ImagerState.StateSetColor[context, color]; } ELSE ImagerRasterMaskStroke[context, path, closed]; }; yellowDash: ARRAY [0..3] OF REAL ¬ [0,2.5,0,2.5]; redDash: ARRAY [0..3] OF REAL ¬ [3,2,3,2]; greenDash: ARRAY [0..3] OF REAL ¬ [1,2,1,2]; blueDash: ARRAY [0..3] OF REAL ¬ [4,2,1,2]; IRBMaskDashedStroke: PROC [context: Context, color: ImagerColor.SpecialColor, path: PathProc, closed: BOOL] = { nameData: ColorRegistry.Data ¬ NARROW[color.data]; Inner: PROC ~ { unit: REAL ¬ 8; array: ARRAY [0..3] OF REAL ¬ SELECT nameData.id FROM $Red => redDash, $Green => greenDash, $Blue => blueDash, $Yellow => yellowDash, ENDCASE => ERROR; Pattern: PROC[i: NAT] RETURNS[REAL] = { v: VEC ¬ ImagerBackdoor.TransformVec[context: context, v: [array[i]*unit, 0], from: device, to: client]; RETURN[Vector2.Length[v]]}; Imager.SetStrokeEnd[context, round]; Imager.SetStrokeJoint[context, round]; Imager.MaskDashedStroke[context, path, 4, Pattern, 0, 0]; }; Imager.DoSave[context, Inner]; }; <> MakeSimpleBrick: PROC [t: ARRAY [0..4) OF PACKED ARRAY [0..4) OF [0..16)] RETURNS [ImagerBrick.Brick] ~ { b: SampleMap ~ ImagerSample.NewSampleMap[box: [max: [4, 4]], bitsPerSample: 8]; FOR s: NAT IN [0..4) DO FOR f: NAT IN [0..4) DO ImagerSample.Put[b, [s, f], t[s][f]]; ENDLOOP; ENDLOOP; RETURN [[maxSample: 15, sampleMap: b, phase: 0]] }; coarseBrick: ImagerBrick.Brick ¬ MakeSimpleBrick[[ [00, 01, 13, 14], [08, 02, 03, 15], [09, 10, 04, 05], [07, 11, 12, 06] ]]; fineBrick: ImagerBrick.Brick ¬ MakeSimpleBrick[[ [00, 08, 02, 10], [14, 04, 12, 06], [03, 11, 01, 09], [13, 07, 15, 05] ]]; defaultBrick: ImagerBrick.Brick ¬ fineBrick; SetBrick: PUBLIC PROC [context: Context, brick: ImagerBrick.Brick] ~ { WITH ImagerRaster.GetDevice[context].data SELECT FROM data: Data => { data.brick ¬ brick; Imager.SetColor[context, ImagerBackdoor.GetColor[context]]; -- to re-validate the color }; ENDCASE => NULL; }; GetBrick: PUBLIC PROC [context: Context] RETURNS [ImagerBrick.Brick] ~ { WITH ImagerRaster.GetDevice[context].data SELECT FROM data: Data => { RETURN [data.brick] }; ENDCASE => NULL; RETURN [[0, NIL, 0]] }; SetSeparation: PUBLIC PROC [context: Context, separation: ATOM] ~ { WITH ImagerRaster.GetDevice[context].data SELECT FROM data: Data => { data.separation ¬ separation; Imager.SetColor[context, ImagerBackdoor.GetColor[context]]; -- to re-validate the color }; ENDCASE => NULL; }; GetSeparation: PUBLIC PROC [context: Context] RETURNS [ATOM] ~ { WITH ImagerRaster.GetDevice[context].data SELECT FROM data: Data => { RETURN [data.separation] }; ENDCASE => NULL; RETURN [NIL] }; GetExtendedBox: PROC [brick: ImagerBrick.Brick] RETURNS [SF.Box] ~ { <> box: SF.Box ¬ ImagerSample.GetBox[brick.sampleMap]; size: SF.Vec ~ ImagerSample.GetSize[brick.sampleMap]; fSizeBox: NAT ~ size.f; IF brick.phase = 0 AND size.f IN [1..16) AND size.s IN [1..16) AND 16 MOD NAT[size.f] = 0 THEN { box.max.f ¬ box.min.f+16; }; RETURN [box] }; MakeTile: PROC [f: REAL, brick: ImagerBrick.Brick] RETURNS [ImagerBrick.Brick] ~ { box: SF.Box ~ GetExtendedBox[brick]; sample: CARDINAL ~ Real.Round[f*(brick.maxSample+1)]; b: ImagerSample.SampleBuffer ~ ImagerSample.ObtainScratchSamples[SF.SizeF[box]]; sampleMap: SampleMap ~ ImagerSample.ObtainScratchMap[box]; FOR s: INTEGER IN [box.min.s..box.max.s) DO ImagerSample.GetTileSamples[tile: brick.sampleMap, phase: brick.phase, initIndex: [s, 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: sampleMap, initIndex: [s, box.min.f], buffer: b]; ENDLOOP; ImagerSample.ReleaseScratchSamples[b]; RETURN [[maxSample: 1, sampleMap: sampleMap, phase: brick.phase]]; }; FractionFromConstantColor: PROC [data: Data, c: ImagerColor.OpConstantColor] RETURNS [REAL] ~ { f: REAL ~ ImagerColorPrivate.GrayFromColor[c]; <> RETURN [f] }; SampledColorData: TYPE ~ REF SampledColorDataRep; SampledColorDataRep: TYPE ~ RECORD [ pa: PixelArray, colorOperator: ColorOperator, separation: ATOM, maxSample: CARDINAL, filterDiameter: NAT, source: ImagerPixel.PixelMap ]; me: REF TEXT ~ "Bitmap"; -- a globally unique REF for use as a clientID in the global cache. BitmapSetColor: PROC [device: Device, color: Color, viewToDevice: Transformation] ~ { data: Data ~ NARROW [device.data]; realRaster: BOOL ~ WITH data.bitmap SELECT FROM r: RasterSampleMap => TRUE ENDCASE => FALSE; allowBitmaps, hardSampledCase: BOOL; { <> data.source ¬ NIL; data.tile.sampleMap ¬ NIL; IF data.scratchSampleMapThatIsInUse # NIL THEN { ImagerSample.ReleaseScratchMap[data.scratchSampleMapThatIsInUse]; data.scratchSampleMapThatIsInUse ¬ NIL; }; }; WITH color SELECT FROM c: ImagerColor.OpConstantColor => { f: REAL ~ FractionFromConstantColor[data, c]; data.case ¬ constant; data.function ¬ [null, null]; SELECT f FROM < 0.00001 => { data.case ¬ constant; data.constant ¬ 0 }; > 0.99999 => { data.case ¬ constant; data.constant ¬ 1 }; ENDCASE => { data.tile ¬ MakeTile[f, data.brick]; data.scratchSampleMapThatIsInUse ¬ data.tile.sampleMap; data.case ¬ tile; }; }; sampledColor: ImagerColor.SampledColor => { BitmapSetSampledColor[device: device, sampledColor: sampledColor, viewToDevice: viewToDevice]; }; s: ImagerColor.SampledBlack => { pa: PixelArray ~ s.pa; ImagerTransformation.ApplyCat[data.paToDevice, pa.m, s.um, viewToDevice]; data.function ¬ IF s.clear THEN [or, null] ELSE [null, null]; SELECT TRUE FROM data.paToDevice.form = 3 AND data.paToDevice.integerTrans => { <> min: SF.Vec ~ [s: data.paToDevice.tx, f: data.paToDevice.ty]; max: SF.Vec ~ [s: min.s + pa.sSize, f: min.f + pa.fSize]; sampleMap: SampleMap ~ ImagerSample.ObtainScratchMap[box: [min: min, max: max]]; ImagerPixelArray.Transfer[pa: pa, dst: sampleMap, dstMin: min]; data.case ¬ tile; data.tile.maxSample ¬ 1; data.tile.sampleMap ¬ sampleMap; data.scratchSampleMapThatIsInUse ¬ sampleMap; data.tile.phase ¬ 0; }; newStuff AND TryTransformingBitmapIntoTile[data, pa] => { <> }; ENDCASE => { <> sampleMap: SampleMap ~ ImagerSample.ObtainScratchMap[box: [max: [pa.sSize, pa.fSize]]]; ImagerPixelArray.Transfer[pa: pa, dst: sampleMap]; data.case ¬ sampledBlack; data.source ¬ ImagerPixel.MakePixelMap[sampleMap]; data.scratchSampleMapThatIsInUse ¬ sampleMap; }; }; s: ImagerColor.SpecialColor => { SELECT s.type FROM $Stipple => { stippleData: ImagerColorPrivate.StippleData ~ NARROW[s.data]; data.function ¬ stippleData.function; SELECT stippleData.word FROM 00000H => { data.case ¬ constant; data.constant ¬ 0 }; 0FFFFH => { data.case ¬ constant; data.constant ¬ 1 }; ENDCASE => { data.case ¬ tile; data.tile.sampleMap ¬ data.scratchStippleMap ¬ ImagerSample.TileFromStipple[stipple: stippleData.word, scratch: data.scratchStippleMap]; data.tile.phase ¬ 0; }; }; $BitmapTile => { <> list: LIST OF REF ~ NARROW[s.data]; brick: REF ImagerBrick.Brick ~ NARROW[list.first]; rf: REF ImagerSample.Function ~ NARROW[list.rest.first]; data.function ¬ rf­; data.case ¬ tile; data.tile.sampleMap ¬ brick.sampleMap; data.tile.phase ¬ brick.phase; }; <<$Distinct, $ChipNDale => { -- the distinct named colors nameData: ColorRegistry.Data ¬ NARROW[s.data]; deviceIndex: NAT ¬ NARROW[Imager.GetProp[context, $DeviceIndex], REF NAT]­; deviceCode: ATOM ¬ NARROW[Imager.GetProp[context, $DeviceCode]]; value: REF ColorRegistry.DisplayBrick; ColorRegistryProcs.InitPrinterColors[deviceType: deviceCode, colorType: s.type]; --won't do any work if already initialized value ¬ NARROW[nameData.deviceValues[deviceIndex]]; data.function ¬ value.function; data.case ¬ tile; data.tile.sampleMap ¬ value.tile.sampleMap; data.tile.phase ¬ value.tile.phase; };>> ENDCASE => { IF s.substitute # NIL THEN { BitmapSetColor[device, s.substitute, viewToDevice] } ELSE { ERROR Imager.Error[[code: $unknownSpecialColor, explanation: "Unknown special color has no substitute value"]] }; }; }; ENDCASE => ERROR; data.maskBitmapFunction ¬ [null, null]; IF data.case = constant THEN SELECT data.function FROM [null, null] => { SELECT data.constant FROM 0 => data.maskBitmapFunction ¬ [and, complement]; 1 => data.maskBitmapFunction ¬ [or, null]; ENDCASE => NULL; }; [xor, null] => { IF data.constant = 1 THEN data.maskBitmapFunction ¬ [xor, null]; }; ENDCASE => NULL; allowBitmaps ¬ (data.maskBitmapFunction # [null, null]); hardSampledCase ¬ data.case = sampledBlack OR data.case = sampled; device.state.allow ¬ [ unorderedBoxes: NOT hardSampledCase, multipleCoverage: (data.function.dstFunc # xor AND NOT hardSampledCase), regionFill: data.case = constant AND realRaster, bitmap: allowBitmaps, rawBitmaps: allowBitmaps AND realRaster, runGroupChar: FALSE, rasterChar: FALSE, maskThinVector: FALSE ]; }; newStuff: BOOL ¬ TRUE; -- for testing TryTransformingBitmapIntoTile: PROC [data: Data, pa: PixelArray] RETURNS [BOOL] ~ { m: Transformation ~ data.paToDevice; IF m.form#0 THEN { sRect: Rectangle ~ [0, 0, pa.sSize, pa.fSize]; dRect: Rectangle ~ ImagerTransformation.TransformRectangle[m, sRect]; IF MAX[ABS[dRect.x], ABS[dRect.y], ABS[dRect.w], ABS[dRect.h]] <= 16383 AND ABS[dRect.w*dRect.h] <= 1048576.0 THEN { sSize: NAT ~ Real.Round[dRect.w]; fSize: NAT ~ Real.Round[dRect.h]; IF dRect.w-sSize+4.0 = 4.0 AND dRect.h-fSize+4.0 = 4.0 THEN { <> action: PROC ~ { pamInverse: Transformation ~ ImagerTransformation.Invert[pa.m]; Imager.TranslateT[data.scratchBitmapContext, [-dRect.x, -dRect.y]]; Imager.ConcatT[data.scratchBitmapContext, m]; Imager.ConcatT[data.scratchBitmapContext, pamInverse]; Imager.MaskPixel[data.scratchBitmapContext, pa]; ImagerTransformation.Destroy[pamInverse]; }; sampleMap: SampleMap ¬ ImagerSample.ObtainScratchMap[box: [max: [sSize, fSize]]]; tileMap: SampleMap ~ ImagerSample.Shift[sampleMap, [s: Real.Floor[dRect.x+0.5], f: Real.Floor[dRect.y+0.5]]]; ImagerSample.Clear[sampleMap]; IF data.scratchBitmapContext = NIL THEN data.scratchBitmapContext ¬ Create[deviceSpaceSize: SF.maxVec, scanMode: [slow: right, fast: up], surfaceUnitsPerInch: [1,1], pixelUnits: TRUE, fontCacheName: $Bitmap]; SetBitmap[data.scratchBitmapContext, sampleMap]; Imager.DoSave[data.scratchBitmapContext, action]; SetBitmap[data.scratchBitmapContext, NIL]; TRUSTED {ImagerSample.ReleaseDescriptor[sampleMap]; sampleMap ¬ NIL}; data.case ¬ tile; data.tile.maxSample ¬ 1; data.tile.sampleMap ¬ tileMap; data.scratchSampleMapThatIsInUse ¬ tileMap; data.tile.phase ¬ 0; RETURN [TRUE]; }; }; }; RETURN [FALSE]; }; ComputeSource: PROC [sampledColor: ImagerColor.SampledColor, maxOut: PROC [i: NAT] RETURNS [CARDINAL], filterDiameter: NAT, separation: ATOM] RETURNS [ImagerPixel.PixelMap] ~ { colorOperator: ColorOperator ~ sampledColor.colorOperator; pixelMap: ImagerPixel.PixelMap ~ ImagerColorPrivate.Translate[colorOperator: sampledColor.colorOperator, output: [type: $Y, samplesPerPixelOut: 1], pa: sampledColor.pa, maxOut: maxOut]; <> RETURN [pixelMap] }; BitmapSetSampledColor: PROC [device: Device, sampledColor: ImagerColor.SampledColor, viewToDevice: Transformation] ~ { data: Data ~ NARROW [device.data]; pa: PixelArray ~ sampledColor.pa; largerPaSize: NAT ~ MIN[pa.sSize, pa.fSize] + 1; cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[]; filterDiameter: NAT ¬ 1; -- for low-pass filtering scd: SampledColorData ¬ NIL; compare: FunctionCache.CompareProc ~ { WITH argument SELECT FROM scd: SampledColorData => RETURN [scd.pa = pa AND scd.colorOperator = sampledColor.colorOperator AND scd.separation = data.separation AND scd.maxSample = data.brick.maxSample+1 AND scd.filterDiameter = filterDiameter]; ENDCASE => RETURN [FALSE] }; maxOut: PROC [i: NAT] RETURNS [CARDINAL] ~ { RETURN [data.brick.maxSample+1] }; ImagerTransformation.ApplyCat[data.paToDevice, pa.m, sampledColor.um, viewToDevice]; IF interpolate THEN filterDiameter ¬ MIN[MAX[Real.Round[1.0/MAX[ImagerTransformation.SingularValues[data.paToDevice].y, 1.0/largerPaSize]], 1], 255]; data.case ¬ sampled; data.function ¬ [null, null]; IF pa.immutable THEN { scd ¬ NARROW[FunctionCache.Lookup[cache, compare, me].value]; IF scd = NIL THEN { pixelMap: ImagerPixel.PixelMap ~ ComputeSource[sampledColor, maxOut, filterDiameter, data.separation]; scd ¬ NEW [SampledColorDataRep ¬ [pa: pa, colorOperator: sampledColor.colorOperator, separation: data.separation, maxSample: data.brick.maxSample+1, filterDiameter: filterDiameter, source: pixelMap]]; FunctionCache.Insert[x: cache, argument: scd, value: scd, size: ImagerSample.WordsForMap[size: ImagerSample.GetSize[pixelMap[0]], bitsPerSample: ImagerSample.GetBitsPerSample[pixelMap[0]]], clientID: me]; }; data.source ¬ scd.source; } ELSE { data.source ¬ ComputeSource[sampledColor, maxOut, filterDiameter, data.separation]; <> }; }; <> interpolate: BOOL ¬ FALSE; BitmapMaskBoxes: PROC [device: Device, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { data: Data ~ NARROW[device.data]; SELECT data.case FROM constant => { ImagerSample.FillBoxes[map: data.bitmap, boxes: boxes, value: data.constant, function: data.function]; }; tile => { ImagerSample.TileBoxes[map: data.bitmap, boxes: boxes, tile: data.tile.sampleMap, phase: data.tile.phase, function: data.function]; }; sampled => TRUSTED { buffer: ImagerSample.SampleBuffer ~ ImagerSample.ObtainScratchSamples[SF.SizeF[bounds]]; Action: SAFE PROC [pixels: ImagerPixel.PixelBuffer, min: SF.Vec] ~ TRUSTED { buffer.length ¬ pixels.length; ImagerSample.GetTileSamples[tile: data.brick.sampleMap, initIndex: min, buffer: buffer, phase: data.brick.phase]; ImagerSample.Halftone[map: data.bitmap, min: min, sampleBuffer: pixels[0], thresholdBuffer: buffer, function: data.function]; }; ImagerPixel.Resample[self: data.source, m: data.paToDevice, interpolate: interpolate, boxes: boxes, bounds: bounds, action: Action]; ImagerSample.ReleaseScratchSamples[buffer]; }; sampledBlack => { Action: PROC [pixels: ImagerPixel.PixelBuffer, min: SF.Vec] ~ { ImagerSample.PutSamples[map: data.bitmap, initIndex: min, buffer: pixels[0], start: 0, count: pixels.length, function: data.function]; }; ImagerPixel.Resample[self: data.source, m: data.paToDevice, interpolate: FALSE, boxes: boxes, bounds: bounds, action: Action]; }; ENDCASE => ERROR; }; BitmapMaskRegion: PROC [device: Device, bounds: SF.Box, edgeGenerator: PROC [ImagerSample.EdgeAction]] ~ { data: Data ~ NARROW[device.data]; IF data.case # constant THEN ERROR; ImagerSample.RegionFill[dst: NARROW[data.bitmap], edgeGenerator: edgeGenerator, value: data.constant, function: data.function]; }; BitmapMaskBitmap: PROC [device: Device, bitmap: SampleMap, delta: SF.Vec, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { data: Data ~ NARROW[device.data]; ImagerSample.TransferBoxes[dst: data.bitmap, src: bitmap, delta: delta, boxes: boxes, function: data.maskBitmapFunction]; }; BitmapMaskRawBitmaps: PROC [device: Device, list: LIST OF ImagerSample.RawDescriptor] ~ { data: Data ~ NARROW[device.data]; ImagerSample.RawListTransfer[dst: NARROW[data.bitmap], src: list, function: data.maskBitmapFunction]; }; BitmapDrawBitmap: PROC [device: Device, bitmap: SampleMap, delta: SF.Vec, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { data: Data ~ NARROW[device.data]; ImagerSample.TransferBoxes[dst: data.bitmap, src: bitmap, delta: delta, boxes: boxes]; }; BitmapMoveBox: PROC [device: Device, dstMin, srcMin, size: SF.Vec] ~ { data: Data ~ NARROW[device.data]; ImagerSample.Move[map: data.bitmap, dstMin: dstMin, srcMin: srcMin, size: size]; }; BitmapSwitchBuffer: PROC [device: Device, bounds: SF.Box, copy: BOOL, alt: BOOL] ~ { data: Data ~ NARROW[device.data]; oldBuffer: SampleMap ~ data.bitmap; newBuffer: SampleMap ~ IF alt THEN ImagerSample.ObtainScratchMap[box: bounds, bitsPerSample: 1] ELSE data.savedBuffer; IF copy THEN ImagerSample.Transfer[dst: newBuffer, src: oldBuffer]; data.bitmap ¬ newBuffer; IF alt THEN { data.savedBuffer ¬ oldBuffer } ELSE { data.savedBuffer ¬ NIL; ImagerSample.ReleaseScratchMap[oldBuffer] }; }; <> objectCache: FunctionCache.Cache ¬ FunctionCache.Create[maxEntries: 30, maxTotalSize: 250000]; ObjectCacheData: TYPE ~ REF ObjectCacheDataRep; ObjectCacheDataRep: TYPE ~ RECORD [ object: Object, clientToDevice: Transformation, v: SELECT tag: * FROM notCached => [], bitmap => [bitmap: SampleMap], < [boxes: ManhattanPolygon],>> ENDCASE ]; < {ok ¬ FALSE; CONTINUE}]; IF ok THEN { o: REF ObjectCacheDataRep.bitmap ¬ NEW[ObjectCacheDataRep.bitmap]; objectCacheData ¬ o; o.bitmap ¬ bitmap; size ¬ ImagerSample.WordsForMap[ImagerSample.GetSize[bitmap]] + 10; } ELSE { objectCacheData ¬ NEW[ObjectCacheDataRep.notCached]; size ¬ SIZE[ObjectCacheDataRep.notCached]; }; objectCacheData.object ¬ object; objectCacheData.clientToDevice ¬ ImagerTransformation.Copy[clientToDevice]; FunctionCache.Insert[x: objectCache, argument: objectCacheData, value: objectCacheData, size: size, clientID: NIL]; }; WITH objectCacheData SELECT FROM ocd: REF ObjectCacheDataRep.bitmap => { t1: VEC ~ ImagerTransformation.TransformVec[clientToDevice, position]; t2: VEC ~ [clientToDevice.c, clientToDevice.f]; t3: VEC ~ [ocd.clientToDevice.c, ocd.clientToDevice.f]; t: VEC ¬ Vector2.Add[t1, Vector2.Sub[t2, t3]]; save: PROC ~ { ImagerBackdoor.SetT[context, identity]; Imager.MaskBitmap[context: context, bitmap: ocd.bitmap, scanMode: [slow: right, fast: up], position: t]; }; Imager.DoSave[context, save]; ImagerTransformation.Destroy[clientToDevice]; RETURN; }; ENDCASE => NULL; }; ImagerTransformation.Destroy[clientToDevice]; }; ImagerPrivate.DefaultDrawObject[context, object, position, interactive]; }; identity: Transformation ~ ImagerTransformation.Scale[1]; >> BitmapGetBufferColorOperator: PROC [context: Context] RETURNS [ColorOperator] ~ { RETURN [ImagerColor.NewColorOperatorGrayLinear[sWhite: 0, sBlack: 1]] }; BitmapAccessBuffer: PROC [device: Device, box: SF.Box, action: PROC [pixelMap: PixelMap]] ~ { data: Data ~ NARROW[device.data]; bitmap: SampleMap ~ ImagerSample.Clip[data.bitmap, box]; pixelMap: PixelMap ~ IF data.scratchPixelMap = NIL THEN NEW[ImagerPixel.PixelMapRep[1]] ELSE data.scratchPixelMap; data.scratchPixelMap ¬ NIL; pixelMap.box ¬ ImagerSample.GetBox[bitmap]; pixelMap[0] ¬ bitmap; action[pixelMap]; pixelMap[0] ¬ NIL; TRUSTED {ImagerSample.ReleaseDescriptor[bitmap]}; data.scratchPixelMap ¬ pixelMap; }; <> deviceClass: ImagerDevice.DeviceClass ~ NEW[ImagerDevice.DeviceClassRep ¬ [ SetColor: BitmapSetColor, SetPriority: NIL, MaskBoxes: BitmapMaskBoxes, MaskRegion: BitmapMaskRegion, MaskBitmap: BitmapMaskBitmap, MaskRawBitmaps: BitmapMaskRawBitmaps, DrawBitmap: BitmapDrawBitmap, MaskChar: NIL, MoveBox: BitmapMoveBox, SwitchBuffer: BitmapSwitchBuffer, AccessBuffer: BitmapAccessBuffer ]]; contextClass: ImagerPrivate.Class ~ CreateClass[]; CreateClass: PROC RETURNS [class: ImagerPrivate.Class] ~ INLINE { class ¬ ImagerRaster.CreateClass[type: classCode]; <> class.GetBufferColorOperator ¬ BitmapGetBufferColorOperator; }; END.