MODULE ImageFilePPMSpecific EXPORTS ImageFilePPM; IMPORT PPM; IMPORT Rd, Wr, Text, Thread, FileWr, FileRd, OSError; FROM Stdio IMPORT stdin, stdout; TYPE ImageParms = RECORD name: TEXT; (* File name (with extension) *) fmv: LONGREAL; (* = FLOAT(maxVal, LONGREAL) *) shift, scale: ChannelParms; (* Mapping parms: file = (real + shift)*scale *) END; REVEAL Writer = WriterPublic BRANDED OBJECT wr: Wr.T; (* The file *) Writer: PPM.Writer; (* Image writer *) h: ImageParms; (* Image parameters *) OVERRIDES open := WriterOpen; put := WriterPut; close := WriterClose; END; PROCEDURE WriterOpen( f: Writer; name: TEXT; NX, NY: CARDINAL; READONLY a, s: ChannelParms; VAR absError, relError: ChannelParms; READONLY maxVal := ChannelRanges{DefaultMaxVal, ..}; ): Writer RAISES {Thread.Alerted, Wr.Failure, OSError.E} = BEGIN IF Text.Empty(name) OR Text.Equal("-", name) THEN f.h.name := "(stdout)"; f.wr := stdout ELSE WITH wr = FileWr.Open(name) DO f.h.name := name; f.wr := wr; END END; <* ASSERT maxVal[0] = maxVal[1] *> <* ASSERT maxVal[0] = maxVal[2] *> f.Writer := NEW(PPM.Writer).init( f.wr, NX, NY, maxVal := maxVal[0], binary := TRUE ); f.h.fmv := FLOAT(maxVal[0], LONGREAL); FOR i := 0 TO 2 DO WITH lo = a[i] - s[i], hi = a[i] + s[i] DO <* ASSERT hi # lo *> f.h.shift[i] := -lo; f.h.scale[i] := f.h.fmv / (hi - lo); absError[i] := 1.0d-200 + ABS(s[i]) / f.h.fmv; relError[i] := 1.0d-14; END END; RETURN f END WriterOpen; PROCEDURE WriterPut(f: Writer; READONLY s: LongRealPixel) RAISES {Thread.Alerted, Wr.Failure} = VAR v: ARRAY [0..2] OF CARDINAL; BEGIN FOR i := 0 TO 2 DO WITH ss = (s[i] + f.h.shift[i])*f.h.scale[i], fv = MAX(0.0d0, MIN(f.h.fmv, ss)) DO v[i] := ROUND(fv) END END; f.Writer.put(v) END WriterPut; PROCEDURE WriterClose(f: Writer) = <* FATAL Thread.Alerted, Wr.Failure *> BEGIN f.Writer.finish(); Wr.Close(f.wr); END WriterClose; REVEAL Reader = ReaderPublic BRANDED OBJECT rd: Rd.T; (* The file *) Reader: PPM.Reader; (* Image reader *) h: ImageParms; (* Image parameters *) OVERRIDES open := ReaderOpen; get := ReaderGet; close := ReaderClose; END; PROCEDURE ReaderOpen( f: Reader; name: TEXT; VAR NX, NY: CARDINAL; READONLY a, s: ChannelParms; VAR absError, relError: ChannelParms; ): Reader RAISES {Rd.Failure, Thread.Alerted, OSError.E} = <* FATAL Wr.Failure *> VAR maxVal: CARDINAL; BEGIN IF Text.Empty(name) OR Text.Equal("-", name) THEN f.rd := stdin; f.h.name := "(stdin)" ELSE WITH rd = FileRd.Open(name) DO f.rd := rd; f.h.name := name; END END; f.Reader := NEW(PPM.Reader).init(f.rd, NX, NY, maxVal := maxVal); f.h.fmv := FLOAT(maxVal, LONGREAL); FOR i := 0 TO 2 DO WITH lo = a[0] - s[0], hi = a[0] + s[0] DO <* ASSERT hi # lo *> f.h.scale[i] := f.h.fmv / (hi - lo); f.h.shift[i] := - lo; absError[i] := 1.0d-200 + ABS(s[i]) / f.h.fmv; relError[i] := 1.0d-14; END END; RETURN f END ReaderOpen; PROCEDURE ReaderGet(f: Reader; VAR s: LongRealPixel) RAISES {Rd.Failure, Thread.Alerted} = VAR v: ARRAY [0..2] OF CARDINAL; BEGIN f.Reader.get(v); FOR i := 0 TO 2 DO s[i] := (FLOAT(v[i], LONGREAL)/f.h.scale[i]) - f.h.shift[i] END END ReaderGet; PROCEDURE ReaderClose(f: Reader) = <*FATAL Rd.Failure, Wr.Failure, Thread.Alerted *> BEGIN f.Reader.finish(); Rd.Close(f.rd); END ReaderClose; BEGIN END ImageFilePPMSpecific.