Skip to content

Commit 28174b3

Browse files
authored
Merge pull request #14 from benjie/raw-lab
Raw Lab colorspace access (for higher performance)
2 parents 835909c + 6b60fa7 commit 28174b3

File tree

3 files changed

+182
-7
lines changed

3 files changed

+182
-7
lines changed

lib/index.js

+16-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ var palette = require('./palette');
66

77
var color = module.exports = {};
88

9-
color.diff = diff.ciede2000;
10-
color.rgb_to_lab = convert.rgb_to_lab;
11-
color.rgba_to_lab = convert.rgba_to_lab;
12-
color.map_palette = palette.map_palette;
13-
color.palette_map_key = palette.palette_map_key;
9+
color.diff = diff.ciede2000;
10+
color.rgb_to_lab = convert.rgb_to_lab;
11+
color.rgba_to_lab = convert.rgba_to_lab;
12+
color.map_palette = palette.map_palette;
13+
color.palette_map_key = palette.palette_map_key;
14+
color.map_palette_lab = palette.map_palette_lab;
15+
color.lab_palette_map_key = palette.lab_palette_map_key;
16+
color.match_palette_lab = palette.match_palette_lab;
1417

1518
color.closest = function(target, relative, bc) {
1619
var key = color.palette_map_key(target);
@@ -27,3 +30,11 @@ color.furthest = function(target, relative, bc) {
2730

2831
return result[key];
2932
};
33+
34+
color.closest_lab = function(target, relative) {
35+
return color.match_palette_lab(target, relative, false);
36+
};
37+
38+
color.furthest_lab = function(target, relative) {
39+
return color.match_palette_lab(target, relative, true);
40+
};

lib/palette.js

+63-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929
/**
3030
* EXPORTS
3131
*/
32-
exports.map_palette = map_palette;
33-
exports.palette_map_key = palette_map_key;
32+
exports.map_palette = map_palette;
33+
exports.map_palette_lab = map_palette_lab;
34+
exports.match_palette_lab = match_palette_lab;
35+
exports.palette_map_key = palette_map_key;
36+
exports.lab_palette_map_key = lab_palette_map_key;
3437

3538
/**
3639
* IMPORTS
@@ -56,6 +59,16 @@ function palette_map_key(c)
5659
return s;
5760
}
5861

62+
/**
63+
* Returns the hash key used for a {labcolor} in a {labpalettemap}
64+
* @param {labcolor} c should have fields L,a,b
65+
* @return {string}
66+
*/
67+
function lab_palette_map_key(c)
68+
{
69+
return "L" + c.L + "a" + c.a + "b" + c.b;
70+
}
71+
5972
/**
6073
* Returns a mapping from each color in a to the closest/farthest color in b
6174
* @param [{rgbcolor}] a each element should have fields R,G,B
@@ -97,6 +110,54 @@ function map_palette(a, b, type, bc)
97110
return c;
98111
}
99112

113+
/**
114+
* Returns the closest (or furthest) color to target_color in palette, operating in the L,a,b colorspace for performance
115+
* @param {labcolor} target_color should have fields L,a,b
116+
* @param [{labcolor}] palette each element should have fields L,a,b
117+
* @param 'find_furthest' should be falsy to find the closest color
118+
* @return {labcolor}
119+
*/
120+
function match_palette_lab(target_color, palette, find_furthest)
121+
{
122+
var color2, current_color_diff;
123+
var best_color = palette[0];
124+
var best_color_diff = ciede2000(target_color, best_color);
125+
for (var idx2 = 1, l = palette.length; idx2 < l; idx2 += 1)
126+
{
127+
color2 = palette[idx2];
128+
current_color_diff = ciede2000(target_color, color2);
129+
130+
if(
131+
(!find_furthest && (current_color_diff < best_color_diff)) ||
132+
(find_furthest && (current_color_diff > best_color_diff))
133+
)
134+
{
135+
best_color = color2;
136+
best_color_diff = current_color_diff;
137+
}
138+
}
139+
return best_color;
140+
}
141+
142+
/**
143+
* Returns a mapping from each color in a to the closest color in b
144+
* @param [{labcolor}] a each element should have fields L,a,b
145+
* @param [{labcolor}] b each element should have fields L,a,b
146+
* @param 'type' should be the string 'closest' or 'furthest'
147+
* @return {labpalettemap}
148+
*/
149+
function map_palette_lab(a, b, type)
150+
{
151+
var c = {};
152+
var find_furthest = type === 'furthest';
153+
for (var idx1 = 0; idx1 < a.length; idx1 += 1)
154+
{
155+
var color1 = a[idx1];
156+
c[lab_palette_map_key(color1)] = match_palette_lab(color1, b, find_furthest);
157+
}
158+
return c;
159+
}
160+
100161
/**
101162
* INTERNAL FUNCTIONS
102163
*/

test/palette.js

+103
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
*/
3232
var assert = require('assert');
3333
var color_palette = require('../lib/palette');
34+
var color_convert = require('../lib/convert');
3435

3536
/**
3637
* CONSTANTS
@@ -42,9 +43,20 @@ var navy = {'R':0 , 'G':0 ,'B':128};
4243
var blue = {'R':0 , 'G':0 ,'B':255};
4344
var yellow = {'R':255 , 'G':255 ,'B':0};
4445
var gold = {'R':255 , 'G':215 ,'B':0};
46+
47+
var white_lab = color_convert.rgb_to_lab(white);
48+
var black_lab = color_convert.rgb_to_lab(black);
49+
var navy_lab = color_convert.rgb_to_lab(navy);
50+
var blue_lab = color_convert.rgb_to_lab(blue);
51+
var yellow_lab = color_convert.rgb_to_lab(yellow);
52+
var gold_lab = color_convert.rgb_to_lab(gold);
53+
4554
var colors1 = [white, black, navy, blue, yellow, gold]
55+
var colors1_lab = [white_lab, black_lab, navy_lab, blue_lab, yellow_lab, gold_lab]
4656
var colors2 = [white, black, blue, gold]
57+
var colors2_lab = [white_lab, black_lab, blue_lab, gold_lab]
4758
var colors3 = [white, black, yellow, blue]
59+
var colors3_lab = [white_lab, black_lab, yellow_lab, blue_lab]
4860

4961
var white_a = {'R':255 , 'G':255 ,'B':255, 'A': 1.0};
5062
var black_a = {'R':0 , 'G':0 ,'B':0, 'A': 1.0};
@@ -54,6 +66,14 @@ var yellow_a = {'R':255 , 'G':255 ,'B':0, 'A': 1.0};
5466
var gold_a = {'R':255 , 'G':215 ,'B':0, 'A': 1.0};
5567
var colors1_a = [white_a, black_a, navy_a, blue_a, yellow_a, gold_a]
5668

69+
var white_a_lab = color_convert.rgb_to_lab(white_a);
70+
var black_a_lab = color_convert.rgb_to_lab(black_a);
71+
var navy_a_lab = color_convert.rgb_to_lab(navy_a);
72+
var blue_a_lab = color_convert.rgb_to_lab(blue_a);
73+
var yellow_a_lab = color_convert.rgb_to_lab(yellow_a);
74+
var gold_a_lab = color_convert.rgb_to_lab(gold_a);
75+
var colors1_a_lab = [white_a_lab, black_a_lab, navy_a_lab, blue_a_lab, yellow_a_lab, gold_a_lab]
76+
5777
/**
5878
* TESTS
5979
*/
@@ -112,6 +132,89 @@ describe('palette', function(){
112132
});
113133

114134
})
135+
136+
describe('#map_palette_lab()', function (){
137+
it('should map all colors to themselves when possible #1',
138+
function(){
139+
var expected1_1 = {};
140+
expected1_1[color_palette.lab_palette_map_key(white_lab)] = white_lab;
141+
expected1_1[color_palette.lab_palette_map_key(black_lab)] = black_lab;
142+
expected1_1[color_palette.lab_palette_map_key(navy_lab)] = navy_lab;
143+
expected1_1[color_palette.lab_palette_map_key(blue_lab)] = blue_lab;
144+
expected1_1[color_palette.lab_palette_map_key(yellow_lab)] = yellow_lab;
145+
expected1_1[color_palette.lab_palette_map_key(gold_lab)] = gold_lab;
146+
assert.deepEqual(expected1_1,
147+
color_palette.map_palette_lab(colors1_lab, colors1_lab));
148+
});
149+
it('should map all colors to themselves when possible #2',
150+
function(){
151+
var expected1_2 = {};
152+
expected1_2[color_palette.lab_palette_map_key(white_a_lab)] = white_a_lab;
153+
expected1_2[color_palette.lab_palette_map_key(black_a_lab)] = black_a_lab;
154+
expected1_2[color_palette.lab_palette_map_key(navy_a_lab)] = navy_a_lab;
155+
expected1_2[color_palette.lab_palette_map_key(blue_a_lab)] = blue_a_lab;
156+
expected1_2[color_palette.lab_palette_map_key(yellow_a_lab)] = yellow_a_lab;
157+
expected1_2[color_palette.lab_palette_map_key(gold_a_lab)] = gold_a_lab;
158+
assert.deepEqual(expected1_2,
159+
color_palette.map_palette_lab(colors1_a_lab, colors1_a_lab));
160+
});
161+
it('should map navy->blue and yellow->gold when navy and yellow are missing',
162+
function(){
163+
var expected2 = {};
164+
expected2[color_palette.lab_palette_map_key(white_lab)] = white_lab;
165+
expected2[color_palette.lab_palette_map_key(black_lab)] = black_lab;
166+
expected2[color_palette.lab_palette_map_key(navy_lab)] = blue_lab;
167+
expected2[color_palette.lab_palette_map_key(blue_lab)] = blue_lab;
168+
expected2[color_palette.lab_palette_map_key(yellow_lab)] = gold_lab;
169+
expected2[color_palette.lab_palette_map_key(gold_lab)] = gold_lab;
170+
assert.deepEqual(expected2,
171+
color_palette.map_palette_lab(colors1_lab, colors2_lab));
172+
});
173+
it('should map white->black & black,navy,blue->yellow & yellow,gold->blue',
174+
function(){
175+
var expected3 = {};
176+
expected3[color_palette.lab_palette_map_key(white_lab)] = black_lab;
177+
expected3[color_palette.lab_palette_map_key(black_lab)] = yellow_lab;
178+
expected3[color_palette.lab_palette_map_key(navy_lab)] = yellow_lab;
179+
expected3[color_palette.lab_palette_map_key(blue_lab)] = yellow_lab;
180+
expected3[color_palette.lab_palette_map_key(yellow_lab)] = blue_lab;
181+
expected3[color_palette.lab_palette_map_key(gold_lab)] = blue_lab;
182+
assert.deepEqual(expected3,
183+
color_palette.map_palette_lab(colors1_lab,
184+
colors3_lab,
185+
'furthest'));
186+
});
187+
188+
})
189+
190+
describe('#match_palette_lab()', function (){
191+
it('should match map_palette results for closest',
192+
function() {
193+
assert.deepEqual(color_palette.match_palette_lab(white_lab, colors1_lab), white_lab);
194+
assert.deepEqual(color_palette.match_palette_lab(black_lab, colors1_lab), black_lab);
195+
assert.deepEqual(color_palette.match_palette_lab(navy_lab, colors1_lab), navy_lab);
196+
assert.deepEqual(color_palette.match_palette_lab(blue_lab, colors1_lab), blue_lab);
197+
assert.deepEqual(color_palette.match_palette_lab(yellow_lab, colors1_lab), yellow_lab);
198+
assert.deepEqual(color_palette.match_palette_lab(gold_lab, colors1_lab), gold_lab);
199+
200+
assert.deepEqual(color_palette.match_palette_lab(white_lab, colors2_lab), white_lab);
201+
assert.deepEqual(color_palette.match_palette_lab(black_lab, colors2_lab), black_lab);
202+
assert.deepEqual(color_palette.match_palette_lab(navy_lab, colors2_lab), blue_lab);
203+
assert.deepEqual(color_palette.match_palette_lab(blue_lab, colors2_lab), blue_lab);
204+
assert.deepEqual(color_palette.match_palette_lab(yellow_lab, colors2_lab), gold_lab);
205+
assert.deepEqual(color_palette.match_palette_lab(gold_lab, colors2_lab), gold_lab);
206+
});
207+
208+
it('should match map_palette results for furthest',
209+
function() {
210+
assert.deepEqual(color_palette.match_palette_lab(white_lab, colors3_lab, true), black_lab);
211+
assert.deepEqual(color_palette.match_palette_lab(black_lab, colors3_lab, true), yellow_lab);
212+
assert.deepEqual(color_palette.match_palette_lab(navy_lab, colors3_lab, true), yellow_lab);
213+
assert.deepEqual(color_palette.match_palette_lab(blue_lab, colors3_lab, true), yellow_lab);
214+
assert.deepEqual(color_palette.match_palette_lab(yellow_lab, colors3_lab, true), blue_lab);
215+
assert.deepEqual(color_palette.match_palette_lab(gold_lab, colors3_lab, true), blue_lab);
216+
});
217+
})
115218
});
116219

117220
// Local Variables:

0 commit comments

Comments
 (0)