| 
class RGBQUAD
 export var rgbBlue, var rgbGreen, var rgbRed, var rgbReserved
 var rgbBlue : nat1
 var rgbGreen : nat1
 var rgbRed : nat1
 var rgbReserved : nat1
 end RGBQUAD
 
 class MONOCHROMESET
 export var color1, var color2, getColor, setBit, isSet
 
 var color1, color2 : int
 color1 := black
 color2 := white
 var bit : boolean := false
 
 fcn getColor : int
 if bit = true then
 result color1
 else
 result color2
 end if
 end getColor
 
 fcn isSet : boolean
 result bit
 end isSet
 
 proc setBit
 bit := true
 end setBit
 end MONOCHROMESET
 
 class Rectangle
 export x, y, w, h, setDimensions, setLocation
 
 var ix, iy : int
 var width, height : int
 
 proc setLocation (x, y : int)
 ix := x
 iy := y
 end setLocation
 
 proc setDimensions (w, h : int)
 width := w
 height := h
 end setDimensions
 
 
 fcn x : int
 result ix
 end x
 fcn y : int
 result iy
 end y
 fcn w : int
 result width
 end w
 fcn h : int
 result height
 end h
 
 end Rectangle
 
 
 class Image
 import Rectangle
 export Destruct, draw, getBounds, getInfoAt
 
 var bounds : ^Rectangle
 new bounds
 var file : string
 new bounds
 
 fcn getBounds : ^Rectangle
 result bounds
 end getBounds
 
 deferred proc draw
 
 deferred fcn getInfoAt (x, y : int) : ^anyclass
 
 proc Destruct
 free bounds
 end Destruct
 end Image
 
 class BitmapFile
 inherit Image
 import RGBQUAD, MONOCHROMESET
 export Construct, BITMAPFILEHEADER, BITMAPINFOHEADER,
 MONOCHROME, COLOR_16, COLOR_256, COLOR_16M, getFileHeader, setFileHeader,
 getInfoHeader, setInfoHeader
 
 % --constants--
 const MONOCHROME := 1
 const COLOR_16 := 4
 const COLOR_256 := 8
 const COLOR_16M := 24
 
 type BITMAPFILEHEADER :         % defaults               % location in file
 record
 bfType : nat2           %:= 19778                       % 1
 bfSize : nat4           %:= ??                          % 3
 bfReserved1 : nat2      %:= 0                           % 7
 bfReserved2 : nat2      %:= 0                           % 9
 bfOffBits : nat4        %:= 1078                        % 11
 end record
 
 type BITMAPINFOHEADER :
 record
 biSize : nat4           %:= 40                          % 15
 biWidth : int4          %:= 100                         % 19
 biHeight : int4         %:= 100                         % 23
 biPlanes : nat2         %:= 1                           % 27
 biBitCount : nat2       %:= COLOR_256                   % 29
 biCompression : nat4    %:= 0                           % 31
 biSizeImage : nat4      %:= 0                           % 35
 biXPelsPerMeter : int4  %:= 0                           % 39
 biYPelsPerMeter : int4  %:= 0                           % 43
 biClrUsed : nat4        %:= 0                           % 47
 biClrImportant : nat4   %:= 0                           % 51
 end record
 
 % --variables--
 var bitmapBits : flexible array 0 .. 0 of ^anyclass
 bounds -> setLocation (0, maxy)
 var fileName : string
 var byteWidth, padding : nat4
 var bitmapFileHeader : BITMAPFILEHEADER
 var bitmapInfoHeader : BITMAPINFOHEADER
 
 var bit : array 1 .. 8 of nat1
 bit (1) := 2#00000001
 bit (2) := 2#00000010
 bit (3) := 2#00000100
 bit (4) := 2#00001000
 bit (5) := 2#00010000
 bit (6) := 2#00100000
 bit (7) := 2#01000000
 bit (8) := 2#10000000
 
 
 fcn getFileHeader : BITMAPFILEHEADER
 result bitmapFileHeader
 end getFileHeader
 
 fcn getInfoHeader : BITMAPINFOHEADER
 result bitmapInfoHeader
 end getInfoHeader
 
 proc setFileHeader (p : BITMAPFILEHEADER)
 bitmapFileHeader := p
 end setFileHeader
 
 proc setInfoHeader (p : BITMAPINFOHEADER)
 bitmapInfoHeader := p
 end setInfoHeader
 
 
 proc _readBitmapFileHeader (sn : int)
 read : sn, bitmapFileHeader.bfType
 read : sn, bitmapFileHeader.bfSize
 read : sn, bitmapFileHeader.bfReserved1
 read : sn, bitmapFileHeader.bfReserved2
 read : sn, bitmapFileHeader.bfOffBits
 end _readBitmapFileHeader
 
 
 proc _readBitmapInfoHeader (sn : int)
 read : sn, bitmapInfoHeader.biSize
 read : sn, bitmapInfoHeader.biWidth
 read : sn, bitmapInfoHeader.biHeight
 read : sn, bitmapInfoHeader.biPlanes
 read : sn, bitmapInfoHeader.biBitCount
 read : sn, bitmapInfoHeader.biCompression
 read : sn, bitmapInfoHeader.biSizeImage
 read : sn, bitmapInfoHeader.biXPelsPerMeter
 read : sn, bitmapInfoHeader.biYPelsPerMeter
 read : sn, bitmapInfoHeader.biClrUsed
 read : sn, bitmapInfoHeader.biClrImportant
 end _readBitmapInfoHeader
 
 
 fcn _getPos (sn : int) : int
 var pos : int
 tell : sn, pos
 result pos
 end _getPos
 
 
 proc _read24BitData (sn : int)
 var r, g, b : nat1
 var rgbQuad : ^RGBQUAD
 var byteCount : nat4 := 0
 
 seek : sn, bitmapFileHeader.bfOffBits
 for i : 0 .. (bounds -> h * bounds -> w) - 1
 read : sn, b
 read : sn, g
 read : sn, r
 byteCount += 3
 new rgbQuad
 rgbQuad -> rgbBlue := b
 rgbQuad -> rgbGreen := g
 rgbQuad -> rgbRed := r
 bitmapBits (i) := rgbQuad
 if byteCount mod byteWidth = 0 then
 seek : sn, _getPos (sn) + padding
 byteCount := 0
 end if
 end for
 end _read24BitData
 
 
 proc _readMonochromeData (sn : int)
 var cbit8 : nat1 := 0
 var tmp : ^MONOCHROMESET := nil
 var byteCount, c : nat := 0
 
 seek : sn, bitmapFileHeader.bfOffBits
 for k : 0 .. (bounds -> h * bounds -> w) - 1 by 8
 read : sn, cbit8
 for decreasing i : 8 .. 1
 if c > bounds -> w * bounds -> h - 1 then
 exit
 end if
 new tmp
 if (cbit8 and bit (i)) = bit (i) then
 tmp -> setBit
 end if
 bitmapBits (c) := tmp
 c += 1
 end for
 byteCount += 1
 if byteCount mod byteWidth = 0 then
 byteCount := 0
 seek : sn, _getPos (sn) + padding
 end if
 end for
 end _readMonochromeData
 
 
 proc Construct (name : string)
 fileName := name
 var sn : int
 open : sn, fileName, read, seek
 
 seek : sn, 0
 _readBitmapFileHeader (sn)
 _readBitmapInfoHeader (sn)
 
 byteWidth := ceil (bitmapInfoHeader.biWidth * (bitmapInfoHeader.biBitCount / 8))
 padding := 4 - (byteWidth mod 4)
 if padding = 4 then
 padding := 0
 end if
 
 bounds -> setDimensions (bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight)
 new bitmapBits, (bounds -> h * bounds -> w) - 1
 
 case bitmapInfoHeader.biBitCount of
 label COLOR_16M :
 _read24BitData (sn)
 label MONOCHROME :
 _readMonochromeData (sn)
 label :
 assert false         % if u've reached here, it's probably cuz ur using a colour
 %                      resolution that is not implemented yet
 end case
 close : sn
 end Construct
 
 
 body fcn getInfoAt (x, y : int) : ^anyclass
 var tmp : ^anyclass := nil
 tmp := bitmapBits (((bounds -> h - y) * bounds -> w) - (bounds -> w - x))
 result tmp
 end getInfoAt
 
 
 body proc draw
 var tmp : ^anyclass
 var colr : int := RGB.AddColour (0, 0, 0)
 case bitmapInfoHeader.biBitCount of
 label COLOR_16M :
 for y : 0 .. bounds -> h - 1 by 1
 for x : 0 .. bounds -> w - 1 by 1
 tmp := getInfoAt (x, y)
 RGB.SetColour (colr, RGBQUAD (tmp).rgbRed / 255, RGBQUAD (tmp).rgbGreen / 255, RGBQUAD (tmp).rgbBlue / 255)
 drawdot (bounds -> x + x, bounds -> y - y, colr)
 end for
 end for
 label MONOCHROME :
 for y : 0 .. bounds -> h - 1 by 1
 for x : 0 .. bounds -> w - 1 by 1
 tmp := getInfoAt (x, y)
 colr := MONOCHROMESET (tmp).getColor
 drawdot (bounds -> x + x, bounds -> y - y, colr)
 end for
 end for
 label :
 assert false             % if u've reached here, it's probably cuz ur using a colour
 %                          resolution that is not implemented yet
 end case
 end draw
 
 
 body proc Destruct
 for i : 0 .. (bounds -> h * bounds -> w) - 1
 if bitmapBits (i) not= nil then
 free bitmapBits (i)
 end if
 end for
 free bitmapBits
 Image.Destruct
 end Destruct
 end BitmapFile
 
 
 |