Skip to content

Commit 4cf16b9

Browse files
committed
4 channel HK and extern "C" functions
Should cover everything except hex
1 parent 825a789 commit 4cf16b9

File tree

3 files changed

+206
-58
lines changed

3 files changed

+206
-58
lines changed

scripts/test_ctypes.py

+49-33
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#! /usr/bin/env python3
22
import ctypes
33
from sys import platform
4+
45
cpixel = ctypes.c_float * 3
56
cpixels = ctypes.POINTER(ctypes.c_float)
67

@@ -13,26 +14,31 @@
1314

1415
colcon = ctypes.CDLL(f"./target/release/{LIBRARY}")
1516

16-
colcon.convert_space_ffi.argtypes = [ctypes.c_char_p, ctypes.c_char_p, cpixels, ctypes.c_uint]
17+
colcon.convert_space_ffi.argtypes = [
18+
ctypes.c_char_p,
19+
ctypes.c_char_p,
20+
cpixels,
21+
ctypes.c_uint,
22+
]
1723
colcon.convert_space_ffi.restype = ctypes.c_int32
1824

1925
# up
20-
colcon.srgb_to_hsv_f32.argtypes = [cpixel]
21-
colcon.srgb_to_lrgb_f32.argtypes = [cpixel]
22-
colcon.lrgb_to_xyz_f32.argtypes = [cpixel]
23-
colcon.xyz_to_cielab_f32.argtypes = [cpixel]
24-
colcon.xyz_to_oklab_f32.argtypes = [cpixel]
25-
colcon.xyz_to_jzazbz_f32.argtypes = [cpixel]
26-
colcon.lab_to_lch_f32.argtypes = [cpixel]
26+
colcon.srgb_to_hsv_3f32.argtypes = [cpixel]
27+
colcon.srgb_to_lrgb_3f32.argtypes = [cpixel]
28+
colcon.lrgb_to_xyz_3f32.argtypes = [cpixel]
29+
colcon.xyz_to_cielab_3f32.argtypes = [cpixel]
30+
colcon.xyz_to_oklab_3f32.argtypes = [cpixel]
31+
colcon.xyz_to_jzazbz_3f32.argtypes = [cpixel]
32+
colcon.lab_to_lch_3f32.argtypes = [cpixel]
2733

2834
# down
29-
colcon.lch_to_lab_f32.argtypes = [cpixel]
30-
colcon.jzazbz_to_xyz_f32.argtypes = [cpixel]
31-
colcon.oklab_to_xyz_f32.argtypes = [cpixel]
32-
colcon.cielab_to_xyz_f32.argtypes = [cpixel]
33-
colcon.xyz_to_lrgb_f32.argtypes = [cpixel]
34-
colcon.lrgb_to_srgb_f32.argtypes = [cpixel]
35-
colcon.srgb_to_hsv_f32.argtypes = [cpixel]
35+
colcon.lch_to_lab_3f32.argtypes = [cpixel]
36+
colcon.jzazbz_to_xyz_3f32.argtypes = [cpixel]
37+
colcon.oklab_to_xyz_3f32.argtypes = [cpixel]
38+
colcon.cielab_to_xyz_3f32.argtypes = [cpixel]
39+
colcon.xyz_to_lrgb_3f32.argtypes = [cpixel]
40+
colcon.lrgb_to_srgb_3f32.argtypes = [cpixel]
41+
colcon.srgb_to_hsv_3f32.argtypes = [cpixel]
3642

3743
# extra
3844
colcon.srgb_eotf_f32.argtypes = [ctypes.c_float]
@@ -47,8 +53,14 @@
4753
colcon.pq_oetf_f32.restype = ctypes.c_float
4854
colcon.pqz_oetf_f32.argtypes = [ctypes.c_float]
4955
colcon.pqz_oetf_f32.restype = ctypes.c_float
50-
colcon.hk_high2023_f32.argtypes = [cpixel]
51-
colcon.hk_high2023_comp_f32.argtypes = [cpixel]
56+
colcon.hk_high2023_3f32.argtypes = [cpixel]
57+
colcon.hk_high2023_comp_3f32.argtypes = [cpixel]
58+
59+
# other dtypes
60+
colcon.srgb_to_lrgb_4f32.argtypes = [ctypes.c_float * 4]
61+
colcon.srgb_to_lrgb_3f64.argtypes = [ctypes.c_double * 3]
62+
colcon.srgb_to_lrgb_4f64.argtypes = [ctypes.c_double * 4]
63+
5264

