Skip to content

Commit c8ab943

Browse files
authored
Merge pull request #7715 from processing/clamp-color
Clamp color() to maxes
2 parents 2cc6cb8 + 6149bf6 commit c8ab943

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

src/color/creating_reading.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ function creatingReading(p5, fn){
408408
return new Color(
409409
arg,
410410
this._renderer.states.colorMode,
411-
this._renderer.states.colorMaxes[this._renderer.states.colorMode]
411+
this._renderer.states.colorMaxes[this._renderer.states.colorMode],
412+
{ clamp: true }
412413
);
413414
};
414415

src/color/p5.Color.js

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,14 @@ import {
3030
} from 'colorjs.io/fn';
3131
import HSBSpace from './color_spaces/hsb.js';
3232

33-
const map = (n, start1, stop1, start2, stop2) =>
34-
((n - start1) / (stop1 - start1) * (stop2 - start2) + start2);
33+
const map = (n, start1, stop1, start2, stop2, clamp) => {
34+
let result = ((n - start1) / (stop1 - start1) * (stop2 - start2) + start2);
35+
if (clamp) {
36+
result = Math.max(result, Math.min(start2, stop2));
37+
result = Math.min(result, Math.max(start2, stop2));
38+
}
39+
return result;
40+
}
3541

3642
const serializationMap = {};
3743

@@ -63,7 +69,7 @@ class Color {
6369
Color.#grayscaleMap[mode] = definition.fromGray;
6470
}
6571

