DIRECTORY AIS, ImagerOps, Terminal, InterminalBackdoor, BasicTime, Convert, DynamicBits, FontEdit, FS, Imager, PixelMapOps, ImagerPixelMap, ImagerPixelSeq, ImagerTransformation, IO, CedarProcess, Process, Random, RasterFontIO, Real, Rope; DBitsMainImpl: CEDAR PROGRAM IMPORTS AIS, ImagerOps, Terminal, InterminalBackdoor, BasicTime, Convert, DynamicBits, FS, PixelMapOps, ImagerPixelMap, ImagerPixelSeq, ImagerTransformation, IO, CedarProcess, Process, Random, Real, Rope ~ BEGIN ROPE: TYPE ~ Rope.ROPE; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; PixelSeq: TYPE ~ ImagerPixelSeq.PixelSeq; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; InternalFont: TYPE ~ RasterFontIO.InternalFont; printerModelNeighborhood: DeviceRectangle _ [-1, -1, 3, 3]; kernelNeighborhood: DeviceRectangle _ [-1, -1, 3, 3]; model: DynamicBits.Model _ NIL; bitMapWhite: [0..1] _ 1; LoadPetersModel: PROC [file: ROPE] ~ { neighbors: DeviceRectangle ~ [-1, -1, 3, 3]; tableSize: INT ~ 90; modelScale: REAL _ 25500; -- Scale factor applied to model model90: ARRAY [0..tableSize) OF NAT; printerModel: DynamicBits.PrinterModel ~ { slow, fast: INTEGER ~ 0; bit: PROC [s, f: INTEGER] RETURNS [[0..1]] ~ { b: [0..1] _ ImagerPixelMap.GetBit[bitmap, s, f]; IF bitMapWhite = 1 THEN b _ 1-b; RETURN [b] }; diags: NAT _ bit[1, 1] + bit[-1, 1] + bit[ 1,-1] + bit[-1,-1]; slows: NAT _ bit[1, 0] + bit[-1, 0]; fasts: NAT _ bit[0, 1] + bit[ 0,-1]; me: NAT _ bit[0, 0]; index: NAT _ 45*me + 15*slows + 5*fasts + diags; RETURN [model90[index], 0] }; kernel: PixelMap _ ImagerPixelMap.Create[4, neighbors]; stream: IO.STREAM _ FS.StreamOpen[fileName: file]; FOR i: INT IN [0..tableSize) DO model90[i] _ Real.RoundI[modelScale*IO.GetReal[stream]]; ENDLOOP; FOR s: INT IN [neighbors.sMin..neighbors.sMin+neighbors.sSize) DO FOR f: INT IN [neighbors.fMin..neighbors.fMin+neighbors.fSize) DO pix: INT _ IO.GetInt[stream]; kernel.Fill[[s,f,1,1], pix]; ENDLOOP; ENDLOOP; IO.Close[stream]; model _ DynamicBits.CreatePrinterModel[neighbors, printerModel, kernel]; printerModelNeighborhood _ neighbors; kernelNeighborhood _ neighbors; }; KernelSpec: TYPE ~ ARRAY [0..9) OF NatLast; NatLast: TYPE ~ NAT _ NAT.LAST; BadToken: SIGNAL [token: ROPE] ~ CODE; LoadPrinterModel: PROC [file: ROPE, noiseWeight: REAL _ 0.0, kernelSpec: KernelSpec] ~ { neighbors: DeviceRectangle ~ IF kernelSpec[1] = NAT.LAST THEN [0,0,1,1] ELSE [-1, -1, 3, 3]; meanIntensity: REF ARRAY [0..512) OF REAL _ NEW[ARRAY [0..512) OF REAL]; stdDev: REF ARRAY [0..512) OF REAL _ NEW[ARRAY [0..512) OF REAL]; minMeanIntensity: REAL _ 9999999999.9; maxMeanIntensity: REAL _ 0; ReadModel: PROC ~ { stream: IO.STREAM _ FS.StreamOpen[fileName: file]; token: REF TEXT _ NEW[TEXT[20]]; Match: PROC [key: ROPE] RETURNS [BOOL] ~ TRUSTED { RETURN [key.Equal[LOOPHOLE[token]]] }; tokenKind: IO.TokenKind _ tokenERROR; stackTop: [0..5] _ 0; stack: ARRAY [0..5) OF REAL; Push: PROC [real: REAL] ~ {stack[stackTop] _ real; stackTop _ stackTop + 1}; Pop: PROC RETURNS [real: REAL] ~ {stackTop _ stackTop - 1; real _ stack[stackTop]}; PopInt: PROC RETURNS [int: INT] ~ {stackTop _ stackTop - 1; int _ Real.RoundLI[stack[stackTop]]}; GetToken: PROC ~ { [tokenKind: tokenKind, token: token] _ stream.GetCedarToken[buffer: token, flushComments: TRUE]; }; c: [0..512) _ 0; GetToken[]; UNTIL tokenKind = tokenEOF DO SELECT tokenKind FROM tokenID => { SELECT TRUE FROM Match["minIntensity"] => [] _ Pop[]; Match["maxIntensity"] => [] _ Pop[]; Match["encoding"] => c _ PopInt[]; Match["aveIntensity"] => meanIntensity[c] _ Pop[]; Match["stdDev"] => stdDev[c] _ Pop[]; Match["occurrences"] => [] _ Pop[]; ENDCASE => SIGNAL BadToken[Rope.FromRefText[token]]; }; tokenDECIMAL, tokenOCTAL, tokenHEX => TRUSTED {Push[Convert.CardFromWholeNumberLiteral[LOOPHOLE[token]]]}; tokenREAL => TRUSTED {Push[Convert.RealFromRope[LOOPHOLE[token]]]}; ENDCASE => SIGNAL BadToken[Rope.FromRefText[token]]; GetToken[]; ENDLOOP; IO.Close[stream]; FOR c: [0..512) IN [0..512) DO minMeanIntensity _ MIN[minMeanIntensity, meanIntensity[c]]; maxMeanIntensity _ MAX[maxMeanIntensity, meanIntensity[c]]; ENDLOOP; }; printerModel: DynamicBits.PrinterModel ~ { intensity: REAL _ meanIntensity[encoding]; scaledIntensity: REAL _ (intensity-minMeanIntensity) / (maxMeanIntensity-minMeanIntensity); RETURN [Real.RoundLI[scaledIntensity*DynamicBits.Intensity.LAST], Real.RoundLI[noiseWeight*stdDev[encoding]]] }; kernel: PixelMap _ ImagerPixelMap.Create[4, neighbors]; j: NAT _ 0; FOR s: INT IN [neighbors.sMin..neighbors.sMin+neighbors.sSize) DO FOR f: INT IN [neighbors.fMin..neighbors.fMin+neighbors.fSize) DO intensity: DynamicBits.Intensity _ kernelSpec[j]; kernel.Fill[[s,f,1,1], intensity]; j _ j+1; ENDLOOP; ENDLOOP; ReadModel[]; model _ DynamicBits.CreatePrinterModel[[-1, -1, 3, 3], printerModel, kernel]; printerModelNeighborhood _ [-1, -1, 3, 3]; kernelNeighborhood _ neighbors; }; screenKernel: ARRAY [0..9) OF NAT _ [1*15, 2*15, 1*15, 2*15, 4*15, 2*15, 1*15, 2*15, 1*15]; LoadScreenModel: PROC ~ { neighbors: DeviceRectangle ~ [-1, -1, 3, 3]; kernel: PixelMap _ ImagerPixelMap.Create[4, neighbors]; printerModel: DynamicBits.PrinterModel ~ { RETURN [IF encoding = bitMapWhite THEN 255 ELSE 0, 0] }; model _ DynamicBits.CreatePrinterModel[[0,0,1,1], printerModel, kernel]; printerModelNeighborhood _ [0,0,1,1]; kernelNeighborhood _ neighbors; }; original: PixelMap; gray: PixelMap; bitmap: PixelMap; initialBitmap: PixelMap; fixedBits: PixelMap; modeledBitmap: PixelMap; SetUpTest: PROC [aisName: ROPE] RETURNS [error: INT, perPixelError: REAL] ~ { [error, perPixelError] _ SetUpFromPixelMap[DynamicBits.AddBorder[PixelMapOps.LoadAIS[aisName].pixelMap, 2, 0]]; }; SetUpFromPixelMap: PROC [pixelMap: PixelMap] RETURNS [error: INT, perPixelError: REAL] ~ { maxPixel: CARDINAL _ Basics.BITSHIFT[1,Basics.BITSHIFT[1,pixelMap.refRep.lgBitsPerPixel]]-1; original _ ImagerPixelSeq.ChangeBitsPerPixel[pixelMap, 3]; ImagerPixelSeq.Renormalize[original, 0, maxPixel, 0, 255]; gray _ original.Copy; DynamicBits.Convolve[gray, model.kernel, 255]; bitmap _ DynamicBits.RandomDither[original]; initialBitmap _ bitmap.Copy; fixedBits _ DynamicBits.FindFixedBits[original, -model.neighborhood.sMin-model.kernel.sOrigin]; modeledBitmap _ DynamicBits.ApplyModel[bitmap, model]; error _ DynamicBits.AbsDiff[gray, modeledBitmap]; perPixelError _ error/(REAL[original.fSize]*original.sSize); DoDisplay[]; }; DoDisplay: PROC ~ TRUSTED { cd: PixelMap _ ImagerOps.PixelMapFromFrameBuffer[Terminal.GetColorFrameBufferA[InterminalBackdoor.terminal]]; w: DeviceRectangle _ original.Window; sMinCenter: INT _ 4-(w.sMin-w.sSize); fMinCenter: INT _ 8-(w.fMin-2*w.fSize); sMaxCenter: INT _ cd.sSize-sMinCenter; fMaxCenter: INT _ cd.fSize-fMinCenter; random: Random.RandomStream _ NIL; IF sMinCenter > sMaxCenter THEN sMinCenter _ sMaxCenter _ cd.sSize/2; IF fMinCenter > fMaxCenter THEN fMinCenter _ fMaxCenter _ cd.fSize/2; random _ Random.Create[seed: w.sMin*INT[12345]+w.fMin*INT[3141592]+w.fSize+w.sSize*1024]; cd _ cd.ShiftMap[-random.ChooseInt[sMinCenter, sMaxCenter], -random.ChooseInt[fMinCenter, fMaxCenter]]; cd.Transfer[original.ShiftMap[-1-w.sSize, -1-w.fSize]]; cd.Transfer[gray.ShiftMap[1, -1-w.fSize]]; ImagerPixelSeq.TransferSamples[cd, bitmap.ShiftMap[-1-w.sSize, 1], ImagerTransformation.Scale[1], FALSE, 255]; cd.Transfer[modeledBitmap.ShiftMap[1, 1]]; ImagerPixelSeq.TransferSamples[cd, initialBitmap.ShiftMap[-1-w.sSize, 3+w.fSize], ImagerTransformation.Scale[1], FALSE, 255]; ImagerPixelSeq.TransferSamples[cd, fixedBits.ShiftMap[-1-w.sSize, -3-2*w.fSize], ImagerTransformation.Scale[1], FALSE, 255]; }; DisplaySwath: PROC [swath: DeviceRectangle] ~ TRUSTED { cd: PixelMap _ ImagerOps.PixelMapFromFrameBuffer[Terminal.GetColorFrameBufferA[InterminalBackdoor.terminal]]; w: DeviceRectangle _ original.Window; cd _ cd.ShiftMap[-cd.sSize/2, -cd.fSize/2]; ImagerPixelSeq.TransferSamples[cd, bitmap.Clip[swath].ShiftMap[-1-w.sSize, 1], ImagerTransformation.Scale[1], FALSE, 255]; }; DoTestPass: PROC [swathSize: NAT _ 1] RETURNS [error: INT, perPixelError: REAL, msPerPixel: REAL] ~ { scratch: REF _ NIL; w: DeviceRectangle ~ original.Window; swath: DeviceRectangle _ [w.sMin, w.fMin, w.sSize, swathSize]; pixels: REAL _ REAL[original.fSize]*original.sSize; startPulses: BasicTime.Pulses ~ BasicTime.GetClockPulses[]; CedarProcess.SetPriority[background]; FOR f: INTEGER IN [w.fMin..w.fMin+w.fSize-swathSize) DO swath: DeviceRectangle _ [w.sMin, f, w.sSize, swathSize]; scratch _ DynamicBits.TuneSwath[gray, bitmap, fixedBits, swath, model, scratch]; DisplaySwath[w]; Process.CheckForAbort[]; ENDLOOP; modeledBitmap _ DynamicBits.ApplyModel[bitmap, model]; error _ DynamicBits.AbsDiff[gray, modeledBitmap]; perPixelError _ error/pixels; msPerPixel _ BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[]-startPulses]/(1000*pixels); DoDisplay[]; }; MakeReplicatedAIS: PROC [name: ROPE, comment: ROPE] ~ { bits: PixelMap _ DynamicBits.AddBorder[bitmap, 4, 255]; page: PixelMap _ ImagerPixelMap.Create[0, [0,0,16*bits.sSize, 16*bits.fSize]]; bits.Fill[bits.Window, 1, [xor, null]]; page.TransferTile[ImagerPixelMap.CreateTile[bits]]; StorePixelMap[name, page, TRUE, comment]; }; GreatestCommonDivisor: PROC [a, b: INT] RETURNS [INT] ~ { a _ ABS[a]; b _ ABS[b]; IF a>b THEN {t: INT _ a; a _ b; b _ t}; WHILE a # 0 DO t: INT _ b MOD a; b _ a; a _ t; ENDLOOP; RETURN [b] }; LeastCommonMultiple: PROC [a, b: INT] RETURNS [INT] ~ { RETURN [ABS[a*b]/GreatestCommonDivisor[a,b]] }; MakePrinterTestPattern: PROC [aisName: ROPE _ "TestPatternS.ais", sPixels: NAT _ 100, fPixels: NAT _ 150, seed: INT _ -1] ~ { bits: PixelMap _ ImagerPixelMap.Create[0, [0, 0, sPixels+8, fPixels+8]]; random: Random.RandomStream _ Random.Create[seed: seed]; bits.Clear; bits.Fill[[1, 1, sPixels+6, fPixels+6], 1]; bits.Fill[[3, 3, sPixels+2, fPixels+2], 0]; bits.Fill[[4, 4, sPixels, fPixels], 1]; bits.Fill[[1, 10, 2, 20], 0]; bits.Fill[[10, 1, 10, 2], 0]; FOR s: NAT IN [0..(sPixels+1)/2) DO FOR f: NAT IN [0..(fPixels+1)/2) DO bit: [0..1] _ random.ChooseInt[0, 1]; bits.Fill[[s+4, f+4, 1, 1], bit]; bits.Fill[[sPixels-1-s+4, f+4, 1, 1], bit]; bits.Fill[[s+4, fPixels-1-f+4, 1, 1], bit]; bits.Fill[[sPixels-1-s+4, fPixels-1-f+4, 1, 1], bit]; ENDLOOP; ENDLOOP; StorePixelMap[aisName, bits, FALSE, IO.PutFR["Symmetric printer calibration pattern sPixels: %g, fPixels: %g, seed: %g", IO.int[sPixels], IO.int[fPixels], IO.int[seed]]]; }; StorePixelMap: PROC [aisFileName: ROPE, source: ImagerPixelMap.PixelMap, bitmap: BOOLEAN _ TRUE, comment: ROPE _ NIL] ~ TRUSTED { output: AIS.FRef _ AIS.CreateFile[name: aisFileName, raster: NEW[AIS.RasterPart _ [ scanCount: source.sSize, scanLength: source.fSize, scanMode: rd, bitsPerPixel: IF source.refRep.lgBitsPerPixel = 0 AND bitmap THEN 0 ELSE Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel], linesPerBlock: -1, paddingPerBlock: 65535 ]]]; outputWindow: AIS.WRef _ AIS.OpenWindow[output]; lineMap: ImagerPixelMap.PixelMap _ ImagerPixelMap.Create[source.refRep.lgBitsPerPixel, [source.sOrigin+source.sMin, source.fOrigin+source.fMin, 1, source.fSize]]; lineBufferDesc: AIS.Buffer _ [length: lineMap.refRep.words, addr: lineMap.refRep.pointer]; AIS.WriteComment[output, comment]; FOR i: NAT IN [0..source.sSize) DO lineMap.Clear; lineMap.Transfer[source]; lineMap.sOrigin _ lineMap.sOrigin + 1; AIS.UnsafeWriteLine[outputWindow, lineBufferDesc, i]; ENDLOOP; AIS.CloseFile[output]; }; ComputePrinterModel: PROC [testPatternName: ROPE, scannedPatternName: ROPE, outputFileName: ROPE] ~ { count: REF ARRAY [0..512) OF INT _ NEW[ARRAY [0..512) OF INT]; intensitySum: REF ARRAY [0..512) OF INT _ NEW[ARRAY [0..512) OF INT]; intensitySquaredSum: REF ARRAY [0..512) OF INT _ NEW[ARRAY [0..512) OF INT]; testPattern: PixelMap _ PixelMapOps.LoadAIS[testPatternName].pixelMap; scannedPattern: PixelMap _ PixelMapOps.LoadAIS[scannedPatternName].pixelMap; testPattern _ testPattern.ShiftMap[-testPattern.sSize/2, -testPattern.fSize/2]; scannedPattern _ scannedPattern.ShiftMap[-scannedPattern.sSize/2, -scannedPattern.fSize/2]; count^ _ ALL[0]; intensitySum^ _ ALL[0]; intensitySquaredSum^ _ ALL[0]; BEGIN w: DeviceRectangle _ ImagerPixelMap.Intersect[testPattern.Window, scannedPattern.Window]; tm: PixelSeq _ ImagerPixelSeq.Create[w.fSize]; -- minus tz: PixelSeq _ ImagerPixelSeq.Create[w.fSize]; -- zero tp: PixelSeq _ ImagerPixelSeq.Create[w.fSize]; -- plus sz: PixelSeq _ ImagerPixelSeq.Create[w.fSize]; out: IO.STREAM _ FS.StreamOpen[outputFileName, $create]; minIntensity: NAT _ NAT.LAST; maxIntensity: NAT _ 0; FOR s: INTEGER IN [w.sMin+1..w.sMin+w.sSize-1) DO tm.LoadF[s-1, w.fMin, w.fSize, testPattern]; tz.LoadF[s, w.fMin, w.fSize, testPattern]; tp.LoadF[s+1, w.fMin, w.fSize, testPattern]; sz.LoadF[s, w.fMin, w.fSize, scannedPattern]; FOR f: NAT IN [1..w.fSize-1) DO c: [0..512) _ 0; intensity: NAT _ sz[f]; Bit: PROC [pix: NAT] ~ {c _ 2*c+MIN[pix, 1]}; IF intensity < minIntensity THEN minIntensity _ intensity; IF intensity > maxIntensity THEN maxIntensity _ intensity; Bit[tm[f-1]]; Bit[tm[f]]; Bit[tm[f+1]]; Bit[tz[f-1]]; Bit[tz[f]]; Bit[tz[f+1]]; Bit[tp[f-1]]; Bit[tp[f]]; Bit[tp[f+1]]; count[c] _ count[c] + 1; intensitySum[c] _ intensitySum[c] + intensity; intensitySquaredSum[c] _ intensitySquaredSum[c] + Basics.LongMult[intensity, intensity]; ENDLOOP; ENDLOOP; out.PutF["%g minIntensity %g maxIntensity\n", IO.int[minIntensity], IO.int[maxIntensity]]; FOR c: [0..512) IN [0..512) DO k: INT _ count[c]; IF k = 0 THEN { out.PutF["%03bB NoData\n", IO.int[c]]; } ELSE { intensity: REAL _ intensitySum[c]; ave: REAL _ intensity/k; var: REAL _ REAL[intensitySquaredSum[c]]/k - ave*ave; out.PutF["%03bB encoding %6g aveIntensity %6g stdDev %g occurrences\n", IO.int[c], IO.real[ave], IO.real[Real.SqRt[var]], IO.int[k]]; }; ENDLOOP; IO.Close[out]; END; }; END. DBitsMainImpl.mesa Copyright (C) 1984, 1985, Xerox Corporation. All rights reserved. Michael Plass, October 18, 1985 1:24:10 pm PDT bc: CHAR _ ' ; ec: CHAR _ '~; DoFont: PROC [fontName: ROPE, outputName: ROPE, bitsPerEm: REAL, passes: NAT _ 4, swathSize: NAT _ 1, bitsPerInch: REAL _ 384] ~ { nominalT: Imager.Transformation _ Imager.Scale[0.125]; tempMap: PixelMap _ [0,0,0,0,0,0,NIL]; font: Imager.FONT _ Imager.MakeFont[fontName, bitsPerEm*8]; bb: Font.Box _ Font.FontBoundingBox[font]; dbb: ImagerPixelMap.DeviceRectangle _ [Real.RoundLI[-bb.ymax], Real.RoundLI[+bb.xmin], Real.RoundLI[bb.ymax]-Real.RoundLI[bb.ymin], Real.RoundLI[bb.xmax]-Real.RoundLI[bb.xmin]]; pixelMap: PixelMap _ ImagerPixelMap.Create[0, [0, 0, dbb.sSize+4, dbb.fSize+4]]; context: Imager.Context _ Imager.Create[$LFDisplay, NEW[ImagerPixelMap.PixelMap _ pixelMap]]; internalFont: InternalFont _ RasterFontIO.Create[dbb, dbb.fSize]; pixelMap _ pixelMap.ShiftMap[dbb.sMin-2, dbb.fMin-2]; IF font.GetProp[$PressFont] = $PressFont THEN { internalFont.family _ UFPressFontReader.Family[[font.graphicsKey, 0]]; internalFont.face _ UFPressFontReader.Face[[font.graphicsKey, 0]]; internalFont.bitsPerEmQuad _ font.actualTransformation.SingularValues.x; }; context.state.T _ Imager.Translate[2-bb.xmin, 2+dbb.sMin+dbb.sSize]; context.SetFont[font]; FOR c: CHAR IN [MAX[font.bc, bc]..MIN[font.ec, ec]] DO widthVector: Font.Pair _ Font.WidthVector[font, c]; pixelMap.Clear; context.SetXY[[0,0]]; context.ShowChar[c]; tempMap _ ImagerPixelSeq.ChangeBitsPerPixel[DynamicBits.AddBorder[pixelMap.Trim, 4*8, 0], 3, tempMap.refRep]; ImagerPixelSeq.Renormalize[tempMap, 0, 1, 0, 255]; ImagerPixelSeq.BoxFilter[tempMap, 9, 9]; ImagerPixelSeq.BoxFilter[tempMap, 5, 5]; ImagerPixelSeq.Renormalize[tempMap, 0, 255, 255, 0]; [] _ SetUpFromPixelMap[ImagerPixelSeq.UnderSample[tempMap, nominalT, TRUE]]; THROUGH [0..passes) DO [] _ DoTestPass[swathSize]; ENDLOOP; bitmap.Fill[bitmap.Window, 1, [xor, null]]; internalFont.charRep[c] _ [ fWidth: widthVector.x/8, sWidth: -widthVector.y/8, pixels: bitmap.Trim[0].Copy ]; ENDLOOP; FontEdit.WriteFormatDerivedFromName[internalFont, outputName, bitsPerInch]; }; MakePD: PROC [name: ROPE] ~ { context: Imager.Context _ Imager.Create[$PD, ImagerPD.Hornet[name]]; bits: PixelMap _ DynamicBits.AddBorder[bitmap, 4, 255]; bits.Fill[bits.Window, 1, [xor, null]]; bits.sOrigin _ bits.fOrigin _ 0; context.state.T _ Imager.Scale[1]; Imager.SetSampledBlack[context, ImagerMasks.PixelArrayFromPixelMap[bits], Imager.Scale[1]]; Imager.MaskRectangle[context, 0, 0, 30000, 30000]; [] _ context.SpecialOp[$Close, NIL]; }; MakePlatemakerPD: PROC [name: ROPE, pixelsPerInch: REAL] ~ { pdFileDescription: ImagerPD.PDFileDescription _ NEW[ImagerPD.PDFileDescriptionRep _ [fileName: name, deviceCode: mig, sResolution: 1200, fResolution: 1200, imageSSize: 11*1200, imageFSize: 85*120, nColors: 1, bandSSize: 16, maxLoadWords: 60000, leftovers: TRUE, copies: 1]]; context: Imager.Context _ Imager.Create[$PD, pdFileDescription]; bits: PixelMap _ DynamicBits.AddBorder[bitmap, 4, 255]; bits.Fill[bits.Window, 1, [xor, null]]; bits.sOrigin _ bits.fOrigin _ 0; context.state.T _ Imager.Scale[1]; Imager.SetSampledBlack[context, ImagerMasks.PixelArrayFromPixelMap[bits], Imager.Scale[1]]; Imager.MaskRectangle[context, 0, 0, 30000, 30000]; [] _ context.SpecialOp[$Close, NIL]; }; testPatternName and scannedPatternName refer to intensity-encoded AIS files. Their sizes need not match exactly, but the will be matched up on centers. The test pattern is assumed to be black-and-white. LoadModel["retuned.tunerModel"]; Êʘšœ™J™BJ™.J™—šÏk œœVœMœ:˜îJ˜—šœ ˜JšœœLœEœ+˜ËJšœ˜J˜Jšœœœ˜Jšœ œ˜)Jšœ œ˜)Jšœœ"˜7Jšœœ˜/J˜Jšœ;˜;šœ5˜5J˜—šœœ˜J˜—šœ˜J˜—šÏnœœœ˜&Jšœ,˜,Jšœ œ˜Jšœ œ Ïc ˜;Jšœ œœœ˜%šœ*˜*Jšœ œ˜šœœœœ ˜.Jšœ0˜0Jšœœ ˜ Jšœ˜ Jšœ˜—Jšœœ4˜>Jšœœ˜$Jšœœ˜%Jšœœ˜Jšœœ&˜0Jšœ˜Jšœ˜—Jšœ7˜7Jšœœœœ˜2šœœœ˜ Jšœ$œ˜8Jšœ˜—šœœœ2˜Ašœœœ2˜AJšœœœ˜Jšœ˜Jšœ˜—Jšœ˜—Jšœ˜JšœH˜HJšœ%˜%Jšœ˜J˜—J˜Jšœ œœœ ˜+Jš œ œœœœ˜Jšœ œ œœ˜&šžœœœœ#˜XJš œœœœœ œ˜\Jšœœœ œœœœ œœ˜HJšœœœ œœœœ œœ˜AJšœœ˜&Jšœœ˜šž œœ˜Jšœœœœ˜2Jš œœœœœ˜ š žœœœœœœ˜2Jšœ œ ˜#Jšœ˜—Jšœ œ˜%Jšœ˜Jšœœœœ˜Jšžœœœ6˜LJšžœœœœ6˜SJšžœœœœC˜ašžœœ˜JšœZœ˜`Jšœ˜—J˜Jšœ ˜ šœ˜šœ ˜šœ ˜ šœœ˜Jšœ$˜$Jšœ$˜$Jšœ"˜"Jšœ2˜2Jšœ%˜%Jšœ#˜#Jšœœ#˜4—Jšœ˜—Jšœ&œ*œ ˜jJšœ œœ ˜CJšœœ#˜4—Jšœ ˜ Jšœ˜—Jšœ˜šœ œ ˜Jšœœ%˜;Jšœœ%˜;Jšœ˜—Jšœ˜—šœ*˜*Jšœ œ˜*šœœ˜JšœC˜C—Jšœ5œ.˜mJšœ˜—Jšœ7˜7Jšœœ˜ šœœœ2˜Ašœœœ2˜AJšœ1˜1Jšœ"˜"J˜Jšœ˜—Jšœ˜—Jšœ ˜ JšœM˜MJšœ*˜*Jšœ˜J˜J˜—šœœœœ:˜[J˜—šžœœ˜Jšœ,˜,Jšœ7˜7šœ*˜*Jšœœœœ˜5Jšœ˜—JšœH˜HJšœ%˜%Jšœ˜J˜J˜—Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜š ž œœ œœ œœ˜MJšœo˜oJ˜J˜—š žœœœ œœ˜ZJšœ œ œ œ&˜\Jšœ:˜:Jšœ:˜:Jšœ˜Jšœ.˜.Jšœ,˜,Jšœ˜Jšœ_˜_Jšœ6˜6Jšœ1˜1Jšœœ!˜˜>Jšœœœ ˜3Jšœ;˜;J˜%šœœœ$˜7Jšœ9˜9JšœP˜PJšœ˜Jšœ˜Jšœ˜—Jšœ6˜6Jšœ1˜1Jšœ˜Jšœb˜bJšœ ˜ Jšœ˜J˜—J–[]šœœ™Jšœœ™šžœœ œœ œ œœœ ™‚Jšœ6™6Jšœ!œ™&Jšœ œ*™;Jšœ*™*Jšœ±™±JšœP™PJšœ4œ&™]JšœA™AJšœ5™5šœ'œ™/JšœF™FJšœB™BJšœH™HJšœ™—JšœD™DJšœ™š œœœœœ™6Jšœ3™3Jšœ™J™J™Jšœm™mJšœ2™2Jšœ(™(Jšœ(™(Jšœ4™4JšœEœ™Lšœ ™Jšœ™Jšœ™—Jšœ+™+šœ™Jšœ™Jšœ™Jšœ™J™—Jš™—JšœK™KJšœ™J™—šžœœœ™JšœD™DJšœ7™7Jšœ'™'Jšœ ™ Jšœ"™"Jšœ[™[Jšœ2™2Jšœœ™$Jšœ™J™—šžœœœ œ˜7Jšœ7˜7JšœN˜NJšœ'˜'Jšœ3˜3Jšœœ ˜)Jšœ˜J˜—š žœœœœœ˜9Jšœœ˜ Jšœœ˜ Jšœœœ˜'šœ˜Jšœœœ˜J˜J˜Jšœ˜—Jšœ˜ Jšœ˜J˜—š žœœœœœ˜7Jšœœ!˜,Jšœ˜J˜—šžœœœœ™Jšœœœ œœœœ œœ˜EJšœœœ œœœœ œœ˜LJšœF˜FJšœL˜LJšœO˜OJšœ[˜[Jšœ œ˜Jšœœ˜Jšœœ˜š˜JšœY˜YJšœ0Ÿ˜8Jšœ0Ÿ˜7Jšœ0Ÿ˜7Jšœ.˜.Jšœœœœ%˜8Jšœœœœ˜Jšœœ˜šœœœ˜1Jšœ,˜,Jšœ*˜*Jšœ,˜,Jšœ-˜-šœœœ˜Jšœ˜Jšœ œ ˜Jšžœœœ œ ˜-Jšœœ˜:Jšœœ˜:Jšœ'˜'Jšœ'˜'Jšœ'˜'Jšœ˜Jšœ.˜.JšœX˜XJšœ˜—Jšœ˜—Jšœ.œœ˜Zšœ œ ˜Jšœœ ˜šœœ˜Jšœœ ˜&Jšœ˜—šœ˜Jšœ œ˜"Jšœœ˜Jšœœœ%˜5Jš œHœ œ œœ ˜…Jšœ˜—Jšœ˜—Jšœ ˜Jšœ˜—Jšœ˜J˜—šœ ™ J™—Jšœ˜——…—5ÎTª