What I've found playing with `Graphics`


I’ve been playing with the Graphics library and have found that while it’s nice to have a fairly easy library to play with there are a number of small to middling issues and inconsistencies.

Here’s a quick program that shows what I mean. It touches on some of the issues that I’ve found, and shows the biggest issue which is that the screen run from 0,0 at the bottom left of the screen but for images the 0,0 coordinate is at top left. As can be seen from the image the darkest point (at 0,0) is in the top left of the image, but the image is placed at 0,0 in the bottom left of the window.

Other things I noticed were:

  1. Minor but there’s no function in the library for getting the r,g,b back out of a color
  2. There’s no way to set the background color, which is used when resizing the window
  3. There are no events for window resizing, you can poll as a workaround but it’s less clean than a propper event would be
  4. Array.make_matrix creates a 2D array that can be used with Graphics.make_image but the dimx and dimy are flipped compared to how make_image expects them


open Graphics

let white = rgb 255 255 255
let blue  = rgb 30 25 255

(* no function for converting color back to rgb in Graphics *)
let color_to_rgb color =
    let r = (color land 0xFF0000) asr 0x10
    and g = (color land 0x00FF00) asr 0x8
    and b = (color land 0x0000FF)
    in r, g, b

let open_window = 
    open_graph " 640x480";
    set_window_title "GraphicsExample"

(* no way of setting background color; resizing shows white *)
let clear_window color = 
    let fg = foreground 
        set_color color;
        fill_rect 0 0 (size_x ()) (size_y ());
        set_color fg

(* create a gradient of colors from black at 0,0 to white at w-1,h-1 *)
let gradient arr w h = 
    for y = 0 to h-1 do 
        for x = 0 to w-1 do 
            let s = 255 * (x+y) / (w+h-2) 
            in arr.(y).(x) <- rgb s s s 

let draw_gradient x y w h = 
    (* w and h are flipped from perspective of the matrix *)
    let arr = Array.make_matrix h w white
        gradient arr w h;
        draw_image (make_image arr) 0 0

let rec event_loop wx wy = 
    (* there's no resize event so polling in required *)
    let _ = wait_next_event [Poll]
    and wx' = size_x () and wy' = size_y ()
        if wx' <> wx || wy' <> wy then 
                clear_window blue;
                draw_gradient 0 0 200 100
        Unix.sleep 1;
        event_loop wx' wy'

let () =
    let r,g,b = color_to_rgb background
        Printf.printf "Background color: %d %d %d\n" r g b;
        try event_loop 0 0 
        with Graphic_failure _ -> print_endline "Exiting..."

And compile line:

ocamlbuild -package graphics -package unix GraphicsExample.native