DIRECTORY
CountedVM USING [Handle, SimpleAllocate],
Imager USING [Context],
ImagerAlphaDevice USING [],
ImagerColorDefs USING [ConstantColor, ConstantColorImplRep],
ImagerColorPrivate USING [ConstantColorImpl, ConstantColorImplRep],
ImagerOps USING [PixelArrayFromPixelMaps],
ImagerFunctionDevice USING [ClientFunc, Create, MakeConstantColor],
ImagerPixelArray USING [FromAIS, Join, PixelArray],
ImagerPixelMap USING [Create, Fill, PixelMap],
ImagerSample USING [GetPointer, NewBuffer, PutSample, SampleBuffer, UnsafeSamples],
ImagerTransformation USING [Transformation],
Real USING [RoundC],
Rope USING [ROPE];
ImagerAlphaDeviceImpl:
CEDAR PROGRAM
IMPORTS CountedVM, ImagerFunctionDevice, ImagerOps, ImagerPixelArray, ImagerPixelMap, ImagerSample, Real
EXPORTS ImagerAlphaDevice, ImagerColorDefs
~
BEGIN
ConstantColor: TYPE ~ ImagerColorDefs.ConstantColor;
ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl;
ConstantColorImplRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorImplRep;
Create:
PUBLIC PROC [
devicePms: LIST OF ImagerPixelMap.PixelMap,
deviceToPixel: ImagerTransformation.Transformation ← NIL, -- transformation from device space
initialScale: REAL ← 1.0]
RETURNS [Imager.Context] ~ {
Length:
PROC [l:
LIST
OF ImagerPixelMap.PixelMap]
RETURNS [n:
NAT] ~ {
IF l=NIL THEN RETURN [0] ELSE RETURN [Length[l.rest]+1]
};
IF Length[devicePms]#4 THEN ERROR; -- need 4 equally sized pixel maps!
RETURN [
ImagerFunctionDevice.Create[4, devicePms, deviceToPixel, initialScale, ApplyAlpha]
]
};
CreateAlphaTable:
PROC [] ~
TRUSTED {
FOR i:
CARDINAL
IN [0..255]
DO
FOR j:
CARDINAL
IN [0..255]
DO
alphaTable[i*256+j] ← (i*j+128)/255;
ENDLOOP;
ENDLOOP;
};
AlphaTable: TYPE = LONG POINTER TO AlphaTableRec;
AlphaTableRec:
TYPE =
RECORD [
t: PACKED SEQUENCE COMPUTED CARDINAL OF [0..255]
];
handle: CountedVM.Handle ← CountedVM.SimpleAllocate[LONG[256]*(256/2)];
alphaTable: AlphaTable ← LOOPHOLE[handle.pointer];
ApplyAlpha: ImagerFunctionDevice.ClientFunc ~
TRUSTED {
alphaCSamples: ImagerSample.UnsafeSamples ← colorSamples.GetPointer[3, fMin, fSize];
alphaDSamples: ImagerSample.UnsafeSamples ← deviceSamples.GetPointer[3, fMin, fSize];
FOR i:
NAT
IN [0..2]
DO
cSamples: ImagerSample.UnsafeSamples ← colorSamples.GetPointer[i, fMin, fSize];
dSamples: ImagerSample.UnsafeSamples ← deviceSamples.GetPointer[i, fMin, fSize];
FOR j:
NAT
IN[0..fSize)
DO
alpha: NAT ← alphaTable[cSamples[j]*256+alphaSamples[j]];
notAlpha: NAT ← alphaTable[dSamples[j]*256+(255-alphaSamples[j])];
dSamples[j] ← MIN[alpha + notAlpha, 255];
ENDLOOP;
ENDLOOP;
MakeConstantColor: PUBLIC PROC [color: ImagerColorDefs.ConstantColor, alpha: REAL ← 1.0]
RETURNS [alphaColor: ConstantColor] ~ {
PixelFromIntensity:
PROC[i:
REAL, maxValue:
CARDINAL]
RETURNS[
CARDINAL] ~ {
IF i<=0.0 THEN RETURN[0];
IF i>=1.0 THEN RETURN[maxValue];
RETURN[Real.RoundC[i*maxValue]];
};
oneSample: ImagerSample.SampleBuffer ← ImagerSample.NewBuffer[4, 1];
WITH color
SELECT
FROM
xcolor: ConstantColor => {
impl: ConstantColorImpl ~ xcolor.impl;
WITH impl: impl
SELECT
FROM
rgb => {
ImagerSample.PutSample[oneSample, 0, 0, PixelFromIntensity[impl.val.R,255]];
ImagerSample.PutSample[oneSample, 1, 0, PixelFromIntensity[impl.val.G,255]];
ImagerSample.PutSample[oneSample, 2, 0, PixelFromIntensity[impl.val.B,255]];
};
ENDCASE => {
grey:NAT ← PixelFromIntensity[impl.Y, 255];
ImagerSample.PutSample[oneSample, 0, 0, grey];
ImagerSample.PutSample[oneSample, 1, 0, grey];
ImagerSample.PutSample[oneSample, 2, 0, grey];
};
};
ENDCASE => ERROR; -- unknown color variant
ImagerSample.PutSample[oneSample, 3, 0, Real.RoundC[alpha*255]];
RETURN [ImagerFunctionDevice.MakeConstantColor[oneSample]]
};
MakePixelArrayFromAIS:
PUBLIC PROC [
r,g,b: Rope.ROPE,
a: Rope.ROPE ← NIL,
defaultAlpha: REAL ← 1.0
] RETURNS [pa: ImagerPixelArray.PixelArray] ~ {
Makes a pixel array suitable for Imager.SetSampledColor on this device.
If 'a' is defaulted then an AIS file the same size as 'r' is assumed. Its value will be defaultAlpha throughout.
paR, paG, paB, paA: ImagerPixelArray.PixelArray;
paR ← ImagerPixelArray.FromAIS[r];
paG ← ImagerPixelArray.FromAIS[g];
paB ← ImagerPixelArray.FromAIS[b];
IF a=
NIL
THEN {
pm: ImagerPixelMap.PixelMap ← ImagerPixelMap.Create[3, [0,0, paR.sSize, paR.fSize]];
pm.Fill[[0, 0, pm.sSize, pm.fSize], Real.RoundC[255*defaultAlpha], [null, null]];
paA ← ImagerOps.PixelArrayFromPixelMaps[LIST[pm], paR.m];
}
ELSE paA ← ImagerPixelArray.FromAIS[a];
RETURN [ImagerPixelArray.Join[LIST[paR, paG, paB, paA]]]
};