MODULE ImageFilePGMSpecific EXPORTS ImageFilePGM; IMPORT PGM, Rd, Wr, Thread, FileWr, FileRd, OSError; FROM Stdio IMPORT stderr; TYPE ImageParms = RECORD name: TEXT; (* File name (with extension) *) fmv: LONGREAL; (* = FLOAT(maxVal, LONGREAL) *) shift, scale: LONGREAL; (* Pixel maping: pixel = round((state + shift)*scale) *) END; REVEAL Writer = WriterPublic BRANDED OBJECT wr: Wr.T; (* The file *) Writer: PGM.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 {Wr.Failure, Thread.Alerted, OSError.E} = BEGIN WITH fileName = name & Extension, wr = FileWr.Open(fileName) DO f.h.name := fileName; f.wr := wr; Wr.PutText(stderr, "( writing " & f.h.name & " ... "); f.Writer := NEW(PGM.Writer).init( f.wr, NX, NY, maxVal := maxVal[0], binary := TRUE ); f.h.fmv := FLOAT(maxVal[0], LONGREAL); WITH i = 0, lo = a[i] - s[i], hi = a[i] + s[i] DO <* ASSERT hi # lo *> f.h.shift := -lo; f.h.scale := f.h.fmv / (hi - lo); absError[i] := 1.0d-200 + ABS(s[i]) / f.h.fmv; relError[i] := 1.0d-10; END END; RETURN f END WriterOpen; PROCEDURE WriterPut(f: Writer; READONLY s: LongRealPixel) RAISES {Wr.Failure, Thread.Alerted} = BEGIN WITH ss = s[0], fv = MAX(0.0d0, MIN(f.h.fmv, (ss + f.h.shift) * f.h.scale)), v = ROUND(fv) DO f.Writer.put(v) END END WriterPut; PROCEDURE WriterClose(f: Writer) RAISES {Wr.Failure, Thread.Alerted} = BEGIN f.Writer.finish(); Wr.Close(f.wr); Wr.PutText(stderr, " done. )\n"); END WriterClose; REVEAL Reader = ReaderPublic BRANDED OBJECT rd: Rd.T; (* The file *) Reader: PGM.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 WITH fileName = name & Extension, rd = FileRd.Open(fileName) DO f.rd := rd; f.h.name := fileName; Wr.PutText(stderr, "( reading " & f.h.name & " ... "); f.Reader := NEW(PGM.Reader).init(rd, NX, NY, maxVal := maxVal); f.h.fmv := FLOAT(maxVal, LONGREAL); WITH i = 0, lo = a[0] - s[0], hi = a[0] + s[0] DO <* ASSERT hi # lo *> f.h.scale := f.h.fmv / (hi - lo); f.h.shift := - lo; absError[0] := 1.0d-200 + ABS(s[0]) / f.h.fmv; relError[0] := 1.0d-14; END; END; RETURN f END ReaderOpen; PROCEDURE ReaderGet(f: Reader; VAR s: LongRealPixel) RAISES {Rd.Failure, Thread.Alerted} = VAR v: CARDINAL; BEGIN f.Reader.get(v); s[0] := FLOAT(v, LONGREAL)/f.h.scale - f.h.shift; END ReaderGet; PROCEDURE ReaderClose(f: Reader) RAISES {Rd.Failure, Thread.Alerted} = <* FATAL Wr.Failure *> BEGIN f.Reader.finish(); Rd.Close(f.rd); Wr.PutText(stderr, " done. )\n"); END ReaderClose; BEGIN END ImageFilePGMSpecific.