DIRECTORY Basics, FunctionCache, Imager, ImagerCache, ImagerColorDefs, ImagerColorPrivate, ImagerDevice, ImagerFunctionDevice, ImagerMask, ImagerOps, ImagerPixelArrayDefs, ImagerPixelMap, ImagerRaster, ImagerSample, ImagerTransformation, PixelMapOps, PrincOps, Real, Vector2; ImagerFunctionDeviceImpl: CEDAR PROGRAM IMPORTS Basics, FunctionCache, Imager, ImagerCache, ImagerMask, ImagerOps, ImagerPixelMap, ImagerRaster, ImagerSample, ImagerTransformation, PixelMapOps, Real EXPORTS ImagerFunctionDevice, ImagerColorDefs ~ BEGIN OPEN ImagerFunctionDevice; Transformation: TYPE ~ ImagerTransformation.Transformation; Color: TYPE ~ ImagerColorDefs.Color; ConstantColor: TYPE ~ ImagerColorDefs.ConstantColor; SampledColor: TYPE ~ ImagerColorDefs.SampledColor; ColorOperator: TYPE ~ ImagerColorDefs.ColorOperator; PixelArray: TYPE ~ ImagerPixelArrayDefs.PixelArray; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; Sample: TYPE ~ ImagerSample.Sample; Sampler: TYPE ~ ImagerSample.Sampler; SampleBuffer: TYPE ~ ImagerSample.SampleBuffer; UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples; DeviceBox: TYPE ~ ImagerDevice.DeviceBox; Rectangle: TYPE ~ ImagerTransformation.Rectangle; Context: TYPE ~ Imager.Context; Device: TYPE ~ ImagerDevice.Device; RunProc: TYPE ~ ImagerDevice.RunProc; BoxProc: TYPE ~ ImagerDevice.BoxProc; ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl; ConstantColorImplRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorImplRep; ConstantColorClass: TYPE ~ ImagerColorPrivate.ConstantColorClass; ConstantColorClassRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorClassRep; bitsPerWord: NAT ~ Basics.bitsPerWord; class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep _ [ type: $FunctionDevice, SetColor: FunctionDeviceSetColor, SetPriority: FunctionDeviceSetPriority, SetHalftone: FunctionDeviceSetHalftone, MaskRuns: FunctionDeviceMaskRuns, MaskBoxes: FunctionDeviceMaskBoxes, MaskBits: FunctionDeviceMaskBits, MoveBoxes: FunctionDeviceMoveBoxes ]]; Lg: PROC [n: NAT] RETURNS [NAT] ~ { RETURN[SELECT n FROM 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4, ENDCASE => ERROR] }; fontCacheID: ATOM ~ $FunctionDevice; fontCacheSize: NAT _ 4000; fontRastWeight: REAL _ 0.0; Case: TYPE ~ {nil, constant, sampled}; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ clientFunc: ClientFunc _ NIL, -- function called to apply color to pms pms: LIST OF ImagerPixelMap.PixelMap, -- device image buffers samplesPerPixel: NAT _ , -- device needs this many 16 bit samples to represent constantColor maxValue: Sample, sOrigin, fOrigin: INTEGER, deviceToPixel: Transformation, case: Case _ nil, -- what type of color: sampled or constant constantColor: SampleBuffer _ NIL, -- samplesPerPixel 8(room for 16) bit numbers sampledColor: LIST OF ImagerPixelMap.PixelMap _ NIL, -- samplesPerPixel 8 bit pixelmaps paToDevice: Transformation _ NIL, -- transformation from pa coords to pixelMap coords sampBuffer: ImagerSample.SampleBuffer _, -- scan line buffer for samples from sampledColor lineBuffer: ImagerSample.SampleBuffer _, -- for ops that cannot go directly to frame sampler: ImagerSample.Sampler _ -- sampler information ]; SampledColorData: TYPE ~ REF SampledColorDataRep; SampledColorDataRep: TYPE ~ RECORD [ colorPms: LIST OF PixelMap ]; me: REF TEXT ~ "FuncDev"; -- a globally unique REF for use as a clientID in the global cache. LikeScreen: PUBLIC PROC [sSize: NAT] RETURNS [Transformation] ~ { m: Transformation ~ ImagerTransformation.Translate[[sSize, 0]]; m.ApplyPreRotate[90]; RETURN [m]; }; Create: PUBLIC PROC [ samplesPerPixel:NAT, -- device color has this many 16 bit samples / pixel devicePms: LIST OF PixelMap, -- where this device stores the image deviceToPixel: Transformation _ NIL, -- transformation from device space initialScale: REAL _ 1.0, -- 1 unit = 1 pixel clientFunc: ClientFunc _ NIL -- devicePms _ clientFunc(devicePms, color) ] RETURNS [context: Context] ~ { device: ImagerDevice.Device ~ DeviceFromPixelMap[samplesPerPixel, devicePms, deviceToPixel, clientFunc]; fontCache: ImagerCache.Ref ~ ImagerCache.GetNamedCache[atom: fontCacheID, createSize: fontCacheSize]; context _ ImagerRaster.Create[device: device, pixelUnits: TRUE, fontCache: fontCache, rastWeight: fontRastWeight]; Imager.ScaleT[context, initialScale]; }; CreateFromDevice: PUBLIC PROC [ device: ImagerDevice.Device, initialScale: REAL _ 1.0 -- 1 unit = 1 pixel ] RETURNS [context: Context] ~ { fontCache: ImagerCache.Ref ~ ImagerCache.GetNamedCache[atom: fontCacheID, createSize: fontCacheSize]; context _ ImagerRaster.Create[device: device, pixelUnits: TRUE, fontCache: fontCache, rastWeight: fontRastWeight]; Imager.ScaleT[context, initialScale]; }; DeviceBoxFromRectangle: PROC [r: Rectangle] RETURNS [DeviceBox] ~ { smin: CARDINAL _ Real.RoundC[r.x]; fmin: CARDINAL _ Real.RoundC[r.y]; smax: CARDINAL _ Real.RoundC[r.x+r.w]; fmax: CARDINAL _ Real.RoundC[r.y+r.h]; IF smin > smax THEN {t: CARDINAL _ smin; smin _ smax; smax _ t}; IF fmin > fmax THEN {t: CARDINAL _ fmin; fmin _ fmax; fmax _ t}; RETURN [[smin: smin, fmin: fmin, smax: smax, fmax: fmax]] }; DeviceFromPixelMap: PUBLIC PROC [ samplesPerPixel:NAT, pms: LIST OF PixelMap, deviceToPixel: Transformation, clientFunc: ClientFunc ] RETURNS [ImagerDevice.Device] ~ { w: ImagerPixelMap.DeviceRectangle _ [0, 0, 0, 0]; normPms: LIST OF PixelMap _ NIL; -- where normalised pixelmaps are stored sampler: ImagerSample.Sampler ~ NEW[ImagerSample.SamplerRep _ []]; maxValue: CARDINAL _ 0; sampBufferSize: NAT _ 0; data: Data; nPms: NAT _ 0; IF pms#NIL THEN { NormalisePms: PROC [lpms:LIST OF PixelMap, s,f: NAT] RETURNS [rpms: LIST OF PixelMap, howMany:NAT _ 0] ~ { IF lpms=NIL THEN RETURN [NIL, 0] ELSE { pm: PixelMap _ lpms.first; IF pm.sSize#s OR pm.fSize#f THEN ERROR; pm _ pm.Clip[w].ShiftMap[-w.sMin, -w.fMin]; [rpms, howMany] _ NormalisePms[lpms.rest, s, f]; RETURN [CONS[pm, rpms], howMany+1]; }; }; firstPm: PixelMap _ pms.first; w _ ImagerPixelMap.BoundedWindow[firstPm]; maxValue _ Basics.BITSHIFT[1, Basics.BITSHIFT[1, firstPm.refRep.lgBitsPerPixel]]-1; [normPms, nPms] _ NormalisePms[pms, pms.first.sSize, pms.first.fSize]; sampBufferSize _ firstPm.fSize; }; data _ NEW[DataRep _ [ clientFunc: clientFunc, pms: normPms, samplesPerPixel: samplesPerPixel, maxValue: maxValue, sOrigin: w.sMin, fOrigin: w.fMin, deviceToPixel: ImagerTransformation.Scale[1], sampBuffer: ImagerSample.NewBuffer[samplesPerPixel, sampBufferSize+2], lineBuffer: ImagerSample.NewBuffer[nPms, sampBufferSize+2], sampler: sampler ]]; RETURN [NEW[ImagerDevice.DeviceRep _ [ class: class, box: [smin: 0, fmin: 0, smax: w.sSize, fmax: w.fSize], surfaceToDevice: deviceToPixel, surfaceUnitsPerInch: [72, 72], surfaceUnitsPerPixel: 1, data: data]]] }; FunctionDeviceSetPriority: PROC [device: Device, priorityImportant: BOOL] ~ { }; FunctionDeviceSetHalftone: PROC [ device: Device, halftone: ImagerDevice.HalftoneParameters] ~ { }; PixelFromIntensity: PROC[i: REAL, maxValue: CARDINAL] RETURNS[CARDINAL] ~ { IF i<=0.0 THEN RETURN[0]; IF i>=1.0 THEN RETURN[maxValue]; RETURN[Real.RoundC[i*maxValue]]; }; FunctionDeviceSetColor: PROC [device: Device, color: Color, viewToDevice: Transformation] ~ { data: Data ~ NARROW[device.data]; data.sampledColor _ NIL; -- drop old pixelmaps on the floor WITH color SELECT FROM color: ConstantColor => { data.case _ constant; data.constantColor _ NARROW[color.data]; }; color: SampledColor => { pa: PixelArray ~ color.pa; cache: FunctionCache.Cache _ FunctionCache.GlobalCache[]; compare: FunctionCache.CompareProc ~ {RETURN [argument=pa]}; colorPms: LIST OF PixelMap _ NARROW[FunctionCache.Lookup[cache, compare, me].value]; IF color = NIL THEN ERROR; IF pa.samplesPerPixel#data.samplesPerPixel THEN ERROR; data.case _ sampled; data.paToDevice _ ImagerTransformation.Cat[pa.m, color.um, viewToDevice]; IF colorPms=NIL THEN { words: LONG CARDINAL _ 0; FOR sampleIx: NAT DECREASING IN [0..pa.samplesPerPixel) DO colorPms _ CONS[ImagerOps.PixelMapFromPixelArray[pa, sampleIx], colorPms]; words _ words + colorPms.first.refRep.words; ENDLOOP; data.sampledColor _ colorPms; FunctionCache.Insert[cache, pa, colorPms, words, me]; } ELSE data.sampledColor _ colorPms; }; ENDCASE => ERROR; -- unknown color variant }; MaskRunsInternal: PROC[data: Data, bounds: DeviceBox, runs: PROC[RunProc]] ~ { sbs: SampleBuffer ~ data.sampBuffer; sampler: ImagerSample.Sampler ~ data.sampler; lbs: SampleBuffer _ data.lineBuffer; pms: LIST OF PixelMap _ data.pms; Run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { localPms: LIST OF PixelMap; IF data.case = sampled THEN { colorPms: LIST OF PixelMap _ data.sampledColor; FOR sampleIx: NAT IN [0..data.samplesPerPixel) DO t: PixelMap _ colorPms.first; sampler.base _ t.refRep.pointer; sampler.wordsPerLine _ t.refRep.rast; sampler.bitsPerSample _ Basics.BITSHIFT[1, t.refRep.lgBitsPerPixel]; sampler.sMin _ t.sMin; sampler.fMin _ t.fMin; sampler.sSize _ t.sSize; sampler.fSize _ t.fSize; ImagerSample.SetSamplerIncrements[sampler, data.paToDevice]; ImagerSample.SetSamplerPosition[sampler: sampler, m: data.paToDevice, s: sMin, f: fMin]; ImagerSample.GetPointSamples[sampler: sampler, s: sMin, f: fMin, buffer: sbs, bi: sampleIx, bj: fMin, count: fSize]; colorPms _ colorPms.rest; ENDLOOP; } ELSE { -- constant FOR sampleIx: NAT IN [0..data.samplesPerPixel) DO PixelMapOps.FillSamples[buffer: sbs, i: sampleIx, j: fMin, count: fSize, sample: ImagerSample.GetSample[data.constantColor, sampleIx, 0]]; ENDLOOP; }; localPms _ pms; FOR sampleIx:NAT _ 0, sampleIx+1 WHILE localPms#NIL DO -- copy destination pixels into a lineBuffer PixelMapOps.GetF[pixelMap: localPms.first, s: sMin, f: fMin, buffer: lbs, bi: sampleIx, bj: fMin, count: fSize]; localPms _ localPms.rest; ENDLOOP; IF data.clientFunc#NIL THEN -- apply the client function data.clientFunc[fMin, fSize, sbs, lbs]; localPms _ pms; FOR sampleIx:NAT _ 0, sampleIx+1 WHILE localPms#NIL DO PixelMapOps.PutF[pixelMap: localPms.first, s: sMin, f: fMin, buffer: lbs, bi: sampleIx, bj: fMin, count: fSize]; localPms _ localPms.rest; ENDLOOP; }; runs[Run]; }; FunctionDeviceMaskRuns: PROC[device: Device, bounds: DeviceBox, runs: PROC[RunProc]] ~ { data: Data ~ NARROW[device.data]; functionDeviceMaskRunsAction: PROC ~ { MaskRunsInternal[data, bounds, runs] }; MaskRunsInternal[data, bounds, runs]; }; FunctionDeviceMaskBoxes: PROC[device: Device, bounds: DeviceBox, boxes: PROC[BoxProc]] ~ { data: Data ~ NARROW[device.data]; maskBoxesInternal: PROC ~ { functionDeviceBox: PROC[box: DeviceBox] ~ { runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBox[box: box, run: run] }; MaskRunsInternal[data: data, bounds: box, runs: runs]; }; boxes[functionDeviceBox]; }; maskBoxesInternal[]; }; FunctionDeviceMaskBits: PROC[device: Device, srcBase: LONG POINTER, srcWordsPerLine: NAT, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ { data: Data ~ NARROW[device.data]; functionDeviceMaskBitsBox: PROC[box: DeviceBox] ~ { functionDeviceMaskBitsBoxAction: PROC ~ { runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBits[ base: srcBase, wordsPerLine: srcWordsPerLine, sBits: box.smin-ts, fBits: box.fmin-tf, sRuns: box.smin, fRuns: box.fmin, sSize: box.smax-box.smin, fSize: box.fmax-box.fmin, run: run]; }; MaskRunsInternal[data: data, bounds: box, runs: runs]; }; functionDeviceMaskBitsBoxAction[]; }; boxes[functionDeviceMaskBitsBox]; }; FunctionDeviceMoveBoxes: PROC [device: Device, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ { ERROR Imager.Error[[$unimplemented, "MoveViewRectangle not implemented"]]; }; MakeConstantColor: PUBLIC PROC [sample: SampleBuffer] RETURNS [color: ImagerColorDefs.ConstantColor] ~ { color _ NEW[ImagerColorDefs.ColorRep[constant]]; color.data _ sample; }; MakePMS: PUBLIC PROC [n, sSize, fSize:NAT] RETURNS [LIST OF PixelMap] ~ { IF n=0 THEN RETURN [NIL] ELSE { pm: PixelMap _ ImagerPixelMap.Create[3, [0,0, sSize, fSize]]; pm.Fill[[0,0,sSize, fSize], 255, [null, null]]; RETURN [CONS[pm, MakePMS[n-1, sSize, fSize]]] } }; END. ΠImagerFunctionDeviceImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Michael Plass, October 7, 1985 11:07:12 am PDT Last edited by: Mik Lamming - November 19, 1985 5:30:36 pm PST Κ κ˜code™Kšœ Οmœ1™K™—šΟk œŠ˜“K˜—K˜KšΠblΠlnœž ˜'Kšžœ—˜žKšžœ&˜-šœžœžœ˜"K˜Kšœžœ'˜;Kšœžœ˜$Kšœžœ!˜4Kšœžœ ˜2Kšœžœ!˜4Kšœ žœ#˜3Kšœ žœ˜)Kšœžœ"˜7Kšœžœ˜#Kšœ žœ˜%Kšœžœ˜/Kšœžœ˜1Kšœ žœ˜)Kšœ žœ"˜1Kšœ žœ˜Kšœžœ˜#Kšœ žœ˜%Kšœ žœ˜%˜K˜—Kšœžœ(˜?Kšœžœžœ+˜LK˜Kšœžœ)˜Ašœžœžœ,˜NK˜—šœ žœ˜&K˜—šœžœ˜9Kšœ˜Kšœ!˜!Kšœ'˜'Kšœ'˜'Kšœ!˜!Kšœ#˜#Kšœ!˜!Kšœ"˜"Kšœ˜K˜K˜—š Οnœžœžœžœžœ˜#Kš žœžœžœ*žœžœ˜OK˜K˜—Kšœ žœ˜$Kšœžœ˜šœžœ˜K˜—šœžœ˜&K˜—Kšœžœžœ ˜šœ žœžœ˜KšœžœΟc(˜GKšœžœžœ’˜=Kšœžœ’C˜\Kšœ˜Kšœžœ˜Kšœ˜Kšœ’+˜=Kšœžœ’-˜PKšœžœžœžœ’$˜YKšœžœ’3˜UKšœ)’1˜ZKšœ)’+˜TKšœžœ’˜6K˜—˜K˜—Kšœžœžœ˜1šœžœžœ˜$Kšœ žœžœ ˜Kšœ˜K˜—Kšœžœžœ’C˜]K˜š ‘ œžœžœ žœžœ˜AKšœ?˜?Kšœ˜Kšžœ˜ Kšœ˜K˜—š‘œžœžœ˜Kšœžœ’5˜KKšœ žœžœ ’%˜BKšœ žœ’#˜HKšœžœ ’˜.Kšœžœ’+˜HKšœ˜Kšžœ˜Kšœh˜hKšœe˜eKšœ:žœ4˜rKšœ%˜%Kšœ˜K˜K˜—š‘œžœžœ˜Kšœ˜Kšœžœ’˜-Kšœ˜Kšžœ˜Kšœe˜eKšœ:žœ4˜rKšœ%˜%Kšœ˜K˜K˜—š‘œžœžœ˜CKšœžœ˜"Kšœžœ˜"Kšœžœ˜&Kšœžœ˜&Kšžœ žœžœ ˜@Kšžœ žœžœ ˜@Kšžœ3˜9Kšœ˜K˜—š‘œž œ˜!Kšœžœ˜Kšœžœžœ ˜Kšœ˜Kšœ˜Kšœžœ˜$Kšœ1˜1Kšœ žœžœ žœ’(˜IKšœ žœ˜BKšœ žœ˜Kšœžœ˜Kšœ ˜ Kšœžœ˜K˜šžœžœž˜š‘ œžœžœžœžœžœžœžœžœ ˜jKš žœžœžœžœžœ˜ šžœ˜Kšœ˜Kšžœ žœ žœžœ˜'Kšœ+˜+Jšœ0˜0Kšžœžœ˜#K˜—K˜—Kšœ˜Kšœ*˜*Kšœžœ žœ&˜SKšœF˜FKšœ˜K˜—šœžœ ˜Kšœ˜Jšœ ˜ Jšœ!˜!K˜Kšœ˜Kšœ˜Kšœ-˜-KšœF˜FKšœ;˜;Kšœ˜Kšœ˜—šžœžœ˜&Kšœ ˜ Kšœ6˜6Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ —Kšœ˜K˜—š‘œžœ%žœ˜MKšœ˜K˜—š‘œžœ˜!Kšœ˜Kšœ.˜.K˜K˜—š ‘œžœžœ žœžœžœ˜KKšžœžœžœ˜Kšžœžœžœ ˜ Kšžœ˜ K˜K˜—š‘œžœA˜]Kšœ žœ˜!Kšœžœ’"˜;šžœžœž˜˜Kšœ˜Kšœžœ ˜(K˜—šœ˜Kšœ˜Kšœ9˜9Kšœ&žœ˜