66-
constructor(vals, colorMode, colorMaxes) {
72+
constructor(vals, colorMode, colorMaxes, { clamp = false } = {}) {
6773
// This changes with the color object
6874
this.mode = colorMode || RGB;
6975

@@ -106,16 +112,16 @@ class Color {
106112
if(colorMaxes){
107113
// NOTE: need to consider different number of arguments (eg. CMYK)
108114
if(vals.length === 4){
109-
mappedVals = Color.mapColorRange(vals, this.mode, colorMaxes);
115+
mappedVals = Color.mapColorRange(vals, this.mode, colorMaxes, clamp);
110116
}else if(vals.length === 3){
111-
mappedVals = Color.mapColorRange([vals[0], vals[1], vals[2]], this.mode, colorMaxes);
117+
mappedVals = Color.mapColorRange([vals[0], vals[1], vals[2]], this.mode, colorMaxes, clamp);
112118
mappedVals.push(1);
113119
}else if(vals.length === 2){
114120
// Grayscale with alpha
115121
if(Color.#grayscaleMap[this.mode]){
116-
mappedVals = Color.#grayscaleMap[this.mode](vals[0], colorMaxes);
122+
mappedVals = Color.#grayscaleMap[this.mode](vals[0], colorMaxes, clamp);
117123
}else{
118-
mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0]], this.mode, colorMaxes);
124+
mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0]], this.mode, colorMaxes, clamp);
119125
}
120126
const alphaMaxes = Array.isArray(colorMaxes[colorMaxes.length-1]) ?
121127
colorMaxes[colorMaxes.length-1] :
@@ -126,15 +132,16 @@ class Color {
126132
alphaMaxes[0],
127133
alphaMaxes[1],
128134
0,
129-
1
135+
1,
136+
clamp
130137
)
131138
);
132139
}else if(vals.length === 1){
133140
// Grayscale only
134141
if(Color.#grayscaleMap[this.mode]){
135-
mappedVals = Color.#grayscaleMap[this.mode](vals[0], colorMaxes);
142+
mappedVals = Color.#grayscaleMap[this.mode](vals[0], colorMaxes, clamp);
136143
}else{
137-
mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0]], this.mode, colorMaxes);
144+
mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0]], this.mode, colorMaxes, clamp);
138145
}
139146
mappedVals.push(1);
140147
}else{
@@ -157,7 +164,7 @@ class Color {
157164
}
158165

159166
// Convert from p5 color range to color.js color range
160-
static mapColorRange(origin, mode, maxes){
167+
static mapColorRange(origin, mode, maxes, clamp){
161168
const p5Maxes = maxes.map((max) => {
162169
if(!Array.isArray(max)){
163170
return [0, max];
@@ -168,7 +175,7 @@ class Color {
168175
const colorjsMaxes = Color.#colorjsMaxes[mode];
169176

170177
return origin.map((channel, i) => {
171-
const newval = map(channel, p5Maxes[i][0], p5Maxes[i][1], colorjsMaxes[i][0], colorjsMaxes[i][1]);
178+
const newval = map(channel, p5Maxes[i][0], p5Maxes[i][1], colorjsMaxes[i][0], colorjsMaxes[i][1], clamp);
172179
return newval;
173180
});
174181
}
@@ -680,7 +687,7 @@ function color(p5, fn, lifecycles){
680687
*/
681688
p5.Color = Color;
682689

683-
sRGB.fromGray = P3.fromGray = function(val, maxes){
690+
sRGB.fromGray = P3.fromGray = function(val, maxes, clamp){
684691
// Use blue max
685692
const p5Maxes = maxes.map((max) => {
686693
if(!Array.isArray(max)){
@@ -690,11 +697,11 @@ function color(p5, fn, lifecycles){
690697
}
691698
});
692699

693-
const v = map(val, p5Maxes[2][0], p5Maxes[2][1], 0, 1);
700+
const v = map(val, p5Maxes[2][0], p5Maxes[2][1], 0, 1, clamp);
694701
return [v, v, v];
695702
};
696703

697-
HSBSpace.fromGray = HSLSpace.fromGray = function(val, maxes){
704+
HSBSpace.fromGray = HSLSpace.fromGray = function(val, maxes, clamp){
698705
// Use brightness max
699706
const p5Maxes = maxes.map((max) => {
700707
if(!Array.isArray(max)){
@@ -704,11 +711,11 @@ function color(p5, fn, lifecycles){
704711
}
705712
});
706713

707-
const v = map(val, p5Maxes[2][0], p5Maxes[2][1], 0, 100);
714+
const v = map(val, p5Maxes[2][0], p5Maxes[2][1], 0, 100, clamp);
708715
return [0, 0, v];
709716
};
710717

711-
HWBSpace.fromGray = function(val, maxes){
718+
HWBSpace.fromGray = function(val, maxes, clamp){
712719
// Use Whiteness and Blackness to create number line
713720
const p5Maxes = maxes.map((max) => {
714721
if(!Array.isArray(max)){
@@ -738,7 +745,7 @@ function color(p5, fn, lifecycles){
738745
LCHSpace.fromGray =
739746
OKLab.fromGray =
740747
OKLCHSpace.fromGray =
741-
function(val, maxes){
748+
function(val, maxes, clamp){
742749
// Use lightness max
743750
const p5Maxes = maxes.map((max) => {
744751
if(!Array.isArray(max)){
@@ -748,7 +755,7 @@ function color(p5, fn, lifecycles){
748755
}
749756
});
750757

751-
const v = map(val, p5Maxes[0][0], p5Maxes[0][1], 0, 100);
758+
const v = map(val, p5Maxes[0][0], p5Maxes[0][1], 0, 100, clamp);
752759
return [v, 0, 0];
753760
};
754761

test/unit/color/creating_reading.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,25 @@ suite('color/CreatingReading', function() {
3131
});
3232
});
3333

34+
suite('constructor clamping', function() {
35+
test('should work on multi channels', function() {
36+
const myColor = mockP5Prototype.color(1000, 1000, 1000, 1000);
37+
assert.deepEqual(myColor.array(), [1, 1, 1, 1]);
38+
});
39+
test('should work on gray + alpha', function() {
40+
const myColor = mockP5Prototype.color(1000, 1000);
41+
assert.deepEqual(myColor.array(), [1, 1, 1, 1]);
42+
});
43+
test('should work on gray', function() {
44+
const myColor = mockP5Prototype.color(1000);
45+
assert.deepEqual(myColor.array(), [1, 1, 1, 1]);
46+
});
47+
test('normal values work', function() {
48+
const myColor = mockP5Prototype.color(255 / 2);
49+
assert.deepEqual(myColor.array(), [0.5, 0.5, 0.5, 1]);
50+
});
51+
});
52+
3453
suite('p5.prototype.lerpColor', function() {
3554
beforeEach(function() {
3655
mockP5Prototype.colorMode(mockP5Prototype.RGB);

0 commit comments

Comments
 (0)