--
--	rasterio: read PPM files
--	Copyright (C) 2009  Carl Ritson
--	Copyright (C) 2009  Adam Sampson <ats@offog.org>
--
--	This library is free software; you can redistribute it and/or
--	modify it under the terms of the GNU Lesser General Public
--	License as published by the Free Software Foundation, either
--	version 2 of the License, or (at your option) any later version.
--
--	This library is distributed in the hope that it will be useful,
--	but WITHOUT ANY WARRANTY; without even the implied warranty of
--	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
--	Lesser General Public License for more details.
--
--	You should have received a copy of the GNU Lesser General Public
--	License along with this library.  If not, see
--	<http://www.gnu.org/licenses/>.
--

--** @module rasterio

#INCLUDE "raster.module"
#INCLUDE "file.module"

--{{{  PROC read.raster.ppm (VAL []BYTE filename, RESULT RASTER raster)
--* Load a PPM file as a raster.
PROC read.raster.ppm (VAL []BYTE filename, RESULT RASTER raster)
  INT fd, result:
  INITIAL BYTE ch IS 0:
  INT width, height, maxval:

  --{{{  FUNCTION is.whitespace
  --* Is a character whitespace, as defined by the PPM spec?
  BOOL FUNCTION is.whitespace (VAL BYTE ch)
    BOOL b:
    VALOF
      CASE ch
        ' ', '*t', '*c', '*n'
          b := TRUE
        ELSE
          b := FALSE
      RESULT b
  :
  --}}}
  --{{{  PROC raw.char
  --* Read a character from the file into ch.
  PROC raw.char ()
    [1]BYTE buf:
    SEQ
      file.read (fd, buf, result)
      ASSERT (result = 1)
      ch := buf[0]
  :
  --}}}
  --{{{  PROC get.char
  --* Read a character from the file into ch, skipping comments.
  PROC get.char ()
    INITIAL BOOL reading IS TRUE:
    WHILE reading
      SEQ
        raw.char ()
        CASE ch
          '#'
            --{{{  comment -- skip until CR or LF
            WHILE (ch <> '*c') AND (ch <> '*n')
              raw.char ()
            --}}}
          ELSE
            reading := FALSE
  :
  --}}}
  --{{{  PROC get.number
  --* Read a decimal number terminated by a single whitespace character from
  -- the file into n, skipping any preceding whitespace.
  PROC get.number (RESULT INT n)
    SEQ
      n := 0
      --{{{  skip initial whitespace
      INITIAL BOOL reading IS TRUE:
      WHILE reading
        SEQ
          get.char ()
          IF
            is.whitespace (ch)
              SKIP
            TRUE
              reading := FALSE
      --}}}
      --{{{  read digits
      INITIAL BOOL reading IS TRUE:
      WHILE reading
        IF
          (ch >= '0') AND (ch <= '9')
            --{{{  got a digit
            SEQ
              n := (n * 10) + (INT (ch - '0'))
              get.char ()
            --}}}
          is.whitespace (ch)
            --{{{  the end
            reading := FALSE
            --}}}
          TRUE
            --{{{  got something unexpected
            CAUSEERROR ()
            --}}}
      --}}}
  :
  --}}}

  SEQ
    file.open (filename, O.RDONLY, fd)
    ASSERT (fd <> (-1))

    get.char ()
    ASSERT (ch = 'P')
    get.char ()
    ASSERT (ch = '6')

    get.number (width)
    get.number (height)
    get.number (maxval)
    ASSERT (maxval > 0)
    ASSERT (maxval < 65536)

    raster := MOBILE [height][width]INT
    SEQ y = 0 FOR height
      SEQ x = 0 FOR width
        INITIAL INT pixel IS 0:
        SEQ
          SEQ channel = 0 FOR 3
            INT value:
            SEQ
              IF
                maxval < 256
                  --{{{  one byte per value
                  SEQ
                    raw.char ()
                    value := INT ch
                  --}}}
                TRUE
                  --{{{  two bytes per value
                  SEQ
                    raw.char ()
                    value := INT ch
                    raw.char ()
                    value := (value << 8) \/ (INT ch)
                  --}}}
              --{{{  scale to 255 being maxval (maxval = 255 is the common case)
              IF
                maxval <> 255
                  value := (value * 255) / maxval
                TRUE
                  SKIP
              --}}}
              pixel := (pixel << 8) \/ value
          raster[y][x] := pixel

    file.close (fd, result)
:
--}}}
