-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.bs
400 lines (306 loc) · 12.7 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
<pre class='metadata'>
Title: Color API
Status: Dream
Work Status: exploring
ED: https://wicg.github.io/color-api
Shortname: color
Level: 1
Abstract: A color space agnostic class for color specification, manipulation, and conversion.
Editor: Chris Lilley, W3C, https://svgees.us/, w3cid 1438
Editor: Lea Verou, Invited Expert, http://lea.verou.me/about, w3cid 52258
Editor: Tab Atkins Jr., Google, http://xanthir.com/contact, w3cid 42199
Repository: wicg/color-api
Inline Github Issues: title
Markup Shorthands: markdown yes
</pre>
<style>
/* Put nice boxes around each algorithm.
Credits: from Typed OM
*/
[data-algorithm]:not(.heading) {
padding: .5em;
border: thin solid #ddd; border-radius: .5em;
margin: .5em calc(-0.5em - 1px);
}
[data-algorithm]:not(.heading) > :first-child {
margin-top: 0;
}
[data-algorithm]:not(.heading) > :last-child {
margin-bottom: 0;
}
[data-algorithm] [data-algorithm] {
margin: 1em 0;
}
</style>
Introduction {#intro}
=====================
Many APIs on the Web platform need to be able to accept color input
and provide color output
in a format more structured than CSS `<color>` strings.
Furthermore, authors often need to perform computations on color values,
such as manipulating components in a variety of color spaces,
computing color differences,
evaluating whether color pairs have sufficient contrast,
or interpolating two colors (regardless of what color space they are specified in).
The API presented in this document aims to address all of the
<a href="https://github.com/LeaVerou/color-api#readme">common use cases</a>,
and provide extensibility points to enable more complex use cases to be expressed.
Issue(1):
{{Color}} class {#color}
=======================
{{Color}} objects represent ...TBD
<xmp class='idl'>
[Exposed=*]
interface Color {
// Default constructor
constructor(
(CSSOMString or ColorSpace) colorSpace,
sequence<double> coords,
optional double alpha = 1
);
// Parse CSS color
constructor(CSSOMString cssText);
// Clone color instance or create from JSON-style object
constructor((Color or CSSColorValue or ColorJSON) color);
attribute ColorSpace colorSpace;
attribute ObservableArray<double> coords;
attribute double alpha;
// Get/set coordinates (in this or other color spaces)
double get((CSSOMString or ColorSpace) colorSpace, (CSSOMString or unsigned short) coord);
double get((CSSOMString or unsigned short) coord);
Color set(
(CSSOMString or ColorSpace) colorSpace,
(CSSOMString or unsigned short) coord,
(double or relativeCoordCallback) value
);
Color set(
(CSSOMString or unsigned short) coord,
(double or relativeCoordCallback) value
);
Color set((CSSOMString or ColorSpace) colorSpace, object values);
Color set(object values);
// Convert to another color space
Color to(CSSOMString colorspace);
// Check whether a color is in gamut of a given color space
boolean inGamut(optional CSSOMString colorspace);
// Bring a color into gamut of a given colorspace
Color toGamut(
optional (CSSOMString or ColorSpace) colorSpace,
optional ToGamutOptions options = {}
);
stringifier;
ColorJSON toJSON();
// Color difference
double deltaE(Color color, optional DeltaEMethod method);
};
dictionary ToGamutOptions {
coordReference? method = "lch.c";
};
dictionary coordReference {
(CSSOMString or ColorSpace) colorSpace;
CSSOMString name;
};
// TODO: we want authors to be able to extend this
// If we keep it an enum, the only way to add custom deltaE methods
// is a separate method.
enum DeltaEMethod {
"76", // fast, but limited accuracy
"2000", // slower, but accurate
};
dictionary ColorJSON {
(CSSOMString or ColorSpace) colorSpace;
sequence<double> coords;
double alpha;
};
callback relativeCoordCallback = double (double coord);
</xmp>
<div algorithm=Color.constructor>
The `new Color(colorspace, coords, alpha)` constructor steps are:
1. [Look up](#colorspace-lookup) the `ColorSpace` object in the registry using the `colorspace` parameter.
1. If the result is `null`, throw a `TypeError`
2. Otherwise, set the color’s color space to it
2. If `coords` is not provided, create an array of zeroes with length equal to the number of coordinates in `colorspace`.
3. If `coords` is provided:
1. If it's not an array, throw a `TypeError`.
2. Create a clone of the array.
3. If its length is greater than the number of coordinates in the color space, trim the excess numbers from the end.
4. If its length is smaller than the number of coordinates in the color space, pad it with zeroes
5. Set the color's `coords` to the cloned array.
6. If `alpha` is not a number, coerce it to a number, then set the color's `alpha` to this number.
Issue(3):
</div>
<div algorithm="Color.get()">
The <dfn method for=Color>get(coord)</dfn> method
of {{Color}} objects must,
when called on [=this=]:
1. If there are two arguments, set refSpace to `ColorSpace.get(colorSpace)`.
2. If there is only one argument, set refSpace to `ColorSpace.get(this.colorSpace)`
3. Let `color = this.to(refSpace)`
4. Return `color.coords[refSpace.coord]`.
</div>
<div algorithm="Color.to()">
The <dfn method for=Color>to(colorSpace)</dfn> method
of {{Color}} objects must,
when called on [=this=]:
1. [Look up the color space object](#colorspace-lookup)
from the current object’s `colorSpace` specifier.
2.
</div>
<div algorithm="Color.inGamut()">
The <dfn method for=Color>inGamut(colorSpace)</dfn> method,
when called,
must perform the following steps:
1. Let `colorSpace` be the [color space object](#colorspace-lookup)
from the current object’s `colorSpace` specifier.
2. While the color space does *not* have an `inGamut` method,
set `colorSpace = ColorSpace.get(colorSpace.base)`
3. If `colorSpace` has an `inGamut` method, return `colorSpace.inGamut(this.coords)`
4. Otherwise, return `true`.
</div>
<div algorithm="Color.toGamut()">
The <dfn method for=Color>toGamut(colorSpace)</dfn> method,
when called,
must perform the following steps:
1. If `colorSpace` is not specified, it is set to `this.colorSpace`.
1. Set `colorSpace` to the result of `ColorSpace.get(colorSpace)`.
2. If `this.inGamut(colorSpace) === true`, clone the current color and return it.
3. Lookup the coordinate reference in `options.method` and
3. Let `color = this.to(colorSpace)`
2. While the color space does *not* have an `inGamut` method,
set `colorSpace = ColorSpace.get(colorSpace.base)`
3. If `colorSpace` has an `inGamut` method, return `colorSpace.inGamut(this.coords)`
4. Otherwise, return `true`.
Issue: Color space objects should not have a method that is only present sometimes.
We need to do this some other way.
</div>
<div algorithm="Color.deltaE()">
The <dfn method for=Color>deltaE(color, deltaEMethod)</dfn> method,
when called,
must perform the following steps:
1. Calculate the color difference between `this` and `color` using the method specified by `deltaEMethod` (see prose below)
2. Return the result.
The value `"76"` corresponds to the deltaE 76 method,
which is a fast but inaccurate method.
The value `"2000"` corresponds to the deltaE 2000 method,
which is a slower but more accurate method.
Future versions of this specification may add additional methods,
or allow authors to define their own methods.
</div>
{{ColorSpace}} class {#colorspace}
=======================
<xmp class='idl'>
[Exposed=*]
interface ColorSpace {
readonly attribute CSSOMString name;
readonly attribute ColorSpaceWhitePoint white;
readonly attribute ColorSpace? base;
readonly attribute sequence<CSSOMString> coords;
constructor(CSSOMString name, ColorSpaceOptions options);
// Register a ColorSpace object
static undefined register(ColorSpace colorspace);
// Creates a new ColorSpace object and registers it
static ColorSpace create(CSSOMString name, ColorSpaceOptions options);
// Array of names for all registered color spaces
static readonly attribute FrozenArray<CSSOMString> names;
// Lookup ColorSpace object by name
static ColorSpace get((CSSOMString or ColorSpace) name);
// Load ICC profile and create a ColorSpace object from it
static Promise<ColorSpace> fromICCProfile((Response or CSSOMString) resource, ReducedColorSpaceOptions options);
};
// White point x and y chromaticities
interface ColorSpaceWhitePoint {
constructor(double x, double y);
readonly attribute double x;
readonly attribute double y;
static readonly attribute ColorSpaceWhitePoint D65;
static readonly attribute ColorSpaceWhitePoint D50;
};
dictionary ReducedColorSpaceOptions {
// Coordinate names and optional metadata
record<DOMString, ColorSpaceCoordinate> coords;
};
dictionary ColorSpaceOptions : ReducedColorSpaceOptions {
(ColorSpaceWhitePoint or object) white;
inGamutCallback inGamut;
// Base color space, if this is a transformation
(CSSOMString or ColorSpace)? base;
toBaseCallback toBase;
fromBaseCallback fromBase;
};
dictionary ColorSpaceCoordinate {
ColorSpaceCoordinateType? type = "number";
// Gamut limits
double? min;
double? max;
// Reference range
double? refMin;
double? refMax;
};
enum ColorSpaceCoordinateType { "angle", "number" };
callback inGamutCallback = boolean (sequence<double> coords);
callback toBaseCallback = sequence<double> (sequence<double> coords);
callback fromBaseCallback = sequence<double> (sequence<double> coords);
</xmp>
Color space coordinates must specify at least one of:
- `type: "angle"`
- `min` and `max`
- `refMin` and `refMax`
Issue(7):
The `ColorSpaceWhitePoint` interface represents the xy chromaticity coordinates of
a white point. For convenience, D50 and D65 are predefined as follows:
- `ColorSpaceWhitePoint.D50` is set to `new ColorSpaceWhitePoint(0.3457, 0.3585)`
- `ColorSpaceWhitePoint.D65` is set to `new ColorSpaceWhitePoint(0.3127, 0.3290)`
<div algorithm="ColorSpace.get()">
The <dfn method for=Color>get(name)</dfn> function:
1. If the argument is a `ColorSpace` object, return it
2. If the argument is a string, look up that string in the internal registry of ColorSpace objects.
1. If a ColorSpace object is found, return it.
2. Otherwise, throw a `ReferenceError` (Color space does not exist)
</div>
Algorithms {#algorithms}
=========================
Getting and setting coordinates {#get-set}
-------------------------------------------
The `color.get()` and `color.set()` methods allow authors to read/write coordinates
in the current color space or even other color spaces.
Color spaces can be provided either as a string (color space id) or a CoorSpace object.
Coordinates can be specified either as a name, or as a numerical index.
`color.set(coord, value)` also accepts a value.
If the value is a function, it is invoked immediately,
with the result of `color.get(coord)` being passed as the first argument.
If the result is a number, the corresponding coordinate is set to it.
Color space lookup {#colorspace-lookup}
----------------------------------------
Color spaces can be looked up either by `ColorSpace` object, or by `name`.
Implementations are expected to maintain an internal `Map` registry of color space names to objects, for fast lookups.
To look up a color space, follow the following steps:
1. If `needle` is a `ColorSpace` object, let `needle = needle.name`
2. If `needle` is a `USVString`, look up if there is an entry with that key in the internal Map of color names to `ColorSpace` objects.
4. Return the `ColorSpace` object, or `null`, if none is found
Converting between color spaces {#converting-colorspaces}
---------------------------------------------------------
To convert a color from color space A to color space B, perform the following steps:
1. If `A.name === B.name`, clone the color and return it
2. Let coords = `A.toBase(color.coords)`.
If `A.base === B.name`, return `new Color(B, coords, color.alpha)`
3. While `A.base !== "xyz"`:
1. Let coords = `A.toBase(color.coords)`.
2. If `A.base === B.name`, return `new Color(B, coords, color.alpha)`
3. Otherwise, let `A = ColorSpace.get(A.base)`
4. Follow B's base chain until `"xyz"` as well, and store the result in an array.
5. Starting from the end, let `coords = B.fromBase(coords)` on each of these colorspaces
6. Return `new Color(B, coords, color.alpha)`
Issue(11):
Note: While this seems complicated in the general case, in virtually every real case
the base chain has a length of max 3, so the algorithm would end very quickly.
Registering a color space {#colorspace-registering}
----------------------------------------------------
TBD.
Should throw if `base` chain doesn't resolve to `"xyz"` eventually.
Should throw if `name` exists.
Security Considerations {#security-considerations}
==================================================
There are no known security issues introduced by these features.
Privacy Considerations {#privacy-considerations}
==================================================
There are no known privacy issues introduced by these features.