lab.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. #include <sparse/general.h>
  11. #include <sparse/QuadTree.h>
  12. #include <edgepaint/lab.h>
  13. #include <math.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <sparse/color_palette.h>
  18. #include <edgepaint/lab_gamut.h>
  19. #include <util/alloc.h>
  20. #include <util/prisize_t.h>
  21. color_rgb color_rgb_init(double r, double g, double b){
  22. color_rgb rgb;
  23. rgb.r = r; rgb.g = g; rgb.b = b;
  24. return rgb;
  25. }
  26. color_xyz color_xyz_init(double x, double y, double z){
  27. color_xyz xyz;
  28. xyz.x = x; xyz.y = y; xyz.z = z;
  29. return xyz;
  30. }
  31. color_lab color_lab_init(double l, double a, double b){
  32. color_lab lab;
  33. lab.l = l; lab.a = a; lab.b = b;
  34. return lab;
  35. }
  36. double XYZEpsilon = 216./24389.;
  37. double XYZKappa = 24389./27.;
  38. static double PivotXYZ(double n){
  39. if (n > XYZEpsilon) return pow(n, 1/3.);
  40. return (XYZKappa*n + 16)/116;
  41. }
  42. static double PivotRgb(double n){
  43. if (n > 0.04045) return 100*pow((n + 0.055)/1.055, 2.4);
  44. return 100*n/12.92;
  45. }
  46. color_xyz RGB2XYZ(color_rgb color){
  47. double r = PivotRgb(color.r/255.0);
  48. double g = PivotRgb(color.g/255.0);
  49. double b = PivotRgb(color.b/255.0);
  50. 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);
  51. }
  52. color_lab RGB2LAB(color_rgb color){
  53. color_xyz white = color_xyz_init(95.047, 100.000, 108.883);
  54. color_xyz xyz = RGB2XYZ(color);
  55. double x = PivotXYZ(xyz.x/white.x);
  56. double y = PivotXYZ(xyz.y/white.y);
  57. double z = PivotXYZ(xyz.z/white.z);
  58. double L = MAX(0, 116*y - 16);
  59. double A = 500*(x - y);
  60. double B = 200*(y - z);
  61. return color_lab_init(L, A, B);
  62. }
  63. void LAB2RGB_real_01(double *color){
  64. /* convert an array[3] of LAB colors to RGB between 0 to 1, in place */
  65. color_rgb rgb;
  66. color_lab lab;
  67. lab.l = color[0];
  68. lab.a = color[1];
  69. lab.b = color[2];
  70. rgb = LAB2RGB(lab);
  71. color[0] = rgb.r/255;
  72. color[1] = rgb.g/255;
  73. color[2] = rgb.b/255;
  74. }
  75. color_rgb LAB2RGB(color_lab color){
  76. double y = (color.l + 16.0)/116.0;
  77. double x = color.a/500.0 + y;
  78. double z = y - color.b/200.0;
  79. color_xyz white = color_xyz_init(95.047, 100.000, 108.883), xyz;
  80. double t1, t2, t3;
  81. if(pow(x, 3.) > XYZEpsilon){
  82. t1 = pow(x, 3.);
  83. } else {
  84. t1 = (x - 16.0/116.0)/7.787;
  85. }
  86. if (color.l > (XYZKappa*XYZEpsilon)){
  87. t2 = pow(((color.l + 16.0)/116.0), 3.);
  88. } else {
  89. t2 = color.l/XYZKappa;
  90. }
  91. if (pow(z, 3.) > XYZEpsilon){
  92. t3 = pow(z, 3.);
  93. } else {
  94. t3 = (z - 16.0/116.0)/7.787;
  95. }
  96. xyz = color_xyz_init(white.x*t1, white.y*t2, white.z*t3);
  97. return XYZ2RGB(xyz);
  98. }
  99. color_rgb XYZ2RGB(color_xyz color){
  100. double x = color.x/100.0;
  101. double y = color.y/100.0;
  102. double z = color.z/100.0;
  103. double r = x*3.2406 + y*(-1.5372) + z*(-0.4986);
  104. double g = x*(-0.9689) + y*1.8758 + z*0.0415;
  105. double b = x*0.0557 + y*(-0.2040) + z*1.0570;
  106. if (r > 0.0031308){
  107. r = 1.055*pow(r, 1/2.4) - 0.055;
  108. } else {
  109. r = 12.92*r;
  110. }
  111. if (g > 0.0031308) {
  112. g = 1.055*pow(g, 1/2.4) - 0.055;
  113. } else {
  114. g = 12.92*g;
  115. }
  116. if (b > 0.0031308){
  117. b = 1.055*pow(b, 1/2.4) - 0.055;
  118. } else {
  119. b = 12.92*b;
  120. }
  121. r = MAX(0, r);
  122. r = MIN(255, r*255);
  123. g = MAX(0, g);
  124. g = MIN(255, g*255);
  125. b = MAX(0, b);
  126. b = MIN(255, b*255);
  127. return color_rgb_init(r, g, b);
  128. }
  129. double *lab_gamut(const int *lightness, int *n) {
  130. /* give a list of n points in the file defining the LAB color gamut.
  131. */
  132. double *xx, *x;
  133. int l1 = lightness[0];
  134. int l2 = lightness[1];
  135. if (l1 < 0) l1 = 0;
  136. if (l2 > 100) l2 = 100;
  137. if (l1 > l2) l1 = l2;
  138. if (Verbose)
  139. fprintf(stderr,"LAB color lightness range = %d,%d\n", l1, l2);
  140. if (Verbose)
  141. fprintf(stderr,"size of lab gamut = %" PRISIZE_T "\n", lab_gamut_data_size);
  142. // each L* value can be paired with 256 a* values and 256 b* values, so
  143. // compute the maximum number of doubles we will need to span the space
  144. size_t m = ((size_t)l2 - (size_t)l1 + 1) * 256 * 256 * 3;
  145. x = gv_calloc(m, sizeof(double));
  146. xx = x;
  147. *n = 0;
  148. for (size_t i = 0; i < lab_gamut_data_size; i += 4){
  149. if (lab_gamut_data[i] >= l1 && lab_gamut_data[i] <= l2){
  150. int b_lower = lab_gamut_data[i + 2];
  151. int b_upper = lab_gamut_data[i + 3];
  152. for (int b = b_lower; b <= b_upper; ++b) {
  153. xx[0] = lab_gamut_data[i];
  154. xx[1] = lab_gamut_data[i+1];
  155. xx[2] = b;
  156. xx += 3;
  157. (*n)++;
  158. }
  159. }
  160. }
  161. return x;
  162. }
  163. QuadTree lab_gamut_quadtree(const int *lightness,
  164. int max_qtree_level) {
  165. /* read the color gamut points list in the form "x y z\n ..." and store in the octtree */
  166. int n;
  167. double *x = lab_gamut(lightness, &n);
  168. QuadTree qt;
  169. int dim = 3;
  170. if (!x) return NULL;
  171. qt = QuadTree_new_from_point_list(dim, n, max_qtree_level, x);
  172. free(x);
  173. return qt;
  174. }
  175. static double lab_dist(color_lab x, color_lab y){
  176. 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));
  177. }
  178. static void lab_interpolate(color_lab lab1, color_lab lab2, double t, double *colors){
  179. colors[0] = lab1.l + t*(lab2.l - lab1.l);
  180. colors[1] = lab1.a + t*(lab2.a - lab1.a);
  181. colors[2] = lab1.b + t*(lab2.b - lab1.b);
  182. }
  183. double *color_blend_rgb2lab(const char *color_list, const int maxpoints) {
  184. /* give a color list of the form "#ff0000,#00ff00,...", get a list of around maxpoints
  185. colors in an array colors0 of size [maxpoints*3] of the form {{l,a,b},...}.
  186. color_list: either "#ff0000,#00ff00,...", or "pastel"
  187. */
  188. int nc = 1, r, g, b, i, ii, jj, cdim = 3;
  189. color_rgb rgb;
  190. double step, dist_current;
  191. const char *cp = color_palettes_get(color_list);
  192. if (cp){
  193. color_list = cp;
  194. }
  195. if (maxpoints <= 0) return NULL;
  196. const char *cl = color_list;
  197. while ((cl=strchr(cl, ',')) != NULL){
  198. cl++; nc++;
  199. }
  200. color_lab *lab = gv_calloc(MAX(nc, 1), sizeof(color_lab));
  201. cl = color_list - 1;
  202. nc = 0;
  203. do {
  204. cl++;
  205. if (sscanf(cl,"#%02X%02X%02X", &r, &g, &b) != 3) break;
  206. rgb.r = r; rgb.g = g; rgb.b = b;
  207. lab[nc++] = RGB2LAB(rgb);
  208. } while ((cl=strchr(cl, ',')) != NULL);
  209. double *dists = gv_calloc(MAX(1, nc), sizeof(double));
  210. dists[0] = 0;
  211. for (i = 0; i < nc - 1; i++){
  212. dists[i+1] = lab_dist(lab[i], lab[i+1]);
  213. }
  214. /* dists[i] is now the summed color distance from the 0-th color to the i-th color */
  215. for (i = 0; i < nc - 1; i++){
  216. dists[i+1] += dists[i];
  217. }
  218. if (Verbose)
  219. fprintf(stderr,"sum = %f\n", dists[nc-1]);
  220. double *colors = gv_calloc(maxpoints * cdim, sizeof(double));
  221. if (maxpoints == 1){
  222. colors[0] = lab[0].l;
  223. colors[1] = lab[0].a;
  224. colors[2] = lab[0].b;
  225. } else {
  226. step = dists[nc-1]/(maxpoints - 1);
  227. ii = 0; jj = 0; dist_current = 0;
  228. while (dists[jj] < dists[ii] + step) jj++;
  229. double *colors_ptr = colors;
  230. for (i = 0; i < maxpoints; i++){
  231. lab_interpolate(lab[ii], lab[jj], (dist_current - dists[ii]) /
  232. MAX(0.001, (dists[jj] - dists[ii])), colors_ptr);
  233. dist_current += step;
  234. colors_ptr += cdim;
  235. if (dist_current > dists[jj]) ii = jj;
  236. while (jj < nc -1 && dists[jj] < dists[ii] + step) jj++;
  237. }
  238. }
  239. free(dists);
  240. free(lab);
  241. return colors;
  242. }