<> <> <> <<>> 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: ROPE _ NIL; 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: ATOM _ NIL; 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; }; <> <> <> <> <> <> <<};>> <> <<};>> <<>> 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.