<<>> <> <> <> <> <> <> DIRECTORY ImagerFourColorContext USING [Toner], Imager USING [Context], ImagerBrick USING [HalftoneProperties], ImagerColor USING [Color], ImagerDevice USING [AllowedMasks, Device, DeviceClass, DeviceClassRep, DeviceParm, MakeDeviceParm], ImagerDeviceColor, ImagerMaskCache USING [GetNamedCache, SetNamedCacheParameters], ImagerPrintColor USING [DeviceColorData, MaskBoxes, NewDeviceColorData, SetDeviceColorData, SetSeparation], ImagerPrintColorPrivate, ImagerPrivate USING [Class], ImagerRaster USING [Create, CreateClass, GetDevice, SetDeviceClipBox], ImagerSample USING [BasicTransfer, Box, Function, GetBox, RasterSampleMap, RawDescriptor, RawListTransfer, SampleMap], ImagerTransformation USING [Transformation, ScanMode], PrintColor USING [ColorCorrection, HalftoneProperties, LogicalDevice, Toner], SF USING [Box, BoxAction, BoxGenerator, Vec], SFInline USING [Size, Sub], Vector2 USING [VEC]; ImagerFourColorContextImpl: CEDAR PROGRAM IMPORTS ImagerDevice, ImagerDeviceColor, ImagerMaskCache, ImagerPrintColor, ImagerPrintColorPrivate, ImagerRaster, ImagerSample, SFInline EXPORTS ImagerFourColorContext ~ BEGIN <> Color: TYPE ~ ImagerColor.Color; Context: TYPE ~ Imager.Context; Transformation: TYPE ~ ImagerTransformation.Transformation; <> Toner: TYPE ~ ImagerFourColorContext.Toner; -- {black, cyan, magenta, yellow}; toners: ARRAY Toner OF PrintColor.Toner ~ [black, cyan, magenta, yellow]; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ bitmaps: ARRAY Toner OF ImagerSample.SampleMap ¬ ALL[NIL], deviceColorData: ARRAY Toner OF ImagerPrintColor.DeviceColorData ¬ ALL[NIL] ]; <> fontCacheName: ATOM ~ $FourColorPrint; fontCacheMaxSize: INT ¬ 8000; <> Create: PUBLIC PROC [deviceSpaceSize: SF.Vec, scanMode: ImagerTransformation.ScanMode, surfaceUnitsPerInch: Vector2.VEC, logicalDevice: PrintColor.LogicalDevice, halftoneProperties: PrintColor.HalftoneProperties, correction: PrintColor.ColorCorrection, interpolate: BOOL, bitmaps: ARRAY Toner OF ImagerSample.SampleMap] RETURNS [Imager.Context] ~ { box: ImagerSample.Box ~ ImagerSample.GetBox[map: bitmaps[black]]; data: Data ~ NEW[DataRep ¬ [ bitmaps: bitmaps, deviceColorData: ALL[NIL] ]]; deviceParm: ImagerDevice.DeviceParm ~ ImagerDevice.MakeDeviceParm[ class: deviceClass, sSize: deviceSpaceSize.s, fSize: deviceSpaceSize.f, scanMode: scanMode, surfaceUnitsPerInch: surfaceUnitsPerInch, surfaceUnitsPerPixel: 1, fontCache: ImagerMaskCache.GetNamedCache[fontCacheName] ]; context: Imager.Context ~ ImagerRaster.Create[class: contextClass, deviceClass: deviceClass, deviceParm: deviceParm, data: data, pixelUnits: FALSE]; device: ImagerDevice.Device ~ ImagerRaster.GetDevice[context]; ImagerRaster.SetDeviceClipBox[context: context, clipBox: box]; FOR t: Toner IN Toner DO deviceColorData: ImagerPrintColor.DeviceColorData = ImagerPrintColor.NewDeviceColorData[logicalDevice: logicalDevice, halftoneProperties: halftoneProperties, correction: correction, interpolate: interpolate]; ImagerPrintColorPrivate.SetDeviceColorControl[deviceColorData, ImagerDeviceColor.GetDeviceColorControl[device]]; ImagerPrintColor.SetSeparation[deviceColorData, toners[t]]; data.deviceColorData[t] ¬ deviceColorData; ENDLOOP; RETURN [context] }; SetBitmaps: PUBLIC PROC [context: Imager.Context, bitmaps: ARRAY Toner OF ImagerSample.SampleMap] ~ { device: ImagerDevice.Device = ImagerRaster.GetDevice[context]; data: Data ~ NARROW[device.data]; box: ImagerSample.Box ~ ImagerSample.GetBox[map: bitmaps[black]]; ImagerRaster.SetDeviceClipBox[context: context, clipBox: box]; FOR t: Toner IN Toner DO data.bitmaps[t] ¬ bitmaps[t]; ENDLOOP; }; <> MySetColor: PROC [device: ImagerDevice.Device, color: Color, viewToDevice: Transformation] ~ { data: Data ~ NARROW[device.data]; constant: BOOL ¬ TRUE; allowFunnyBoxes: BOOL ¬ TRUE; allRasterSampleMaps: BOOL ¬ TRUE; FOR t: Toner IN Toner DO deviceColorData: ImagerPrintColor.DeviceColorData ~ data.deviceColorData[t]; ImagerPrintColor.SetDeviceColorData[deviceColorData, color, viewToDevice]; IF deviceColorData.case # constant THEN constant ¬ FALSE; IF deviceColorData.case >= sampledColor THEN allowFunnyBoxes ¬ FALSE; IF NOT ISTYPE[data.bitmaps[t], ImagerSample.RasterSampleMap] THEN allRasterSampleMaps ¬ FALSE ENDLOOP; device.state.allow ¬ [ unorderedBoxes: allowFunnyBoxes, multipleCoverage: allowFunnyBoxes, bitmap: constant, rawBitmaps: (constant AND allRasterSampleMaps) ]; }; <> <> <> <> <> <> <<[boxAction: SF.BoxAction]>> <> <> <> <> <<};>> <> <<};>> <> <<};>> <<>> 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: ImagerDevice.Device, halftoneProperties: ImagerBrick.HalftoneProperties] ~ { data: Data ~ NARROW[device.data]; h: PrintColor.HalftoneProperties ~ TranslateHalftoneProperties[halftoneProperties]; FOR which: Toner IN Toner DO data.deviceColorData[which].halftoneProperties ¬ h; ENDLOOP; <> }; MyMaskBoxes: PROC [device: ImagerDevice.Device, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { data: Data ~ NARROW[device.data]; FOR which: Toner IN Toner DO ImagerPrintColor.MaskBoxes[data.bitmaps[which], data.deviceColorData[which], bounds, boxes]; ENDLOOP; }; MyMaskBitmap: PROC [device: ImagerDevice.Device, bitmap: ImagerSample.SampleMap, delta: SF.Vec, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { data: Data ~ NARROW[device.data]; function: ARRAY Toner OF ImagerSample.Function ¬ ALL[[null, null]]; Box: SF.BoxAction = { <<[box: SF.Box]>> FOR t: Toner IN Toner DO ImagerSample.BasicTransfer[dst: data.bitmaps[t], src: bitmap, dstMin: box.min, srcMin: SFInline.Sub[box.min, delta], size: SFInline.Size[box], function: function[t]]; ENDLOOP; }; FOR t: Toner IN Toner DO IF data.deviceColorData[t].case # constant THEN ERROR; SELECT data.deviceColorData[t].ink FROM nop => NULL; set => function[t] ¬ [or, null]; remove => function[t] ¬ [and, complement]; ENDCASE => ERROR; ENDLOOP; boxes[Box]; }; MyMaskRawBitmaps: PROC [device: ImagerDevice.Device, list: LIST OF ImagerSample.RawDescriptor] = { data: Data = NARROW[device.data]; function: ImagerSample.Function ¬ [null, null]; FOR t: Toner IN Toner DO local: ImagerSample.RasterSampleMap ~ NARROW [data.bitmaps[t]]; IF data.deviceColorData[t].case # constant THEN ERROR; SELECT data.deviceColorData[t].ink FROM nop => NULL; set => function ¬ [or, null]; remove => function ¬ [and, complement]; ENDCASE => ERROR; ImagerSample.RawListTransfer[dst: local, src: list, function: function]; ENDLOOP; }; <> deviceClass: ImagerDevice.DeviceClass ~ NEW[ImagerDevice.DeviceClassRep ¬ [ SetColor: MySetColor, SetHalftoneProperties: MySetHalftoneProperties, MaskBoxes: MyMaskBoxes, MaskBitmap: MyMaskBitmap, MaskRawBitmaps: MyMaskRawBitmaps ]]; contextClass: ImagerPrivate.Class ~ ImagerRaster.CreateClass[type: $FourColor]; ImagerMaskCache.SetNamedCacheParameters[fontCacheName, [sizeLimit: fontCacheMaxSize, runsCost: [slope: 2, offset: 3]]]; END.