5365
SRGB = [0.20000000, 0.35000000, 0.95000000]
5466
LRGB = [0.03310477, 0.10048151, 0.89000541]
@@ -59,69 +71,73 @@
5971
OKLAB = [0.53893206, -0.01239956, -0.23206808]
6072
JZAZBZ = [0.00601244, -0.00145433, -0.01984568]
6173

74+
6275
def pixcmp(a, b):
6376
epsilon = 1e-5
64-
for (ac, bc) in zip(a, b):
77+
for ac, bc in zip(a, b):
6578
if abs(ac - bc) > epsilon:
66-
print(f"\nFAIL:\n[{a[0]:.8f}, {a[1]:.8f}, {a[2]:.8f}]\n[{b[0]:.8f}, {b[1]:.8f}, {b[2]:.8f}]\n")
79+
print(
80+
f"\nFAIL:\n[{a[0]:.8f}, {a[1]:.8f}, {a[2]:.8f}]\n[{b[0]:.8f}, {b[1]:.8f}, {b[2]:.8f}]\n"
81+
)
6782
break
6883

84+
6985
# up
7086
pix = cpixel(*SRGB)
71-
colcon.srgb_to_hsv_f32(pix)
87+
colcon.srgb_to_hsv_3f32(pix)
7288
pixcmp(list(pix), HSV)
7389

7490
pix = cpixel(*SRGB)
75-
colcon.srgb_to_lrgb_f32(pix)
91+
colcon.srgb_to_lrgb_3f32(pix)
7692
pixcmp(list(pix), LRGB)
7793

7894
pix = cpixel(*LRGB)
79-
colcon.lrgb_to_xyz_f32(pix)
95+
colcon.lrgb_to_xyz_3f32(pix)
8096
pixcmp(list(pix), XYZ)
8197

8298
pix = cpixel(*XYZ)
83-
colcon.xyz_to_cielab_f32(pix)
99+
colcon.xyz_to_cielab_3f32(pix)
84100
pixcmp(list(pix), LAB)
85101

86102
pix = cpixel(*XYZ)
87-
colcon.xyz_to_oklab_f32(pix)
103+
colcon.xyz_to_oklab_3f32(pix)
88104
pixcmp(list(pix), OKLAB)
89105

90106
pix = cpixel(*XYZ)
91-
colcon.xyz_to_jzazbz_f32(pix)
107+
colcon.xyz_to_jzazbz_3f32(pix)
92108
pixcmp(list(pix), JZAZBZ)
93109

94110
pix = cpixel(*LAB)
95-
colcon.lab_to_lch_f32(pix)
111+
colcon.lab_to_lch_3f32(pix)
96112
pixcmp(list(pix), LCH)
97113

98114
# down
99115
pix = cpixel(*LCH)
100-
colcon.lch_to_lab_f32(pix)
116+
colcon.lch_to_lab_3f32(pix)
101117
pixcmp(list(pix), LAB)
102118

103119
pix = cpixel(*LAB)
104-
colcon.cielab_to_xyz_f32(pix)
120+
colcon.cielab_to_xyz_3f32(pix)
105121
pixcmp(list(pix), XYZ)
106122

107123
pix = cpixel(*JZAZBZ)
108-
colcon.jzazbz_to_xyz_f32(pix)
124+
colcon.jzazbz_to_xyz_3f32(pix)
109125
pixcmp(list(pix), XYZ)
110126

111127
pix = cpixel(*OKLAB)
112-
colcon.oklab_to_xyz_f32(pix)
128+
colcon.oklab_to_xyz_3f32(pix)
113129
pixcmp(list(pix), XYZ)
114130

