DIRECTORY Basics, ImagerPixel USING [PixelBuffer, PixelBufferRep, PixelMap, PixelMapRep, PixelProc, ResampleAction], ImagerSample USING [BitsPerSample, Function, Get, GetSamples, CopySamples, maxCount, NewSampleMap, NewSamples, GetBox, MultipleReleaseOfScratch, nullFunction, PutSamples, RasterSampleMap, Sample, SampleBuffer, SampleBufferRep, SampleMap, zeroVec], ImagerTransformation USING [InverseTransform, InverseTransformVec, Singular, Transformation], RealInline, SF USING [Box, BoxAction, BoxGenerator, SizeF, Vec]; ImagerPixelImpl: CEDAR MONITOR IMPORTS Basics, ImagerSample, ImagerTransformation, RealInline, SF EXPORTS ImagerPixel SHARES ImagerSample ~ BEGIN OPEN ImagerPixel; bitsPerUnit: NAT ~ BITS[UNIT]; bitsPerWord: NAT ~ BITS[WORD]; RawSamples: TYPE ~ Basics.RawWords; RawSamplesPtr: TYPE ~ LONG POINTER TO Basics.RawWords; Transformation: TYPE ~ ImagerTransformation.Transformation; InlinePointerToSamples: PROC [samples: ImagerSample.SampleBuffer, start: NAT, count: NAT] RETURNS [LONG POINTER TO RawSamples] ~ TRUSTED INLINE { check: NAT ~ NAT[samples.maxLength-start]-count; RETURN[LOOPHOLE[samples, LONG POINTER]+SIZE[ImagerSample.SampleBufferRep[start]]]; }; NewPixels: PUBLIC PROC [samplesPerPixel: NAT, length: NAT, scratch: PixelBuffer ¬ NIL] RETURNS [PixelBuffer] ~ { new: PixelBuffer ¬ scratch; IF new=NIL OR new.samplesPerPixel#samplesPerPixel THEN new ¬ NEW[PixelBufferRep[samplesPerPixel]]; FOR i: NAT IN [0..samplesPerPixel) DO new[i] ¬ ImagerSample.NewSamples[length: length]; ENDLOOP; new.length ¬ length; RETURN[new]; }; nScratchPixelBuffers: NAT ~ 12; scratchPixelBuffers: ARRAY [0..nScratchPixelBuffers) OF PixelBuffer ¬ ALL[NIL]; ObtainScratchPixels: PUBLIC ENTRY PROC [samplesPerPixel: NAT, length: NAT] RETURNS [PixelBuffer] ~ { FOR i: NAT IN [0..nScratchPixelBuffers) DO buf: PixelBuffer ~ scratchPixelBuffers[i]; IF buf # NIL AND buf.samplesPerPixel = samplesPerPixel AND buf.length >= length THEN { scratchPixelBuffers[i] ¬ NIL; buf.length ¬ length; FOR j: NAT IN [0..samplesPerPixel) DO buf[j].length ¬ length; ENDLOOP; RETURN [buf]; }; ENDLOOP; RETURN[NewPixels[samplesPerPixel: samplesPerPixel, length: length]] }; ReleaseScratchPixels: PUBLIC ENTRY PROC [pixels: PixelBuffer] ~ { slot: NAT ¬ 0; IF pixels.samplesPerPixel = 0 THEN RETURN; -- Joker FOR j: NAT IN [1..pixels.samplesPerPixel) DO IF pixels[j].maxLength # pixels[0].maxLength THEN RETURN ENDLOOP; FOR i: NAT IN [0..nScratchPixelBuffers) DO t: PixelBuffer ¬ scratchPixelBuffers[i]; IF t = NIL THEN slot ¬ i ELSE IF pixels = t THEN RETURN WITH ERROR ImagerSample.MultipleReleaseOfScratch; ENDLOOP; pixels.length ¬ pixels[0].maxLength; scratchPixelBuffers[slot] ¬ pixels; }; DoWithScratchPixels: PUBLIC PROC [samplesPerPixel: NAT, length: NAT, action: PROC [PixelBuffer]] ~ { scratch: PixelBuffer ~ ObtainScratchPixels[samplesPerPixel: samplesPerPixel, length: length]; action[scratch ! UNWIND => ReleaseScratchPixels[scratch]]; ReleaseScratchPixels[scratch]; }; NewPixelMap: PUBLIC PROC [samplesPerPixel: NAT, box: SF.Box, maxSample: PixelProc] RETURNS [PixelMap] ~ { new: PixelMap ¬ NEW[PixelMapRep[samplesPerPixel]]; FOR i: NAT IN [0..samplesPerPixel) DO bitsPerSample: ImagerSample.BitsPerSample ~ SELECT maxSample[i] FROM <2 => 1, <4 => 2, <16 => 4, <256 => 8, <=65535 => 16, ENDCASE => ImagerSample.BitsPerSample.LAST; new[i] ¬ ImagerSample.NewSampleMap[box: box, bitsPerSample: bitsPerSample]; ENDLOOP; new.box ¬ box; RETURN[new]; }; MakePixelMap: PUBLIC PROC [s0, s1, s2, s3, s4: ImagerSample.SampleMap ¬ NIL] RETURNS [PixelMap] ~ { s: ARRAY [0..5) OF ImagerSample.SampleMap ~ [s0, s1, s2, s3, s4]; Count: PROC RETURNS [i: NAT ¬ 0] ~ INLINE {WHILE i < 5 AND s[i] # NIL DO i ¬ i + 1 ENDLOOP}; n: NAT ~ Count[]; new: PixelMap ~ NEW[PixelMapRep[n]]; new.box ¬ IF n = 0 THEN [ImagerSample.zeroVec, ImagerSample.zeroVec] ELSE ImagerSample.GetBox[s[0]]; FOR i: NAT IN [0..n) DO assert: BOOL[TRUE..TRUE] ~ ImagerSample.GetBox[s[i]] = new.box; new[i] ¬ s[i]; ENDLOOP; FOR i: NAT IN [n..5) DO assert: BOOL[TRUE..TRUE] ~ s[i] = NIL; ENDLOOP; RETURN [new] }; GetPixels: PUBLIC PROC [self: PixelMap, initIndex: SF.Vec ¬ ImagerSample.zeroVec, delta: SF.Vec ¬ [s: 0, f: 1], pixels: PixelBuffer, start: NAT ¬ 0, count: NAT ¬ ImagerSample.maxCount] ~ { FOR i: NAT IN [0..self.samplesPerPixel) DO ImagerSample.GetSamples[self[i], initIndex, delta, pixels[i], start, count]; ENDLOOP; }; PutPixels: PUBLIC PROC [self: PixelMap, initIndex: SF.Vec ¬ ImagerSample.zeroVec, delta: SF.Vec ¬ [s: 0, f: 1], pixels: PixelBuffer, start: NAT ¬ 0, count: NAT ¬ ImagerSample.maxCount, function: ImagerSample.Function ¬ ImagerSample.nullFunction] ~ { FOR i: NAT IN [0..self.samplesPerPixel) DO ImagerSample.PutSamples[self[i], initIndex, delta, pixels[i], start, count, function]; ENDLOOP; }; realLastInt: REAL ¬ REAL[LAST[INT]]; ScaledFromRealMod: PROC [d: REAL, m: CARDINAL[0..32768]] RETURNS [INT] ~ { s: Basics.LongNumber ¬ [li[0]]; IF m # 0 THEN { modulus: REAL ~ m; SELECT d FROM IN [0..modulus) => s.li ¬ RealInline.MCFix[ d * 65536.0 ]; IN (-modulus..0) => s.li ¬ (m*65536) - RealInline.MCFix[ -d * 65536.0 ]; ENDCASE => s.li ¬ RealInline.MCRound[ (d-modulus*RealInline.MCFloor[d/modulus]) * 65536.0 ]; IF s.li < 0 THEN {s.hi ¬ s.hi + m}; IF s.hi >= m THEN {s.hi ¬ s.hi - m}; IF s.hi >= m THEN ERROR; }; RETURN [s.li]; }; Sample1: TYPE ~ ImagerSample.Sample[0..1B]; Sample8: TYPE ~ ImagerSample.Sample[0..377B]; Sample16: TYPE ~ ImagerSample.Sample[0..177777B]; RawSamples1: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample1]; RawSamples8: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample8]; RawSamples16: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF Sample16]; Pointer1: TYPE ~ LONG POINTER TO RawSamples1; Pointer8: TYPE ~ LONG POINTER TO RawSamples8; Pointer16: TYPE ~ LONG POINTER TO RawSamples16; Resample1: PROC [dest, source: PixelMap, m: Transformation, interpolate: BOOL] ~ { boxes: SF.BoxGenerator ~ {boxAction[dest.box]}; action: ResampleAction ~ { FOR j: NAT IN [0..pixels.samplesPerPixel) DO ImagerSample.PutSamples[map: dest[j], buffer: pixels[j], initIndex: min]; ENDLOOP; }; Resample[self: source, m: m, interpolate: interpolate, boxes: boxes, bounds: dest.box, action: action]; }; Resample: PUBLIC PROC [self: PixelMap, m: Transformation, interpolate: BOOL, boxes: SF.BoxGenerator, bounds: SF.Box, action: ResampleAction] ~ { IF NOT ImagerTransformation.Singular[m] THEN { samplesPerPixel: NAT ~ self.samplesPerPixel; sSize: NAT15 ~ self.box.max.s-self.box.min.s; -- source size in slow (scan line) direction fSize: NAT15 ~ self.box.max.f-self.box.min.f; -- source size in fast (pixel) direction ssDelta: Basics.LongNumber; -- source delta s for destination s increment fsDelta: Basics.LongNumber; -- source delta f for destination s increment sfDelta: Basics.LongNumber; -- source delta s for destination f increment ffDelta: Basics.LongNumber; -- source delta f for destination f increment d0: SF.Vec ¬ bounds.min; -- initial destination position s0: Basics.LongNumber; -- initial source s (corresponding to d0) f0: Basics.LongNumber; -- initial source f (corresponding to d0) pixels: PixelBuffer ~ ObtainScratchPixels[samplesPerPixel, SF.SizeF[bounds]]; rs, rf: REAL ¬ 0.0; boxActionPointSamples: SF.BoxAction ~ { count: NAT ~ SF.SizeF[box]; smax: Basics.LongNumber ~ [pair[hi: sSize, lo: 0]]; fmax: Basics.LongNumber ~ [pair[hi: fSize, lo: 0]]; ssup: Basics.LongNumber ~ ssDelta; fsup: Basics.LongNumber ~ fsDelta; ssdn: Basics.LongNumber ~ [lc[smax.lc-ssup.lc]]; fsdn: Basics.LongNumber ~ [lc[fmax.lc-fsup.lc]]; sfup: Basics.LongNumber ~ sfDelta; ffup: Basics.LongNumber ~ ffDelta; sfdn: Basics.LongNumber ~ [lc[smax.lc-sfup.lc]]; ffdn: Basics.LongNumber ~ [lc[fmax.lc-ffup.lc]]; d1s, d1f: INTEGER; -- destination position at start of scan line s1: Basics.LongNumber ¬ s0; -- source s corresponding to [d1s, d1f] f1: Basics.LongNumber ¬ f0; -- source f corresponding to [d1s, d1f] [d1s, d1f] ¬ d0; WHILE d1sbox.min.s DO d1s ¬ d1s-1; IF s1.lc>=ssup.lc THEN s1.lc ¬ s1.lc-ssup.lc ELSE s1.lc ¬ s1.lc+ssdn.lc; IF f1.lc>=fsup.lc THEN f1.lc ¬ f1.lc-fsup.lc ELSE f1.lc ¬ f1.lc+fsdn.lc; ENDLOOP; d0 ¬ [d1s, d1f]; s0.lc ¬ s1.lc; f0.lc ¬ f1.lc; WHILE d1fbox.min.f DO d1f ¬ d1f-1; IF s1.lc>=sfup.lc THEN s1.lc ¬ s1.lc-sfup.lc ELSE s1.lc ¬ s1.lc+sfdn.lc; IF f1.lc>=ffup.lc THEN f1.lc ¬ f1.lc-ffup.lc ELSE f1.lc ¬ f1.lc+ffdn.lc; ENDLOOP; pixels.length ¬ count; DO --For each scan line of box-- FOR i: NAT IN [0..samplesPerPixel) DO map: ImagerSample.SampleMap ~ self[i]; rasterMap: ImagerSample.RasterSampleMap ~ WITH map SELECT FROM r: ImagerSample.RasterSampleMap => r ENDCASE => NIL; easyLineCalc: BOOL ~ rasterMap # NIL AND rasterMap.base.bit=0 AND (rasterMap.bitsPerLine MOD bitsPerWord)=0; samples: ImagerSample.SampleBuffer ~ pixels[i]; s: Basics.LongNumber ¬ s1; f: Basics.LongNumber ¬ f1; SELECT TRUE FROM sfDelta.li = 0 AND ffDelta = [pair[hi: 1, lo: 0]] => { count1: NAT ~ MIN [count, fSize-f.hi]; count2: NAT ~ MIN [count-count1, f.hi]; count3: NAT ~ count-count1-count2; ImagerSample.GetSamples[map: map, initIndex: [s: s.hi+self.box.min.s, f: f.hi+self.box.min.f], buffer: samples, start: 0, count: count1]; IF count2 # 0 THEN ImagerSample.GetSamples[map: map, initIndex: [s: s.hi+self.box.min.s, f: self.box.min.f], buffer: samples, start: count1, count: count2]; IF count3 # 0 THEN ImagerSample.CopySamples[dst: samples, src: samples, dstStart: count1+count2, srcStart: 0, count: count3]; }; easyLineCalc AND rasterMap.bitsPerSample=1 => { base: Pointer1 ~ LOOPHOLE[rasterMap.base.word]; upl: NAT ~ rasterMap.bitsPerLine/bitsPerUnit; result: RawSamplesPtr ~ InlinePointerToSamples[samples, 0, count]; lastSHi: CARDINAL ¬ s.hi; line: Pointer1 ¬ base+lastSHi*upl; FOR k: NAT IN [0..count) DO IF lastSHi # s.hi THEN {lastSHi ¬ s.hi; line ¬ base+lastSHi*upl}; TRUSTED { result[k] ¬ line[f.hi] }; IF s.lc { base: Pointer8 ~ LOOPHOLE[rasterMap.base.word]; upl: NAT ~ rasterMap.bitsPerLine/bitsPerUnit; result: RawSamplesPtr ~ InlinePointerToSamples[samples, 0, count]; IF sfup.lc=0 THEN { line: Pointer8 ~ base+LONG[s.hi]*upl; FOR k: NAT IN [0..count) DO TRUSTED { result[k] ¬ line[f.hi] }; IF f.lc { base: Pointer16 ~ LOOPHOLE[rasterMap.base.word]; upl: NAT ~ rasterMap.bitsPerLine/bitsPerUnit; result: RawSamplesPtr ~ InlinePointerToSamples[samples, 0, count]; lastSHi: CARDINAL ¬ s.hi; line: Pointer16 ¬ base+LONG[lastSHi]*upl; FOR k: NAT IN [0..count) DO IF lastSHi # s.hi THEN {lastSHi ¬ s.hi; line ¬ base+lastSHi*upl}; TRUSTED { result[k] ¬ line[f.hi] }; IF s.lc { -- the slow but general way FOR k: NAT IN [0..count) DO samples[k] ¬ ImagerSample.Get[map, [s: s.hi+self.box.min.s, f: f.hi+self.box.min.f]]; IF s.lcbox.min.s DO d1s ¬ d1s-1; IF s1.lc>=ssup.lc THEN s1.lc ¬ s1.lc-ssup.lc ELSE s1.lc ¬ s1.lc+ssdn.lc; IF f1.lc>=fsup.lc THEN f1.lc ¬ f1.lc-fsup.lc ELSE f1.lc ¬ f1.lc+fsdn.lc; ENDLOOP; d0 ¬ [d1s, d1f]; s0.lc ¬ s1.lc; f0.lc ¬ f1.lc; WHILE d1fbox.min.f DO d1f ¬ d1f-1; IF s1.lc>=sfup.lc THEN s1.lc ¬ s1.lc-sfup.lc ELSE s1.lc ¬ s1.lc+sfdn.lc; IF f1.lc>=ffup.lc THEN f1.lc ¬ f1.lc-ffup.lc ELSE f1.lc ¬ f1.lc+ffdn.lc; ENDLOOP; pixels.length ¬ count; DO --For each scan line of box-- FOR i: NAT IN [0..samplesPerPixel) DO map: ImagerSample.SampleMap ~ self[i]; rasterMap: ImagerSample.RasterSampleMap ~ WITH map SELECT FROM r: ImagerSample.RasterSampleMap => r ENDCASE => NIL; samples: ImagerSample.SampleBuffer ~ pixels[i]; s: Basics.LongNumber ¬ s1; f: Basics.LongNumber ¬ f1; IF rasterMap#NIL AND rasterMap.base.bit=0 AND (rasterMap.bitsPerLine MOD bitsPerWord)=0 AND rasterMap.bitsPerSample=8 THEN { base: Pointer8 ~ LOOPHOLE[rasterMap.base.word]; unitsPerLine: NAT ~ rasterMap.bitsPerLine/bitsPerUnit; result: LONG POINTER TO RawSamples ~ InlinePointerToSamples[samples, 0, count]; FOR k: NAT IN [0..count) DO is0: CARDINAL ~ s.hi; is1: CARDINAL ~ IF is0