<<>> <> <> <> <> <> <> <<>> DIRECTORY Imager, ImagerBrick, ImagerColor, ImagerDevice, ImagerDeviceWorks, ImagerMaskCache, ImagerPixelArray, ImagerPrintColor, ImagerPrintContext, ImagerPrintDevice, ImagerPrivate, ImagerRaster, ImagerSample, ImagerTransformation, PrintColor, SF, Vector2; ImagerPrintContextImpl: CEDAR PROGRAM IMPORTS ImagerBrick, ImagerDevice, ImagerDeviceWorks, ImagerMaskCache, ImagerPixelArray, ImagerPrintColor, ImagerRaster, ImagerSample, ImagerTransformation EXPORTS ImagerPrintContext, ImagerPrintDevice ~ BEGIN Device: TYPE ~ ImagerDevice.Device; PixelArray: TYPE ~ ImagerPixelArray.PixelArray; Transformation: TYPE ~ ImagerTransformation.Transformation; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ bitmap: ImagerSample.SampleMap ¬ NIL, deviceColorData: ImagerPrintColor.DeviceColorData ]; defaultDotShape: REAL ¬ 0.48; defaultScreenAngle: ARRAY PrintColor.Toner[black..yellow] OF REAL ¬ [ black: 45, cyan: 75, magenta: 105, yellow: 90 ]; MakeHalftoneProperties: PROC [logicalDevice: PrintColor.LogicalDevice, pixelsPerHalftoneDot: REAL, toners: PrintColor.TonerUniverse] RETURNS [h: PrintColor.HalftoneProperties ¬ NIL] ~ { angle: ARRAY PrintColor.Toner[black..yellow] OF REAL ¬ defaultScreenAngle; <> FOR t: PrintColor.Toner IN PrintColor.Toner[black..yellow] DO IF toners[t] THEN { angle: REAL ~ defaultScreenAngle[t]; brick: ImagerBrick.Brick ~ ImagerBrick.BrickFromDotScreen[pixelsPerDot: pixelsPerHalftoneDot, degrees: angle, shape: defaultDotShape]; h ¬ CONS[[type: NIL, toner: t, brick: brick], h]; }; ENDLOOP; }; SimpleCreate: PUBLIC PROC [deviceSpaceSize: SF.Vec, scanMode: ImagerTransformation.ScanMode, surfaceUnitsPerInch: Vector2.VEC, logicalDevice: PrintColor.LogicalDevice, pixelsPerHalftoneDot: REAL, toners: PrintColor.TonerUniverse] RETURNS [Imager.Context] ~ { halftoneProperties: PrintColor.HalftoneProperties ~ MakeHalftoneProperties[logicalDevice, pixelsPerHalftoneDot, toners]; RETURN [Create[deviceSpaceSize: deviceSpaceSize, scanMode: scanMode, surfaceUnitsPerInch: surfaceUnitsPerInch, logicalDevice: logicalDevice, halftoneProperties: halftoneProperties, correction: NIL, interpolate: FALSE]]; }; Create: PUBLIC PROC [deviceSpaceSize: SF.Vec, scanMode: ImagerTransformation.ScanMode, surfaceUnitsPerInch: Vector2.VEC, logicalDevice: PrintColor.LogicalDevice, halftoneProperties: PrintColor.HalftoneProperties, correction: PrintColor.ColorCorrection, interpolate: BOOL, fontCacheName: ATOM ¬ $Print, parameters: ImagerMaskCache.Parameters ¬ NIL] RETURNS [Imager.Context] ~ { data: Data ~ NEW[DataRep ¬ [bitmap: NIL, deviceColorData: ImagerPrintColor.NewDeviceColorData[logicalDevice: logicalDevice, halftoneProperties: halftoneProperties, correction: correction, interpolate: interpolate]]]; deviceParm: ImagerDevice.DeviceParm ~ ImagerDevice.MakeDeviceParm[ class: deviceClass, sSize: deviceSpaceSize.s, fSize: deviceSpaceSize.f, scanMode: scanMode, surfaceUnitsPerInch: surfaceUnitsPerInch, surfaceUnitsPerPixel: 1, fontCache: ImagerMaskCache.GetNamedCache[fontCacheName], parameters: parameters ]; context: Imager.Context ~ ImagerRaster.Create[class: contextClass, deviceClass: deviceClass, deviceParm: deviceParm, data: data, pixelUnits: FALSE]; device: Device ~ ImagerRaster.GetDevice[context]; device.works ¬ worksClass; ImagerRaster.SetDeviceClipBox[context, [[0,0], [0,0]]]; RETURN [context] }; IsPrintDevice: PUBLIC PROC [device: Device] RETURNS [BOOL] ~ { WITH device.data SELECT FROM data: Data => RETURN [TRUE]; ENDCASE => RETURN [FALSE]; }; GetDeviceBitmap: PUBLIC PROC [device: Device] RETURNS [ImagerSample.SampleMap] ~ { data: Data ~ NARROW[device.data]; RETURN [data.bitmap] }; SetDeviceBitmap: PUBLIC PROC [device: Device, bitmap: ImagerSample.SampleMap] ~ { data: Data ~ NARROW[device.data]; IF ImagerSample.GetBox[bitmap] = ImagerSample.GetBox[data.bitmap] THEN data.bitmap ¬ bitmap ELSE ERROR; -- client bug ValidateAllow[device, data]; }; GetColorData: PUBLIC PROC [device: Device] RETURNS [ImagerPrintColor.DeviceColorData] ~ { data: Data ~ NARROW[device.data]; RETURN [data.deviceColorData] }; ValidateAllow: PROC [device: Device, data: Data] ~ { realRaster: BOOL ~ ISTYPE[data.bitmap, ImagerSample.RasterSampleMap]; device.state.allow ¬ [ unorderedBoxes: (data.deviceColorData.case < sampledColor), multipleCoverage: (data.deviceColorData.case < sampledColor), regionFill: data.deviceColorData.case = constant AND realRaster, bitmap: data.deviceColorData.case = constant, rawBitmaps: (data.deviceColorData.case = constant AND realRaster) ]; }; SetColorData: PUBLIC PROC [device: Device, deviceColorData: ImagerPrintColor.DeviceColorData] ~ { data: Data ~ NARROW[device.data]; data.deviceColorData ¬ data.deviceColorData; ValidateAllow[device, data]; }; SetBitmap: PUBLIC PROC [context: Imager.Context, bitmap: ImagerSample.SampleMap] ~ { device: Device = ImagerRaster.GetDevice[context]; data: Data ~ NARROW[device.data]; data.bitmap ¬ bitmap; ImagerRaster.SetDeviceClipBox[context, IF bitmap = NIL THEN [] ELSE ImagerSample.GetBox[bitmap]]; ValidateAllow[device, data]; }; SetSeparation: PUBLIC PROC [context: Imager.Context, toner: PrintColor.Toner] ~ { data: Data ~ NARROW[ImagerRaster.GetDevice[context].data]; ImagerPrintColor.SetSeparation[data.deviceColorData, toner]; }; MySetColor: PROC [device: Device, color: ImagerColor.Color, viewToDevice: ImagerTransformation.Transformation] ~ { data: Data ~ NARROW[device.data]; ImagerPrintColor.SetDeviceColorData[data.deviceColorData, color, viewToDevice]; ValidateAllow[device, data]; }; TranslateHalftoneProperties: PROC [h: ImagerBrick.HalftoneProperties] RETURNS [PrintColor.HalftoneProperties] ~ { <> RETURN[ IF h = NIL THEN NIL ELSE CONS[ [type: h.first.type, toner: LOOPHOLE[h.first.toner], brick: h.first.brick], TranslateHalftoneProperties[h.rest]]] }; MySetHalftoneProperties: PROC [device: Device, halftoneProperties: ImagerBrick.HalftoneProperties] ~ { data: Data ~ NARROW[device.data]; data.deviceColorData.halftoneProperties ¬ TranslateHalftoneProperties[halftoneProperties]; ImagerPrintColor.SetSeparation[data.deviceColorData, data.deviceColorData.toner]; -- validate deviceColorData.brick <> }; MyMaskBoxes: PROC [device: Device, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { data: Data ~ NARROW[device.data]; ImagerPrintColor.MaskBoxes[data.bitmap, data.deviceColorData, bounds, boxes]; }; MyMaskBitmap: PROC [device: Device, bitmap: ImagerSample.SampleMap, delta: SF.Vec, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { data: Data ~ NARROW[device.data]; function: ImagerSample.Function ¬ [null, null]; IF data.deviceColorData.case # constant THEN ERROR; SELECT data.deviceColorData.ink FROM nop => RETURN; set => function ¬ [or, null]; remove => function ¬ [and, complement]; ENDCASE => ERROR; ImagerSample.TransferBoxes[dst: data.bitmap, src: bitmap, delta: delta, boxes: boxes, function: function]; }; MyMaskRegion: PROC [device: Device, bounds: SF.Box, edgeGenerator: PROC [ImagerSample.EdgeAction]] ~ { data: Data ~ NARROW[device.data]; value: CARDINAL ¬ 1; IF data.deviceColorData.case # constant THEN ERROR; SELECT data.deviceColorData.ink FROM nop => RETURN; set => value ¬ 1; remove => value ¬ 0; ENDCASE => ERROR; ImagerSample.RegionFill[dst: NARROW[data.bitmap], edgeGenerator: edgeGenerator, value: value, function: [null, null]]; }; MyMaskRawBitmaps: PROC [device: Device, list: LIST OF ImagerSample.RawDescriptor] ~ { data: Data ~ NARROW[device.data]; function: ImagerSample.Function ¬ [null, null]; IF data.deviceColorData.case # constant THEN ERROR; SELECT data.deviceColorData.ink FROM nop => RETURN; set => function ¬ [or, null]; remove => function ¬ [and, complement]; ENDCASE => ERROR; ImagerSample.RawListTransfer[dst: NARROW[data.bitmap], src: list, function: function]; }; GetSimpleClip: PROC [device: Device] RETURNS [LIST OF SF.Box] ~ INLINE { <> b: LIST OF SF.Box ~ device.worksState.clipper.clipMask; IF b = NIL OR b.rest = NIL THEN RETURN[b] ELSE RETURN [NIL]; }; WMaskPixelArray: PROC [device: Device, bitmap: PixelArray, clientToDevice: Transformation] ~ { <> clip: LIST OF SF.Box ~ GetSimpleClip[device]; maskToDevice: Transformation ¬ ImagerTransformation.Concat[bitmap.m, clientToDevice]; form: INT ~ maskToDevice.form; integerTrans: BOOL ~ maskToDevice.integerTrans; s0: INT ~ maskToDevice.tx; f0: INT ~ maskToDevice.ty; ImagerTransformation.Destroy[maskToDevice]; maskToDevice ¬ NIL; IF form = 3 AND integerTrans AND clip # NIL THEN { data: Data ~ NARROW[device.data]; IF data.deviceColorData.case = constant THEN { function: ImagerSample.Function ¬ [null, null]; SELECT data.deviceColorData.ink FROM nop => RETURN; set => function ¬ [or, null]; remove => function ¬ [and, complement]; ENDCASE; IF function # [null, null] THEN { sMin: INT ~ MAX[clip.first.min.s, s0]; fMin: INT ~ MAX[clip.first.min.f, f0]; sMax: INT ~ MIN[clip.first.max.s, s0 + bitmap.sSize]; fMax: INT ~ MIN[clip.first.max.f, f0 + bitmap.fSize]; IF sMin < sMax AND fMin < fMax THEN { ImagerPixelArray.Transfer[pa: bitmap, i: 0, s: sMin-s0, f: fMin-f0, dst: data.bitmap, dstMin: [sMin, fMin], size: [sMax-sMin, fMax-fMin], function: function]; }; RETURN; }; }; }; ImagerDeviceWorks.StandardMaskPixelArray[device, bitmap, clientToDevice]; }; deviceClass: ImagerDevice.DeviceClass ~ NEW[ImagerDevice.DeviceClassRep ¬ [ SetColor: MySetColor, SetHalftoneProperties: MySetHalftoneProperties, MaskBoxes: MyMaskBoxes, MaskRegion: MyMaskRegion, MaskBitmap: MyMaskBitmap, MaskRawBitmaps: MyMaskRawBitmaps ]]; worksClass: ImagerDevice.WorksClass ~ NEW[ImagerDevice.WorksClassRep ¬ [ Clip: ImagerDeviceWorks.StandardClip, MaskFill: ImagerDeviceWorks.StandardMaskFill, MaskRectangle: ImagerDeviceWorks.StandardMaskRectangle, MaskStroke: ImagerDeviceWorks.StandardMaskStroke, MaskVector: ImagerDeviceWorks.StandardMaskVector, MaskDashedStroke: ImagerDeviceWorks.StandardMaskDashedStroke, MaskBitmap: ImagerDeviceWorks.StandardMaskBitmap, MaskPixelArray: WMaskPixelArray, MaskBoxes: ImagerDeviceWorks.StandardMaskBoxes, MaskCharMask: ImagerDeviceWorks.StandardMaskCharMask, Show: ImagerDeviceWorks.StandardShow ]]; contextClass: ImagerPrivate.Class ~ ImagerRaster.CreateClass[type: $Print]; SetMaskCacheTradeoffs: PUBLIC PROC [fontCacheName: ATOM] ~ { x: ImagerMaskCache.MaskCache ~ ImagerMaskCache.GetNamedCache[fontCacheName]; changed: BOOL ¬ FALSE; Val: PROC [from: REAL, to: REAL] RETURNS [REAL] ~ INLINE { IF from # to THEN changed ¬ TRUE; RETURN [to] }; Action: PROC [p: ImagerMaskCache.Parameters] ~ { p.rasterCost.slope ¬ Val[p.rasterCost.slope, 1]; p.rasterCost.offset ¬ Val[p.rasterCost.offset, 0]; p.runsCost.slope ¬ Val[p.runsCost.slope, 2]; p.runsCost.offset ¬ Val[p.runsCost.offset, 3]; }; ImagerMaskCache.UpdateParameters[x, Action]; IF changed THEN ImagerMaskCache.Flush[x]; }; SetMaskCacheTradeoffs[$Print]; END.