Graphviz 14.1.2~dev.20260118.0226
Loading...
Searching...
No Matches
lab.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <sparse/general.h>
14#include <sparse/QuadTree.h>
15#include <edgepaint/lab.h>
16#include <math.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
21#include <edgepaint/lab_gamut.h>
22#include <util/alloc.h>
23#include <util/prisize_t.h>
24
25color_rgb color_rgb_init(double r, double g, double b){
26 color_rgb rgb;
27 rgb.r = r; rgb.g = g; rgb.b = b;
28 return rgb;
29}
30
31color_xyz color_xyz_init(double x, double y, double z){
32 color_xyz xyz;
33 xyz.x = x; xyz.y = y; xyz.z = z;
34 return xyz;
35}
36
37
38color_lab color_lab_init(double l, double a, double b){
39 color_lab lab;
40 lab.l = l; lab.a = a; lab.b = b;
41 return lab;
42}
43
44double XYZEpsilon = 216./24389.;
45double XYZKappa = 24389./27.;
46
47static double PivotXYZ(double n){
48 if (n > XYZEpsilon) return pow(n, 1/3.);
49 return (XYZKappa*n + 16)/116;
50}
51
52static double PivotRgb(double n){
53 if (n > 0.04045) return 100*pow((n + 0.055)/1.055, 2.4);
54 return 100*n/12.92;
55}
56
58 double r = PivotRgb(color.r/255.0);
59 double g = PivotRgb(color.g/255.0);
60 double b = PivotRgb(color.b/255.0);
61 return color_xyz_init(r*0.4124 + g*0.3576 + b*0.1805, r*0.2126 + g*0.7152 + b*0.0722, r*0.0193 + g*0.1192 + b*0.9505);
62}
63
65 color_xyz white = color_xyz_init(95.047, 100.000, 108.883);
66 color_xyz xyz = RGB2XYZ(color);
67 double x = PivotXYZ(xyz.x/white.x);
68 double y = PivotXYZ(xyz.y/white.y);
69 double z = PivotXYZ(xyz.z/white.z);
70 double L = MAX(0, 116*y - 16);
71 double A = 500*(x - y);
72 double B = 200*(y - z);
73 return color_lab_init(L, A, B);
74}
75
76void LAB2RGB_real_01(double *color){
77 /* convert an array[3] of LAB colors to RGB between 0 to 1, in place */
78 color_rgb rgb;
79 color_lab lab;
80
81 lab.l = color[0];
82 lab.a = color[1];
83 lab.b = color[2];
84 rgb = LAB2RGB(lab);
85 color[0] = rgb.r/255;
86 color[1] = rgb.g/255;
87 color[2] = rgb.b/255;
88}
90 double y = (color.l + 16.0)/116.0;
91 double x = color.a/500.0 + y;
92 double z = y - color.b/200.0;
93 color_xyz white = color_xyz_init(95.047, 100.000, 108.883), xyz;
94 double t1, t2, t3;
95 if(pow(x, 3.) > XYZEpsilon){
96 t1 = pow(x, 3.);
97 } else {
98 t1 = (x - 16.0/116.0)/7.787;
99 }
100 if (color.l > (XYZKappa*XYZEpsilon)){
101 t2 = pow(((color.l + 16.0)/116.0), 3.);
102 } else {
103 t2 = color.l/XYZKappa;
104 }
105 if (pow(z, 3.) > XYZEpsilon){
106 t3 = pow(z, 3.);
107 } else {
108 t3 = (z - 16.0/116.0)/7.787;
109 }
110 xyz = color_xyz_init(white.x*t1, white.y*t2, white.z*t3);
111 return XYZ2RGB(xyz);
112}
113
115 double x = color.x/100.0;
116 double y = color.y/100.0;
117 double z = color.z/100.0;
118 double r = x*3.2406 + y*(-1.5372) + z*(-0.4986);
119 double g = x*(-0.9689) + y*1.8758 + z*0.0415;
120 double b = x*0.0557 + y*(-0.2040) + z*1.0570;
121 if (r > 0.0031308){
122 r = 1.055*pow(r, 1/2.4) - 0.055;
123 } else {
124 r = 12.92*r;
125 }
126 if (g > 0.0031308) {
127 g = 1.055*pow(g, 1/2.4) - 0.055;
128 } else {
129 g = 12.92*g;
130 }
131 if (b > 0.0031308){
132 b = 1.055*pow(b, 1/2.4) - 0.055;
133 } else {
134 b = 12.92*b;
135 }
136 r = MAX(0, r);
137 r = MIN(255, r*255);
138 g = MAX(0, g);
139 g = MIN(255, g*255);
140 b = MAX(0, b);
141 b = MIN(255, b*255);
142
143 return color_rgb_init(r, g, b);
144}
145
146double *lab_gamut(const int *lightness, int *n) {
147 /* give a list of n points in the file defining the LAB color gamut.
148 */
149 double *xx, *x;
150
151 int l1 = lightness[0];
152 int l2 = lightness[1];
153
154 if (l1 < 0) l1 = 0;
155 if (l2 > 100) l2 = 100;
156 if (l1 > l2) l1 = l2;
157
158 if (Verbose)
159 fprintf(stderr,"LAB color lightness range = %d,%d\n", l1, l2);
160
161 if (Verbose)
162 fprintf(stderr,"size of lab gamut = %" PRISIZE_T "\n", lab_gamut_data_size);
163
164 // each L* value can be paired with 256 a* values and 256 b* values, so
165 // compute the maximum number of doubles we will need to span the space
166 size_t m = ((size_t)l2 - (size_t)l1 + 1) * 256 * 256 * 3;
167
168 x = gv_calloc(m, sizeof(double));
169 xx = x;
170 *n = 0;
171 for (size_t i = 0; i < lab_gamut_data_size; i += 4){
172 if (lab_gamut_data[i] >= l1 && lab_gamut_data[i] <= l2){
173 int b_lower = lab_gamut_data[i + 2];
174 int b_upper = lab_gamut_data[i + 3];
175 for (int b = b_lower; b <= b_upper; ++b) {
176 xx[0] = lab_gamut_data[i];
177 xx[1] = lab_gamut_data[i+1];
178 xx[2] = b;
179 xx += 3;
180 (*n)++;
181 }
182 }
183 }
184
185 return x;
186}
187
188QuadTree lab_gamut_quadtree(const int *lightness,
189 int max_qtree_level) {
190 /* read the color gamut points list in the form "x y z\n ..." and store in the octtree */
191 int n;
192 double *x = lab_gamut(lightness, &n);
193 QuadTree qt;
194 int dim = 3;
195
196 if (!x) return NULL;
197 qt = QuadTree_new_from_point_list(dim, n, max_qtree_level, x);
198
199
200 free(x);
201 return qt;
202}
203
204static double lab_dist(color_lab x, color_lab y){
205 return sqrt((x.l-y.l)*(x.l-y.l) +(x.a-y.a)*(x.a-y.a) +(x.b-y.b)*(x.b-y.b));
206}
207
208static void lab_interpolate(color_lab lab1, color_lab lab2, double t, double *colors){
209 colors[0] = lab1.l + t*(lab2.l - lab1.l);
210 colors[1] = lab1.a + t*(lab2.a - lab1.a);
211 colors[2] = lab1.b + t*(lab2.b - lab1.b);
212}
213
214double *color_blend_rgb2lab(const char *color_list, const int maxpoints) {
215 /* give a color list of the form "#ff0000,#00ff00,...", get a list of around maxpoints
216 colors in an array colors0 of size [maxpoints*3] of the form {{l,a,b},...}.
217 color_list: either "#ff0000,#00ff00,...", or "pastel"
218 */
219
220 int nc = 1, r, g, b, i, ii, jj, cdim = 3;
221 color_rgb rgb;
222 double step, dist_current;
223 const char *cp = color_palettes_get(color_list);
224 if (cp){
225 color_list = cp;
226 }
227
228 if (maxpoints <= 0) return NULL;
229
230 const char *cl = color_list;
231 while ((cl=strchr(cl, ',')) != NULL){
232 cl++; nc++;
233 }
234 color_lab *lab = gv_calloc(MAX(nc, 1), sizeof(color_lab));
235
236 cl = color_list - 1;
237 nc = 0;
238 do {
239 cl++;
240 if (sscanf(cl,"#%02X%02X%02X", &r, &g, &b) != 3) break;
241 rgb.r = r; rgb.g = g; rgb.b = b;
242 lab[nc++] = RGB2LAB(rgb);
243 } while ((cl=strchr(cl, ',')) != NULL);
244
245 double *dists = gv_calloc(MAX(1, nc), sizeof(double));
246 dists[0] = 0;
247 for (i = 0; i < nc - 1; i++){
248 dists[i+1] = lab_dist(lab[i], lab[i+1]);
249 }
250 /* dists[i] is now the summed color distance from the 0-th color to the i-th color */
251 for (i = 0; i < nc - 1; i++){
252 dists[i+1] += dists[i];
253 }
254 if (Verbose)
255 fprintf(stderr,"sum = %f\n", dists[nc-1]);
256
257 double *colors = gv_calloc(maxpoints * cdim, sizeof(double));
258 if (maxpoints == 1){
259 colors[0] = lab[0].l;
260 colors[1] = lab[0].a;
261 colors[2] = lab[0].b;
262 } else {
263 step = dists[nc-1]/(maxpoints - 1);
264 ii = 0; jj = 0; dist_current = 0;
265 while (dists[jj] < dists[ii] + step) jj++;
266
267 double *colors_ptr = colors;
268 for (i = 0; i < maxpoints; i++){
269 lab_interpolate(lab[ii], lab[jj], (dist_current - dists[ii]) /
270 MAX(0.001, (dists[jj] - dists[ii])), colors_ptr);
271 dist_current += step;
272 colors_ptr += cdim;
273 if (dist_current > dists[jj]) ii = jj;
274 while (jj < nc -1 && dists[jj] < dists[ii] + step) jj++;
275 }
276 }
277 free(dists);
278 free(lab);
279 return colors;
280}
QuadTree QuadTree_new_from_point_list(int dim, int n, int max_level, double *coord)
Definition QuadTree.c:311
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define MIN(a, b)
Definition arith.h:28
#define MAX(a, b)
Definition arith.h:33
const char * color_palettes_get(const char *color_palette_name)
#define A(n, t)
Definition expr.h:76
static bool Verbose
Definition gml2gv.c:26
static attrs_t * L
Definition gmlparse.c:94
void free(void *)
node NULL
Definition grammar.y:181
static void color(Agraph_t *g)
Definition gvcolor.c:118
static int z
#define B
Definition hierarchy.c:120
QuadTree lab_gamut_quadtree(const int *lightness, int max_qtree_level)
construct a quadtree of the LAB gamut points
Definition lab.c:188
double * lab_gamut(const int *lightness, int *n)
Definition lab.c:146
color_xyz RGB2XYZ(color_rgb color)
Definition lab.c:57
void LAB2RGB_real_01(double *color)
Definition lab.c:76
static double PivotXYZ(double n)
Definition lab.c:47
color_rgb color_rgb_init(double r, double g, double b)
Definition lab.c:25
color_rgb XYZ2RGB(color_xyz color)
Definition lab.c:114
color_lab color_lab_init(double l, double a, double b)
Definition lab.c:38
static double PivotRgb(double n)
Definition lab.c:52
color_lab RGB2LAB(color_rgb color)
Definition lab.c:64
static double lab_dist(color_lab x, color_lab y)
Definition lab.c:204
color_xyz color_xyz_init(double x, double y, double z)
Definition lab.c:31
double XYZEpsilon
Definition lab.c:44
double * color_blend_rgb2lab(const char *color_list, const int maxpoints)
Definition lab.c:214
static void lab_interpolate(color_lab lab1, color_lab lab2, double t, double *colors)
Definition lab.c:208
double XYZKappa
Definition lab.c:45
color_rgb LAB2RGB(color_lab color)
Definition lab.c:89
const signed char lab_gamut_data[]
Definition lab_gamut.c:16
const size_t lab_gamut_data_size
static const int dim
#define PRISIZE_T
Definition prisize_t.h:25
double b
l: 0 to 100, a,b: -128 to 128
Definition lab.h:24
double a
Definition lab.h:24
double l
Definition lab.h:24
double r
Definition lab.h:14
double g
Definition lab.h:14
double b
Definition lab.h:14
double x
Definition lab.h:19
double z
Definition lab.h:19
double y
Definition lab.h:19