Show a basic storage type to handle a simple RGB raster graphics image,
and some primitive associated functions.

If possible provide a function to allocate an uninitialised image,
given its width and height, and provide 3 additional functions:

   one to fill an image with a plain RGB color,
   one to set a given pixel with a color,
   one to get the color of a pixel.


(If there are specificities about the storage or the allocation, explain those.)

These functions are used as a base for the articles in the category raster graphics operations, 
and a basic output function to check the results
is available in the article write ppm file.




 
//pure functional version ... changing a pixel color provides a new Bitmap
type Color = {red: byte; green: byte; blue: byte}
type Point = {x:uint32; y:uint32}
type Bitmap = {color: Color array; maxX: uint32; maxY: uint32} 
 
let colorBlack = {red = (byte) 0; green = (byte) 0; blue = (byte) 0}
let emptyBitmap = {color = Array.empty; maxX = (uint32) 0; maxY = (uint32) 0}
let bitmap (width: uint32) (height: uint32) = 
    match width, height with
    | 0u,0u | 0u,_ | _, 0u -> emptyBitmap
    | _,_ -> {color = Array.create ((int) (width * height)) colorBlack; 
            maxX = width; 
            maxY = height}
let getPixel point bitmap =
    match bitmap.color with
    | c when c |> Array.isEmpty -> None 
    | c when (uint32) c.Length <= (point.y * bitmap.maxY + point.x) -> None
    | c -> Some c.[(int) (point.y * bitmap.maxY + point.x)]
let setPixel point color bitmap =
    {bitmap with color = bitmap.color |> Array.mapi (function 
                | i when i = (int) (point.y * bitmap.maxY + point.x) -> 
                    (fun _ -> color) 
                | _ -> id)}    
let fill color bitmap = {bitmap with color = bitmap.color |> Array.map (fun _ ->color)}
 