115131
pix = cpixel(*XYZ)
116-
colcon.xyz_to_lrgb_f32(pix)
132+
colcon.xyz_to_lrgb_3f32(pix)
117133
pixcmp(list(pix), LRGB)
118134

119135
pix = cpixel(*LRGB)
120-
colcon.lrgb_to_srgb_f32(pix)
136+
colcon.lrgb_to_srgb_3f32(pix)
121137
pixcmp(list(pix), SRGB)
122138

123139
pix = cpixel(*SRGB)
124-
colcon.srgb_to_hsv_f32(pix)
140+
colcon.srgb_to_hsv_3f32(pix)
125141
pixcmp(list(pix), HSV)
126142

127143
pix = (ctypes.c_float * len(SRGB))(*SRGB)

src/lib.rs

+156-24
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,10 @@ pub const HIGH2023_MEAN: f32 = 20.956442;
429429

430430
/// Returns difference in perceptual lightness based on hue, aka the Helmholtz-Kohlrausch effect.
431431
/// High et al 2023 implementation.
432-
pub fn hk_high2023<T: DType>(lch: &[T; 3]) -> T {
432+
pub fn hk_high2023<T: DType, const N: usize>(lch: &[T; N]) -> T
433+
where
434+
Channels<N>: ValidChannels,
435+
{
433436
let fby: T = T::ff32(K_HIGH2022[0]).fma(
434437
((lch[2] - 90.0.to_dt()) / 2.0.to_dt()).to_radians().sin().abs(),
435438
K_HIGH2022[1].to_dt(),
@@ -446,7 +449,10 @@ pub fn hk_high2023<T: DType>(lch: &[T; 3]) -> T {
446449

447450
/// Compensates CIE LCH's L value for the Helmholtz-Kohlrausch effect.
448451
/// High et al 2023 implementation.
449-
pub fn hk_high2023_comp<T: DType>(lch: &mut [T; 3]) {
452+
pub fn hk_high2023_comp<T: DType, const N: usize>(lch: &mut [T; N])
453+
where
454+
Channels<N>: ValidChannels,
455+
{
450456
lch[0] = lch[0] + (T::ff32(HIGH2023_MEAN) - hk_high2023(lch)) * (lch[1] / 100.0.to_dt())
451457
}
452458

@@ -1390,26 +1396,42 @@ macro_rules! cdef1 {
13901396
}
13911397

13921398
macro_rules! cdef3 {
1393-
($base:ident, $f32:ident, $f64:ident) => {
1399+
($base:ident, $f32_3:ident, $f64_3:ident, $f32_4:ident, $f64_4:ident) => {
1400+
#[no_mangle]
1401+
extern "C" fn $f32_3(pixel: &mut [f32; 3]) {
1402+
$base(pixel)
1403+
}
13941404
#[no_mangle]
1395-
extern "C" fn $f32(pixel: &mut [f32; 3]) {
1405+
extern "C" fn $f64_3(pixel: &mut [f64; 3]) {
13961406
$base(pixel)
13971407
}
13981408
#[no_mangle]
1399-
extern "C" fn $f64(pixel: &mut [f64; 3]) {
1409+
extern "C" fn $f32_4(pixel: &mut [f32; 4]) {
1410+
$base(pixel)
1411+
}
1412+
#[no_mangle]
1413+
extern "C" fn $f64_4(pixel: &mut [f64; 4]) {
14001414
$base(pixel)
14011415
}
14021416
};
14031417
}
14041418

14051419
macro_rules! cdef31 {
1406-
($base:ident, $f32:ident, $f64:ident) => {
1420+
($base:ident, $f32_3:ident, $f64_3:ident, $f32_4:ident, $f64_4:ident) => {
1421+
#[no_mangle]
1422+
extern "C" fn $f32_3(pixel: &[f32; 3]) -> f32 {
1423+
$base(pixel)
1424+
}
1425+
#[no_mangle]
1426+
extern "C" fn $f64_3(pixel: &[f64; 3]) -> f64 {
1427+
$base(pixel)
1428+
}
14071429
#[no_mangle]
1408-
extern "C" fn $f32(pixel: &[f32; 3]) -> f32 {
1430+
extern "C" fn $f32_4(pixel: &[f32; 4]) -> f32 {
14091431
$base(pixel)
14101432
}
14111433
#[no_mangle]
1412-
extern "C" fn $f64(pixel: &[f64; 3]) -> f64 {
1434+
extern "C" fn $f64_4(pixel: &[f64; 4]) -> f64 {
14131435
$base(pixel)
14141436
}
14151437
};
@@ -1424,25 +1446,135 @@ cdef1!(pq_oetf, pq_oetf_f32, pq_oetf_f64);
14241446
cdef1!(pqz_oetf, pqz_oetf_f32, pqz_oetf_f64);
14251447

14261448
// Helmholtz-Kohlrausch
1427-
cdef31!(hk_high2023, hk_high2023_f32, hk_high2023_f64);
1428-
cdef3!(hk_high2023_comp, hk_high2023_comp_f32, hk_high2023_comp_f64);
1449+
cdef31!(
1450+
hk_high2023,
1451+
hk_high2023_3f32,
1452+
hk_high2023_3f64,
1453+
hk_high2023_4f32,
1454+
hk_high2023_4f64
1455+
);
1456+
cdef3!(
1457+
hk_high2023_comp,
1458+
hk_high2023_comp_3f32,
1459+
hk_high2023_comp_3f64,
1460+
hk_high2023_comp_4f32,
1461+
hk_high2023_comp_4f64
1462+
);
14291463

14301464
// Forward
1431-
cdef3!(srgb_to_hsv, srgb_to_hsv_f32, srgb_to_hsv_f64);
1432-
cdef3!(srgb_to_lrgb, srgb_to_lrgb_f32, srgb_to_lrgb_f64);
1433-
cdef3!(lrgb_to_xyz, lrgb_to_xyz_f32, lrgb_to_xyz_f64);
1434-
cdef3!(xyz_to_cielab, xyz_to_cielab_f32, xyz_to_cielab_f64);
1435-
cdef3!(xyz_to_oklab, xyz_to_oklab_f32, xyz_to_oklab_f64);
1436-
cdef3!(xyz_to_jzazbz, xyz_to_jzazbz_f32, xyz_to_jzazbz_f64);
1437-
cdef3!(lab_to_lch, lab_to_lch_f32, lab_to_lch_f64);
1465+
cdef3!(
1466+
srgb_to_hsv,
1467+
srgb_to_hsv_3f32,
1468+
srgb_to_hsv_3f64,
1469+
srgb_to_hsv_4f32,
1470+
srgb_to_hsv_4f64
1471+
);
1472+
cdef3!(
1473+
srgb_to_lrgb,
1474+
srgb_to_lrgb_3f32,
1475+
srgb_to_lrgb_3f64,
1476+
srgb_to_lrgb_4f32,
1477+
srgb_to_lrgb_4f64
1478+
);
1479+
cdef3!(
1480+
lrgb_to_xyz,
1481+
lrgb_to_xyz_3f32,
1482+
lrgb_to_xyz_3f64,
1483+
lrgb_to_xyz_4f32,
1484+
lrgb_to_xyz_4f64
1485+
);
1486+
cdef3!(
1487+
xyz_to_cielab,
1488+
xyz_to_cielab_3f32,
1489+
xyz_to_cielab_3f64,
1490+
xyz_to_cielab_4f32,
1491+
xyz_to_cielab_4f64
1492+
);
1493+
cdef3!(
1494+
xyz_to_oklab,
1495+
xyz_to_oklab_3f32,
1496+
xyz_to_oklab_3f64,
1497+
xyz_to_oklab_4f32,
1498+
xyz_to_oklab_4f64
1499+
);
1500+
cdef3!(
1501+
xyz_to_jzazbz,
1502+
xyz_to_jzazbz_3f32,
1503+
xyz_to_jzazbz_3f64,
1504+
xyz_to_jzazbz_4f32,
1505+
xyz_to_jzazbz_4f64
1506+
);
1507+
cdef3!(
1508+
lab_to_lch,
1509+
lab_to_lch_3f32,
1510+
lab_to_lch_3f64,
1511+
lab_to_lch_4f32,
1512+
lab_to_lch_4f64
1513+
);
1514+
cdef3!(
1515+
_lrgb_to_ictcp,
1516+
_lrgb_to_ictcp_3f32,
1517+
_lrgb_to_ictcp_3f64,
1518+
_lrgb_to_ictcp_4f32,
1519+
_lrgb_to_ictcp_4f64
1520+
);
14381521

14391522
// Backward
1440-
cdef3!(hsv_to_srgb, hsv_to_srgb_f32, hsv_to_srgb_f64);
1441-
cdef3!(lrgb_to_srgb, lrgb_to_srgb_f32, lrgb_to_srgb_f64);
1442-
cdef3!(xyz_to_lrgb, xyz_to_lrgb_f32, xyz_to_lrgb_f64);
1443-
cdef3!(cielab_to_xyz, cielab_to_xyz_f32, cielab_to_xyz_f64);
1444-
cdef3!(oklab_to_xyz, oklab_to_xyz_f32, oklab_to_xyz_f64);
1445-
cdef3!(jzazbz_to_xyz, jzazbz_to_xyz_f32, jzazbz_to_xyz_f64);
1446-
cdef3!(lch_to_lab, lch_to_lab_f32, lch_to_lab_f64);
1523+
cdef3!(
1524+
hsv_to_srgb,
1525+
hsv_to_srgb_3f32,
1526+
hsv_to_srgb_3f64,
1527+
hsv_to_srgb_4f32,
1528+
hsv_to_srgb_4f64
1529+
);
1530+
cdef3!(
1531+
lrgb_to_srgb,
1532+
lrgb_to_srgb_3f32,
1533+
lrgb_to_srgb_3f64,
1534+
lrgb_to_srgb_4f32,
1535+
lrgb_to_srgb_4f64
1536+
);
1537+
cdef3!(
1538+
xyz_to_lrgb,
1539+
xyz_to_lrgb_3f32,
1540+
xyz_to_lrgb_3f64,
1541+
xyz_to_lrgb_4f32,
1542+
xyz_to_lrgb_4f64
1543+
);
1544+
cdef3!(
1545+
cielab_to_xyz,
1546+
cielab_to_xyz_3f32,
1547+
cielab_to_xyz_3f64,
1548+
cielab_to_xyz_4f32,
1549+
cielab_to_xyz_4f64
1550+
);
1551+
cdef3!(
1552+
oklab_to_xyz,
1553+
oklab_to_xyz_3f32,
1554+
oklab_to_xyz_3f64,
1555+
oklab_to_xyz_4f32,
1556+
oklab_to_xyz_4f64
1557+
);
1558+
cdef3!(
1559+
jzazbz_to_xyz,
1560+
jzazbz_to_xyz_3f32,
1561+
jzazbz_to_xyz_3f64,
1562+
jzazbz_to_xyz_4f32,
1563+
jzazbz_to_xyz_4f64
1564+
);
1565+
cdef3!(
1566+
lch_to_lab,
1567+
lch_to_lab_3f32,
1568+
lch_to_lab_3f64,
1569+
lch_to_lab_4f32,
1570+
lch_to_lab_4f64
1571+
);
1572+
cdef3!(
1573+
_ictcp_to_lrgb,
1574+
_ictcp_to_lrgb_3f32,
1575+
_ictcp_to_lrgb_3f64,
1576+
_ictcp_to_lrgb_4f32,
1577+
_ictcp_to_lrgb_4f64
1578+
);
14471579

14481580
// }}}

src/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::*;
33
const HEX: &str = "#3359F2";
44
const IRGB: [u8; 3] = [51, 89, 242];
55

6-
const HEXA: &str = "#3359F259";
6+
const _HEXA: &str = "#3359F259";
77
const IRGBA: [u8; 4] = [51, 89, 242, 89];
88

99
// ### COLOUR-REFS ### {{{

0 commit comments

Comments
 (0)