DIRECTORY Basics USING [bitsPerWord, RawWords], CountedVM USING [Handle], ImagerTransformation USING [Transformation], PrincOps USING [BitAddress, SrcFunc, DstFunc], SF USING [Box, BoxAction, BoxGenerator, maxVec, Vec, zeroVec], Terminal USING [FrameBuffer]; ImagerSample: CEDAR DEFINITIONS ~ BEGIN Transformation: TYPE ~ ImagerTransformation.Transformation; Vec: TYPE ~ SF.Vec; zeroVec: Vec ~ SF.zeroVec; maxVec: Vec ~ SF.maxVec; Box: TYPE ~ SF.Box; maxBox: Box ~ [min: zeroVec, max: maxVec]; BoxAction: TYPE ~ SF.BoxAction; BoxGenerator: TYPE ~ SF.BoxGenerator; maxCount: NAT ~ NAT.LAST; MultipleReleaseOfScratch: ERROR; Sample: TYPE ~ WORD; maxSample: Sample ~ Sample.LAST; RawSamples: TYPE ~ Basics.RawWords; maxBitsPerSample: NAT ~ Basics.bitsPerWord; BitsPerSample: TYPE ~ NAT[0..maxBitsPerSample]; SampleBuffer: TYPE ~ REF SampleBufferRep; SampleBufferRep: TYPE ~ RECORD [ length: NAT, samples: SEQUENCE maxLength: NAT OF Sample ]; NewSamples: PROC [length: NAT, scratch: SampleBuffer _ NIL] RETURNS [SampleBuffer]; ObtainScratchSamples: PROC [length: NAT] RETURNS [SampleBuffer]; ReleaseScratchSamples: PROC [samples: SampleBuffer]; DoWithScratchSamples: PROC [length: NAT, action: PROC [SampleBuffer]]; PointerToSamples: PROC [samples: SampleBuffer, start, count: NAT] RETURNS [LONG POINTER TO RawSamples]; FlipSamples: PROC [samples: SampleBuffer]; FillSamples: PROC [samples: SampleBuffer, value: Sample, start: NAT _ 0, count: NAT _ maxCount]; SampleMap: TYPE ~ REF SampleMapRep; SampleMapRep: TYPE ~ RECORD [ size: Vec, -- [s: , f: ] bitsPerSample: NAT, -- number of bits per sample bitsPerLine: NAT, -- bits per scan line base: PrincOps.BitAddress, -- starting bit address ref: REF -- for retaining the underlying storage ]; UnsafeNewSampleMap: UNSAFE PROC [size: Vec, bitsPerSample: BitsPerSample, bitsPerLine: NAT, base: PrincOps.BitAddress, ref: REF, words: INT, scratchDescriptor: SampleMap _ NIL] RETURNS [SampleMap]; BitsForSamples: PROC [fSize: NAT, bitsPerSample: NAT] RETURNS [NAT]; WordsForLines: PROC [sSize: NAT, bitsPerLine: NAT] RETURNS [INT]; WordsForMap: PROC [size: Vec, bitsPerSample: BitsPerSample _ 1, bitsPerLine: NAT _ 0] RETURNS [INT]; NewSampleMap: PROC [size: Vec, bitsPerSample: BitsPerSample _ 1, bitsPerLine: NAT _ 0, scratch: SampleMap _ NIL] RETURNS [SampleMap]; MapFromVM: PROC [vm: CountedVM.Handle, size: Vec, bitsPerSample: BitsPerSample _ 1, bitsPerLine: NAT _ 0 ] RETURNS [SampleMap]; MapFromFrameBuffer: PROC [frameBuffer: Terminal.FrameBuffer] RETURNS [SampleMap]; SubMap: PROC [self: SampleMap, box: Box _ maxBox] RETURNS [SampleMap]; CopyMap: PROC [self: SampleMap, box: Box _ maxBox] RETURNS [SampleMap]; ObtainScratchMap: PROC [size: Vec, bitsPerSample: BitsPerSample _ 1] RETURNS [SampleMap]; ReleaseScratchMap: PROC [self: SampleMap]; DoWithScratchMap: PROC [size: Vec, bitsPerSample: BitsPerSample _ 1, action: PROC [SampleMap]]; Function: TYPE ~ RECORD [dstFunc: PrincOps.DstFunc, srcFunc: PrincOps.SrcFunc]; nullFunction: Function ~ [null, null]; Get: PROC [self: SampleMap, index: Vec] RETURNS [Sample]; Put: PROC [self: SampleMap, index: Vec, value: Sample, function: Function _ nullFunction]; GetSamples: PROC [self: SampleMap, min: Vec _ zeroVec, delta: Vec _ [s: 0, f: 1], samples: SampleBuffer, start: NAT _ 0, count: NAT _ maxCount]; PutSamples: PROC [self: SampleMap, min: Vec _ zeroVec, delta: Vec _ [s: 0, f: 1], samples: SampleBuffer, start: NAT _ 0, count: NAT _ maxCount, function: Function _ nullFunction]; Clear: PROC [self: SampleMap]; Transfer: PROC [dst: SampleMap, src: SampleMap, dstMin: Vec _ zeroVec, srcMin: Vec _ zeroVec, size: Vec _ maxVec, function: Function _ nullFunction]; TransferBoxes: PROC [dst: SampleMap, src: SampleMap, boxes: BoxGenerator, dstOffset: Vec _ zeroVec, srcOffset: Vec _ zeroVec, function: Function _ nullFunction]; Move: PROC [self: SampleMap, dstMin: Vec _ zeroVec, srcMin: Vec _ zeroVec, size: Vec _ maxVec, function: Function _ nullFunction]; MoveBoxes: PROC [self: SampleMap, boxes: BoxGenerator, dstOffset: Vec _ zeroVec, srcOffset: Vec _ zeroVec, function: Function _ nullFunction]; Fill: PROC [self: SampleMap, box: Box _ maxBox, value: Sample _ maxSample, function: Function _ nullFunction]; FillBoxes: PROC [self: SampleMap, boxes: BoxGenerator, value: Sample _ maxSample, function: Function _ nullFunction]; TileFromStipple: PROC [stipple: WORD, bitsPerSample: BitsPerSample _ 1, value0: Sample _ 0, value1: Sample _ maxSample, scratch: SampleMap _ NIL] RETURNS [SampleMap]; Tile: PROC [self: SampleMap, box: Box _ maxBox, tile: SampleMap, s0, f0: INT _ 0, phase: NAT _ 0, function: Function _ nullFunction]; TileBoxes: PROC [self: SampleMap, boxes: BoxGenerator, tile: SampleMap, s0, f0: INT _ 0, phase: NAT _ 0, function: Function _ nullFunction]; Trim: PROC [self: SampleMap, box: Box _ maxBox, background: Sample _ 0] RETURNS [Box]; IsAll: PROC [self: SampleMap, box: Box _ maxBox, value: Sample _ 0] RETURNS [BOOL]; Equal: PROC [map1: SampleMap, box1: Box _ maxBox, map2: SampleMap, box2: Box _ maxBox] RETURNS [BOOL]; PixelProc: TYPE ~ PROC [i: NAT] RETURNS [Sample]; PixelBuffer: TYPE ~ REF PixelBufferRep; PixelBufferRep: TYPE ~ RECORD [ length: NAT, sampleBuffers: SEQUENCE samplesPerPixel: NAT OF SampleBuffer ]; NewPixels: PROC [samplesPerPixel: NAT, length: NAT, scratch: PixelBuffer _ NIL] RETURNS [PixelBuffer]; ObtainScratchPixels: PROC [samplesPerPixel: NAT, length: NAT] RETURNS [PixelBuffer]; ReleaseScratchPixels: PROC [pixels: PixelBuffer]; DoWithScratchPixels: PROC [samplesPerPixel: NAT, length: NAT, action: PROC [PixelBuffer]]; PixelMap: TYPE ~ REF PixelMapRep; PixelMapRep: TYPE ~ RECORD [ size: Vec, sampleMaps: SEQUENCE samplesPerPixel: NAT OF SampleMap ]; NewPixelMap: PROC [samplesPerPixel: NAT, size: Vec, maxSample: PixelProc, scratch: PixelMap _ NIL] RETURNS [PixelMap]; GetPixels: PROC [self: PixelMap, min: Vec _ zeroVec, delta: Vec _ [s: 0, f: 1], pixels: PixelBuffer, start: NAT _ 0, count: NAT _ maxCount]; PutPixels: PROC [self: PixelMap, min: Vec _ zeroVec, delta: Vec _ [s: 0, f: 1], pixels: PixelBuffer, start: NAT _ 0, count: NAT _ maxCount, function: Function _ nullFunction]; ResampleAction: TYPE ~ PROC [pixels: PixelBuffer, min: Vec]; Resample: PROC [self: PixelMap, m: Transformation, interpolate: BOOL, boxes: BoxGenerator, bounds: Box, action: ResampleAction]; END. เImagerSample.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Michael Plass, December 4, 1985 11:31:32 am PST Doug Wyatt, March 7, 1986 2:41:21 pm PST Samples and SampleBuffers SampleMap creation -- It is unsafe for clients to alter these fields. -- This type defines a two-dimensional array of samples. To avoid confusion no matter how the represented image is oriented, terms like height and width are avoided, and the coordinates are expressed in terms of s and f, for slow and fast. On a display, the s axis is normally vertical, and points down, but on a printer that scans in the long direction, the f axis will point up. It is the client's responsibility to ensure that an appropriate block of storage is provided; the parameters will be checked for internal consistency; words declares the number of words of storage supplied, starting at base.word; scratchDescriptor may be provided to avoid the need to allocate a new descriptor. Returns number of bits for fSize samples, rounded up to a whole number of words. Returns number of words for sSize scan lines, starting at a word boundary. Returns number of words required for a new sample map of given size. If bitsPerLine=0, bitsPerLine _ BitsForSamples[size.f, bitsPerSample]. Allocates counted storage or counted VM, as needed. If bitsPerLine=0, bitsPerLine _ BitsForSamples[size.f, bitsPerSample]. Like NewSampleMap, but uses client-supplied VM. BoundsFault if insufficent storage is supplied. Creates a descriptor for the frame buffer. Creates a new descriptor on the same sample storage. Allocates a new map and copies the samples. SampleMap operations [null, null] dst _ src [or, null] dst _ BITOR[dst, src] [and, null] dst _ BITAND[dst, src] [and, complement] dst _ BITAND[dst, BITNOT[src]] [xor, null] dst _ BITXOR[dst, src] etcetera. Gets the indexed sample from the map. BoundsFault if index.s NOT IN[0..self.size.s) OR index.f NOT IN[0..self.size.f) Puts modified value into the map at indexed location, dropping extra high-order bits. BoundsFault if index.s NOT IN[0..self.size.s) OR index.f NOT IN[0..self.size.f) Gets a run of samples from the map into a buffer. The effect is: FOR j: NAT IN [0..MIN[samples.length-start, count]) DO offset: Vec ~ [s: j*delta.s, f: j*delta.f]; samples[start+j] _ self.Get[min.Add[offset]]; ENDLOOP; Stores a run of samples from a buffer into the map. The effect is: FOR j: NAT IN [0..MIN[samples.length-start, count]) DO offset: Vec ~ [s: j*delta.s, f: j*delta.f]; self.Put[min.Add[offset], samples[start+j], function]; ENDLOOP; A fast way to clear a map to zero. Clears the padding bits on both ends of the scan lines as well as the actual samples. Does not clear words that are entirely unused. Transfers samples to dst from src. The effect is: actualSize: Vec ~ NonNegative[Min3[size, dst.size.Sub[dstMin], src.size.Sub[srcMin]]] FOR s: NAT IN [0..actualSize.s) DO FOR f: NAT IN [0..actualSize.f) DO offset: Vec ~ [s: s, f: f]; value: Sample ~ src.Get[srcMin.Add[offset]]; dst.Put[dstMin.Add[offset], value, function]; ENDLOOP; ENDLOOP; Transfers several boxes. The effect is: transferBox: PROC [box: Box] ~ { dstMin: Vec ~ box.min.Add[dstOffset]; srcMin: Vec ~ box.min.Add[srcOffset]; Transfer[dst, src, dstMin, srcMin, box.Size, function]; }; boxes[transferBox]; Like Transfer with dst=src=self, but avoids ripple if the source and destination overlap. Moves several boxes; ds=(src.s-dst.s), df=(src.f-dst.f). The effect is: moveBox: PROC [box: Box] ~ { dstMin: Vec ~ box.min.Add[dstOffset]; srcMin: Vec ~ box.min.Add[srcOffset]; Move[self, dstMin, srcMin, box.Size, function]; }; boxes[moveBox]; Fills a box with a constant sample value. The effect is: actualSize: Vec ~ NonNegative[self.size.Min[box.max].Sub[box.min]] FOR s: NAT IN [0..actualSize.s) DO FOR f: NAT IN [0..actualSize.f) DO offset: Vec ~ [s: s, f: f]; self.Put[box.min.Add[offset], value, function]; ENDLOOP; ENDLOOP; Fills several boxes. The effect is: fillBox: PROC [box: Box] ~ { Fill[self, box, value, function]; }; boxes[fillBox]; Makes a tile from a 4-by-4 pattern. Tiles the box with the pattern designated by (tile, s0, f0, phase). The effect is: actualSize: Vec ~ NonNegative[self.size.Min[box.max].Sub[box.min]] FOR s: NAT IN [box.min.s..box.min.s+actualSize.s) DO FOR f: NAT IN [box.min.f..box.min.f+actualSize.f) DO sTile: INT ~ s-s0; fTile: INT ~ f-(f0+phase*(sTile div tile.size.s)); value: Sample ~ tile.Get[[sTile mod tile.size.s, fTile mod tile.size.f]]; self.Put[[s, f], value, function]; ENDLOOP; ENDLOOP; For div and mod, the sign of the remainder is the sign of the divisor, not the dividend. Tiles each of the boxes. The effect is: tileBox: PROC [box: Box] ~ { Tile[self, box, tile, s0, f0, phase, function] }; boxes[tileBox]; For removing a constant border. All of the samples outside the resulting box will be equal to background. Tests for a constant. Tests for equality. Pixels, PixelBuffers and PixelMaps Gets a run of pixels from a pixel map into a pixel buffer. The effect is: FOR i: NAT IN [0..self.samplesPerPixel) DO self[i].GetSamples[min, delta, pixels[i], start, count]; ENDLOOP; Stores a run of pixels into a pixel map from a pixel buffer. The effect is: FOR i: NAT IN [0..self.samplesPerPixel) DO self[i].PutSamples[min, delta, pixels[i], start, count, function]; ENDLOOP; ส ๑˜codešœ™Kšœ ฯmœ7™BK™/K™(—K˜šฯk ˜ Kšœžœ˜%Kšœ žœ ˜Kšœžœ˜,Kšœ žœ ˜.Kšžœžœ6˜>Kšœ žœ˜—K˜Kšะbl œžœž ˜šœž˜K˜Kšœžœ'˜;K˜Kšœžœžœ˜Kšœžœ ˜Kšœžœ˜Kšœžœžœ˜Kšœ*˜*Kšœ žœžœ ˜Kšœžœžœ˜%Kšœ žœžœžœ˜K˜šœžœ˜ K˜——head™Kšœžœžœ˜Kšœžœ˜ Kšœ žœ˜#Kšœžœ˜+Kšœžœžœ˜/K˜Kšœžœžœ˜)šœžœžœ˜ Kšœžœ˜ Kšœ žœ žœžœ˜*Kšœ˜K˜—K˜š ฯn œžœ žœžœžœ˜TK˜—š œžœ žœžœ˜@K™—š œžœ˜4K˜—š œžœ žœ žœ˜FK˜—š œžœ'žœžœžœžœžœ ˜hK˜—š  œžœ˜*K˜—š  œžœ0žœ žœ ˜aK˜——™Kšœ žœžœ˜#šœžœžœ˜K™5Kšœ ฯc:˜EKšœžœก˜0Kšœ žœก˜'Kšœก˜2Kšœžœก'˜0Kšœ˜Kš œาฯbœขœ(ขœdขœ™๛K˜—K˜š œžœžœ9žœ"žœ žœ"žœžœ ˜วKšœท™ทK˜—K˜š  œžœ žœžœžœžœ˜DK™PK˜—š   œžœ žœžœžœžœ˜AK™JK˜—š   œžœ=žœžœžœ˜eK™DKšœG™GK™—K˜š   œžœ<žœžœžœ ˜†K™3KšœG™GK˜—š  œžœSžœžœ ˜€Kšœ/™/Kšœ/™/K˜—š œžœ%žœ ˜QK™*K˜—K˜š œžœ&žœ ˜FK™4K˜—š œžœ&žœ ˜GKšœ+™+K˜—K˜š œžœ0žœ ˜ZK˜—š œžœ˜*K˜—š œžœ8žœ˜`K˜——™Kšœ žœžœ8˜Ošœ&˜&Kšœ™Kšœžœ ™!Kšœžœ ™#Kšœžœžœ™1Kšœžœ ™#K™ K™—K˜š œžœžœ ˜9K™%Kš œžœžœžœ žœžœ™OK˜—š œžœR˜[KšœU™UKš œžœžœžœ žœžœ™OK˜—K˜š  œžœ`žœ žœ ˜™Aš žœžœžœžœž™6Kšœ+™+Kšœ-™-Kšžœ™——K˜—š  œžœ`žœ žœ0˜ณ™Cš žœžœžœžœž™6Kšœ+™+Kšœ6™6Kšžœ™——K˜—K˜š œžœ˜Kšœ"™"K™UK™.K™—š œžœˆ˜–™2KšœU™Ušžœžœžœž™"šžœžœžœž™"K™Kšœ,™,Kšœ-™-Kšžœ™—Kšžœ™——K˜—š  œžœ˜ข™(šœ žœ™ Kšœ%™%Kšœ%™%Kšœ7™7Kšœ™—Kšœ™—K˜—š œžœz˜„KšœY™YK˜—š  œžœ˜™Hšœ žœ™Kšœ%™%Kšœ%™%Kšœ/™/Kšœ™—K™—K˜—š œžœe˜o™9KšœB™Bšžœžœžœž™"šžœžœžœž™"K™Kšœ/™/Kšžœ™—Kšžœ™——K˜—š  œžœg˜v™$šœ žœ™K™!Kšœ™—Kšœ™—K˜—K˜š  œžœ žœkžœžœ ˜จKšœ#™#K˜—š œžœ@žœ žœ*˜‡šœS™SKšœB™Bšžœžœžœ%ž™4šžœžœžœ%ž™4Kšœžœ™Kšœžœขœ™2Kšœ ขœขœ™IKšœ"™"Kšžœ™—Kšžœ™—KšœขœขœI™X—K˜—š  œžœAžœ žœ*˜šœ(™(šœ žœ™Kšœ.™.Kšœ™—Kšœ™—K™—š œžœ>žœ˜VK™KšœI™IK˜—K˜š œžœ9žœžœ˜SK™K™—š œžœMžœžœ˜gK™K™——™"Kš œ žœžœžœžœ ˜1K˜Kšœ žœžœ˜'šœžœžœ˜Kšœžœ˜ Kšœžœžœžœ ˜