Skip to content

Commit 7ede039

Browse files
committed
add types
1 parent 62b88da commit 7ede039

File tree

19 files changed

+652
-231
lines changed

19 files changed

+652
-231
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.ml linguist-language=OCaml
2+
*.mli linguist-language=OCaml

.ocamlformat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
version = 0.26.1

CHANGES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# 0.1.0
2+
3+
First release.
4+
5+
Provides:
6+
- record types for the different color spaces (HSLuv, HPLuv, RGB, XYZ, LCH, LUV)
7+
- HSLuv and HPLuv color conversion functions
8+
- color conversion functions between some of the other color spaces used to enable the HSLuv and HPluv conversions
9+
- pretty printers for all provided color types
10+
- a library `hsluv.float_conv` for conversions between float triples and the provided color types
11+
- tests against the HSLuv reference (revision 4)

README.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,32 @@ The HSLuv color space is particularly beneficial in scenarios where perceptual u
1818

1919
4. **Digital Art and Image Processing**: Offers fine-tuning of colors for subtle and precise adjustments.
2020

21-
5. **Color Grading in Film and Photography**: Facilitates harmonious color transitions and adjustments.
22-
2321
In summary, HSLuv's appeal lies in its ability to provide visually consistent and natural-looking colors, making it suitable for design, data visualization, and artistic applications.
2422

