DIRECTORY Basics, ImagerPixelMap, ImagerSample, PixelMapOps, PrincOps, PrincOpsUtils, Real, AIS, Rope; PixelMapOpsImpl: CEDAR PROGRAM IMPORTS Basics, ImagerPixelMap, ImagerSample, PrincOpsUtils, Real, AIS EXPORTS PixelMapOps ~ BEGIN DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; PixelMapRep: TYPE ~ ImagerPixelMap.PixelMapRep; SampleBuffer: TYPE ~ ImagerSample.SampleBuffer; UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples; Sample: TYPE ~ ImagerSample.Sample; Sampler: TYPE ~ ImagerSample.Sampler; AISData: TYPE ~ PixelMapOps.AISData; ROPE: TYPE ~ Rope.ROPE; bitsPerWord: NAT ~ Basics.bitsPerWord; Check: PROC[x: CARDINAL, max: NAT] RETURNS[NAT] ~ TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK }; GetPointer: PROC [buffer: SampleBuffer, i, j, count: NAT] RETURNS [UnsafeSamples] ~ INLINE { k: NAT ~ Basics.BoundsCheck[i, buffer.iSize]*buffer.jSize+Basics.BoundsCheck[j, buffer.jSize]; IF count#0 THEN [] _ Basics.BoundsCheck[j+count-1, buffer.jSize]; TRUSTED { RETURN[LOOPHOLE[@buffer[k]]] }; }; ClearSamples: PUBLIC PROC [buffer: SampleBuffer, i, j: NAT _ 0, count: NAT] ~ TRUSTED { pointer: LONG POINTER ~ GetPointer[buffer, i, j, count]; PrincOpsUtils.LongZero[where: pointer, nwords: count*SIZE[Sample]]; }; FillSamples: PUBLIC PROC [buffer: SampleBuffer, i, j: NAT _ 0, count: NAT, sample: Sample] ~ TRUSTED { IF count # 0 THEN { wps: NAT ~ SIZE[Sample]; pointer: UnsafeSamples ~ GetPointer[buffer, i, j, count]; pointer[0] _ sample; PrincOpsUtils.LongCopy[from: pointer, nwords: (count-1)*wps, to: pointer+wps]; }; }; CopySamples: PUBLIC PROC [buffer: SampleBuffer, bi, bj: NAT _ 0, count: NAT, source: SampleBuffer, si, sj: NAT _ 0] ~ TRUSTED { dst: UnsafeSamples ~ GetPointer[buffer, bi, bj, count]; src: UnsafeSamples ~ GetPointer[source, si, sj, count]; PrincOpsUtils.LongCopy[from: src, nwords: count, to: dst]; }; GetF: PUBLIC PROC [pixelMap: PixelMap, s: INTEGER, f: INTEGER, buffer: SampleBuffer, bi: NAT, bj: NAT, count: NAT] ~ TRUSTED { lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel; wpl: NAT ~ pixelMap.refRep.rast; ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp]; lines: NAT ~ pixelMap.refRep.lines; sbuf: NAT ~ Basics.BoundsCheck[s-pixelMap.sOrigin, lines]; fbuf: NAT ~ f-pixelMap.fOrigin; fbufmax: NAT ~ Check[fbuf+count, ppl]; destPointer: UnsafeSamples ~ GetPointer[buffer, bi, bj, count]; ImagerSample.UnsafeGetF[samples: destPointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp]]; }; PutF: PUBLIC PROC [pixelMap: PixelMap, s: INTEGER, f: INTEGER, buffer: SampleBuffer, bi: NAT, bj: NAT, count: NAT, srcFunc: PrincOps.SrcFunc _ null, dstFunc: PrincOps.DstFunc _ null] ~ TRUSTED { lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel; wpl: NAT ~ pixelMap.refRep.rast; ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp]; lines: NAT ~ pixelMap.refRep.lines; sbuf: NAT ~ Basics.BoundsCheck[s-pixelMap.sOrigin, lines]; fbuf: NAT ~ f-pixelMap.fOrigin; fbufmax: NAT ~ Check[fbuf+count, ppl]; sourcePointer: UnsafeSamples ~ GetPointer[buffer, bi, bj, count]; ImagerSample.UnsafePutF[samples: sourcePointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp], srcFunc: srcFunc, dstFunc: dstFunc]; }; GetS: PUBLIC PROC [pixelMap: PixelMap, s: INTEGER, f: INTEGER, buffer: SampleBuffer, bi: NAT, bj: NAT, count: NAT] ~ TRUSTED { lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel; wpl: NAT ~ pixelMap.refRep.rast; ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp]; lines: NAT ~ pixelMap.refRep.lines; sbuf: NAT ~ s-pixelMap.sOrigin; fbuf: NAT ~ Basics.BoundsCheck[f-pixelMap.fOrigin, ppl]; sbufmax: NAT ~ Check[sbuf+count, lines]; destPointer: UnsafeSamples ~ ImagerSample.GetPointer[buffer, bi, bj, count]; ImagerSample.UnsafeGetS[samples: destPointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp]]; }; PutS: PUBLIC PROC [pixelMap: PixelMap, s: INTEGER, f: INTEGER, buffer: SampleBuffer, bi: NAT, bj: NAT, count: NAT, srcFunc: PrincOps.SrcFunc _ null, dstFunc: PrincOps.DstFunc _ null] ~ TRUSTED { lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel; wpl: NAT ~ pixelMap.refRep.rast; ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp]; lines: NAT ~ pixelMap.refRep.lines; sbuf: NAT ~ s-pixelMap.sOrigin; fbuf: NAT ~ Basics.BoundsCheck[f-pixelMap.fOrigin, ppl]; sbufmax: NAT ~ Check[sbuf+count, lines]; sourcePointer: UnsafeSamples ~ ImagerSample.GetPointer[buffer, bi, bj, count]; ImagerSample.UnsafePutS[samples: sourcePointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp], srcFunc: srcFunc, dstFunc: dstFunc]; }; Halftone: PUBLIC PROC [pixelMap: PixelMap, s: INTEGER, f: INTEGER, samples, thresholds: UnsafeSamples, count: NAT, invertOutput: BOOL _ FALSE, transparent: BOOL _ FALSE] ~ TRUSTED { lgbpp: [0..0] ~ pixelMap.refRep.lgBitsPerPixel; wpl: NAT ~ pixelMap.refRep.rast; ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp]; lines: NAT ~ pixelMap.refRep.lines; sbuf: NAT ~ Basics.BoundsCheck[s-pixelMap.sOrigin, lines]; fbuf: NAT ~ f-pixelMap.fOrigin; fbufmax: NAT ~ Check[fbuf+count, ppl]; UnsafeHalftone[samples: samples, thresholds: thresholds, count: count, base: pixelMap.refRep.pointer, wordsPerLine: wpl, s: sbuf, f: fbuf, invertOutput: invertOutput, transparent: transparent]; }; Hi: PROC [a: CARDINAL] RETURNS [CARDINAL] ~ INLINE {RETURN[Basics.BITSHIFT[a, 1-bitsPerWord]]}; Shift: PROC [a: CARDINAL, amt: INTEGER] RETURNS [CARDINAL] ~ INLINE {RETURN[Basics.BITSHIFT[a, amt]]}; SixteenWords: TYPE ~ MACHINE DEPENDENT RECORD [ w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15: CARDINAL ]; UnsafeHalftone: PUBLIC UNSAFE PROC [samples, thresholds: UnsafeSamples, count: NAT, base: LONG POINTER, wordsPerLine: NAT, s, f: NAT _ 0, invertOutput: BOOL _ FALSE, transparent: BOOL _ FALSE] ~ UNCHECKED { linePointer: LONG POINTER ~ base+Basics.LongMult[s, wordsPerLine]; bitOffset: CARDINAL ~ f; p: LONG POINTER TO SixteenWords _ LOOPHOLE[@samples[0]]; q: LONG POINTER TO SixteenWords _ LOOPHOLE[@thresholds[0]]; allInvert: CARDINAL _ IF invertOutput THEN LAST[CARDINAL] ELSE 0; GetN: UNSAFE PROC [n: [0..16)] RETURNS [CARDINAL] ~ UNCHECKED { w: CARDINAL _ 0; THROUGH [0..n) DO w _ w*2 + Hi[p^.w0-q^.w0]; p _ p + 1; q _ q + 1; ENDLOOP; RETURN [Basics.BITXOR[w, Basics.BITSHIFT[allInvert, n-16]]]; }; -- GetFirst sixteen: [16..16] ~ bitsPerWord; Get16: UNSAFE PROC RETURNS [CARDINAL] ~ UNCHECKED { s, h: SixteenWords; s _ p^; p _ p + SIZE[SixteenWords]; h _ q^; q _ q + SIZE[SixteenWords]; RETURN [Basics.BITXOR[allInvert, ((((((((((((((Hi[s.w0-h.w0]*2+Hi[s.w1-h.w1])*2+Hi[s.w2-h.w2])*2+Hi[s.w3-h.w3])*2+Hi[s.w4-h.w4])*2+Hi[s.w5-h.w5])*2+Hi[s.w6-h.w6])*2+Hi[s.w7-h.w7])*2+Hi[s.w8-h.w8])*2+Hi[s.w9-h.w9])*2+Hi[s.w10-h.w10])*2+Hi[s.w11-h.w11])*2+Hi[s.w12-h.w12])*2+Hi[s.w13-h.w13])*2+Hi[s.w14-h.w14])*2+Hi[s.w15-h.w15]]] }; -- Get16 d: LONG POINTER TO CARDINAL _ LOOPHOLE[linePointer + bitOffset/16]; IF transparent THEN { IF bitOffset MOD 16 # 0 THEN { firstBits: INTEGER _ 16-(bitOffset MOD 16); z: INTEGER _ MAX[firstBits-INTEGER[count], 0]; d^ _ Basics.BITOR[d^, Shift[GetN[firstBits-z], z]]; d _ d + 1; count _ count - (firstBits-z); }; WHILE count >= 16 DO d^ _ Basics.BITOR[d^, Get16[]]; d _ d + 1; count _ count - 16; ENDLOOP; IF count > 0 THEN { d^ _ Basics.BITOR[d^, Shift[GetN[count], 16-count]]; }; } ELSE { IF bitOffset MOD 16 # 0 THEN { firstBits: INTEGER _ 16-(bitOffset MOD 16); z: INTEGER _ MAX[firstBits-INTEGER[count], 0]; m: CARDINAL _ Shift[1, firstBits] - Shift[1, z]; d^ _ Basics.BITOR[Basics.BITAND[d^, Basics.BITNOT[m]], Shift[GetN[firstBits-z], z]]; d _ d + 1; count _ count - (firstBits-z); }; WHILE count >= 16 DO d^ _ Get16[]; d _ d + 1; count _ count - 16; ENDLOOP; IF count > 0 THEN { d^ _ Basics.BITOR[Basics.BITAND[d^, Shift[1, 16-count]-1], Shift[GetN[count], 16-count]]; }; }; }; BoxFilter: PUBLIC PROC [pixelMap: PixelMap, sSizeBox, fSizeBox: [0..256), wrap: BOOL _ TRUE] ~ { lgbps: [0..3] ~ pixelMap.refRep.lgBitsPerPixel; IF LONG[sSizeBox]*fSizeBox*255 > CARDINAL.LAST THEN { BoxFilter[pixelMap, sSizeBox, 1]; BoxFilter[pixelMap, 1, fSizeBox]; } ELSE { unit: LONG CARDINAL ~ LONG[LAST[WORD]]+1; half: LONG CARDINAL ~ unit/2; sHalf: NAT ~ sSizeBox/2; fHalf: NAT ~ (fSizeBox+1)/2; sStart: INTEGER ~ pixelMap.sOrigin+pixelMap.sMin; sEnd: INTEGER ~ sStart + pixelMap.sSize; fStart: INTEGER ~ pixelMap.fOrigin+pixelMap.fMin; fEnd: INTEGER ~ fStart+pixelMap.fSize; fSize: NAT ~ pixelMap.fSize; sum: ARRAY [0..256) OF SampleBuffer; nPixels: CARDINAL ~ Basics.LongMult[sSizeBox, fSizeBox]; nPixelsRecip: CARDINAL ~ Basics.LongDiv[unit, nPixels]; sOrigin: INTEGER _ sStart-2*sSizeBox+sHalf; result: SampleBuffer _ ImagerSample.NewBuffer[iSize: 1, jSize: fSize]; paddedSize: NAT _ fSize+2*fSizeBox; MoveToNextRow: PROC ~ { t: SampleBuffer _ sum[0]; s: INTEGER _ sOrigin+1+sSizeBox; IF wrap THEN { WHILE s >= sEnd DO s _ s - pixelMap.sSize ENDLOOP; WHILE s < sStart DO s _ s + pixelMap.sSize ENDLOOP; } ELSE {s _ MAX[MIN[s, sEnd-1], sStart]}; FOR i: NAT IN [0..sSizeBox) DO sum[i] _ sum[i+1]; ENDLOOP; GetF[pixelMap: pixelMap, s: s, f: fStart, buffer: t, bi: 0, bj: fSizeBox, count: fSize]; IF wrap THEN { CopySamples[buffer: t, bi: 0, bj: fSizeBox+fSize, count: fSizeBox, source: t, si: 0, sj: fSizeBox]; CopySamples[buffer: t, bi: 0, bj: 0, count: fSizeBox, source: t, si: 0, sj: fSize]; } ELSE { FillSamples[buffer: t, i: 0, j: fSize+fSizeBox, count: fSizeBox, sample: t.GetSample[0, fSize+fSizeBox-1]]; FillSamples[buffer: t, i: 0, j: 0, count: fSizeBox, sample: t.GetSample[0, fSizeBox]]; }; ImagerSample.AddSamples[samples: t, si: 0, sj: 0, buffer: t, bi: 0, bj: 1, count: paddedSize-1]; -- ripple add! ImagerSample.AddSamples[samples: sum[sSizeBox-1], si: 0, sj: 0, buffer: t, bi: 0, bj: 0, count: paddedSize]; sOrigin _ sOrigin + 1; sum[sSizeBox] _ t; }; FOR i: NAT IN [0..sSizeBox] DO sum[i] _ ImagerSample.NewBuffer[iSize: 1, jSize: paddedSize]; ENDLOOP; FOR s: INTEGER IN [sStart..sEnd) DO WHILE sOrigin+sHalf+1 # s DO MoveToNextRow[] ENDLOOP; TRUSTED { prevLine: UnsafeSamples ~ ImagerSample.GetPointer[sum[sSizeBox], 0, 0, paddedSize]; curLine: UnsafeSamples ~ ImagerSample.GetPointer[sum[0], 0, 0, paddedSize]; resultLine: UnsafeSamples ~ ImagerSample.GetPointer[result, 0, 0, fSize]; FOR j: INTEGER IN [0..fSize) DO f0: NAT ~ j+fSizeBox-fHalf; f1: NAT ~ Basics.BoundsCheck[f0+fSizeBox, paddedSize]; boxSum: Sample _ prevLine[f1] - prevLine[f0] - curLine[f1] + curLine[f0]; val: CARDINAL ~ Basics.HighHalf[Basics.LongMult[boxSum, nPixelsRecip] + half]; resultLine[j] _ val; ENDLOOP; }; PutF[pixelMap: pixelMap, s: s, f: fStart, buffer: result, bi: 0, bj: 0, count: fSize, srcFunc: null, dstFunc: null]; ENDLOOP; }; }; ChangeBitsPerPixel: PUBLIC PROC [pixelMap: PixelMap, newLgBitsPerPixel: [0..4], scratch: REF PixelMapRep _ NIL] RETURNS [pm: PixelMap] ~ { action: PROC [sampleBuffer: SampleBuffer] ~ { bounds: DeviceRectangle ~ pixelMap.Window; new: PixelMap _ ImagerPixelMap.Reshape[scratch, newLgBitsPerPixel, bounds]; FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO GetF[pixelMap, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize]; PutF[new, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize, null, null]; ENDLOOP; pm _ new; }; ImagerSample.DoWithScratchBuffer[1, pixelMap.fSize, action]; }; ChangeContrast: PUBLIC PROC [pixelMap: PixelMap, oldminvalue, oldmaxvalue, newminvalue, newmaxvalue: REAL] ~ { action: PROC [sampleBuffer: SampleBuffer] ~ TRUSTED { bounds: DeviceRectangle ~ pixelMap.Window; sample: UnsafeSamples ~ GetPointer[sampleBuffer, 0, 0, bounds.fSize]; m: REAL ~ (newmaxvalue-newminvalue)/(oldmaxvalue-oldminvalue); maxVal: INT ~ CARDINAL[Basics.BITSHIFT[1, Basics.BITSHIFT[1, pixelMap.refRep.lgBitsPerPixel]]-1]; FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO GetF[pixelMap, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize]; FOR j: NAT IN [0..bounds.fSize) DO pix: REAL _ sample[j]; out: REAL _ (pix-oldminvalue)*m+newminvalue; sample[j] _ MAX[MIN[Real.Round[out], maxVal], 0]; ENDLOOP; PutF[pixelMap, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize, null, null]; ENDLOOP; }; ImagerSample.DoWithScratchBuffer[1, pixelMap.fSize, action]; }; ReadAIS: PUBLIC PROC [pixelMap: PixelMap, aisName: ROPE] ~ TRUSTED { ais: AIS.FRef _ AIS.OpenFile[aisName]; window: AIS.WRef _ AIS.OpenWindow[ais]; raster: AIS.Raster _ AIS.ReadRaster[ais]; lgBitsPerPixel: [0..4] _ SELECT raster.bitsPerPixel FROM 0, 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4, ENDCASE => ERROR; comment: ROPE ~ AIS.ReadComment[ais]; lineMap: PixelMap _ ImagerPixelMap.Create[lgBitsPerPixel, [0, 0, 1, raster.scanLength]]; lineBufferDesc: AIS.Buffer _ [length: lineMap.refRep.words, addr: lineMap.refRep.pointer]; w: DeviceRectangle _ ImagerPixelMap.Window[pixelMap]; FOR i: NAT IN [MAX[w.sMin, 0]..MIN[raster.scanCount, w.sMin+w.sSize]) DO AIS.UnsafeReadLine[window, lineBufferDesc, i]; pixelMap.Transfer[lineMap]; lineMap.sOrigin _ lineMap.sOrigin + 1; ENDLOOP; AIS.CloseWindow[window]; AIS.CloseFile[ais]; }; LoadAIS: PUBLIC PROC [aisName: ROPE] RETURNS [AISData] ~ TRUSTED { ais: AIS.FRef _ AIS.OpenFile[aisName]; window: AIS.WRef _ AIS.OpenWindow[ais]; raster: AIS.Raster _ AIS.ReadRaster[ais]; lgBitsPerPixel: [0..4] _ SELECT raster.bitsPerPixel FROM 0, 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4, ENDCASE => ERROR; comment: ROPE ~ AIS.ReadComment[ais]; lineMap: PixelMap _ ImagerPixelMap.Create[lgBitsPerPixel, [0, 0, 1, raster.scanLength]]; lineBufferDesc: AIS.Buffer _ [length: lineMap.refRep.words, addr: lineMap.refRep.pointer]; pixelMap: PixelMap _ ImagerPixelMap.Create[lgBitsPerPixel, [0, 0, raster.scanCount, raster.scanLength]]; FOR i: NAT IN [0..raster.scanCount) DO AIS.UnsafeReadLine[window, lineBufferDesc, i]; pixelMap.Transfer[lineMap]; lineMap.sOrigin _ lineMap.sOrigin + 1; ENDLOOP; AIS.CloseWindow[window]; AIS.CloseFile[ais]; RETURN [[ pixelMap: pixelMap, bitmap: raster.bitsPerPixel=0, comment: comment ]] }; StoreAIS: PUBLIC PROC [aisName: ROPE, aisData: AISData] ~ { source: PixelMap ~ aisData.pixelMap; output: AIS.FRef _ AIS.CreateFile[name: aisName, raster: NEW[AIS.RasterPart _ [ scanCount: source.sSize, scanLength: source.fSize, scanMode: rd, bitsPerPixel: IF source.refRep.lgBitsPerPixel = 0 AND aisData.bitmap THEN 0 ELSE Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel], linesPerBlock: -1, paddingPerBlock: 65535 ]]]; outputWindow: AIS.WRef _ AIS.OpenWindow[output]; lineMap: 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, aisData.comment]; FOR i: NAT IN [0..source.sSize) DO lineMap.Clear; lineMap.Transfer[source]; lineMap.sOrigin _ lineMap.sOrigin + 1; TRUSTED {AIS.UnsafeWriteLine[outputWindow, lineBufferDesc, i]}; ENDLOOP; AIS.CloseFile[output]; }; END. ΚPixelMapOpsImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Michael Plass, March 10, 1986 11:56:39 am PST IF x IN[0..max] THEN RETURN[x] ELSE ERROR RuntimeError.BoundsFault Κ’˜™Icodešœ Οmœ1™Kš œžœžœžœ žœ(˜ašžœžœžœ)ž˜