<> <> <> <> 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; }; < {>> <> <> <> <> <> <> <> <> <> <> <> <> <> < {>> <> <> <> <> <> <> <> <> <> <<};>> < {>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> < ERROR; -- unknown ColorOperator>> <> <> <> <> <> <<};>> 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.