DIRECTORY ImagerColor, ImagerDevice USING [Class, ClassRep, Device, DeviceRep, HalftoneParameters, RunProc], ImagerPDDevice USING [], ImagerPixelArray, ImagerPixelArrayOps, ImagerPixelMap USING [Create, DeviceRectangle, PixelMap], ImagerPixelRow, ImagerSampler USING [CreateSampler, DotScreen, HalftoneLine, ObtainInterpolatedSamples, Sampler], ImagerTransformation USING [ApplyPreRotate, ApplyPreScale2, ApplyPreTranslate, Cat, Copy, Scale, Transformation], PDFileWriter USING [ColorSamples, DoForEachToner, LoadReference, MaskRunGroup, NewPriorityLevel, PDState, SetColorClear, SetColorInk, SetPriorityImportant, Toner], PrincOps USING [zBNDCK, zINC], Real USING [FixC], Vector2 USING [Div]; ImagerPDDeviceImpl: CEDAR PROGRAM IMPORTS ImagerPixelArrayOps, ImagerPixelMap, ImagerPixelRow, ImagerSampler, ImagerTransformation, PDFileWriter, Real, Vector2 EXPORTS ImagerPDDevice ~ BEGIN Device: TYPE ~ ImagerDevice.Device; RunProc: TYPE ~ ImagerDevice.RunProc; HalftoneParameters: TYPE ~ ImagerDevice.HalftoneParameters; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; Transformation: TYPE ~ ImagerTransformation.Transformation; Color: TYPE ~ ImagerColor.Color; ConstantColor: TYPE ~ ImagerColor.ConstantColor; SampledColor: TYPE ~ ImagerColor.SampledColor; ColorOperator: TYPE ~ ImagerColor.ColorOperator; ColorOperatorRep: TYPE ~ ImagerColor.ColorOperatorRep; PDState: TYPE ~ PDFileWriter.PDState; Toner: TYPE ~ PDFileWriter.Toner; LoadReference: TYPE ~ PDFileWriter.LoadReference; dummyLoadReference: LoadReference ~ LAST[LoadReference]; GrayTileArray: TYPE ~ ARRAY Toner OF ARRAY [0..64) OF LoadReference; StippleRep: TYPE ~ RECORD[loadReference: LoadReference, stipple: PixelMap]; Case: TYPE ~ {nil, constant, gray, sampled}; defaultHalftone: HalftoneParameters _ [dotsPerInch: 50, angle: 30, shape: 0.5]; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ pdState: PDState _ NIL, sSize, fSize: CARDINAL, case: Case _ nil, -- what type of color grayTileRef: GrayTileArray _ ALL[ALL[dummyLoadReference]], stipples: LIST OF StippleRep _ NIL, dot: ImagerPixelMap.PixelMap, -- a halftone dot halftone: HalftoneParameters _ defaultHalftone, -- halftone screen parameters pa: ImagerPixelArray.PixelArray _ NIL, -- pixel array from sampled color transparent: BOOL _ FALSE, -- transparent flag from sampled color multiplier: CARDINAL _ 1, lgScale: INTEGER _ 0, -- scale pa samples to match dot samples paToDevice: Transformation _ NIL, -- transformation from pa coords to display dotToDevice: Transformation _ NIL, -- transformation from dot coords to display source: ImagerPixelMap.PixelMap _ [0, 0, 0, 0, 0, 0, NIL], -- source values from pixel array paSampler: ImagerSampler.Sampler _ NIL, -- for sampling pixel array dotSampler: ImagerSampler.Sampler _ NIL, -- for sampling halftone dot paRow: ImagerPixelRow.PixelRow _ NIL, -- buffer for pixels sampled from pa dotRow: ImagerPixelRow.PixelRow _ NIL -- buffer for pixels sampled from dot ]; class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep _ [ type: $PD, SetColor: SetColor, SetPriority: SetPriority, SetHalftone: SetHalftone, MaskRuns: MaskRuns ]]; defaultDot: ImagerPixelMap.PixelMap ~ ImagerSampler.DotScreen[ r: 0.5, sSize: 16, fSize: 16, maxPixelValue: 255]; Create: PUBLIC PROC[pdState: PDState, sSize, fSize, sPixelsPerInch, fPixelsPerInch: CARDINAL] RETURNS[Device] ~ { data: Data ~ NEW[DataRep _ [pdState: pdState, sSize: sSize, fSize: fSize, dot: defaultDot]]; sInches: REAL ~ REAL[sSize]/REAL[sPixelsPerInch]; fInches: REAL ~ REAL[fSize]/REAL[fPixelsPerInch]; surfaceToDevice: Transformation ~ ImagerTransformation.Scale[1]; xPixelsPerInch: CARDINAL _ sPixelsPerInch; yPixelsPerInch: CARDINAL _ fPixelsPerInch; IF sInches>fInches THEN { -- s (y) is top-to-bottom, f (x) is left-to-right surfaceToDevice.ApplyPreTranslate[[sSize, 0]]; surfaceToDevice.ApplyPreRotate[90]; xPixelsPerInch _ fPixelsPerInch; yPixelsPerInch _ sPixelsPerInch; } ELSE NULL; -- s (x) is left-to-right, f (y) is bottom-to-top data.paRow _ ImagerPixelRow.CreatePixelRow[sMin: 0, fMin: 0, fSize: fSize]; data.dotRow _ ImagerPixelRow.CreatePixelRow[sMin: 0, fMin: 0, fSize: fSize]; RETURN[NEW[ImagerDevice.DeviceRep _ [class: class, clipBox: [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize], surfaceToDevice: surfaceToDevice, surfaceUnitsPerInch: [xPixelsPerInch, yPixelsPerInch], surfaceUnitsPerPixel: 1, data: data]]]; }; Val: TYPE ~ ImagerPixelArrayOps.Val; Table: TYPE ~ REF TableRep; TableRep: TYPE ~ RECORD[SEQUENCE size: NAT OF CARDINAL]; BuildTable: PROC[max: Val, scale: REAL, sWhite, sBlack: REAL, map: ImagerColor.SampleMap _ NIL] RETURNS[Table] ~ { table: Table ~ NEW[TableRep[max+1]]; FOR s0: Val IN[0..max] DO s: REAL ~ IF map=NIL THEN s0 ELSE map[s0]; v: REAL ~ MIN[MAX[(s-sBlack)/(sWhite-sBlack), 0], 1]; table[s0] _ Real.FixC[scale*v]; ENDLOOP; RETURN[table]; }; SetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ { data: Data ~ NARROW[device.data]; WITH color SELECT FROM color: ConstantColor => { SELECT color.cie.Y FROM 0 => { -- black SetInk: PROC[toner: Toner] ~ {data.pdState.SetColorInk[toner]}; data.pdState.DoForEachToner[SetInk]; }; 1 => { -- white SetClear: PROC[toner: Toner] ~ {data.pdState.SetColorClear[toner]}; data.pdState.DoForEachToner[SetClear]; }; ENDCASE => ERROR; -- not yet implemented data.case _ constant; }; ENDCASE => ERROR; -- unknown color variant }; SetPriority: PROC[device: Device, priorityImportant: BOOL] ~ { data: Data ~ NARROW[device.data]; [] _ data.pdState.SetPriorityImportant[priorityImportant]; }; SetHalftone: PROC[device: Device, halftone: HalftoneParameters] ~ { data: Data ~ NARROW[device.data]; data.halftone _ halftone; }; Check: PROC[x: INTEGER, max: NAT] RETURNS[NAT] ~ TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK }; MaskRuns: PROC[device: Device, runs: PROC[RunProc]] ~ { data: Data ~ NARROW[device.data]; SELECT data.case FROM nil => ERROR; -- color not initialized constant => { deliverRuns: PROC[captureRun: PROC[sMin, fMin, fSize: CARDINAL]] ~ { run: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ { captureRun[sMin, fMin, fSize] }; runs[run]; }; PDFileWriter.MaskRunGroup[data.pdState, deliverRuns]; }; sampled => { lineBuffer: ImagerPixelMap.PixelMap _ ImagerPixelMap.Create[lgBitsPerPixel: 0, bounds: [sMin: 0, fMin: 0, sSize: 1, fSize: data.fSize]]; linePointer: LONG POINTER ~ lineBuffer.refRep.pointer; deliverLine: PROC[captureLine: PROC[LONG POINTER]] ~ { captureLine[linePointer] }; paRow: ImagerPixelRow.PixelRow ~ data.paRow; dotRow: ImagerPixelRow.PixelRow ~ data.dotRow; source: ImagerPixelMap.PixelMap ~ data.source; run: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ { lineBuffer.sOrigin _ paRow.sOrigin _ dotRow.sOrigin _ Check[sMin, data.sSize]; lineBuffer.fOrigin _ paRow.fOrigin _ dotRow.fOrigin _ Check[fMin, data.fSize]; lineBuffer.fSize _ paRow.fSize _ dotRow.fSize _ Check[fSize, data.fSize-fMin]; ImagerSampler.ObtainInterpolatedSamples[sampler: data.paSampler, pixelRow: paRow, source: source, multiplier: data.multiplier, lgScale: data.lgScale]; ImagerSampler.ObtainInterpolatedSamples[sampler: data.dotSampler, pixelRow: dotRow, source: data.dot]; ImagerSampler.HalftoneLine[dest: lineBuffer, pixels: paRow, thresholds: dotRow, invertOutput: FALSE, transparent: data.transparent]; PDFileWriter.ColorSamples[pdState: data.pdState, toner: black, sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize, deliverProc: deliverLine, tFlag: IF data.transparent THEN transparent ELSE opaque]; }; PDFileWriter.NewPriorityLevel[pdState: data.pdState, toner: black]; runs[run]; }; ENDCASE => ERROR; -- illegal case }; END. \ImagerPDDeviceImpl.mesa Copyright c 1984, 1985 Xerox Corporation. All rights reserved. Michael Plass, June 22, 1984 9:41:51 am PDT Doug Wyatt, March 7, 1985 6:31:05 pm PST Call the larger dimension y; see the Interpress standard, section 4.3.1. color: SampledColor => { pa: ImagerPixelArray.PixelArray ~ color.pa; samples: ImagerPixelArrayOps.Row ~ NEW[ImagerPixelArrayOps.RowRep[pa.fSize]]; row: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[ sMin: 0, fMin: 0, fSize: pa.fSize]; data.pa _ pa; data.colorOperator _ color.colorOperator; data.paToDevice _ ImagerTransformation.Cat[pa.paToClient, color.um, viewToDevice]; data.dotToDevice _ viewToDevice.Copy[]; data.dotToDevice.ApplyPreScale2[device.surfaceUnitsPerInch.Div[data.halftone.dotsPerInch*16]]; data.dotToDevice.ApplyPreRotate[data.halftone.angle]; data.source _ ImagerPixelMap.Create[lgBitsPerPixel: 3, bounds: [sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize]]; WITH color.colorOperator SELECT FROM op: REF ColorOperatorRep.grayLinear => { table: Table _ NIL; IF pa.samplesPerPixel#1 THEN ERROR; -- samplesPerPixel must be 1 table _ BuildTable[max: ImagerPixelArrayOps.MaxSampleValue[pa, 0], scale: 255, sWhite: op.sWhite, sBlack: op.sBlack, map: op.map]; FOR s: NAT IN[0..pa.sSize) DO ImagerPixelArrayOps.GetRow[pa, samples, s, 0, 0]; FOR f: NAT IN[0..pa.fSize) DO row[f] _ table[samples[f]] ENDLOOP; row.sOrigin _ s; ImagerPixelRow.StorePixelRow[row, data.source]; ENDLOOP; }; op: REF ColorOperatorRep.separations => { tables: ARRAY[0..4) OF Table _ ALL[NIL]; IF pa.samplesPerPixel#op.samplesPerPixel THEN ERROR; -- samplesPerPixel must match FOR i: NAT IN[0..pa.samplesPerPixel) DO sep: ImagerColor.Separation ~ op[i]; tables[i] _ BuildTable[max: ImagerPixelArrayOps.MaxSampleValue[pa, i], scale: 255*sep.cie.Y, sWhite: sep.sMax, sBlack: sep.sMin, map: sep.map]; ENDLOOP; FOR s: NAT IN[0..pa.sSize) DO row.sOrigin _ s; ImagerPixelRow.ClearPixelRow[row]; FOR i: NAT IN[0..pa.samplesPerPixel) DO table: Table ~ tables[i]; ImagerPixelArrayOps.GetRow[pa, samples, s, 0, i]; FOR f: NAT IN[0..pa.fSize) DO row[f] _ row[f]+table[samples[f]] ENDLOOP; ENDLOOP; ImagerPixelRow.StorePixelRow[row, data.source]; ENDLOOP; }; ENDCASE => ERROR; -- unknown ColorOperator data.paSampler _ ImagerSampler.CreateSampler[ m: data.paToDevice, x: 0, y: 0, sPixels: pa.sSize, fPixels: pa.fSize]; data.dotSampler _ ImagerSampler.CreateSampler[ m: data.dotToDevice, x: 0, y: 0, sPixels: data.dot.sSize, fPixels: data.dot.fSize]; data.case _ sampled; }; IF x IN[0..max] THEN RETURN[x] ELSE ERROR RuntimeError.BoundsFault Might want either to interpolate or to average here. How do we decide? Κ ˜˜codešœ™Kšœ Οmœ4™?K™+K™(—K˜šΟk ˜ Kšœ ˜ Kšœ žœC˜UKšœžœ˜Kšœ˜Kšœ˜Kšœžœ%˜9Kšœ˜KšœžœN˜aKšœžœW˜qKšœ žœ‘˜£Kšœ žœ˜Kšœžœ˜Kšœžœ˜—K˜KšΠblœžœž˜!Kšžœv˜}Kšžœ˜šœž˜K˜—Kšœžœ˜#Kšœ žœ˜%Kšœžœ#˜;Kšœžœ"˜7Kšœ žœ˜)K˜Kšœžœ'˜;Kšœžœ˜ Kšœžœ˜0Kšœžœ˜.Kšœžœ˜0Kšœžœ ˜6K˜Kšœ žœ˜%Kšœžœ˜!Kšœžœ˜1Kšœ$žœ˜8Kš œžœžœžœžœ žœ˜DKšœ žœžœ2˜KK˜Kšœžœ"˜,K˜KšœO˜OK˜Kšœžœžœ ˜šœ žœžœ˜Kšœžœ˜Kšœžœ˜KšœΟc˜'Kšœžœžœ˜:Kšœ žœžœžœ˜#Kšœ ˜/Kšœ0 ˜MKšœ"žœ !˜HKšœ žœžœ &˜AKšœ žœžœ (˜XKšœžœ +˜MKšœžœ ,˜OKšœ5žœ !˜\Kšœ#žœ ˜CKšœ$žœ ˜EKšœ!žœ $˜JKšœ"žœ %˜KKšœ˜K˜—šœžœ˜9Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—šœ>˜>Kšœ2˜2K˜—šΟnœžœžœAžœ˜]Kšžœ ˜Kšœ žœL˜\Kšœ žœžœžœ˜1Kšœ žœžœžœ˜1Kšœ@˜@Kšœžœ˜*Kšœžœ˜*K™Hšžœžœ 1˜KKšœ.˜.Kšœ#˜#KšœA˜AK˜—Kšžœžœ 1˜™>—šžœžœž™$šœžœ!™(Kšœžœ™Kšžœžœžœ ™@Kšœƒ™ƒšžœžœžœž™Kšœ1™1Kš žœžœžœžœžœ™AK™K™/Kšžœ™—K™—šœžœ"™)Kš œžœžœ žœžœ™(Kšžœ'žœžœ ™Ršžœžœžœž™'K™$Kšœ[žœ4™Kšžœ™—šžœžœžœž™K™Kšœ"™"šžœžœžœž™'K™Kšœ1™1Kš žœžœžœžœ#žœ™HKšžœ™—Kšœ/™/Kšžœ™—K™—Kšžœžœ ™*—šœ-™-KšœF™F—šœ.™.KšœS™S—K™K™—Kšžœžœ ˜*—Kšœ˜K˜—š‘ œžœ$žœ˜>Kšœ žœ˜!Kšœ:˜:K˜K˜—š‘ œžœ2˜CKšœ žœ˜!K˜K˜K˜—š ‘œžœžœžœžœžœ˜0Kšžœžœžœ$˜8Kš žœžœ žœžœžœžœ™BK˜—š‘œžœžœ˜7Kšœ žœ˜!šžœ ž˜Kšœžœ ˜&šœ ˜ šœ žœ žœžœ˜DKšœžœ žœ žœ&˜OKšœ ˜ K˜—Kšœ5˜5K˜—˜ šœN˜NKšœ9˜9—Kšœ žœžœ˜6Kš œ žœžœžœžœ"˜RK˜,Kšœ.˜.Kšœ.˜.šœžœ žœ žœ˜.KšœN˜NKšœN˜NKšœN˜NKšœF™Fšœ@˜@KšœU˜U—šœA˜AKšœ$˜$—šœO˜OKšœžœ!˜4—šœ>˜>KšœI˜IKšœžœžœ žœ ˜9—K˜—KšœC˜CK˜ K˜—Kšžœžœ ˜!—Kšœ˜K˜—K˜Kšžœ˜—…—Ξ1Β