T Colour Byte r, g, b F (r, g, b) .r = r .g = g .b = b F ==(other) R .r == other.r & .g == other.g & .b == other.b V black = Colour(0, 0, 0) V white = Colour(255, 255, 255) T Bitmap Int width, height Colour background [[Colour]] map F (width = 40, height = 40, background = white) assert(width > 0 & height > 0) .width = width .height = height .background = background .map = (0 .< height).map(h -> (0 .< @width).map(w -> @@background)) F fillrect(x, y, width, height, colour = black) assert(x >= 0 & y >= 0 & width > 0 & height > 0) L(h) 0 .< height L(w) 0 .< width .map[y + h][x + w] = colour F set(x, y, colour = black) .map[y][x] = colour F get(x, y) R .map[y][x] F togreyscale() L(h) 0 .< .height L(w) 0 .< .width V (r, g, b) = .get(w, h) V l = Int(0.2126 * r + 0.7152 * g + 0.0722 * b) .set(w, h, Colour(l, l, l)) F writeppmp3() V magic = "P3\n" V comment = "# generated from Bitmap.writeppmp3\n" V s = magic‘’comment‘’("#. #.\n#.\n".format(.width, .height, 255)) L(h) (.height - 1 .< -1).step(-1) L(w) 0 .< .width V (r, g, b) = .get(w, h) s ‘’= ‘ #3 #3 #3’.format(r, g, b) s ‘’= "\n" R s F tokenize(fstr) [String] tokens L(line) fstr.split("\n") I !line.starts_with(‘#’) L(t) line.split(‘ ’, group_delimiters' 1B) tokens.append(t) R tokens F ppmp3tobitmap(fstr) V tokens = tokenize(fstr) V tokeni = -1 F nexttoken() @tokeni++ R @tokens[@tokeni] assert(‘P3’ == nexttoken(), ‘Wrong filetype’) V width = Int(nexttoken()) V height = Int(nexttoken()) V maxval = Int(nexttoken()) V bitmap = Bitmap(width, height, Colour(0, 0, 0)) L(h) (height - 1 .< -1).step(-1) L(w) 0 .< width V r = Int(nexttoken()) V g = Int(nexttoken()) V b = Int(nexttoken()) bitmap.set(w, h, Colour(r, g, b)) R bitmap V ppmtxt = |‘P3 # feep.ppm 4 4 15 0 0 0 0 0 0 0 0 0 15 0 15 0 0 0 0 15 7 0 0 0 0 0 0 0 0 0 0 0 0 0 15 7 0 0 0 15 0 15 0 0 0 0 0 0 0 0 0 ’ V bitmap = ppmp3tobitmap(ppmtxt) print(‘Grey PPM:’) bitmap.togreyscale() print(bitmap.writeppmp3())