aboutsummaryrefslogtreecommitdiff
path: root/pnm/read.scm
blob: 01e74d04a63a9a98a2f1bcc12775c7717ee848c1 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
(define-library (pnm read)
  (export image-read)
  (import (scheme base)
          (pnm image)
          (pnm pgm)
          (pnm ppm))
  (begin
    (define (image-read in)
      (define (unexpected-eof-error)
        (error "(pnm read) image-read: Unexpected end of file"))
      (define (unexpected-char-error)
        (error "(pnm read) image-read: Unexpected character"))
      (define (read-u8*)
        (let ((u8 (read-u8 in)))
          (when (eof-object? u8)
            (unexpected-eof-error))
          u8))
      (define (read-magic-number*)
        (let ((magic-number (read-magic-number in)))
          (when (eof-object? magic-number)
            (unexpected-eof-error))
          (unless magic-number
            (error "(pnm read) image-read: Not supported magic number"))
          magic-number))
      (define (read-number*)
        (let ((n (read-number in)))
          (when (eof-object? n)
            (unexpected-eof-error))
          (unless n
            (unexpected-char-error))
          n))
      (define (read-whitespaces*)
        (when (eof-object? (read-whitespaces in))
          (unexpected-eof-error)))

      (let ((magic-number (read-magic-number*)))
        (read-whitespaces*)
        (let ((width (read-number in)))
          (read-whitespaces*)
          (let ((height (read-number in)))
            (read-whitespaces*)
            (let ((maxval (read-number in)))
              (unless (whitespace? (read-u8*))
                (unexpected-char-error))
              (case magic-number
                ((P6)
                 (make-ppm-image width height maxval
                                 (if (< maxval 256)
                                     (read-bytevector (* 3 width height) in)
                                     (read-bytevector (* 6 width height) in))))
                ((P5)
                 (make-pgm-image width height maxval
                                 (if (< maxval 256)
                                     (read-bytevector (* width height) in)
                                     (read-bytevector (* 2 width height) in))))))))))

    (define (whitespace? u8)
      (case (integer->char u8)
        ((#\newline #\return #\tab #\space) #t)
        (else #f)))

    (define (comment? u8)
      (char=? #\# (integer->char u8)))

    (define (newline? u8)
      (case (integer->char u8)
        ((#\newline #\return) #t)
        (else #f)))

    (define (read-comment in)
      (let ((u8 (peek-u8 in)))
        (cond ((eof-object? u8) (eof-object))
              ((newline? u8)
               (read-u8 in)
               (read-whitespaces in))
              (else
               (read-u8 in)
               (read-comment in)))))

    (define (digit? u8)
      (and (<= 48 u8)
           (<= u8 57)))

    (define (u8->integer u8)
      (- u8 48))

    (define (read-magic-number in)
      (let* ((P/u8 (char->integer #\P))
             (u8-1 (read-u8 in))
             (u8-2 (read-u8 in))
             (u8-2/int (u8->integer u8-2)))
        (cond
         ((or (eof-object? u8-1) (eof-object? u8-2)) (eof-object))
         ((and (= u8-1 P/u8) (= u8-2/int 6)) 'P6)
         ((and (= u8-1 P/u8) (= u8-2/int 5)) 'P5)
         (else #f))))

    (define (read-whitespaces in)
      (let ((u8 (peek-u8 in)))
        (cond ((eof-object? u8) (eof-object))
              ((whitespace? u8)
               (read-u8 in)
               (read-whitespaces in))
              ((comment? u8)
               (read-u8 in)
               (read-comment in))
              (else #t))))

    (define (read-number in)
      (call-with-current-continuation
       (lambda (return)
         (let ((u8 (peek-u8 in)))
           (when (or (eof-object? u8)
                     (not (digit? u8)))
             (return #f)))
         (let loop ((number 0))
           (let ((u8 (peek-u8 in)))
             (cond ((eof-object? u8) (eof-object))
                   ((digit? u8)
                    (read-u8 in)
                    (loop (+ (* number 10) (u8->integer u8))))
                   (else number)))))))))