DIRECTORY Basics, FunctionCache, Imager, ImagerBitmapContext, ImagerColor, ImagerColorPrivate, ImagerPixel, ImagerPixelArray, ImagerPrintColor, ImagerSample, ImagerTransformation, PrintColor, SF, Real; ImagerPrintColorImpl: CEDAR PROGRAM IMPORTS FunctionCache, Imager, ImagerColorPrivate, ImagerPixelArray, ImagerSample, ImagerTransformation, SF, Real, ImagerPixel EXPORTS ImagerPrintColor ~ BEGIN kU: PrintColor.TonerUniverse ~ [black: TRUE]; cmyU: PrintColor.TonerUniverse ~ [cyan: TRUE, magenta: TRUE, yellow: TRUE]; cmykU: PrintColor.TonerUniverse ~ [black: TRUE, cyan: TRUE, magenta: TRUE, yellow: TRUE]; 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]]; }; 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]; }; NewDeviceColorData: PUBLIC PROC [logicalDevice: PrintColor.LogicalDevice, halftoneProperties: PrintColor.HalftoneProperties, correction: PrintColor.ColorCorrection _ NIL, interpolate: BOOL _ FALSE] RETURNS [ImagerPrintColor.DeviceColorData] ~ { deviceColorData: ImagerPrintColor.DeviceColorData _ NEW[ImagerPrintColor.DeviceColorDataRep]; deviceColorData.halftoneProperties _ halftoneProperties; deviceColorData.correction _ correction; deviceColorData.interpolate _ interpolate; deviceColorData.case _ nil; deviceColorData.pixelToDevice _ ImagerTransformation.Scale[1]; deviceColorData.bitmap _ NEW[ImagerPixel.PixelMapRep[1]]; deviceColorData.tonerUniverse _ ALL[FALSE]; FOR each: LIST OF PrintColor.HalftonePropertiesForSeparation _ halftoneProperties, each.rest UNTIL each = NIL DO deviceColorData.tonerUniverse[each.first.toner] _ TRUE; ENDLOOP; RETURN [deviceColorData] }; SetSeparation: PUBLIC PROC [deviceColorData: ImagerPrintColor.DeviceColorData, toner: PrintColor.Toner] ~ { IF NOT deviceColorData.tonerUniverse[toner] THEN ERROR Imager.Error[[code: $invalidToner, explanation: "Illegal toner (no halftone properties supplied)"]]; deviceColorData.brick _ [0, NIL, 0]; FOR each: LIST OF PrintColor.HalftonePropertiesForSeparation _ deviceColorData.halftoneProperties, each.rest UNTIL each = NIL DO IF each.first.toner = toner THEN deviceColorData.brick _ each.first.brick; ENDLOOP; deviceColorData.toner _ toner; }; SetDeviceColorData: PUBLIC PROC [deviceColorData: ImagerPrintColor.DeviceColorData, color: ImagerColor.Color, viewToDevice: ImagerTransformation.Transformation] ~ { deviceColorData.case _ nil; deviceColorData.ink _ set; deviceColorData.tileBits _ NIL; deviceColorData.alpha _ 255; deviceColorData.separation _ NIL; deviceColorData.bitmap[0] _ NIL; IF deviceColorData.sampleMapInUse # NIL THEN { ImagerSample.ReleaseScratchMap[deviceColorData.sampleMapInUse]; deviceColorData.sampleMapInUse _ NIL; }; deviceColorData.function _ [null, null]; DO WITH color SELECT FROM specialColor: ImagerColor.SpecialColor => { SELECT specialColor.type FROM $PrintColor => { data: PrintColor.PrintSpecialColorData ~ NARROW[specialColor.data]; IF deviceColorData.logicalDevice < data.size THEN { IF data[deviceColorData.logicalDevice] = NIL THEN { }; IF data[deviceColorData.logicalDevice] # NIL THEN { SetLogicalDeviceColor[deviceColorData, data[deviceColorData.logicalDevice]]; RETURN; }; }; color _ specialColor.substitute; LOOP; }; ENDCASE => { IF specialColor.substitute = NIL THEN ERROR Imager.Error[[code: $unknownSpecialColor, explanation: "Unknown special color has no substitute value"]] ELSE { color _ specialColor.substitute; LOOP } }; }; opColor: ImagerColor.OpConstantColor => { SetOpConstantColor[deviceColorData, opColor]; }; sampledColor: ImagerColor.SampledColor => { ImagerTransformation.ApplyCat[deviceColorData.pixelToDevice, sampledColor.pa.m, sampledColor.um, viewToDevice]; SetSampledColor[deviceColorData, sampledColor]; }; sampledBlack: ImagerColor.SampledBlack => { ImagerTransformation.ApplyCat[deviceColorData.pixelToDevice, sampledBlack.pa.m, sampledBlack.um, viewToDevice]; SetSampledBlack[deviceColorData, sampledBlack]; }; ENDCASE => ERROR; EXIT; ENDLOOP; }; SetInk: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, ink: PrintColor.Ink] ~ { deviceColorData.case _ constant; deviceColorData.ink _ ink; }; SetFraction: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, f: REAL] ~ { SELECT f FROM >= 0.9999 => { -- all toner SetInk[deviceColorData, set] }; <= 0.0001 => { -- no toner SetInk[deviceColorData, remove] }; ENDCASE => { brick: ImagerBitmapContext.Brick ~ deviceColorData.brick; 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; SetTile[deviceColorData: deviceColorData, tileBits: bitmap, tilePhase: shape.phase, function: [null, null]]; deviceColorData.sampleMapInUse _ bitmap; -- for eventual recycling }; }; SetTile: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, tileBits: ImagerSample.SampleMap, tilePhase: NAT, function: ImagerSample.Function] ~ { deviceColorData.case _ tile; deviceColorData.tileBits _ tileBits; deviceColorData.tilePhase _ tilePhase; deviceColorData.function _ function; }; SetLogicalDeviceColor: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, lData: PrintColor.LogicalDeviceColorData] ~ { IF deviceColorData.logicalDevice # lData.logicalDevice THEN ERROR; -- bad color def FOR e: LIST OF PrintColor.BehaviorForSeparation _ lData.behaviors, e.rest UNTIL e = NIL DO b: PrintColor.BehaviorForSeparation ~ e.first; IF b.toner = deviceColorData.toner THEN { WITH b SELECT FROM b: REF PrintColor.BehaviorForSeparationRep.constant => SetInk[deviceColorData, b.ink]; b: REF PrintColor.BehaviorForSeparationRep.fraction => SetFraction[deviceColorData, b.f]; b: REF PrintColor.BehaviorForSeparationRep.tile => SetTile[deviceColorData, b.tileBits, b.tilePhase, b.function]; ENDCASE => ERROR; RETURN; }; ENDLOOP; SetInk[deviceColorData, remove]; -- no behavior was specified. }; SetSubtractivePrimaries: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, color: ImagerColor.OpConstantColor, output: ImagerColorPrivate.ColorOutput] ~ { indexFromToner: ARRAY PrintColor.Toner[black..yellow] OF NAT ~ [cyan: 0, magenta: 1, yellow: 2, black: 3]; min: PrintColor.Toner ~ IF output.type = $CMYK THEN black ELSE cyan; PixelIn: ImagerColorPrivate.PixelProc ~ { RETURN[color.pixel[i]] }; DoTuple: PROC [tupleOut: ImagerColorPrivate.TupleProc] ~ { IF deviceColorData.toner IN [min..yellow] THEN {SetFraction[deviceColorData, tupleOut[indexFromToner[deviceColorData.toner]]]} ELSE {SetInk[deviceColorData, remove]}; }; ImagerColorPrivate.TupleFromPixel[color.colorOperator, output, PixelIn, DoTuple]; }; SetRGB: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, rgb: ImagerColor.RGB] ~ { IF deviceColorData.correction # NIL THEN { pixelsRGB: ImagerPixel.PixelBuffer ~ ImagerPixel.ObtainScratchPixels[samplesPerPixel: 3, length: 1]; pixelsOut: ImagerPixel.PixelBuffer ~ ImagerPixel.ObtainScratchPixels[samplesPerPixel: IF deviceColorData.tonerUniverse[black] THEN 4 ELSE 3, length: 1]; pixelsRGB[0][0] _ Real.InlineRoundC[rgb.R*255]; pixelsRGB[1][0] _ Real.InlineRoundC[rgb.G*255]; pixelsRGB[2][0] _ Real.InlineRoundC[rgb.B*255]; deviceColorData.correction.correctionProc[self: deviceColorData.correction, pixelsOut: pixelsOut, maxSampleOut: ALL[255], rgbIn: pixelsRGB]; SetFraction[deviceColorData, SELECT deviceColorData.toner FROM cyan => pixelsOut[0][0]/255.0, magenta => pixelsOut[1][0]/255.0, yellow => pixelsOut[2][0]/255.0, black => pixelsOut[3][0]/255.0, ENDCASE => 0.0 ]; ImagerPixel.ReleaseScratchPixels[pixelsRGB]; ImagerPixel.ReleaseScratchPixels[pixelsOut]; } ELSE { SetFraction[deviceColorData, SELECT deviceColorData.toner FROM cyan => 1.0 - rgb.R, magenta => 1.0 - rgb.G, yellow => 1.0 - rgb.B, ENDCASE => 0.0 ]; }; }; SetGray: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, f: REAL] ~ { IF deviceColorData.tonerUniverse[black] THEN { IF deviceColorData.toner = black THEN SetFraction[deviceColorData, f] ELSE SetInk[deviceColorData, remove]; } ELSE { SetInk[deviceColorData, set]; SIGNAL Imager.Warning[[$illegalColor, "Unable to render gray on this device"]]; }; }; SetOpConstantColor: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, color: ImagerColor.OpConstantColor] ~ { tu: PrintColor.TonerUniverse ~ deviceColorData.tonerUniverse; SELECT tu FROM cmyU => { IF ImagerColorPrivate.SupportsOutput[color.colorOperator, $CMY] THEN { SetSubtractivePrimaries[deviceColorData, color, [type: $CMY, samplesPerPixelOut: 3]]; RETURN; }; }; cmykU => { IF ImagerColorPrivate.SupportsOutput[color.colorOperator, $CMYK] THEN { SetSubtractivePrimaries[deviceColorData, color, [type: $CMYK, samplesPerPixelOut: 4]]; RETURN; }; }; ENDCASE => NULL; IF tu[cyan] AND tu[magenta] AND tu[yellow] THEN { SetRGB[deviceColorData, ImagerColorPrivate.RGBFromColor[color]] } ELSE { SetGray[deviceColorData, 1.0 - ImagerColorPrivate.IntensityFromColor[color]] }; }; SampledColorData: TYPE ~ REF SampledColorDataRep; SampledColorDataRep: TYPE ~ RECORD [ pa: ImagerPixelArray.PixelArray, colorOperator: ImagerColor.ColorOperator, fullColor: BOOL, colorCorrection: PrintColor.ColorCorrection, source: ImagerPixel.PixelMap ]; SetSampledColor: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, color: ImagerColor.SampledColor] ~ { pa: ImagerPixelArray.PixelArray ~ color.pa; cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[]; colorOperator: ImagerColor.ColorOperator ~ color.colorOperator; tu: PrintColor.TonerUniverse ~ deviceColorData.tonerUniverse; fullColor: BOOL ~ colorOperator.chromatic AND tu[cyan] AND tu[magenta] AND tu[yellow]; Compare: FunctionCache.CompareProc ~ { WITH argument SELECT FROM scd: SampledColorData => RETURN [scd.pa = pa AND scd.colorOperator = colorOperator AND scd.fullColor = fullColor AND scd.colorCorrection = deviceColorData.correction]; ENDCASE => RETURN [FALSE] }; toner: PrintColor.Toner ~ deviceColorData.toner; index: NAT ~ IF fullColor THEN (SELECT toner FROM black => 3, cyan => 0, magenta => 1, yellow => 2, ENDCASE => 0) ELSE 0; scd: SampledColorData _ NARROW[FunctionCache.Lookup[x: cache, compare: Compare, clientID: $PrintColor].value]; IF scd = NIL THEN { pixelMap: ImagerPixel.PixelMap ~ ComputeSource[deviceColorData, color]; scd _ NEW [SampledColorDataRep _ [pa: pa, colorOperator: colorOperator, fullColor: fullColor, colorCorrection: deviceColorData.correction, source: pixelMap]]; IF pa.immutable THEN FunctionCache.Insert[x: cache, argument: scd, value: scd, size: PixelMapWords[pixelMap], clientID: $PrintColor]; }; IF index >= scd.source.samplesPerPixel THEN { SetInk[deviceColorData, remove] } ELSE { deviceColorData.case _ sampledColor; deviceColorData.separation _ ImagerPixel.MakePixelMap[scd.source[index]]; }; }; ComputeSource: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, color: ImagerColor.SampledColor] RETURNS [ImagerPixel.PixelMap] ~ { pa: ImagerPixelArray.PixelArray ~ color.pa; colorOperator: ImagerColor.ColorOperator ~ color.colorOperator; tu: PrintColor.TonerUniverse ~ deviceColorData.tonerUniverse; fullColor: BOOL ~ colorOperator.chromatic AND tu[cyan] AND tu[magenta] AND tu[yellow]; MaxOut: ImagerPixel.PixelProc ~ { RETURN[BYTE.LAST] }; -- for now SELECT tu FROM cmyU => { IF ImagerColorPrivate.SupportsOutput[color.colorOperator, $CMY] THEN { RETURN [ImagerColorPrivate.Translate[colorOperator: colorOperator, output: [type: $CMY, samplesPerPixelOut: 3], pa: pa, maxOut: MaxOut]] }; }; cmykU => { IF ImagerColorPrivate.SupportsOutput[color.colorOperator, $CMYK] THEN { RETURN [ImagerColorPrivate.Translate[colorOperator: colorOperator, output: [type: $CMYK, samplesPerPixelOut: 4], pa: pa, maxOut: MaxOut]] } }; ENDCASE => NULL; CHECKED { size: SF.Vec ~ [s: NAT[pa.sSize], f: NAT[pa.fSize]]; MaxIn: ImagerPixel.PixelProc ~ { RETURN[ImagerPixelArray.MaxSampleValue[pa, i]] }; samplesPerPixelOut: NAT ~ SELECT TRUE FROM fullColor AND tu[black] AND deviceColorData.correction#NIL => 4, -- CMYK fullColor => 3, -- CMY ENDCASE => 1; -- Intensity 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 ImagerPixelArray.GetPixels[pa: pa, s: s, f: 0, pixels: pixelsIn]; IF fullColor THEN { correction: PrintColor.ColorCorrection ~ deviceColorData.correction; translate[pixelsIn: pixelsIn, pixelsOut: pixelsRGB]; IF correction # NIL THEN { correction.correctionProc[self: correction, pixelsOut: pixelsOut, maxSampleOut: ALL[255], rgbIn: pixelsRGB]; } 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; }; } ELSE { 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 }; }; pixelMap.PutPixels[initIndex: [s, 0], pixels: pixelsOut, count: size.f]; ENDLOOP; ImagerPixel.ReleaseScratchPixels[pixelsIn]; ImagerPixel.ReleaseScratchPixels[pixelsRGB]; ImagerPixel.ReleaseScratchPixels[pixelsOut]; }; ImagerColorPrivate.TranslatePixels[colorOperator: colorOperator, output: IF fullColor THEN [type: $RGB, samplesPerPixelOut: 3] ELSE [type: $Y, samplesPerPixelOut: 1], maxIn: MaxIn, maxOut: MaxOut, translateAction: TranslateAction]; RETURN [pixelMap]; }; }; SetSampledBlack: PROC [deviceColorData: ImagerPrintColor.DeviceColorData, color: ImagerColor.SampledBlack] ~ { pa: ImagerPixelArray.PixelArray ~ color.pa; IF deviceColorData.tonerUniverse[black] AND deviceColorData.toner # black THEN { deviceColorData.case _ constant; deviceColorData.ink _ IF color.clear THEN nop ELSE remove; RETURN }; deviceColorData.function _ IF color.clear THEN [or, null] ELSE [null, null]; SELECT TRUE FROM deviceColorData.pixelToDevice.form = 3 AND deviceColorData.pixelToDevice.integerTrans => { min: SF.Vec ~ [s: deviceColorData.pixelToDevice.tx, f: deviceColorData.pixelToDevice.ty]; max: SF.Vec ~ [s: min.s + pa.sSize, f: min.f + pa.fSize]; sampleMap: ImagerSample.SampleMap ~ ImagerSample.ObtainScratchMap[box: [min: min, max: max]]; ImagerPixelArray.Transfer[pa: pa, dst: sampleMap, dstMin: min]; deviceColorData.case _ tile; deviceColorData.tilePhase _ 0; deviceColorData.tileBits _ sampleMap; deviceColorData.sampleMapInUse _ sampleMap; }; FALSE => { }; ENDCASE => { sampleMap: ImagerSample.SampleMap ~ ImagerSample.ObtainScratchMap[box: [max: [pa.sSize, pa.fSize]]]; ImagerPixelArray.Transfer[pa: pa, dst: sampleMap]; deviceColorData.case _ sampledBlack; deviceColorData.bitmap[0] _ sampleMap; deviceColorData.bitmap.box _ ImagerSample.GetBox[sampleMap]; deviceColorData.sampleMapInUse _ sampleMap; }; }; MaskBoxes: PUBLIC PROC [bitmap: ImagerSample.SampleMap, deviceColorData: ImagerPrintColor.DeviceColorData, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { SELECT deviceColorData.case FROM constant => { IF deviceColorData.ink # nop THEN { function: ImagerSample.Function ~ IF deviceColorData.ink = set THEN [or, null] ELSE [and, complement]; ImagerSample.FillBoxes[map: bitmap, boxes: boxes, value: 1, function: function]; }; }; tile => { ImagerSample.TileBoxes[map: bitmap, boxes: boxes, tile: deviceColorData.tileBits, phase: deviceColorData.tilePhase, function: deviceColorData.function]; }; sampledColor => 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: deviceColorData.brick.sampleMap, initIndex: min, buffer: buffer, phase: deviceColorData.brick.phase]; ImagerSample.Halftone[map: bitmap, min: min, sampleBuffer: pixels[0], thresholdBuffer: buffer, function: [deviceColorData.function.dstFunc, IF deviceColorData.function.srcFunc = null THEN complement ELSE null]]; }; ImagerPixel.Resample[self: deviceColorData.separation, m: deviceColorData.pixelToDevice, interpolate: deviceColorData.interpolate, boxes: boxes, bounds: bounds, action: Action]; ImagerSample.ReleaseScratchSamples[buffer]; }; sampledBlack => { Action: PROC [pixels: ImagerPixel.PixelBuffer, min: SF.Vec] ~ { ImagerSample.PutSamples[map: bitmap, initIndex: min, buffer: pixels[0], start: 0, count: pixels.length, function: deviceColorData.function]; }; ImagerPixel.Resample[self: deviceColorData.bitmap, m: deviceColorData.pixelToDevice, interpolate: FALSE, boxes: boxes, bounds: bounds, action: Action]; }; ENDCASE => ERROR; }; END. ImagerPrintColorImpl.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Michael Plass, July 13, 1987 2:56:13 pm PDT Can turn this to a 16 by 16 brick. ColorRegistry.?? set primaries directly, no color correction SetRGB may do color correction This requires a black toner to be present. SetRGB may do color correction This bitmap is already in the right orientation for the output raster; just use it! Want a case here to attempt to build a tile. See ImagerBitmapContextImpl The hard case - use the sampler Κb˜codešœ™K™˜>Kšœœ˜9Kšœ œœ˜+š œœœLœœ˜pKšœ2œ˜7Kšœ˜—Kšœ˜Kšœ˜K˜—šŸ œœœQ˜kKšœœ&œœe˜›Kšœœ˜$š œœœ\œœ˜€Kšœœ*˜JKšœ˜—Kšœ˜Kšœ˜K˜—šŸœœœ…˜€Kšœ˜Kšœ˜Kšœœ˜Kšœ˜Kšœœ˜!Kšœœ˜ šœ"œœ˜.Kšœ?˜?Kšœ!œ˜%Kšœ˜—Kšœ(˜(š˜šœœ˜šœ+˜+šœ˜šœ˜šœ)œ˜Cšœ+œ˜3šœ'œœ˜3K™Kšœ˜—šœ'œœ˜3KšœL˜LKšœ˜Kšœ˜—Kšœ˜——Kšœ!œ˜&Kšœ˜—šœ˜ šœ˜ Kšœœi˜sKšœ$œ˜.—Kšœ˜——Kšœ˜—šœ)˜)Kšœ-˜-Kšœ˜—šœ+˜+K–ξ[m: ImagerTransformation.Transformation, m1: ImagerTransformation.Transformation _ NIL, m2: ImagerTransformation.Transformation _ NIL, m3: ImagerTransformation.Transformation _ NIL, m4: ImagerTransformation.Transformation _ NIL]šœo˜oKšœ/˜/Kšœ˜—šœ+˜+K–ξ[m: ImagerTransformation.Transformation, m1: ImagerTransformation.Transformation _ NIL, m2: ImagerTransformation.Transformation _ NIL, m3: ImagerTransformation.Transformation _ NIL, m4: ImagerTransformation.Transformation _ NIL]šœo˜oKšœ/˜/Kšœ˜—Kšœœ˜—Kšœ˜Kšœ˜—Kšœ˜K˜—šŸœœM˜YKšœ ˜ Kšœ˜Kšœ˜K˜—šŸ œœ8œ˜Ršœ˜ šœΟc ˜Kšœ˜Kšœ˜—šœ  ˜Kšœ˜Kšœ˜—šœ˜ Kšœ9˜9KšœS˜SKšœP˜PKšœAœ˜VKšœœ(˜8Kšœ˜šœœœ$˜7Kšœs˜sšœœœ˜"Kšœœœœ˜&Kšœ˜—KšœQ˜QKšœ˜—Kšœl˜lKšœ* ˜CKšœ˜——Kšœ˜K˜—šŸœœbœ&˜˜Kšœ˜Kšœ$˜$Kšœ&˜&Kšœ$˜$Kšœ˜K˜—šŸœœb˜}Kšœ5œœ ˜Sš œœœ<œœ˜ZKšœ.˜.šœ!œ˜)šœœ˜KšœœP˜VKšœœS˜YKšœœk˜qKšœœ˜—Kšœ˜Kšœ˜—Kšœ˜—Kšœ! ˜>Kšœ˜K˜—šŸœœ„˜‘Kšœ+™+Kšœœ!œœ.˜jKšœœœœ˜DKšŸœ#œ˜CšŸœœ-˜:šœœ˜)KšœP˜TKšœ#˜'—Kšœ˜—KšœQ˜QKšœ˜K˜—šŸœœFœ˜ZKšœ™šœ˜#šœ˜Kšœd˜dKšœVœ&œœ˜˜Kšœ/˜/Kšœ/˜/Kšœ/˜/Kšœpœ˜Œšœ˜šœ˜!Kšœ˜Kšœ!˜!Kšœ ˜ Kšœ˜Kšœ˜—K˜—Kšœ,˜,Kšœ,˜,Kšœ˜—šœ˜šœ˜šœ˜!Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜—Kšœ˜——Kšœ˜K˜—šŸœœ8œ˜NK™*šœ%˜'šœ˜šœ˜ Kšœ ˜$Kšœ!˜%—Kšœ˜—šœ˜Kšœ˜KšœI˜OKšœ˜——Kšœ˜K˜—šŸœœ\˜tKšœ=˜=šœ˜šœ ˜ šœ>œ˜FKšœU˜UKšœ˜Kšœ˜—Kšœ˜—šœ ˜ šœ?œ˜GKšœV˜VKšœ˜Kšœ˜—Kšœ˜—Kšœœ˜—šœ œ œ ˜*Kšœ™KšœD˜HKšœR˜V—Kšœ˜K˜—Kšœœœ˜1šœœœ˜$Kšœ ˜ Kšœ)˜)Kšœ œ˜Kšœ,˜,Kšœ˜Kšœ˜K˜—šŸœœY˜nKšœ+˜+Kšœ9˜9Kšœ?˜?Kšœ=˜=Kš œ œœ œ œ ˜VšŸœ˜&šœ œ˜Kš œœœ#œœ3˜§Kšœœœ˜—Kšœ˜—Kšœ0˜0Kšœœœ œœœ3œœ˜yK–j[x: FunctionCache.Cache, compare: FunctionCache.CompareProc, clientID: FunctionCache.ClientID _ NIL]šœœP˜nšœœœ˜KšœG˜GKšœœ•˜žK–U[size: SF.Vec, bitsPerSample: IISample.BitsPerSample _ 1, bitsPerLine: NAT _ 0]šœœq˜…Kšœ˜—šœ$˜&Kšœ$˜(šœ˜Kšœ$˜$KšœI˜IK˜——Kšœ˜K˜—šŸ œœVœ˜‹Kšœ+˜+Kšœ?˜?Kšœ=˜=Kš œ œœ œ œ ˜VKš Ÿœœœœ  ˜Ašœ˜šœ ˜ šœ>œ˜FK–š[colorOperator: ImagerColor.ColorOperator, output: ImagerColorPrivate.ColorOutput, pa: ImagerPixelArray.PixelArray, maxOut: ImagerPixel.PixelProc]šœ‚˜ˆKšœ˜—Kšœ˜—šœ ˜ šœ?œ˜GK–š[colorOperator: ImagerColor.ColorOperator, output: ImagerColorPrivate.ColorOutput, pa: ImagerPixelArray.PixelArray, maxOut: ImagerPixel.PixelProc]šœƒ˜‰Kšœ˜—Kšœ˜—Kšœœ˜—šœ˜ Kšœœ œœ ˜4KšŸœœ+˜Ršœœ˜šœœ˜Kšœ œ œœ ˜HKšœ ˜Kšœ  ˜——Kšœƒ˜ƒšŸœœ2˜GKšœ`˜`KšœP˜PKšœa˜ašœœœ˜(Kšœ'˜'Kšœ˜—šœœœ ˜K˜Ašœ ˜ šœ˜KšœD˜DKšœ4˜4šœ˜šœ˜KšœPœ˜lKšœ˜—šœœ˜šœœœ˜Kšœœœœ`˜rKšœœœœ`˜rKšœœœ œœœœ ˜YKšœ˜—Kšœ˜——K˜—šœ˜Kšœœœœ`˜tKšœ4˜4šœ˜ Kšœœœ œ œœœ ˜]Kšœ˜—Kšœ˜——KšœH˜HKšœ˜—Kšœ+˜+Kšœ,˜,Kšœ,˜,K˜—KšœIœ œ%œd˜ηK–΄[s0: ImagerSample.SampleMap _ NIL, s1: ImagerSample.SampleMap _ NIL, s2: ImagerSample.SampleMap _ NIL, s3: ImagerSample.SampleMap _ NIL, s4: ImagerSample.SampleMap _ NIL]šœ ˜Kšœ˜—Kšœ˜K˜—šŸœœY˜nKšœ+˜+šœ&œœ˜PKšœ ˜ Kšœœ œœ˜:Kš˜Kšœ˜—Kšœœ œ œ˜Lšœœ˜šœ'œ0˜ZK™SKšœœR˜YKšœœ2˜9Kšœ]˜]Kšœ?˜?Kšœ˜Kšœ˜Kšœ%˜%Kšœ+˜+Kšœ˜—šœ˜ K™IKšœ˜—šœ˜ K™Kšœd˜dKšœ2˜2Kšœ$˜$Kšœ&˜&Kšœ<˜