On 12-Jan-06, at 12:59 AM, Bradley Lucier wrote:
Marc:
The file formats used by the image library netpbm (pbm, pgm, ppm, pnm, ...) are mixed ascii/binary format; the first few lines are ASCII that have a magic number for the file, the size of the image (rows and columns) and the maximum value of the pixels (for greyscale images). Then, after a single newline, comes the binary data.
So:
[lindv2:Arrays/srfi2/stacey] lucier% head -3 2314.pgm P5 1605 2244 255
<binary data follows here>
Now, in beta 16 and beta 17, I get the error:
[lindv2:Arrays/srfi2/stacey] lucier% gsc Gambit Version 4.0 beta 17
(load "convex2.scm")
*** ERROR IN #<procedure #2>, "../generic-arrays.scm"@1171.44 -- Input port character buffer is not empty (read-u8 '#<input-port #3 "/Users/lucier/lang/scheme/Arrays/srfi2/ stacey/2314.pgm">) 1> ,b 0 #<procedure #2> "../generic-arrays.scm"@1171:44 (domain-getter i j) 1 #<procedure #4> "../generic-arrays.scm"@283:9 (f i j) 2 Array->Fixed-array "../generic-arrays.scm"@1169:6 (Interval-for-each (case (##Interval-dimension domain) ((1) (lambda (i) (range-setter (domain-... 3 #<procedure #5> "../pgm.scm"@44:5 (Array->Fixed- array generic-array-manipulators (build-Array (build-Interval '#(0 0) (vector rows colu... 4 call-with-input-file 5 (interaction) "convex2.scm"@77:21 (read-pgm (string-append name ".pgm")) 6 ##load 7 ##load 8 (interaction) (console)@1:1 (load "convex2.scm") 1> ,e i = 0 j = 0 range-setter = (lambda (value i j) (manipulator-setter body (indexer i j) value)) domain-getter = (lambda (i j) (read-u8 port)) result = '#<Array-base #6 domain: #<Interval #7 lower-bounds: #(0 0) upper-bounds: #(2244 1605)> getter: #<procedure #8> setter: #<procedure #9> manipulat... domain = '#<Interval #7 lower-bounds: #(0 0) upper-bounds: #(2244 1605)> result-manipulators = '#<Array-manipulators #10 getter: #<procedure #11> setter: #<procedure #12> maker: #<procedure #13 make-vector> length: #<procedure ... array = '#<Array-base #15 domain: #<Interval #7 lower-bounds: #(0 0) upper-bounds: #(2244 1605)> getter: #<procedure #16> setter: #f manipulators: #f body... (current-exception-handler) = primordial-exception-handler (current-input-port) = '#<input-output-port #17 (console)> (current-output-port) = '#<input-output-port #17 (console)> (current-directory) = "/Users/lucier/lang/scheme/Arrays/srfi2/ stacey/" 1>
and I read from the manual:
procedure: read-u8 [port]
This procedure reads the byte input-port port and returns the
byte at the current byte location and advances the current byte location to the next byte, unless the port is already at end-of- file in which case read-u8 returns the end-of-file object. If it is not specified, port defaults to the current input-port.
This procedure must be called before any use of the port in a
character input operation (i.e. a call to the procedures read, read-char, peek-char, etc) because otherwise the character-stream and byte-stream may be out of sync due to the port buffering.
So, how do I deal with meta-data like this? Read the u8 numbers, call integer->char, put them all into a string, call read on the string, ...? Why should I have to do this instead of the runtime doing this? Or perhaps you have a better suggestion.
Brad
The specification in the manual is more restrictive than the implementation (I will change the manual). You can only read a byte with read-u8 if the character buffer is empty. This can be guaranteed by reading the character from a port that is not buffered (i.e. buffering: #f). Then you can switch to reading bytes with read- u8 or read-subu8vector. So what you want looks like this (tested on Mac OS X and Linux with beta 16 and 17):
#! /usr/bin/env gsi-script
; File: "text-bin-io.scm"
(define (open-input-file-for-text-bin-io path) (open-input-file (list path: path char-encoding: 'latin1 eol-encoding: 'lf buffering: #f)))
(define (read-pgm-P5 path) (let ((p (open-input-file-for-text-bin-io path))) (let* ((char1 (read-char p)) (char2 (read-char p))) (if (not (and (char? char1) (char? char2) (char=? char1 #\P) (char=? char2 #\5))) (error "P5 magic number expected") (let* ((width (read p)) (height (read p)) (maxval (read p)) (char3 (read-char p))) (if (not (and (char? char3) (char-whitespace? char3))) (error "whitespace expected after maxval") (let* ((bytes-per-pixel (if (< maxval 256) 1 2)) (nb-bytes (* bytes-per-pixel width height)) (image (make-u8vector nb-bytes))) (let ((n (read-subu8vector image 0 nb-bytes p))) (if (= n nb-bytes) (vector width height maxval image) (error "truncated file"))))))))))
; create a pgm P5 file we can read... (with-output-to-file "foo.pgm" (lambda () (display "P5\n2 3\n255\n123456")))
(define (main) (let ((image (read-pgm-P5 "foo.pgm"))) (pp image)))
Marc