Skip to content

Commit f770051

Browse files
committed
implement HSV and hexadecimal color inputs
1 parent 6f5d18b commit f770051

File tree

4 files changed

+78
-4
lines changed

4 files changed

+78
-4
lines changed

core/color.ml

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,62 @@ let graya v a = rgba v v v a
2222

2323
let gray v = graya v 255
2424

25-
let hsv h s v = failwith "HSV color unimplemented"
25+
let hsv h s v =
26+
if h < 0 || h > 360
27+
then failwith ("hsv h out of range [0, 360]: " ^ string_of_int h) else
28+
if s < 0 || s > 100
29+
then failwith ("hsv s out of range [0, 100]: " ^ string_of_int s) else
30+
if v < 0 || v > 100
31+
then failwith ("hsv v out of range [0, 100]: " ^ string_of_int v) else
32+
let open Math in
33+
let sat = ~.s /. 100. in
34+
let value = ~.v /. 100. in
35+
let chroma = value *. sat in
36+
let h' = ~.h /. 60. in
37+
let x = chroma *. (1. -. Math.absf ((mod_float h' 2.) -. 1.)) in
38+
let r', g', b' =
39+
if h' >= 0. && h' < 1. then chroma, x, 0. else
40+
if h' >= 1. && h' < 2. then x, chroma, 0. else
41+
if h' >= 2. && h' < 3. then 0., chroma, x else
42+
if h' >= 3. && h' < 4. then 0., x, chroma else
43+
if h' >= 4. && h' < 5. then x, 0., chroma else
44+
if h' >= 5. && h' <= 6. then chroma, 0., x else 0., 0., 0. in
45+
let m = value -. chroma in
46+
rgb
47+
((r' +. m) *. 255. |> Math.round)
48+
((g' +. m) *. 255. |> Math.round)
49+
((b' +. m) *. 255. |> Math.round)
2650

2751
let hsva h s v a = {(hsv h s v) with alpha = a}
2852

29-
let hex hex = failwith "Hexadecimal color unimplemented"
53+
let hex hex =
54+
(* remove leading pound sign *)
55+
let hex' =
56+
if String.length hex > 0 && String.get hex 0 = '#'
57+
then String.sub hex 1 (String.length hex - 1)
58+
else hex in
59+
(* add alpha characters if not present *)
60+
let hex'' =
61+
if String.length hex' = 6 then "FF" ^ hex'
62+
else if String.length hex' = 8 then hex'
63+
else failwith ("Invalid hex color: " ^ hex) in
64+
(* convert a hex digit [0-9A-Za-z] to an integer *)
65+
let int_of_hex_digit c =
66+
if Char.code c >= Char.code 'a' && Char.code c <= Char.code 'f'
67+
then Char.code c - Char.code 'a' + 10
68+
else if Char.code c >= Char.code 'A' && Char.code c <= Char.code 'F'
69+
then Char.code c - Char.code 'A' + 10
70+
else if Char.code c >= Char.code '0' && Char.code c <= Char.code '9'
71+
then Char.code c - Char.code '0'
72+
else failwith ("Invalid hex char '" ^ (String.make 1 c) ^ " in: " ^ hex) in
73+
(* convert two hex digits into an integer *)
74+
let int_of_hex_pair c1 c2 =
75+
16 * (int_of_hex_digit c1) + (int_of_hex_digit c2) in
76+
(* convert two sequential hex digits from [hex] into an integer *)
77+
let int_of_str_pair_pos i =
78+
int_of_hex_pair (String.get hex'' i) (String.get hex'' (i + 1)) in
79+
let a = int_of_str_pair_pos 0 in
80+
let r = int_of_str_pair_pos 2 in
81+
let g = int_of_str_pair_pos 4 in
82+
let b = int_of_str_pair_pos 6 in
83+
rgba r g b a

core/color.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ val hsva : int -> int -> int -> int -> color
3636

3737
(** [hex hex_str] is the color represented by [hex_str] in hexadecimal notation.
3838
[hex_str] may or may not begin with a pound ([#]), and may specify alpha
39-
(eight hex numbers) or not (six hex numbers). *)
39+
([#AARRGGBB]) or not ([#RRGGBB]). *)
4040
val hex : string -> color

core/math.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module Math = struct
3737
let normf v lower upper = mapf v lower upper 0. 1.
3838
let norm v lower upper = normf (float_of_int v)
3939
(float_of_int lower) (float_of_int upper)
40-
let round v = Pervasives.floor (v +. (if v > 0. then 0.5 else -0.5))
40+
let round v = Pervasives.floor (v +. (if v >= 0. then 0.5 else -0.5))
4141
|> int_of_float
4242
let sqrt = Pervasives.sqrt
4343

examples/hsv.ml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
open P5.Gtkc
3+
4+
module Hsv : Sketch = struct
5+
include Base
6+
7+
type state = unit
8+
9+
let display = `Size (400, 400)
10+
11+
let setup _ = ()
12+
13+
let draw conf _ =
14+
let h = conf.frame_count mod 360 in
15+
let s = ~.(conf.mouse_x) /. ~.(conf.width) *. 100. |> Math.round in
16+
let v = ~.(conf.mouse_y) /. ~.(conf.height) *. 100. |> Math.round in
17+
background (hsv h s v)
18+
end
19+
20+
let () = run_sketch (module Hsv)

0 commit comments

Comments
 (0)