Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
hsluv.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
4 * Authors:
5 * 2015 Alexei Boronine (original idea, JavaScript implementation)
6 * 2015 Roger Tallada (Obj-C implementation)
7 * 2017 Martin Mitas (C implementation, based on Obj-C implementation)
8 * 2021 Massinissa Derriche (C++ implementation for Inkscape, based on C implementation)
9 * 2023 Martin Owens (New Color classes)
10 *
11 * Copyright (C) 2023 Authors
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include "hsluv.h"
16
17#include <cmath>
18
20
27std::array<Geom::Line, 6> HSLuv::get_bounds(double l)
28{
29 std::array<Geom::Line, 6> bounds;
30
31 double tl = l + 16.0;
32 double sub1 = (tl * tl * tl) / 1560896.0;
33 double sub2 = (sub1 > EPSILON ? sub1 : (l / KAPPA));
34 int channel;
35 int t;
36
37 for (channel = 0; channel < 3; channel++) {
38 double m1 = d65[channel][0];
39 double m2 = d65[channel][1];
40 double m3 = d65[channel][2];
41
42 for (t = 0; t < 2; t++) {
43 double top1 = (284517.0 * m1 - 94839.0 * m3) * sub2;
44 double top2 = (838422.0 * m3 + 769860.0 * m2 + 731718.0 * m1) * l * sub2 - 769860.0 * t * l;
45 double bottom = (632260.0 * m3 - 126452.0 * m2) * sub2 + 126452.0 * t;
46
47 bounds[channel * 2 + t].setCoefficients(top1, -bottom, top2);
48 }
49 }
50
51 return bounds;
52}
53
61static double max_chroma_for_lh(double l, double h)
62{
63 double min_len = std::numeric_limits<double>::max();
64 auto const ray = Geom::Ray(Geom::Point(0, 0), Geom::rad_from_deg(h));
65
66 for (auto const &line : HSLuv::get_bounds(l)) {
67 auto intersections = line.intersect(ray);
68 if (intersections.empty()) {
69 continue;
70 }
71 double len = intersections[0].point().length();
72
73 if (len >= 0 && len < min_len) {
74 min_len = len;
75 }
76 }
77
78 return min_len;
79}
80
86void HSLuv::toLch(std::vector<double> &in_out)
87{
88 double h = in_out[0] * 360;
89 double s = in_out[1] * 100;
90 double l = in_out[2] * 100;
91 double c;
92
93 /* White and black: disambiguate chroma */
94 if (l > 99.9999999 || l < 0.00000001) {
95 c = 0.0;
96 } else {
97 c = max_chroma_for_lh(l, h) / 100.0 * s;
98 }
99
100 /* Grays: disambiguate hue */
101 if (s < 0.00000001) {
102 h = 0.0;
103 }
104
105 in_out[0] = l;
106 in_out[1] = c;
107 in_out[2] = h;
108}
109
115void HSLuv::fromLch(std::vector<double> &in_out)
116{
117 double l = in_out[0];
118 double c = in_out[1];
119 double h = in_out[2];
120 double s;
121
122 /* White and black: disambiguate saturation */
123 if (l > 99.9999999 || l < 0.00000001) {
124 s = 0.0;
125 } else {
126 s = c / max_chroma_for_lh(l, h) * 100.0;
127 }
128
129 /* Grays: disambiguate hue */
130 if (c < 0.00000001) {
131 h = 0.0;
132 }
133
134 in_out[0] = h / 360;
135 in_out[1] = s / 100;
136 in_out[2] = l / 100;
137}
138
139}; // namespace Inkscape::Colors::Space
uint32_t Color
Geom::IntRect bounds
Definition canvas.cpp:182
Two-dimensional point that doubles as a vector.
Definition point.h:66
Straight ray from a specific point to infinity.
Definition ray.h:53
static void toLch(std::vector< double > &output)
Convert a color from the the HSLuv colorspace to the LCH colorspace.
Definition hsluv.cpp:86
static void fromLch(std::vector< double > &output)
Convert a color from the the LCH colorspace to the HSLuv colorspace.
Definition hsluv.cpp:115
static std::array< Geom::Line, 6 > get_bounds(double l)
Calculate the bounds of the Luv colors in RGB gamut.
Definition hsluv.cpp:27
double c[8][4]
std::string original
static double max_chroma_for_lh(double l, double h)
Calculate the maximum in gamut chromaticity for the given luminance and hue.
Definition hsluv.cpp:61
constexpr double KAPPA
Definition luv.h:19
constexpr double EPSILON
Definition luv.h:20
const std::vector< double > d65[3]
Definition xyz.h:23
Helper class to stream background task notifications as a series of messages.
auto len
Definition safe-printf.h:21