DIRECTORY
CountedVM USING [Handle, SimpleAllocate],
Imager USING [Context],
ImagerAlpha4Device USING [],
ImagerColorDefs USING [ConstantColor, ConstantColorImplRep],
ImagerColorPrivate USING [ConstantColorImpl, ConstantColorImplRep],
ImagerDevice USING [Device],
ImagerOps USING [PixelArrayFromPixelMaps],
ImagerFunctionDevice USING [ClientFunc, Create, DeviceFromPixelMap, MakeConstantColor],
ImagerPixelArray USING [FromAIS, Join, PixelArray],
ImagerPixelMap USING [Create, Fill, GetPixel, PutPixel, PixelMap],
ImagerSample USING [GetPointer, NewBuffer, PutSample, SampleBuffer, UnsafeSamples],
ImagerTransformation USING [Transformation],
IO, PixelMapOps,
Real USING [RoundC],
Rope USING [Cat, ROPE];
ImagerAlpha4DeviceImpl:
CEDAR PROGRAM
IMPORTS IO, CountedVM, ImagerFunctionDevice, ImagerOps, ImagerPixelArray, ImagerPixelMap, ImagerSample, PixelMapOps, Real, Rope
EXPORTS ImagerAlpha4Device, 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]
]
};
CreateDevice:
PUBLIC PROC [
devicePms: LIST OF ImagerPixelMap.PixelMap,
deviceToPixel: ImagerTransformation.Transformation ← NIL -- transformation from device space
]
RETURNS [ImagerDevice.Device] ~ {
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.DeviceFromPixelMap[4, devicePms, deviceToPixel, ApplyAlpha]
]
};
ApplyAlpha: ImagerFunctionDevice.ClientFunc ~
TRUSTED {
aCSamples: ImagerSample.UnsafeSamples ← colorSamples.GetPointer[3, fMin, fSize];
aDSamples: ImagerSample.UnsafeSamples ← deviceSamples.GetPointer[3, fMin, fSize];
FOR j:
NAT
IN[0..fSize)
DO
aC: NAT ← aCSamples[j];
aD: NAT ← aDSamples[j];
aDSamples[j] ← aD + aC - mult8x8[aD*256+aC];
ENDLOOP;
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
newValue:CARDINAL ← dSamples[j] + cSamples[j] - mult8x8[dSamples[j]*256+aCSamples[j]];
dSamples[j] ← MIN[newValue, 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[alpha*impl.val.R,255]];
ImagerSample.PutSample[oneSample, 1, 0, PixelFromIntensity[alpha*impl.val.G,255]];
ImagerSample.PutSample[oneSample, 2, 0, PixelFromIntensity[alpha*impl.val.B,255]];
};
ENDCASE => {
grey:NAT ← PixelFromIntensity[alpha*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]]
};
MakeConstantAIS:
PROC [file: Rope.
ROPE, sSize, fSize:
NAT, value:
NAT ← 255] ~ {
aData: PixelMapOps.AISData;
aData.pixelMap ← ImagerPixelMap.Create[3, [0, 0, sSize, fSize]];
aData.bitmap ← FALSE;
aData.comment ← NIL;
aData.pixelMap.Fill[[0, 0, sSize, fSize], value, [null, null]];
aData.comment ← Rope.Cat[aData.comment, "Constant ", IO.PutFR["%g", IO.card[value]]];
PixelMapOps.StoreAIS[file, aData];
};
PremultiplyAIS:
PROC [r, g, b, a, ra, ga, ba: Rope.
ROPE] ~ {
rData: PixelMapOps.AISData ← PixelMapOps.LoadAIS[r];
gData: PixelMapOps.AISData ← PixelMapOps.LoadAIS[g];
bData: PixelMapOps.AISData ← PixelMapOps.LoadAIS[b];
aData: PixelMapOps.AISData ← PixelMapOps.LoadAIS[a];
pmR, pmG, pmB, pmA: ImagerPixelMap.PixelMap;
pmR ← rData.pixelMap; pmG ← gData.pixelMap;
pmB ← bData.pixelMap; pmA ← aData.pixelMap;
FOR row:
NAT
IN [0..pmA.sSize)
DO
FOR col:
NAT
IN [0..pmA.fSize)
DO TRUSTED {
alpha: NAT ← pmA.GetPixel[row, col];
pmR.PutPixel[row, col, mult8x8[pmR.GetPixel[row, col]*256+alpha]];
pmG.PutPixel[row, col, mult8x8[pmG.GetPixel[row, col]*256+alpha]];
pmB.PutPixel[row, col, mult8x8[pmB.GetPixel[row, col]*256+alpha]];
}
ENDLOOP;
ENDLOOP;
rData.comment ← Rope.Cat[rData.comment, "\nCopy of ", r, "\nNormalised for ", a];
gData.comment ← Rope.Cat[gData.comment, "\nCopy of ", g, "\nNormalised for ", a];
bData.comment ← Rope.Cat[bData.comment, "\nCopy of ", g, "\nNormalised for ", a];
PixelMapOps.StoreAIS[ra, rData]; PixelMapOps.StoreAIS[ga, gData];
PixelMapOps.StoreAIS[ba, bData];
};
GetComment:
PROC [name:Rope.
ROPE]
RETURNS [Rope.
ROPE] ~ {
RETURN[PixelMapOps.LoadAIS[name].comment];
};
MakePixelArrayFromAIS:
PUBLIC PROC [
r,g,b,a: Rope.ROPE ← NIL
] 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.
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], 255, [null, null]];
paA ← ImagerOps.PixelArrayFromPixelMaps[LIST[pm], paR.m];
}
ELSE paA ← ImagerPixelArray.FromAIS[a];
RETURN [ImagerPixelArray.Join[LIST[paR, paG, paB, paA]]]
};