ImagerPrintContextImpl.mesa
Copyright Ó 1987, 1989, 1991, 1992 by Xerox Corporation. All rights reserved.
Michael Plass, October 28, 1993 1:28 pm PDT
Dave Rumph, July 27, 1988 6:14:26 pm PDT
Doug Wyatt, September 14, 1989 2:34:01 pm PDT
Catapano, August 21, 1990 11:47 am PDT
DIRECTORY Imager, ImagerBrick, ImagerColor, ImagerDevice, ImagerDeviceColor, ImagerDeviceWorks, ImagerManhattan, ImagerMaskCache, ImagerPixelArray, ImagerPrintColor, ImagerPrintColorPrivate, ImagerPrintContext, ImagerPrintDevice, ImagerPrivate, ImagerRaster, ImagerSample, ImagerTransformation, PrintColor, SF, Vector2;
ImagerPrintContextImpl: CEDAR PROGRAM
IMPORTS ImagerBrick, ImagerDevice, ImagerDeviceColor, ImagerDeviceWorks, ImagerManhattan, ImagerMaskCache, ImagerPixelArray, ImagerPrintColor, ImagerPrintColorPrivate, ImagerRaster, ImagerSample, ImagerTransformation, SF
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;
IF toners = [black: TRUE] THEN angle[black] ← 45;
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];
ImagerPrintColorPrivate.SetDeviceColorControl[data.deviceColorData, ImagerDeviceColor.GetDeviceColorControl[device]];
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] RETURNS [clipperNeedsFixing: BOOL] ~ {
data: Data ~ NARROW[device.data];
box: SF.Box = IF bitmap = NIL THEN [] ELSE ImagerSample.GetBox[bitmap];
clipper: ImagerDevice.DeviceClipper = device.worksState.clipper;
clipperNeedsFixing ¬ NOT SF.Inside[box, device.state.bounds];
device.state.bounds ¬ box;
clipper.clipMask ¬ ImagerManhattan.DestructiveClip[clipper.clipMask, box];
clipper.clipBox ¬ ImagerManhattan.BoundingBox[clipper.clipMask];
data.bitmap ¬ bitmap;
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];
IF SetDeviceBitmap[device, bitmap].clipperNeedsFixing THEN {
ImagerRaster.SetDeviceClipBox[context, device.state.bounds];
};
};
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] ~ {
Eliminate this when PrintColor.HalftoneProperties becomes the same as ImagerBrick.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
Note that a SetColor should be done before further masking.
};
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 {
Returns a singleton list iff the clipping region is a non-empty rectangle.
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] ~ {
This is a fast case that avoids the banding steps that happen in the normal path.
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.