25-
## Implementation
23+
## Implementation Notes
24+
25+
This started as a port of the [Go implementation of hsluv.org](https://github.com/hsluv/hsluv-go).
26+
27+
The following color conversions are provided:
28+
29+
| From/To | HSLuv | HPLuv | RGB | XYZ | LUV | LCH | HEX |
30+
|--------------|------------------|------------------|---------------------|---------------------|---------------------|---------------------|---------------------|
31+
| **HSLuv** | - | - | `hsluv_to_rgb` | - | - | `conv_hsluv_lch` | `hsluv_to_hex` |
32+
| **HPLuv** | - | - | `hpluv_to_rgb` | - | - | `conv_hpluv_lch` | `hpluv_to_hex` |
33+
| **RGB** | `hsluv_from_rgb` | `hpluv_from_rgb` | - | `conv_rgb_xyz` | - | `conv_rgb_lch` | `conv_rgb_hex` |
34+
| **XYZ** | - | - | `conv_xyz_rgb` | - | `conv_xyz_luv` | - | - |
35+
| **LUV** | - | - | - | `conv_luv_xyz` | - | `conv_luv_lch` | - |
36+
| **LCH** | `conv_lch_hsluv` | `conv_lch_hpluv` | `conv_lch_rgb` | - | `conv_luv_lch` | - | - |
37+
| **HEX** | `hsluv_from_hex` | `hpluv_from_hex` | `conv_hex_rgb` | - | - | - | - |
2638

27-
This is a mostly faithful port of the Go implementation of hsluv.org at https://github.com/hsluv/hsluv-go.
39+
In addition to the HSLuv and HPLuv conversion functions, this package also exposes
40+
- color conversion functions between the various color spaces used to enable the HSLuv and HPluv conversions
41+
- pretty printers `pp_hsluv`, `pp_hpluv`, etc.
42+
- a library `hsluv.float_conv` for conversions between float triples and the provided color types
2843

2944
## Tests
3045

31-
The implementation is tested against the [hsluv snapshot (revision 4)](https://raw.githubusercontent.com/hsluv/hsluv/master/snapshots/snapshot-rev4.json). Test cases are included and can be run with
46+
The implementation is tested against the [hsluv snapshot (revision 4)](https://raw.githubusercontent.com/hsluv/hsluv/master/snapshots/snapshot-rev4.json). Tests for all conversion functions are included and can be run with
3247

3348
```
3449
opam exec -- dune test

doc/dune

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(documentation
2+
(package hsluv))

doc/index.mld

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{0 HSLuv}
2+
3+
HSLuv is a color space designed to provide a more human-friendly and uniform representation of colors, compared to traditional color spaces like RGB or HSL.
4+
5+
The key feature of HSLuv is its ability to maintain perceived color brightness and contrast uniformly across its hue and saturation range.
6+
7+
HSLuv is particularly useful in applications where color consistency and perceptual uniformity are important, such as in graphical design, data visualization, and user interface development.
8+
9+
You can find more information about HSLuv on {{: https://www.hsluv.org/}the official HSLuv website}.
10+
11+
{1 Libraries}
12+
13+
{2 hsluv}
14+
15+
Module:
16+
- {!Hsluv} - HSLuv and HPLuv color models as well as other common color spaces like RGB and XYZ, modeled as record types; provides conversion functions between the different color spaces and pretty-printers for all the color types.
17+
18+
{2 hsluv.float_conv}
19+
20+
Module:
21+
- {!Hsluv_float_conv} - convert between the record types of the different color spaces defined in {!Hsluv} and float triple representations

dune-project

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
(name hsluv)
44

5-
(documentation "https://ocaml.org/p/hsluv/latest")
5+
(version 0.1.0)
66

77
(source (github sabine/hsluv-ocaml))
8+
(homepage "https://github.com/sabine/hsluv-ocaml")
89

910
(license MIT)
1011

@@ -19,7 +20,12 @@
1920
(package
2021
(name hsluv)
2122
(synopsis "HSLuv human-friendly color space implementation in OCaml")
22-
(description "This package implements the HSLuv color space model, providing a perceptually uniform alternative to traditional HSL. It includes functions for converting between HSLuv/HPLuv and other color spaces like RGB, XYZ, and Luv.")
23+
(description "This package implements the HSLuv color space model,
24+
providing a perceptually uniform alternative to traditional HSL.
25+
It includes functions for converting between HSLuv/HPLuv
26+
and other color spaces like RGB, XYZ, LCH, and LUV, as well as hexadecimal
27+
color representation.")
28+
(tags ("color" "hsluv" "hpluv" "rgb" "xyz" "lch" "luv" "color space" "color conversion" "perceptually uniform colors"))
2329
(depends
2430
(ocaml (>= 4.08.0))
2531
dune

hsluv.opam

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
# This file is generated by dune, edit dune-project instead
22
opam-version: "2.0"
3+
version: "0.1.0"
34
synopsis: "HSLuv human-friendly color space implementation in OCaml"
4-
description:
5-
"This package implements the HSLuv color space model, providing a perceptually uniform alternative to traditional HSL. It includes functions for converting between HSLuv/HPLuv and other color spaces like RGB, XYZ, and Luv."
5+
description: """
6+
This package implements the HSLuv color space model,
7+
providing a perceptually uniform alternative to traditional HSL.
8+
It includes functions for converting between HSLuv/HPLuv
9+
and other color spaces like RGB, XYZ, LCH, and LUV, as well as hexadecimal
10+
color representation."""
611
maintainer: ["Sabine Schmaltz"]
712
authors: ["Sabine Schmaltz"]
813
license: "MIT"
14+
tags: [
15+
"color"
16+
"hsluv"
17+
"hpluv"
18+
"rgb"
19+
"xyz"
20+
"lch"
21+
"luv"
22+
"color space"
23+
"color conversion"
24+
"perceptually uniform colors"
25+
]
926
homepage: "https://github.com/sabine/hsluv-ocaml"
10-
doc: "https://ocaml.org/p/hsluv/latest"
1127
bug-reports: "https://github.com/sabine/hsluv-ocaml/issues"
1228
depends: [
1329
"ocaml" {>= "4.08.0"}
File renamed without changes.

lib/hsluv.ml renamed to hsluv/hsluv.ml

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
(* Ported from https://github.com/hsluv/hsluv-go/blob/cff9eb7ee0694105b0250075bb56243b1651165e/hsluv.go *)
22

3+
include Types
4+
35
(* Constants *)
46
let pi = Float.pi
57

@@ -103,18 +105,18 @@ let l_to_y l = if l <= 8.0 then l /. kappa else ((l +. 16.0) /. 116.0) ** 3.0
103105

104106
(* Conversions *)
105107

106-
let conv_xyz_luv (x, y, z) =
107-
if y = 0.0 then (0.0, 0.0, 0.0)
108+
let conv_xyz_luv { x; y; z } =
109+
if y = 0.0 then { l = 0.0; u = 0.0; v = 0.0 }
108110
else
109111
let l = y_to_l y in
110112
let var_u = 4.0 *. x /. (x +. (15.0 *. y) +. (3.0 *. z)) in
111113
let var_v = 9.0 *. y /. (x +. (15.0 *. y) +. (3.0 *. z)) in
112114
let u = 13.0 *. l *. (var_u -. ref_u) in
113115
let v = 13.0 *. l *. (var_v -. ref_v) in
114-
(l, u, v)
116+
{ l; u; v }
115117

116-
let conv_luv_xyz (l, u, v) =
117-
if l = 0.0 then (0.0, 0.0, 0.0)
118+
let conv_luv_xyz { l; u; v } =
119+
if l = 0.0 then { x = 0.0; y = 0.0; z = 0.0 }
118120
else
119121
let var_u = (u /. (13.0 *. l)) +. ref_u in
120122
let var_v = (v /. (13.0 *. l)) +. ref_v in
@@ -125,48 +127,48 @@ let conv_luv_xyz (l, u, v) =
125127
let z =
126128
((9.0 *. y) -. (15.0 *. var_v *. y) -. (var_v *. x)) /. (3.0 *. var_v)
127129
in
128-
(x, y, z)
130+
{ x; y; z }
129131

130-
let conv_luv_lch (l, u, v) =
132+
let conv_luv_lch { l; u; v } =
131133
let c = sqrt ((u ** 2.0) +. (v ** 2.0)) in
132134
let h_rad = atan2 v u in
133135
let h =
134136
if c < 0.00000001 then 0.0
135137
else mod_float (h_rad *. 360.0 /. (2.0 *. pi)) 360.0
136138
in
137-
(l, c, h)
139+
{ l; c; h }
138140

139-
let conv_lch_luv (l, c, h) =
141+
let conv_lch_luv { l; c; h } =
140142
let h_rad = h /. 360.0 *. 2.0 *. pi in
141143
let u = cos h_rad *. c in
142144
let v = sin h_rad *. c in
143-
(l, u, v)
145+
{ l; u; v }
144146

145-
let conv_hsluv_lch (h, s, l) =
146-
if l > 99.9999999 || l < 0.00000001 then (l, 0., h)
147+
let conv_hsluv_lch { h; s; l } =
148+
if l > 99.9999999 || l < 0.00000001 then { l; c = 0.; h }
147149
else
148150
let max = max_chroma_for_lh l h in
149-
(l, max /. 100.0 *. s, h)
151+
{ l; c = max /. 100.0 *. s; h }
150152

151-
let conv_lch_hsluv (l, c, h) =
152-
if l > 99.9999999 || l < 0.00000001 then (h, 0., l)
153+
let conv_lch_hsluv { l; c; h } =
154+
if l > 99.9999999 || l < 0.00000001 then { h; s = 0.; l }
153155
else
154156
let max = max_chroma_for_lh l h in
155-
(h, c /. max *. 100.0, l)
157+
{ h; s = c /. max *. 100.0; l }
156158

157-
let conv_hpluv_lch (h, s, l) =
158-
if l > 99.9999999 || l < 0.00000001 then (l, 0., h)
159+
let conv_hpluv_lch { h; p; l } =
160+
if l > 99.9999999 || l < 0.00000001 then { l; c = 0.; h }
159161
else
160162
let max = max_safe_chroma_for_l l in
161-
(l, max /. 100. *. s, h)
163+
{ l; c = max /. 100. *. p; h }
162164

163-
let conv_lch_hpluv (l, c, h) =
164-
if l > 99.9999999 || l < 0.00000001 then (h, 0., l)
165+
let conv_lch_hpluv { l; c; h } =
166+
if l > 99.9999999 || l < 0.00000001 then { h; p = 0.; l }
165167
else
166168
let max = max_safe_chroma_for_l l in
167-
(h, c /. max *. 100.0, l)
169+
{ h; p = c /. max *. 100.0; l }
168170

169-
let conv_rgb_hex (r, g, b) =
171+
let conv_rgb_hex { r; g; b } =
170172
let rV = round (max 0.0 (min r 1.0) *. 255.0) in
171173
let gV = round (max 0.0 (min g 1.0) *. 255.0) in
172174
let bV = round (max 0.0 (min b 1.0) *. 255.0) in
@@ -181,49 +183,57 @@ let conv_hex_rgb hex =
181183
let rV = int_of_string ("0x" ^ String.sub hex 0 2) in
182184
let gV = int_of_string ("0x" ^ String.sub hex 2 2) in
183185
let bV = int_of_string ("0x" ^ String.sub hex 4 2) in
184-
(float_of_int rV /. 255.0, float_of_int gV /. 255.0, float_of_int bV /. 255.0)
186+
{
187+
r = float_of_int rV /. 255.0;
188+
g = float_of_int gV /. 255.0;
189+
b = float_of_int bV /. 255.0;
190+
}
185191

186-
let conv_xyz_rgb (x, y, z) =
192+
let conv_xyz_rgb { x; y; z } =
187193
let r = from_linear (dot_product m.(0) [| x; y; z |]) in
188194
let g = from_linear (dot_product m.(1) [| x; y; z |]) in
189195
let b = from_linear (dot_product m.(2) [| x; y; z |]) in
190-
(r, g, b)
196+
{ r; g; b }
191197

192-
let conv_rgb_xyz (r, g, b) =
198+
let conv_rgb_xyz { r; g; b } =
193199
let r = to_linear r in
194200
let g = to_linear g in
195201
let b = to_linear b in
196202
let x = dot_product m_inv.(0) [| r; g; b |] in
197203
let y = dot_product m_inv.(1) [| r; g; b |] in
198204
let z = dot_product m_inv.(2) [| r; g; b |] in
199-
(x, y, z)
205+
{ x; y; z }
200206

201-
let conv_lch_rgb (l, c, h) =
202-
conv_lch_luv (l, c, h) |> conv_luv_xyz |> conv_xyz_rgb
207+
let conv_lch_rgb { l; c; h } =
208+
conv_lch_luv { l; c; h } |> conv_luv_xyz |> conv_xyz_rgb
203209

204-
let conv_rgb_lch (r, g, b) =
205-
conv_rgb_xyz (r, g, b) |> conv_xyz_luv |> conv_luv_lch
210+
let conv_rgb_lch { r; g; b } =
211+
conv_rgb_xyz { r; g; b } |> conv_xyz_luv |> conv_luv_lch
206212

207-
let conv_hsluv_rgb (h, s, l) = conv_hsluv_lch (h, s, l) |> conv_lch_rgb
208-
let conv_rgb_hsluv (r, g, b) = conv_rgb_lch (r, g, b) |> conv_lch_hsluv
213+
let conv_hsluv_rgb { h; s; l } = conv_hsluv_lch { h; s; l } |> conv_lch_rgb
214+
let conv_rgb_hsluv { r; g; b } = conv_rgb_lch { r; g; b } |> conv_lch_hsluv
209215

210216
(* Hsluv and Hpluv *)
211217

212-
let hsluv_to_hex (h, s, l) = conv_hsluv_rgb (h, s, l) |> conv_rgb_hex
218+
let hsluv_to_hex { h; s; l } = conv_hsluv_rgb { h; s; l } |> conv_rgb_hex
213219
let hsluv_from_hex hex = conv_hex_rgb hex |> conv_rgb_hsluv
214220
let hsluv_to_rgb = conv_hsluv_rgb
215221
let hsluv_from_rgb = conv_rgb_hsluv
216222

217-
let hpluv_to_hex (h, s, l) =
218-
(h, s, l) |> conv_hpluv_lch |> conv_lch_luv |> conv_luv_xyz |> conv_xyz_rgb
223+
let hpluv_to_hex { h; p; l } =
224+
{ h; p; l } |> conv_hpluv_lch |> conv_lch_luv |> conv_luv_xyz |> conv_xyz_rgb
219225
|> conv_rgb_hex
220226

221227
let hpluv_from_hex hex =
222228
hex |> conv_hex_rgb |> conv_rgb_xyz |> conv_xyz_luv |> conv_luv_lch
223229
|> conv_lch_hpluv
224230

225-
let hpluv_to_rgb (h, s, l) =
226-
(h, s, l) |> conv_hpluv_lch |> conv_lch_luv |> conv_luv_xyz |> conv_xyz_rgb
231+
let hpluv_to_rgb { h; p; l } =
232+
{ h; p; l } |> conv_hpluv_lch |> conv_lch_luv |> conv_luv_xyz |> conv_xyz_rgb
233+
234+
let hpluv_from_rgb { r; g; b } =
235+
{ r; g; b } |> conv_rgb_xyz |> conv_xyz_luv |> conv_luv_lch |> conv_lch_hpluv
236+
237+
(* Pretty-printers *)
227238

228-
let hpluv_from_rgb (r, g, b) =
229-
(r, g, b) |> conv_rgb_xyz |> conv_xyz_luv |> conv_luv_lch |> conv_lch_hpluv
239+
include Pretty_printers

0 commit comments

Comments
 (0)