ImagerColorOperatorImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Doug Wyatt, May 29, 1985 11:16:19 pm PDT
Michael Plass, August 1, 1985 5:16:47 pm PDT
DIRECTORY
Atom USING [GetPName],
Imager USING [black, Error, white],
ImagerColor USING [ColorFromAtom, ColorFromGray, ColorFromRGB],
ImagerColorDefs USING [ColorOperator, ColorOperatorClassRep, ColorOperatorImplRep, ColorOperatorRep, ConstantColor],
ImagerColorOperator USING [Mapper, MapperRep, PixelProc],
ImagerColorOperatorPrivate USING [ColorOperatorClass, ColorOperatorClassRep, ColorOperatorImpl, ColorOperatorImplRep, SampleMap, SampleMapRep],
ImagerColorPrivate USING [ComponentFromColor],
ImagerSample USING [GetSample, LookupPixels, NewBuffer, PutSample, Sample, SampleBuffer],
Real USING [Round],
RealFns USING [Power],
Rope USING [Concat];
ImagerColorOperatorImpl: CEDAR PROGRAM
IMPORTS Atom, Imager, ImagerColor, ImagerColorPrivate, ImagerSample, Real, RealFns, Rope
EXPORTS ImagerColorOperator, ImagerColorDefs
~ BEGIN OPEN ImagerColorOperator, ImagerColorOperatorPrivate, ImagerColorDefs;
Sample: TYPE ~ ImagerSample.Sample;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
ColorOperatorImpl: TYPE ~ ImagerColorOperatorPrivate.ColorOperatorImpl;
ColorOperatorImplRep: PUBLIC TYPE ~ ImagerColorOperatorPrivate.ColorOperatorImplRep;
ColorOperatorClass: TYPE ~ ImagerColorOperatorPrivate.ColorOperatorClass;
ColorOperatorClassRep: PUBLIC TYPE ~ ImagerColorOperatorPrivate.ColorOperatorClassRep;
BlackData: TYPE ~ REF ColorOperatorImplRep.black;
GrayLinearData: TYPE ~ REF ColorOperatorImplRep.grayLinear;
GrayDensityData: TYPE ~ REF ColorOperatorImplRep.grayDensity;
GrayVisualData: TYPE ~ REF ColorOperatorImplRep.grayVisual;
MapData: TYPE ~ REF ColorOperatorImplRep.map;
RGBLinearData: TYPE ~ REF ColorOperatorImplRep.rgbLinear;
GetColorOperatorClass: PUBLIC PROC [op: ColorOperator] RETURNS [ATOM] ~ {
impl: ColorOperatorImpl ~ op.impl;
class: ColorOperatorClass ~ op.class;
IF class # NIL THEN RETURN [class.classID];
RETURN [WITH impl SELECT FROM
data: BlackData => (
IF data.clear THEN $SampledBlackClear
ELSE $SampledBlack
),
data: GrayLinearData => $GrayLinear,
data: GrayDensityData => $GrayDensity,
data: GrayVisualData => $GrayVisual,
data: MapData => $Map,
data: RGBLinearData => $RGBLinear,
ENDCASE => NIL];
};
GrayLinearGrayFromSample: PROC [data: GrayLinearData, s0: Sample] RETURNS [REAL] ~ {
s: REAL ~ IF data.map=NIL THEN REAL[s0] ELSE data.map[s0];
f: REAL ~ (s-data.sWhite)/(data.sBlack-data.sWhite);
IF f<=0 THEN RETURN[0];
IF f>=1 THEN RETURN[1];
RETURN[f];
};
GrayDensityGrayFromSample: PROC [data: GrayDensityData, s0: Sample] RETURNS [REAL] ~ {
s: REAL ~ IF data.map=NIL THEN REAL[s0] ELSE data.map[s0];
d: REAL ~ ((s-data.sWhite)/(data.sBlack-data.sWhite))*data.dBlack;
f: REAL ~ RealFns.Power[base: 10, exponent: -d];
IF f<=0 THEN RETURN[0];
IF f>=1 THEN RETURN[1];
RETURN[f];
};
GrayVisualGrayFromSample: PROC [data: GrayVisualData, s0: Sample] RETURNS [REAL] ~ {
s: REAL ~ IF data.map=NIL THEN REAL[s0] ELSE data.map[s0];
L: REAL ~ (s-data.sBlack)/(data.sWhite-data.sBlack);
Y: REAL ~ IF L<=0.09 THEN L/0.09 ELSE RealFns.Power[base: (L+0.16)/0.25, exponent: 3];
f: REAL ~ 1-0.01*Y;
IF f<=0 THEN RETURN[0];
IF f>=1 THEN RETURN[1];
RETURN[f];
};
MapColorFromSample: PROC [data: MapData, s0: Sample] RETURNS [ConstantColor] ~ {
RETURN[data.v[s0]];
};
ColorFromPixel: PUBLIC PROC [op: ColorOperator,
pixel: PROC [i: NAT] RETURNS [Sample]] RETURNS [ConstantColor] ~ {
impl: ColorOperatorImpl ~ op.impl;
class: ColorOperatorClass ~ op.class;
IF class # NIL AND class.ColorFromPixel # NIL THEN RETURN [class.ColorFromPixel[op, pixel]];
WITH impl SELECT FROM
data: BlackData => {
IF pixel[0] = 0 THEN {
IF data.clear THEN RETURN [ImagerColor.ColorFromAtom[$Clear]] ELSE RETURN [Imager.white];
}
ELSE RETURN [Imager.black];
};
data: GrayLinearData => {
f: REAL ~ GrayLinearGrayFromSample[data, pixel[0]];
RETURN[ImagerColor.ColorFromGray[f]];
};
data: GrayDensityData => {
f: REAL ~ GrayDensityGrayFromSample[data, pixel[0]];
RETURN[ImagerColor.ColorFromGray[f]];
};
data: GrayVisualData => {
f: REAL ~ GrayVisualGrayFromSample[data, pixel[0]];
RETURN[ImagerColor.ColorFromGray[f]];
};
data: MapData => {
RETURN[MapColorFromSample[data, pixel[0]]];
};
data: RGBLinearData => {
max: REAL ← data.maxSampleValue;
r: REALMIN[MAX[pixel[0]/max, 0.0], 1.0];
g: REALMIN[MAX[pixel[1]/max, 0.0], 1.0];
b: REALMIN[MAX[pixel[2]/max, 0.0], 1.0];
RETURN[ImagerColor.ColorFromRGB[[R: r, G: g, B: b]]];
};
ENDCASE => ERROR Imager.Error[[code: $unimplemented,
explanation: "Color operator has an unrecognized color model."]];
};
ColorFromSamples: PUBLIC PROC [op: ColorOperator, s0, s1, s2, s3: Sample ← 0]
RETURNS
[ConstantColor] ~ {
pixel: PROC [i: NAT] RETURNS [Sample] ~ { check: [0..4) ~ i;
RETURN[SELECT i FROM 0 => s0, 1 => s1, 2 => s2, ENDCASE => s3];
};
RETURN[ColorFromPixel[op, pixel]];
};
BlackMapPixel: PROC [mapper: Mapper, pixel: PixelProc] RETURNS [Sample] ~ {
s0: [0..1] ~ pixel[0];
RETURN[IF s0=1 THEN 0 ELSE mapper.maxOut];
};
BlackMapPixels: PROC [mapper: Mapper, pixels: SampleBuffer, j: NAT ← 0,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ {
FOR k: NAT IN[0..count) DO
s0: [0..1] ~ pixels.GetSample[0, j+k];
buffer.PutSample[bi, bj+k, IF s0=1 THEN 0 ELSE mapper.maxOut];
ENDLOOP;
};
BlackColorModel: PUBLIC PROC[clear: BOOLFALSE] RETURNS [ColorOperator] ~ {
data: BlackData ~ NEW[ColorOperatorImplRep.black ← [black[clear: clear]]];
RETURN[NEW[ColorOperatorRep ← [samplesPerPixel: 1, impl: data]]];
};
TableMapPixel: PROC [mapper: Mapper, pixel: PixelProc] RETURNS [Sample] ~ {
tables: SampleBuffer ~ NARROW[mapper.data];
sum: Sample ← 0;
FOR i: NAT IN[0..tables.iSize) DO
sample: Sample ~ pixel[i];
sum ← sum+tables.GetSample[i, sample];
ENDLOOP;
RETURN[sum];
};
TableMapPixels: PROC [mapper: Mapper, pixels: SampleBuffer, j: NAT ← 0,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ {
tables: SampleBuffer ~ NARROW[mapper.data];
ImagerSample.LookupPixels[tables: tables, pixels: pixels, pj: j,
buffer: buffer, bi: bi, bj: bj, count: count];
};
NewMapper: PUBLIC PROC [op: ColorOperator, component: ATOM,
maxIn, maxOut: Sample] RETURNS [Mapper] ~ {
impl: ColorOperatorImpl ~ op.impl;
class: ColorOperatorClass ~ op.class;
IF class # NIL AND class.NewMapper # NIL THEN RETURN [class.NewMapper[op, component, maxIn, maxOut]];
WITH impl SELECT FROM
data: BlackData => {
check: [0..1] ~ maxIn;
RETURN[NEW[MapperRep ← [op: op, component: component,
maxIn: maxIn, maxOut: maxOut,
MapPixel: BlackMapPixel, MapPixels: BlackMapPixels, data: NIL]]];
};
data: GrayLinearData => {
tableSize: NAT ~ maxIn+1;
table: SampleBuffer ~ ImagerSample.NewBuffer[1, tableSize];
FOR s: Sample IN[0..tableSize) DO
R: REAL ~ 1.0-GrayLinearGrayFromSample[data, s];
val: Sample ~ Real.Round[R*maxOut];
table.PutSample[0, s, val];
ENDLOOP;
RETURN[NEW[MapperRep ← [op: op, component: component,
maxIn: maxIn, maxOut: maxOut,
MapPixel: TableMapPixel, MapPixels: TableMapPixels, data: table]]];
};
data: MapData => {
tableSize: NAT ~ maxIn+1;
table: SampleBuffer ~ ImagerSample.NewBuffer[1, tableSize];
FOR s: Sample IN[0..tableSize) DO
color: ConstantColor ~ data[s];
R: REAL ~ ImagerColorPrivate.ComponentFromColor[color, component];
val: Sample ~ Real.Round[MIN[MAX[R, 0.0], 1.0]*maxOut];
table.PutSample[0, s, val];
ENDLOOP;
RETURN[NEW[MapperRep ← [op: op, component: component, maxIn: maxIn, maxOut: maxOut,
MapPixel: TableMapPixel, MapPixels: TableMapPixels, data: table]]];
};
data: RGBLinearData => {
scale: REAL ~ data.maxSampleValue;
tableSize: NAT ~ maxIn+1;
tables: SampleBuffer ~ ImagerSample.NewBuffer[3, tableSize];
factors: ARRAY [0..3) OF REALALL[0];
SELECT component FROM
$Intensity => factors ← [0.30, 0.59, 0.11];
$Red => factors ← [1, 0, 0];
$Green => factors ← [0, 1, 0];
$Blue => factors ← [0, 0, 1];
ENDCASE => ERROR Imager.Error[[$unimplemented, Rope.Concat["Unimplemented color operator component: $", Atom.GetPName[component]]]];
FOR i: NAT IN [0..3) DO
FOR s: Sample IN[0..tableSize) DO
R: REAL ~ factors[i]*s/scale;
val: Sample ~ Real.Round[MIN[MAX[R, 0.0], 1.0]*maxOut];
tables.PutSample[i, s, val];
ENDLOOP;
ENDLOOP;
RETURN[NEW[MapperRep ← [op: op, component: component, maxIn: maxIn, maxOut: maxOut, MapPixel: TableMapPixel, MapPixels: TableMapPixels, data: tables]]];
};
ENDCASE => ERROR Imager.Error[[$unimplemented, "Unimplemented color operator."]];
};
MapPixel: PUBLIC PROC [mapper: Mapper, pixel: PixelProc] RETURNS [Sample] ~ {
RETURN mapper.MapPixel[mapper, pixel];
};
MapSamples: PUBLIC PROC [mapper: Mapper, s0, s1, s2, s3: Sample ← 0] RETURNS [Sample] ~ {
pixel: PROC [i: NAT] RETURNS [Sample] ~ { n: [0..4) ~ i;
RETURN[SELECT n FROM 0 => s0, 1 => s1, 2 => s2, 3 => s3, ENDCASE => ERROR];
};
RETURN mapper.MapPixel[mapper, pixel];
};
MapPixels: PUBLIC PROC [mapper: Mapper, pixels: SampleBuffer, j: NAT ← 0,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ {
mapper.MapPixels[mapper: mapper, pixels: pixels, j: j, buffer: buffer, bi: bi, bj: bj, count: count];
};
NewSampleMap: PROC [maxSampleValue: Sample, sampleMap: PROC [Sample] RETURNS [REAL]]
RETURNS [map: SampleMap ← NIL] ~ {
IF maxSampleValue#0 AND sampleMap#NIL THEN {
size: NAT ~ maxSampleValue+1;
map ← NEW[SampleMapRep[size]];
FOR s0: Sample IN[0..maxSampleValue] DO map[s0] ← sampleMap[s0] ENDLOOP;
};
};
GrayLinearColorModel: PUBLIC PROC [sWhite, sBlack: REAL,
maxSampleValue: Sample ← 0, sampleMap: PROC [Sample] RETURNS [REAL] ← NIL
] RETURNS [ColorOperator] ~ {
map: SampleMap ~ NewSampleMap[maxSampleValue, sampleMap];
impl: GrayLinearData ~ NEW[ColorOperatorImplRep.grayLinear ← [grayLinear[
sWhite: sWhite, sBlack: sBlack, map: map]]];
RETURN[NEW[ColorOperatorRep ← [samplesPerPixel: 1, impl: impl]]];
};
GrayDensityColorModel: PUBLIC PROC [sWhite, sBlack, dBlack: REAL,
maxSampleValue: Sample ← 0, sampleMap: PROC [Sample] RETURNS [REAL] ← NIL
] RETURNS [ColorOperator] ~ {
map: SampleMap ~ NewSampleMap[maxSampleValue, sampleMap];
impl: GrayDensityData ~ NEW[ColorOperatorImplRep.grayDensity ← [grayDensity[
sWhite: sWhite, sBlack: sBlack, dBlack: dBlack, map: map]]];
RETURN[NEW[ColorOperatorRep ← [samplesPerPixel: 1, impl: impl]]];
};
GrayVisualColorModel: PUBLIC PROC [sWhite, sBlack: REAL,
maxSampleValue: Sample ← 0, sampleMap: PROC [Sample] RETURNS [REAL] ← NIL
] RETURNS [ColorOperator] ~ {
map: SampleMap ~ NewSampleMap[maxSampleValue, sampleMap];
impl: GrayVisualData ~ NEW[ColorOperatorImplRep.grayVisual ← [grayVisual[
sWhite: sWhite, sBlack: sBlack, map: map]]];
RETURN[NEW[ColorOperatorRep ← [samplesPerPixel: 1, impl: impl]]];
};
MapColorModel: PUBLIC PROC [
maxSampleValue: Sample, map: PROC [Sample] RETURNS [ConstantColor]
] RETURNS [ColorOperator] ~ {
size: Sample ~ maxSampleValue+1;
impl: MapData ~ NEW[ColorOperatorImplRep.map[size] ← [map[v: ]]];
FOR s0: Sample IN [0..maxSampleValue] DO impl.v[s0] ← map[s0] ENDLOOP;
RETURN[NEW[ColorOperatorRep ← [samplesPerPixel: 1, impl: impl]]];
};
RGBLinearColorModel: PUBLIC PROC [maxSampleValue: Sample]
RETURNS
[op: ColorOperator] ~ {
impl: RGBLinearData ~ NEW[ColorOperatorImplRep.rgbLinear ← [rgbLinear[maxSampleValue: maxSampleValue]]];
RETURN[NEW[ColorOperatorRep ← [samplesPerPixel: 3, impl: impl]]];
};
END.