IPImagerImpl.mesa
Copyright © 1984 Xerox Corporation. All rights reserved.
Doug Wyatt, November 15, 1984 5:45:54 pm PST
DIRECTORY
FS,
Imager USING [ConcatT],
ImagerColor,
ImagerFont USING [Char, Find, Font, Modify],
ImagerPixelArray,
IO,
IPImager USING [],
IPInterpreter,
IPMaster,
Rope,
RuntimeError USING [BoundsFault];
IPImagerImpl: CEDAR PROGRAM
IMPORTS FS, Imager, ImagerFont, IO, IPInterpreter, IPMaster, Rope, RuntimeError
EXPORTS IPImager
= BEGIN OPEN IPInterpreter;
ROPE: TYPE ~ Rope.ROPE;
Font: TYPE ~ ImagerFont.Font;
Char: TYPE ~ ImagerFont.Char; -- CARDINAL
$Font Vectors
fontClass: VectorClass ~ NEW[VectorClassRep ← [type: $Font,
shape: FontShape, get: FontGet]];
FontShape: PROC[v: Vector] RETURNS[VectorShape] ~ {
RETURN[[l: 0, n: INT[CARDINAL.LAST]+1]];
};
FontGet: PROC[v: Vector, j: Integer] RETURNS[Any] ~ {
font: Font ~ NARROW[v.data];
RETURN[OperatorFromChar[font: font, char: j]];
};
VectorFromFont: PUBLIC PROC[font: Font] RETURNS[Vector] ~ {
RETURN[NEW[VectorRep ← [class: fontClass, data: font]]];
};
FontFromVector: PUBLIC PROC[v: Vector] RETURNS[Font] ~ {
IF v.class=fontClass THEN WITH v.data SELECT FROM
font: Font => RETURN[font]; ENDCASE;
RETURN[NIL];
};
$Char Operators (the result of Get[font, j])
CharData: TYPE ~ REF CharDataRep;
CharDataRep: TYPE ~ RECORD[font: Font, char: Char];
charClass: OperatorClass ~ NEW[OperatorClassRep ← [type: $Char, do: CharDo]];
CharDo: PROC[op: Operator, state: State] ~ {
data: CharData ~ NARROW[op.data];
font: Font ~ data.font;
font.class.MaskChar[font, data.char, state.imager];
};
OperatorFromChar: PROC[font: Font, char: Char] RETURNS[Operator] ~ {
data: CharData ~ NEW[CharDataRep ← [font: font, char: char]];
RETURN[NEW[OperatorRep ← [class: charClass, data: data]]];
};
$Modified Vectors (the result of ModifyFont[v, ...] where v is not a $Font Vector)
ModifiedData: TYPE ~ REF ModifiedDataRep;
ModifiedDataRep: TYPE ~ RECORD[v: Vector, m: Transformation];
modifiedClass: VectorClass ~ NEW[VectorClassRep ← [type: $Modified,
shape: ModifiedShape, get: ModifiedGet]];
ModifiedShape: PROC[v: Vector] RETURNS[VectorShape] ~ {
data: ModifiedData ~ NARROW[v.data];
RETURN[Shape[data.v]];
};
ModifiedGet: PROC[v: Vector, j: Integer] RETURNS[Any] ~ {
data: ModifiedData ~ NARROW[v.data];
val: Any ~ Get[data.v, j];
WITH val SELECT FROM
op: Operator => RETURN[OperatorFromModifiedChar[e: op, m: data.m]];
ENDCASE => {
MasterError[$wrongType, "Element of font vector is not an Operator."];
ERROR Error;
};
};
$ModifiedChar Operators (the result of Get[v, j], where v is a $Modified Vector)
ModifiedCharData: TYPE ~ REF ModifiedCharDataRep;
ModifiedCharDataRep: TYPE ~ RECORD[e: Operator, m: Transformation];
modifiedCharClass: OperatorClass ~ NEW[OperatorClassRep ← [type: $ModifiedChar,
do: ModifiedCharDo]];
ModifiedCharDo: PROC[op: Operator, state: State] ~ {
data: ModifiedCharData ~ NARROW[op.data];
state.imager.ConcatT[data.m]; Do[state, data.e];
};
OperatorFromModifiedChar: PROC[e: Operator, m: Transformation] RETURNS[Operator] ~ {
data: ModifiedCharData ~ NEW[ModifiedCharDataRep ← [e: e, m: m]];
RETURN[NEW[OperatorRep ← [class: modifiedCharClass, data: data]]];
};
NameFromVector: PROC[v: Vector] RETURNS[ROPE] ~ {
shape: VectorShape ~ Shape[v];
name: ROPENIL;
FOR i: Integer IN[0..shape.n) DO
id: Identifier ~ IdentifierFromAny[Get[v, shape.l+i]];
IF name#NIL THEN name ← name.Concat["/"];
name ← name.Concat[id.rope];
ENDLOOP;
RETURN[name];
};
FindFont: PUBLIC PROC[self: State, v: Vector] RETURNS[Vector] ~ {
name: ROPE ~ NameFromVector[v];
font: Font ~ ImagerFont.Find[name];
RETURN[VectorFromFont[font]];
};
FindFontVec: PUBLIC PROC[self: State, v: Vector] RETURNS[Vector] ~ {
MasterError[$unimplemented, "FINDFONTVEC is not implemented."];
ERROR Error;
};
ModifyFont: PUBLIC PROC[v: Vector, m: Transformation] RETURNS[Vector] ~ {
IF v.class.type=$Font THEN {
font: Font ~ NARROW[v.data];
RETURN[VectorFromFont[ImagerFont.Modify[font, m]]];
}
ELSE {
data: ModifiedData ~ NEW[ModifiedDataRep ← [v: v, m: m]];
RETURN[NEW[VectorRep ← [class: modifiedClass, data: data]]];
};
};
LargeVectorData: TYPE ~ REF LargeVectorDataRep;
LargeVectorDataRep: TYPE ~ RECORD[
file: FS.OpenFile,
start, length: INT,
bytesPerElement: NAT,
elements: INT
];
largeVectorClass: VectorClass ~ NEW[VectorClassRep ← [type: $LargeVector,
shape: LargeVectorShape, get: LargeVectorGet]];
LargeVectorShape: PROC[v: Vector] RETURNS[VectorShape] ~ {
data: LargeVectorData ~ NARROW[v.data];
RETURN[[l: 0, n: data.elements]];
};
LargeVectorGet: PROC[v: Vector, j: Integer] RETURNS[x: Any ← NIL] ~ {
data: LargeVectorData ~ NARROW[v.data];
IF j IN[0..data.elements) THEN {
bytesPerElement: NAT ~ data.bytesPerElement;
stream: STREAM ~ FS.StreamFromOpenFile[data.file];
IO.SetIndex[stream, data.start+j*bytesPerElement];
IF bytesPerElement<=4 THEN {
value: INT ~ IPMaster.GetSigned[stream, bytesPerElement];
x ← NumberFromInt[value];
}
ELSE {
value: REAL ~ IPMaster.GetInteger[stream, bytesPerElement];
x ← NumberFromReal[value];
};
IO.Close[stream];
}
ELSE ERROR RuntimeError.BoundsFault;
};
MakeLargeVector: PUBLIC PROC[
stream: STREAM,
length: INT,
bytesPerElement: NAT
] RETURNS[Vector] ~ {
start: INT ~ IO.GetIndex[stream];
IPMaster.SkipBytes[stream, length];
IF bytesPerElement#0 AND (length MOD bytesPerElement)=0 THEN {
file: FS.OpenFile ~ FS.OpenFileFromStream[stream];
data: LargeVectorData ~ NEW[LargeVectorDataRep ← [file: file,
start: start, length: length, bytesPerElement: bytesPerElement,
elements: length/bytesPerElement]];
RETURN[NEW[VectorRep ← [class: largeVectorClass, data: data]]];
}
ELSE ERROR;
};
PixelArray: TYPE ~ ImagerPixelArray.PixelArray;
PixelArrayRep: TYPE ~ ImagerPixelArray.PixelArrayRep;
Row: TYPE ~ ImagerPixelArray.Row;
RowRep: TYPE ~ ImagerPixelArray.RowRep;
Val: TYPE ~ ImagerPixelArray.Val;
PixelArrayData: TYPE ~ REF PixelArrayDataRep;
PixelArrayDataRep: TYPE ~ RECORD[
stream: STREAM, -- a stream on the file
start: INT ← 0, -- byte index of the beginning of the raster section
bytesPerElement: INT ← 0, -- bytes per element
bytesPerLine: INT ← 0 -- bytes per scan line
];
MakePixelArray: PUBLIC PROC[
xPixels, yPixels: Integer, -- number of pixels in slow and fast directions
samplesPerPixel: Integer, -- number of sample values for each pixel
maxSampleValue: Vector, -- maximum sample value; if NIL, use maxSampleValueI
maxSampleValueI: Integer, -- constant maximum sample value, if maxSampleValue=NIL
samplesInterleaved: BOOL, -- if true, samples for one pixel are contiguous
m: Transformation, -- transformation from pixel coordinates to master coordinates
samples: Vector -- the actual samples
] RETURNS[PixelArray] ~ {
IF maxSampleValue=NIL THEN {
IF maxSampleValueI#255 THEN ERROR;
}
ELSE {
shape: VectorShape ~ Shape[maxSampleValue];
IF shape.l#0 OR shape.n#samplesPerPixel THEN ERROR;
FOR i: Integer IN[0..samplesPerPixel) DO
max: Integer ~ GetInteger[maxSampleValue, i];
IF max#255 THEN ERROR;
ENDLOOP;
};
IF samplesInterleaved AND samplesPerPixel>1 THEN ERROR;
IF samples.class=largeVectorClass THEN {
lv: LargeVectorData ~ NARROW[samples.data];
data: PixelArrayData ~ NEW[PixelArrayDataRep ← [
stream: FS.StreamFromOpenFile[lv.file],
start: lv.start,
bytesPerElement: lv.bytesPerElement,
bytesPerLine: yPixels*lv.bytesPerElement
]];
IF (samplesPerPixel*xPixels*yPixels)#lv.elements THEN ERROR;
IF lv.bytesPerElement#1 THEN ERROR;
RETURN[NEW[PixelArrayRep ← [class: pixelArrayClass, data: data,
sSize: xPixels, fSize: yPixels, samplesPerPixel: samplesPerPixel, m: m]]];
}
ELSE {
ERROR;
};
};
pixelArrayClass: ImagerPixelArray.Class ~ NEW[ImagerPixelArray.ClassRep ← [
type: $Interpress,
MaxSampleValue: IPMaxSampleValue,
GetSample: IPGetSample,
GetRow: IPGetRow
]];
IPMaxSampleValue: PROC[pa: PixelArray, i: NAT] RETURNS[Val] ~ {
IF i IN[0..pa.samplesPerPixel) THEN {
RETURN[255]
}
ELSE ERROR RuntimeError.BoundsFault;
};
IPGetSample: PROC[pa: PixelArray, s, f, i: NAT ← 0] RETURNS[Val] ~ {
IF s IN[0..pa.sSize) AND f IN[0..pa.fSize) AND i IN[0..pa.samplesPerPixel) THEN {
data: PixelArrayData ~ NARROW[pa.data];
ERROR;
}
ELSE ERROR RuntimeError.BoundsFault;
};
IPGetRow: PROC[pa: PixelArray, row: Row, s, f, i: NAT ← 0] ~ {
IF s IN[0..pa.sSize) AND f IN[0..pa.fSize) AND i IN[0..pa.samplesPerPixel) THEN {
data: PixelArrayData ~ NARROW[pa.data];
IF data.bytesPerElement=1 THEN {
count: NAT ~ MIN[row.size, pa.fSize-f];
stream: STREAM ~ data.stream;
index: INT ~ data.start+data.bytesPerLine*(pa.sSize*i+s)+data.bytesPerElement*f;
IO.SetIndex[stream, index];
TRUSTED {
base: LONG POINTER ~ LOOPHOLE[row, LONG POINTER]+SIZE[RowRep[0]];
IF IO.UnsafeGetBlock[self: stream, block: [base: base, count: count]]=count THEN NULL
ELSE ERROR IO.EndOfStream[stream];
};
}
ELSE ERROR;
}
ELSE ERROR RuntimeError.BoundsFault;
};
FindDecompressor: PUBLIC PROC[self: State, v: Vector] RETURNS[Operator] ~ {
name: ROPE ~ NameFromVector[v];
ERROR;
};
Color: TYPE ~ ImagerColor.Color;
ColorOperator: TYPE ~ ImagerColor.ColorOperator;
ColorOperatorRep: TYPE ~ ImagerColor.ColorOperatorRep;
Separation: TYPE ~ ImagerColor.Separation;
SeparationRep: TYPE ~ ImagerColor.SeparationRep;
SampleMap: TYPE ~ ImagerColor.SampleMap;
SampleMapRep: TYPE ~ ImagerColor.SampleMapRep;
FindColor: PUBLIC PROC[self: State, v: Vector] RETURNS[Color] ~ {
name: ROPE ~ NameFromVector[v];
ERROR;
};
FindColorOperator: PUBLIC PROC[self: State, v: Vector] RETURNS[Operator] ~ {
name: ROPE ~ NameFromVector[v];
ERROR;
};
FindColorModelOperator: PUBLIC PROC[self: State, v: Vector] RETURNS[Operator] ~ {
name: ROPE ~ NameFromVector[v];
atom: ATOMNIL;
SELECT TRUE FROM
Rope.Equal[name, "standard/grayLinear", FALSE] => atom ← $grayLinear;
Rope.Equal[name, "standard/grayDensity", FALSE] => atom ← $grayDensity;
Rope.Equal[name, "standard/grayVisual", FALSE] => atom ← $grayVisual;
Rope.Equal[name, "standard/map", FALSE] => atom ← $map;
Rope.Equal[name, "standard/buildMap", FALSE] => atom ← $buildMap;
Rope.Equal[name, "standard/separations", FALSE] => atom ← $separations;
ENDCASE;
IF atom=NIL THEN ERROR;
RETURN[NEW[OperatorRep ← [class: colorModelOperatorClass, data: atom]]];
};
colorModelOperatorClass: OperatorClass ~ NEW[OperatorClassRep ← [
type: $ColorModelOperator, do: ColorModelOperatorDo]];
ColorModelOperatorDo: PROC[op: Operator, state: State] ~ {
SELECT op.data FROM
$grayLinear => GrayLinearColorModelOperator[state];
$grayDensity => GrayDensityColorModelOperator[state];
$grayVisual => GrayVisualColorModelOperator[state];
$map => MapColorModelOperator[state];
$separations => SeparationsColorModelOperator[state];
ENDCASE => ERROR;
};
GetSampleMap: PROC[v: Vector, i: Integer] RETURNS[SampleMap] ~ {
x: Any ~ Get[v, i];
WITH x SELECT FROM
pixelMap: Vector => {
shape: VectorShape ~ Shape[pixelMap];
IF shape.l#0 THEN ERROR
ELSE {
map: SampleMap ~ NEW[SampleMapRep[shape.n]];
FOR s: NAT IN[0..map.size) DO map[s] ← GetReal[pixelMap, s] ENDLOOP;
RETURN[map];
};
};
ENDCASE;
IF IntegerFromAny[x]=0 THEN RETURN[NIL]
ELSE ERROR;
};
GrayLinearColorModelOperator: PROC[self: State] ~ {
v: Vector ~ PopVector[self];
shape: VectorShape ~ Shape[v];
IF shape.l=0 AND shape.n=3 THEN {
sWhite: REAL ~ GetReal[v, 0];
sBlack: REAL ~ GetReal[v, 1];
map: SampleMap ~ GetSampleMap[v, 2];
colorOp: ColorOperator ~ NEW[ColorOperatorRep.grayLinear ← [
grayLinear[sWhite: sWhite, sBlack: sBlack, map: map]]];
PushOperator[self, OperatorFromColorOperator[colorOp]];
};
ERROR;
};
GrayDensityColorModelOperator: PROC[self: State] ~ {
v: Vector ~ PopVector[self];
shape: VectorShape ~ Shape[v];
IF shape.l=0 AND shape.n=4 THEN {
sWhite: REAL ~ GetReal[v, 0];
sBlack: REAL ~ GetReal[v, 1];
dBlack: REAL ~ GetReal[v, 2];
map: SampleMap ~ GetSampleMap[v, 3];
colorOp: ColorOperator ~ NEW[ColorOperatorRep.grayDensity ← [
grayDensity[sWhite: sWhite, sBlack: sBlack, dBlack: dBlack, map: map]]];
PushOperator[self, OperatorFromColorOperator[colorOp]];
};
ERROR;
};
GrayVisualColorModelOperator: PROC[self: State] ~ {
v: Vector ~ PopVector[self];
shape: VectorShape ~ Shape[v];
IF shape.l=0 AND shape.n=3 THEN {
sWhite: REAL ~ GetReal[v, 0];
sBlack: REAL ~ GetReal[v, 1];
map: SampleMap ~ GetSampleMap[v, 2];
colorOp: ColorOperator ~ NEW[ColorOperatorRep.grayVisual ← [
grayVisual[sWhite: sWhite, sBlack: sBlack, map: map]]];
PushOperator[self, OperatorFromColorOperator[colorOp]];
};
ERROR;
};
MapColorModelOperator: PROC[self: State] ~ {
v: Vector ~ PopVector[self];
shape: VectorShape ~ Shape[v];
IF shape.l=0 AND shape.n=1 THEN {
map: Vector ~ VectorFromAny[Get[v, 0]];
PushOperator[self, OperatorFromColorOperator[colorOp]];
};
ERROR;
};
SeparationsColorModelOperator: PROC[self: State] ~ {
v: Vector ~ PopVector[self];
shape: VectorShape ~ Shape[v];
IF shape.l=0 THEN {
samplesPerPixel: Integer ~ shape.n;
op: REF ColorOperatorRep.separations ~ NEW[ColorOperatorRep.separations[samplesPerPixel]];
FOR i: Integer IN[0..samplesPerPixel) DO
s: Vector ~ VectorFromAny[Get[v, i]];
sh: VectorShape ~ Shape[s];
IF sh.l=0 AND sh.n=6 THEN {
X: REAL ~ GetReal[s, 0];
Y: REAL ~ GetReal[s, 1];
Z: REAL ~ GetReal[s, 2];
sMax: REAL ~ GetReal[s, 3];
sMin: REAL ~ GetReal[s, 4];
map: SampleMap ~ GetSampleMap[s, 5];
op[i] ← NEW[SeparationRep ← [cie: [X, Y, Z], sMax: sMax, sMin: sMin, map: map]];
}
ELSE ERROR;
ENDLOOP;
PushOperator[self, OperatorFromColorOperator[op]];
}
ELSE ERROR;
};
colorOperatorClass: OperatorClass ~ NEW[OperatorClassRep ← [
type: $ColorOperator, do: ColorOperatorDo]];
ColorOperatorDo: PROC[op: Operator, state: State] ~ {
colorOp: ColorOperator ~ NARROW[op.data];
v: Vector ~ PopVector[state];
WITH colorOp SELECT FROM
op: REF ColorOperatorRep.grayLinear => ERROR;
op: REF ColorOperatorRep.grayDensity => ERROR;
op: REF ColorOperatorRep.grayVisual => ERROR;
op: REF ColorOperatorRep.map => ERROR;
op: REF ColorOperatorRep.separations => ERROR;
ENDCASE => ERROR;
};
ColorOperatorFromOperator: PUBLIC PROC[op: Operator] RETURNS[ColorOperator] ~ {
IF op.class=colorOperatorClass THEN WITH op.data SELECT FROM
colorOp: ColorOperator => RETURN[colorOp]; ENDCASE;
RETURN[NIL];
};
OperatorFromColorOperator: PUBLIC PROC[colorOp: ColorOperator] RETURNS[Operator] ~ {
RETURN[NEW[OperatorRep ← [class: colorOperatorClass, data: colorOp]]];
};
END.