ImagerDeviceColorImpl.mesa
Copyright Ó 1993 by Xerox Corporation. All rights reserved.
Michael Plass, October 26, 1993 2:13 pm PDT
DIRECTORY
Prop USING [Get, Put],
RealInline USING [IsValid, MCFix],
ImagerDevice USING [Device],
ImagerColorPrivate USING [ColorPoint],
ImagerDeviceColor;
ImagerDeviceColorImpl: CEDAR PROGRAM
IMPORTS Prop, RealInline
EXPORTS ImagerDeviceColor
~ BEGIN
LookupTable: TYPE = REF LookupTableRep;
LookupTableRep: TYPE = ImagerDeviceColor.LookupTableRep;
ColorLookupTableType: TYPE = ImagerDeviceColor.ColorLookupTableType;
DeviceColorControl: TYPE = REF DeviceColorControlRep;
DeviceColorControlRep: TYPE = ImagerDeviceColor.DeviceColorControlRep;
GetDeviceColorControl: PUBLIC PROC [device: ImagerDevice.Device] RETURNS [DeviceColorControl] = {
key: ATOM = $DeviceColorControl;
WITH Prop.Get[device.parm.propList, key] SELECT FROM
control: DeviceColorControl => RETURN [control];
ENDCASE => {
control: DeviceColorControl = NEW[DeviceColorControlRep ¬ [stamp: 0, table: ALL[NIL], setLookupTable: DefaultSetLookupTable]];
NOTE: control.private is not used at present.
device.parm.propList ¬ Prop.Put[device.parm.propList, key, control];
RETURN [control];
};
};
DefaultSetLookupTable: PUBLIC PROC [control: DeviceColorControl, which: ColorLookupTableType, table: LookupTable] = {
ident: BOOL ¬ TRUE;
IF table # NIL AND table.size = 0 THEN table ¬ NIL; -- don't store empty tables.
control.table[which] ¬ table;
FOR i: ColorLookupTableType IN [redTransfer..grayTransfer] DO
IF control.table[i] # NIL THEN {ident ¬ FALSE; EXIT};
ENDLOOP;
control.allIdentity ¬ ident;
control.stamp ¬ control.stamp + 1;
};
LookupReal: PUBLIC PROC [table: LookupTable, real: REAL] RETURNS [REAL] = {
IF table = NIL THEN RETURN [real] ELSE {
limit: INT = table.size-1;
IF real <= 0.0 THEN RETURN [table[0]] ELSE
IF real >= 1.0 THEN RETURN [table[limit]] ELSE
IF NOT RealInline.IsValid[real] THEN RETURN [real] ELSE {
s: REAL = limit*real;
k: INT = RealInline.MCFix[s]; -- as good as Floor, since s > 0.0
d: REAL = s-REAL[k];
v: REAL = table[k];
RETURN [IF d <= 0.0 OR k >= limit THEN v ELSE v + d * (table[k+1]-v)]
};
};
};
LookupFlipped: PUBLIC PROC [table: LookupTable, real: REAL] RETURNS [REAL] = {
IF table = NIL THEN RETURN [real] ELSE {
limit: INT = table.size-1;
real ¬ 1.0-real;
IF real <= 0.0 THEN RETURN [1.0-table[0]] ELSE
IF real >= 1.0 THEN RETURN [1.0-table[limit]] ELSE
IF NOT RealInline.IsValid[real] THEN RETURN [real] ELSE {
s: REAL = limit*real;
k: INT = RealInline.MCFix[s]; -- as good as Floor, since s > 0.0
d: REAL = s-REAL[k];
v: REAL = table[k];
RETURN [1.0-(IF d <= 0.0 OR k >= limit THEN v ELSE v + d * (table[k+1]-v))]
};
};
};
ColorPoint: TYPE = ImagerColorPrivate.ColorPoint;
CMYKFromCMYK: PUBLIC PROC [control: DeviceColorControl, c, m, y, k: REAL, maxOut: REAL, out: ColorPoint] = {
oog: BOOL ¬ FALSE;
CS: PROC [r: REAL] RETURNS [REAL] = INLINE {
r ¬ r * maxOut;
IF r < 0.0 THEN {oog ¬ TRUE; r ¬ 0.0}
ELSE IF r > maxOut THEN {oog ¬ TRUE; r ¬ maxOut};
RETURN [r]
};
out[0] ¬ CS[LookupFlipped[control.table[$redTransfer], c]];
out[1] ¬ CS[LookupFlipped[control.table[$greenTransfer], m]];
out[2] ¬ CS[LookupFlipped[control.table[$blueTransfer], y]];
out[3] ¬ CS[LookupFlipped[control.table[$grayTransfer], k]];
out.outOfGamut ¬ oog;
};
CMYKFromCMY: PUBLIC PROC [control: DeviceColorControl, c, m, y: REAL, maxOut: REAL, out: ColorPoint] = {
oog: BOOL ¬ FALSE;
CS: PROC [r: REAL] RETURNS [REAL] = INLINE {
r ¬ r * maxOut;
IF r < 0.0 THEN {oog ¬ TRUE; r ¬ 0.0}
ELSE IF r > maxOut THEN {oog ¬ TRUE; r ¬ maxOut};
RETURN [r]
};
bg: LookupTable = control.table[$blackGeneration];
ucr: LookupTable = control.table[$undercolorRemoval];
min: REAL = MIN[c, m, y];
k: REAL ¬ IF bg = NIL THEN 0.0 ELSE LookupReal[bg, min];
IF ucr # NIL THEN {
u: REAL = LookupReal[ucr, min];
c ¬ c - u;
m ¬ m - u;
k ¬ k - u;
};
out[0] ¬ CS[LookupFlipped[control.table[$redTransfer], c]];
out[1] ¬ CS[LookupFlipped[control.table[$greenTransfer], m]];
out[2] ¬ CS[LookupFlipped[control.table[$blueTransfer], y]];
out[3] ¬ CS[LookupFlipped[control.table[$grayTransfer], k]];
out.outOfGamut ¬ oog;
};
CMYKFromRGB: PUBLIC PROC [control: DeviceColorControl, r, g, b: REAL, maxOut: REAL, out: ColorPoint] = {
CMYKFromCMY[control, 1.0-r, 1.0-g, 1.0-b, maxOut, out];
};
RGBFromRGB: PUBLIC PROC [control: DeviceColorControl, r, g, b: REAL, maxOut: REAL, out: ColorPoint] = {
oog: BOOL ¬ FALSE;
CS: PROC [r: REAL] RETURNS [REAL] = INLINE {
r ¬ r * maxOut;
IF r < 0.0 THEN {oog ¬ TRUE; r ¬ 0.0}
ELSE IF r > maxOut THEN {oog ¬ TRUE; r ¬ maxOut};
RETURN [r]
};
out[0] ¬ CS[LookupReal[control.table[$redTransfer], r]];
out[1] ¬ CS[LookupReal[control.table[$greenTransfer], g]];
out[2] ¬ CS[LookupReal[control.table[$blueTransfer], b]];
out.outOfGamut ¬ oog;
};
RGBFromCMYK: PUBLIC PROC [control: DeviceColorControl, c, m, y, k: REAL, maxOut: REAL, out: ColorPoint] = {
RGBFromRGB[control, 1.0-(c+k), 1.0-(m+k), 1.0-(y+k), maxOut, out];
};
YFromY: PUBLIC PROC [control: DeviceColorControl, Y: REAL, maxOut: REAL, out: ColorPoint] = {
g: BOOL ¬ FALSE;
CS: PROC [r: REAL] RETURNS [REAL] = INLINE {
r ¬ r * maxOut;
IF r < 0.0 THEN {g ¬ TRUE; r ¬ 0.0}
ELSE IF r > maxOut THEN {g ¬ TRUE; r ¬ maxOut};
RETURN [r]
};
out[0] ¬ CS[LookupReal[control.table[$grayTransfer], Y]];
out.outOfGamut ¬ g;
};
KFromY: PUBLIC PROC [control: DeviceColorControl, Y: REAL, maxOut: REAL, out: ColorPoint] = {
g: BOOL ¬ FALSE;
CS: PROC [r: REAL] RETURNS [REAL] = INLINE {
r ¬ r * maxOut;
IF r < 0.0 THEN {g ¬ TRUE; r ¬ 0.0}
ELSE IF r > maxOut THEN {g ¬ TRUE; r ¬ maxOut};
RETURN [r]
};
out[0] ¬ CS[1.0-LookupReal[control.table[$grayTransfer], Y]];
out.outOfGamut ¬ g;
};
CMYKFromY: PUBLIC PROC [control: DeviceColorControl, Y: REAL, maxOut: REAL, out: ColorPoint] = {
g: BOOL ¬ FALSE;
CS: PROC [r: REAL] RETURNS [REAL] = INLINE {
r ¬ r * maxOut;
IF r < 0.0 THEN {g ¬ TRUE; r ¬ 0.0}
ELSE IF r > maxOut THEN {g ¬ TRUE; r ¬ maxOut};
RETURN [r]
};
out[0] ¬ out[1] ¬ out[2] ¬ 0.0;
out[3] ¬ CS[1.0-LookupReal[control.table[$grayTransfer], Y]];
out.outOfGamut ¬ g;
};
END.