-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRGB_Calc_instructions.html
1699 lines (1596 loc) · 110 KB
/
RGB_Calc_instructions.html
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
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name='description' content='utility for color-space conversions'>
<meta name='author' content='Joe Golembieski, SoftMoon-WebWare'>
<meta name='copyright' content='Copyright © 2013, 2022, 2023, 2024 Joe Golembieski, SoftMoon-WebWare'>
<meta name='page_last-udate' content='November 18, 2024'>
<title>RGB_Calc instructions from SoftMoon-WebWare</title>
<link rel="icon" type="image/x-icon" href="images/SoftMoonWebWare.gif">
<style type="text/css">
body, header, main, aside, section, footer, figure, div, h1, h2, h4, h5, img, menu, li {
margin: 0;
padding: 0; }
body {
min-width: 57em;
scroll-behavior: smooth;
font-family: serif;
color: #000000;
background-color: #FFDEAD;
background-image: /* SteelBlue */
linear-gradient(to right, #4682B4FF, 304px, #4682B400 800px),
linear-gradient(to bottom, #4682B4FF, 266px, #4682B400 700px),
linear-gradient(to top, #4682B4FF, 38px, #4682B400 100px);
}
header h1 {
font-size: 1.618em;
font-weight: bold;
clear: both;
text-align: center; }
header h1:first-child {
font-family: sans-serif;
padding: .618em 1em 0 1em;
text-align: left; }
header h1 span {
padding: 0 0 0 2.618em;
font-size: .764em } /* ≈ Φ + ((1-Φ) - (1-Φ)*Φ) */
header h1 + span {
display: block;
text-align: center;
position: relative;
transform: rotate(-21.246deg); /* (90°-(90°*Φ))*Φ */
font-size: 1.382em;
color: red;
text-decoration: underline; }
header figure {
margin-left: .382rem;
float: left; }
#logo {
opacity: .78;
font-size: 1.618em; /*for alt text*/
font-weight: bold;
line-height: 150%; }
header figcaption {
font-size: 1.382em;
font-weight: bold;
text-align: center;
width: 27em; }
header h1 span,
header figcaption span {
display: block;
font-style: oblique; }
main {
font-size: 1.236em;
text-align: center;
position: relative;
container: main / inline-size; }
aside {
margin: .618em;
padding: 0;
display: inline-block;
width: 9em; }
@container main (width > 60em) {
aside {
position: absolute;
top: 0;
left: 0;
bottom: auto;
right: auto; }
}
aside a {
display: block;
white-space: nowrap;
font-weight: bold;
font-size: 116%; }
p {
padding: 0;
text-indent: .618em; }
ul p {
text-indent: 0; }
p + p,
code.block + p,
ul + p,
dl + p {
margin-top: .618em; }
p, ul, dl {
text-align: left;
max-width: 38.2em;
margin: 0 auto; }
kbd {
display: inline-block;
text-indent: 0; }
kbd span {
display: inline-block;
position: relative;
border: 1px solid #8080FF;
border-bottom: 2px solid #404080;
border-right: 2px solid #404080;
border-radius: 1.618em / 2em;
color: white;
background-color: #202040;
text-align: center;
margin: 0 .382em;
padding: 0 .618em;
font-size: 85.4%;
line-height: .854em;
vertical-align: center; }
numerance,
footmark {
font-size: .618em;
font-weight: normal;
vertical-align: top; }
code {
text-align: left;
white-space: pre; }
code.block {
display: inline-block;
max-width: 94%;
overflow: auto;
margin: .328em auto;
padding: 0 0 0 .382em;
border-left: 3px double lightSteelBlue; }
dd code.block,
li code.block {
display: block; }
main > div {
margin: 2em 0; }
h4 {
font-size: 1.618rem;
font-weight: bold; }
h3, h4 {
margin: .382em 0 0 0.016em; }
ul {
list-style-type: disc;
list-style-position: outside; }
ul.range li {
position: relative; }
range {
font-size: 1.28em;
color: red; }
ul.range range {
position: absolute;
right: calc(100% + 1em);
left: auto;
top: -0.14em;
bottom: auto; }
ul#color-space-models li > abbr:first-child,
ul.range range + abbr,
ul.range range + abbr + br + abbr {
font-size: 1.382em;
font-weight: bold; }
ul.range specs {
display: block; }
dl { }
dt {
font-weight: bold; }
dd {
margin-left: 2em; }
dd ul {
list-style-type: square; }
div.help ul ul {
list-style-type: circle;
margin-right: 0; }
div.help ul ul.keybrd {
list-style-type: none;
margin-left: 0; }
div.help ul p {
margin: 0;
padding: 0; }
div.help dd {
margin: 0 1.168em; }
div.help li:nth-child(3) ul:first-child li kbd {
/* text shows XYZ limits */
padding-left: 1.382em; }
dd table {
margin-bottom: .618em;
text-align: center;
border-collapse: separate; }
dd th, dd td {
border: 1px solid; }
dd caption, dd th {
background-color: lightGreen;
font-weight: bold; }
dd th footmark { }
div.object dt.internal code,
div.object dt.stringFormat code,
div.object code.internal,
div.object span.internal {
background-color: #B0FFB0; }
div.object dt.internal.audit code {
background-color: #D8FFD8; }
div.object dt.static code,
div.object dt.private code {
background-color: #FF80FF; }
div.object dt.static.external code {
background-color: #FFD0FF; }
div.object > dl + p {
margin-top: .38em; }
footer p {
max-width: 100%;
text-indent: 0;
margin: 0 1.618em;
font-size: .78em;
font-weight: bold; }
footer note {
margin-right: 2.618em; }
footer note:last-child {
margin-right: 0; }
abbr[tm] {
font-size: .763924em;
vertical-align: .236076em;
line-height: 100%; }
</style>
</head>
<body>
<header>
<h1>Custom Web Software Development</h1>
<figure>
<img id='logo' src="images/SoftMoon-WebWare.gif" alt="SoftMoon-WebWare">
<figcaption>JavaScript<abbr tm>™</abbr>, <abbr>HTML 5</abbr>, <abbr>CSS 4</abbr>, & <abbr>PHP 8</abbr>:
<span>Innovative Enterprise level Scripting for interactive sites, <acronym title='software as a service'>SaaS</acronym>, & cross-platform desktop apps</span></figcaption>
</figure>
<h1><code>RGB_Calc</code> color-space conversion calculator</h1>
<span>and</span>
<h1><code>ColorFactory</code> color-space interpreter & conversion calculator</h1>
</header>
<main id='content'>
<aside>Download it from:
<a href='https://SoftMoon-WebWare.com/OpenSource.php'>our code vault</a>
or Git it on GitHub:
<a href='https://github.com/SoftMoonWebWare/RGB_Calc-color-space-converter'><code>RGB_Calc</code></a>
</aside>
<div class='intro'>
<p>The <code>RGB_Calc</code> Class was born of the need for speed, yet also the need to accommodate flexible input & output formats.
In testing, I found using <code>Array</code>s to pass data in & out provided the fastest execution times by far.
The predecessor of this class passed back only (custom) “color-<code>Object</code>s,”
and (if memory serves) it “processed” all input before actually converting any colors,
and when I replaced that previous class with this new <code>RGB_Calc</code> Class in my “MasterColorPicker” project
and configured this new Class to pass back simple <code>Array</code>s instead
(using the same conversion functions internally with about the same extraneous overhead),
maximum palette draw-time went from about 8.5 seconds to about 1.5 seconds (timed by eye/ear using the clicks on my analog wall-clock).
I was shocked (but happy☺) at the dramatic increase; I expected maybe 25%-100% faster times, but 700% faster is even better!</p>
<p>The <code>RGB_Calc</code> Class focuses on converting the
<abbr>sRGB</abbr> (standard Red-Green-Blue) color space model
to & from various other color space models.
In the (hopefully near) future, it will evolve into handling other <abbr>RGB</abbr> color-spaces with wider gamuts as well.
It also has utility functions for calculating
<a href='https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_Colors_and_Luminance' target="Mozilla">►Luminance and Color-Contrast</a>.
Included with this package is also the <code>ColorFactory</code> Class,
which can: interpret a (user-input) string and return the properly interpreted values;
copy a color-object (with universal but somewhat defined properties) to another color-object;
and convert one color space model to another in the most direct way, skipping the <abbr>RGB</abbr> color space when possible.
Color-object support is supplied with somewhat universal “color-Array” classes
(collectively, we call them <code>…A_Array</code>s, the “A” signifying that they also carry an alpha-channel value),
one for each color space model.
Finally, <code>…A_Array</code>s also have extended versions (<code>…A_Colors</code>) that can filter (user-)input for proper values.</p>
<p>Note a “color-<em>space</em>” is a conceptual, imaginary construct, that defines a specific range of (usually visible) colors.
A “color-<em>model</em>” is a mathematical way of describing a color-space,
and often has defined limits to values — the sRGB color space model limits each value to integers ranging from <kbd>0—255</kbd>.
In reality, colors could be more intense (have more chroma by allowing greater values),
or be more densely packed throughout the range of intensity (have a greater bit-depth),
but integers from <kbd>0</kbd> to <kbd>255</kbd> is the limit that computers use
(at least for now… coming soon: universal <abbr title='ultra-high definition monitor'>UHD</abbr> support!).
(By the way … chroma, or color-intensity, should not be confused with saturation, brightness, or luminance; it is a mix of them.)
So we generally define sRGB color-space-model-values like this: <kbd>(64, 128, 255)</kbd>,
but any color-</strong>model</strong> (including an RGB model) can generally also use percent values like this <kbd>(25%, 50%, 100%)</kbd>;
or some use hue-angles which correlate to a percentage of distance around the circumference of a circle <kbd>(90deg, 50%, 100%)</kbd>.
The mathematical color space model is then applied to the monitor, and every monitor has its own gamut;
that is the actual range of colors that the monitor will show, related to its contrast-ratio,
where generally speaking, the higher the contrast, the darker the black is, and the more bright and pure and less washed-out the colors appear.
This all gets more confusing as we try to compare computer monitors with real-life and
different wavelengths of light bouncing off different objects that reflect that wave in different ways,
and how the eye perceives color and vision in general,
and that is where this discussion leads…but not here.<p>
<p>To use the package, you must first create a couple of namespaces for it.
Typically, these namespaces are JavaScript<abbr tm>™</abbr> constants,
and are used by many of SoftMoon-WebWare’s various different library packages,
so they can’t all create the constant.
The <code>SoftMoon</code> namespace is our root, and it holds simple “universal” data
that different libraries may need.
The <code>SoftMoon.WebWare</code> namespace holds executable code.
Also, you need to create an <code>Array</code> for named-color-palette files to load themselves into
if you are hard-loading them with <script> tags
(<a href='#palettes'>▼more on that in the Palettes section below</a>).
If you are only loading palettes from a server
(using “ajax” via <code>SoftMoon.WebWare.loadPalettes()</code>),
or not at all, you don’t need the
<code>SoftMoon.loaded_palettes</code> property.
If you are not loading palettes from a server (using “ajax”), you do not need the <kbd>HTTP.js</kbd> file.
Don’t confuse the fact that you <strong>can</strong> load the palettes using <script> tags from a server
— but that is <strong>not</strong> using “ajax.”
The following <abbr>HTML</abbr> code will create the proper namespace <code>Objects</code>
and then load the code files and the <abbr>CSS</abbr> palette file:</p>
<code class='block' id='example1'><script type='text/javascript'>
const SoftMoon=Object.defineProperties({}, {
WebWare: {value: {}, enumerable: true},
loaded_palettes: {value: [], enumerable: true}
});
</script>
<script type='text/javascript' src='JS_toolbucket/+++JS/+++.js' defer></script>
<script type='text/javascript' src='JS_toolbucket/+++JS/+++Math.js' defer></script>
<script type='text/javascript' src='JS_toolbucket/SoftMoon-WebWare/HTTP.js' defer></script>
<script type='text/javascript' src='JS_toolbucket/Alexei_Boronine.HSLᵤᵥ_color_space_model.js' defer></script>
<script type='text/javascript' src='JS_toolbucket/Björn_Ottosson.OK_color_space_models.js' defer></script>
<script type='text/javascript' src='JS_toolbucket/SoftMoon-WebWare/RGB_Calc.js' defer></script>
<script type='text/javascript' src='color_palettes/desktop_palettes/CSS4.palette.js'
defer onload='SoftMoon.WebWare.addPalette(SoftMoon.loaded_palettes.pop())'></script>
</code>
<p id='quick'>Once loaded, the <code>RGB_Calc</code> Class is already set up
to give you access to all of the individual conversion functions
and the luminance and contrast-ratio functions.
These <a href='#quick-audit-mini'>▼<strong>“quick”</strong> functions</a> are tuned for maximum speed,
and are members of <code>RGB_Calc</code> so they depend being called as such to access the
configuration options: <code>RGB_Calc.config</code>.
They all require passing in an <code>Array</code> of “proper” values (see each function); that is,
converting from <abbr>sRGB</abbr> (→to→ any color-model) requires passing in values from <kbd>0—255</kbd>,
converting from other color-models typically (but not by all)
requires passing in factor-values from <kbd>0.0—1.0</kbd>,
and “improper” input values yield undefined results;
they are not checked for “improper” values, as this slows the calculator.</p>
<code class='block'>const RGB_Calc=SoftMoon.WebWare.RGB_Calc;
const c1=RGB_Calc.from.hsl([0.3, 0.5, 0.84]);
// By default, the returned value is a simple Array object
console.log(c1);
const c2=RGB_Calc.to.hsl([202, 235, 194]);
// By default, the returned value is a simple Array object;
console.log(c2);
// We can also get conversion values returned in:
// • a “color-Array” (a.k.a. an …A_Array),
// • a “Color-Object” (a.k.a. an …A_Color),
// • or YOUR custom Class object.
// To temporarily change a configuration value:
RGB_Calc.config.stack({RGBA_Factory: {value:SoftMoon.WebWare.RGBA_Array}});
// ↑ with .stack(), the passed value must be a properties descriptor
const c3=RGB_Calc.from.hsl([0.3, 0.5, 0.84]);
// now the returned value is a custom RGBA_Array object;
// its .toString('css') method yields: "RGB(202, 235, 194)"
console.log(c3);
// Note the slight difference in conversion values;
// this is because RGBA_Array objects’ .toString() method has rounded the resulting RGB values to integers.
// To find the precision RGB values
// **when the calculator’s configuration options do NOT round the RGB result**:
console.log(...c3) // ←the precision values
console.log(c3.red, c3.green, c3.blue) // ←the precision values
c3.red=128;
console.log(c3[0]); // ← now is 128, because .red is a getter/setter
c3[1]=64;
console.log(c3.green) // ← now is 64, because .green is a getter/setter
console.log(c3.rgba) // ←yields a simple Array that you can manipulate & mutilate without affecting the original
// (note we can also directly change config values without having first .stack()ed if we want them to be more permanent)
RGB_Calc.config.RGBA_Factory=MyCustomColorClass; // this should point to YOUR constructor function
const c4=RGB_Calc.from.hsl([0.3, 0.5, 0.84]); // ←c4 is an instance of MyCustomColorClass
RGB_Calc.config.OKHCGA_Factory=SoftMoon.WebWare.OKHCGA_Array;
const c5=RGB_Calc.to.okhcg([128,23,226]);
// ↑ c5 is an instance of SoftMoon.WebWare.OKHCGA_Array, not the original default simple Array
const c6=RGB_Calc.to.okhcg([128,23,226], MyCustom_OKHCG_Class);
// ↑ c6 is an instance of MyCustom_OKHCG_Class, overriding the new default SoftMoon.WebWare.OKHCGA_Array
// ↑ Only RGB_Calc.to. methods accept a “factory” parameter. RGB_Calc.from methods do NOT!
RGB_Calc.config.cull(); // now the RGBA_Factory & the OKHCGA_Factory are whatever they were before we .stack()ed</code>
<p>For all calculators, both <strong>“quick”</strong> and <strong>“auditing”</strong> types,
values returned (in whatever Object) are always in the “byte” range of <samp>0-255</samp> for
the <abbr>sRGB</abbr> color-space-model (they may be numeric-floats if <code>.config.roundRGB==false</code>,
so we can’t exactly call them “bytes” or call this the <abbr>sRGB</abbr> color-model);
and factors from <samp>0.0–1.0</samp> for most other color-models,
excepting “-axis” and “Chroma” values (<strong>¡not</strong> “Chroma∝”<strong>!</strong> That is a factor!).</p>
<h4 id='introuducing …A_'>Introducing … Color-Arrays (<code>…A_Array</code>s) & Color-Objects (<code>…A_Color</code>s)</h4>
<p>Before we continue describing the <code>RGB_Calc</code> class, we need to take a fast look at
SoftMoon-WebWare’s “color-Arrays” (<abbr title='also known as'>a.k.a.</abbr> <code>…A_Array</code>s)
and “Color-Objects” (<abbr title='also known as'>a.k.a.</abbr> <code>…A_Color</code>s).
The <code>…A_Array</code>s construct quickly like normal simple Arrays,
as they are extensions of the <code>Array</code> class, but they have prototyped getters & setters
that allow you to access a color-model’s dimensional values through named properties like: <code>clr.b, clr.blu, clr.blue, clr.alpha</code>, etc.
For many color-spaces, they also have prototyped conversion functions to related color space models.
These <code>…A_Array</code>s also have nice custom <code>.toString()</code> prototyped methods that allow you to easily specify the output format.
They filter out any <code>undefined</code> alpha (opacity) values you may pass in upon construction,
so the <code>undefined</code> value does not become a member of the resulting array (keeping its length value trimmed),
and therefore they construct just a tad bit slower than a simple <code>Array</code>.
For the <code>RGBA_Array</code> class, the constructor also takes an optional <code>profile</code> argument;
at this time, only <code>"sRGB"</code> is valid for <code>profile</code>,
but eventually other RGB color spaces will be supported (Wide-Gamut RGB (UHD), pro-Photo RGB, Adobe RGB, etc.).
For the <code>XYZA_Array</code> class, the constructor also takes optional <code>illuminant</code> & <code>observer</code> arguments;
the list of illuminants can be found below, but for now the only observer supported is the standard <code>"2°"</code>.
If you don’t supply these <code>illuminant</code> & <code>observer</code> arguments,
they default to <code>"D65"</code> & <code>"2°"</code>.
The <code>…A_Color</code>s construct a little slower, so they are not recommended for (graphics creation) algorithmic loops;
but they offer “audited” input once constructed, if you need such.
Unlike their parent <code>…A_Array</code>s, they do not simply “ignore” an <code>undefined</code> alpha (opacity) value
if you pass one in: they fall back on the <a href='#ConfigStack'>▼<code>.config.defaultAlpha</code> value</a>.
They are extensions of their corresponding <code>…A_Array</code>s, so they have all those properties and methods, also.
There are <a href='#…A_'>▼more details about <code>…A_Array</code>s & <code>…A_Color</code>s</a> which can be found below.</p>
<h4>Constructing new Calculators</h4>
<p id='auditing'>Besides being a simple stand-alone static-functional class,
<code>RGB_Calc</code> is also a Class constructor to create new “calculators” with their own set of options.
But the calculators you can construct can offer greater input flexibility, specifically, but not limited to,
the ability to <strong>“audit”</strong> (interpret) a <code>String</code> similar to a <abbr>CSS</abbr> color-definition;
except it can interpret any color-model that <code>RGB_Calc</code>
is set-up to convert (you can plug-in your own and extend it),
as well as <a href='#palettes'>▼“named-colors” from any of the “palettes”</a> that are loaded.
The individual <a href='#quick-audit-mini'>▼<strong>“audit”</strong> conversion/luminance/contrast-ratio functions</a> can accept
a single <code>String</code> with the values separated by commas and/or spaces,
or an <code>Array</code> of values in either <code>String</code> or numeric (<code>Number</code>) format.
They generally (except see special option <code>RGB_Calc.config.inputAsFactor</code>)
accept values with limits that a <abbr>CSS</abbr> definition would impose:
i.e. <kbd>0</kbd>–<kbd>255</kbd> for sRGB, and <kbd>0%</kbd>–<kbd>100%</kbd> for others,
or for hue-angles, any value is accepted and automatically transformed into a standard angle
(since angles are circular, 45° = 405° = −335°).
Any value outside the limits will not be accepted, and may throw an <code>Error</code> if you choose
(see <code>RGB_Calc.config.onError</code>).
Besides the individual conversion functions, a newly constructed “audit” <code>RGB_Calc</code> Class object
offers a “general input” interpreter that interprets just about any format you throw at it and returns
the <abbr>RGBA</abbr> values in the <code>Object</code> of your choice;
an explanation of the <a href='#valid_strings'>▼<code>String</code> values it can interpret</a> follows below:</p>
<code class='block'>const myCalc=new SoftMoon.WebWare.RGB_Calc;
const c1=myCalc( "HSL(0.3turn, 50%, 84%)" );
// By default, the returned value is a custom RGBA_Color object;
// its .toString('css') method yields: "RGB(202, 235, 194)"
console.log(c1);
const c2=myCalc.to.hsl( "CMYK(14.0255%, 0%, 17.44681%, 7.84314%)" );
// Here, the CMYK color is converted to RGB internally, and then to HSL.
// RGB values may be rounded if myCalc.config.roundRGB=true
// and this can affect the final HSL conversion values slightly.
// Note that rounding the RGB values makes the
// final HSL values a true representation of the sRGB color-space.
// By default, the returned value is a custom HSLA_Color object;
// its .toString('css') method yields: "HSL(108.29deg, 50.61728%, 84.11765%)"
console.log(c2);
const c3=myCalc.from.hsl("108.29deg, 50.61728%, 84.11765%");
// By default, the returned value is a custom RGBA_Color object;
// its .toString('css') method yields: "RGB(202, 235, 194)"
console.log(c3);
// you can even leave out the units:
// “audit” calculators by default use percents not factors (except for RGB uses bytes!)
// except for hue-angles use the unit in myCalc.config.hueAngleUnit ("deg" by default)
// UNLESS myCalc.config.inputAsFactor=true ←then (almost) ALL values are considered factors (0.0–0.1)
// ↑↑↑ except .config.inputAsNumeric applies for some color-models
const c4=myCalc.from.hsl("108.29, 50.61728, 84.11765");
console.log(c4);
myCalc.config.inputAsFactor=true; // we can also use .config.stack(…)
const c5=myCalc.from.hsl("0.3, 0.5, 84%") //←all values are factors, except 84% because it has a qualifier!
const c6=myCalc.from.hsl([0.3, 0.5, "84%"]) //←we can even pass an array of numeric and/or string values
// Just like the “quick-calc” examples above, we can also get conversion values
// returned in a simple Array, a “color-Array” (…A_Array), or YOUR custom Class object,
// using myCalc.config.stack()
// or by changing myCalc.config. values directly.</code>
<h4 id='quick-audit-mini'><strong>“audit”</strong>, <strong>“quick”</strong>, & “mini” calculators</h4>
<p>When you create your own new calculator, it can be either an “audit” or “quick” type.
This is controlled by passing <code>true</code> for a <a href='#quick'>▲“quick” calculator</a>,
or <code>false</code> (the default) for an <a href='#auditing'>▲“auditing” calculator</a>,
as the 2<numerance>nd</numerance> parameter to the constructor.
You can even make your own custom “mini” calculators that only have the conversion function(s) you specifically need.
The “mini” calculator descriptor <code>Object</code> (passed into the constructor as the 3<numerance>rd</numerance> parameter)
can have “to” and/or “from” options (property keys), and their values should be an <code>Array</code>
listing the conversion functions as individual <code>String</code> values.
You can have any combination of these options, such as a “quick-mini” calculator that returns native <code>Array</code>s.</p>
<code class='block'>// This is the calculator that the “Rigden-colorblind_websafe-table_interpolator”
// plug-in for this <code>RGB_Calc</code> class uses in its own internal workings.
// It is a “quick” calculator that only has RGB to HCG functionality, and it returns an Array.
const rgb_calc=new SoftMoon.WebWare.RGB_Calc(
{HCGA_Factory: Array, defaultAlpha: undefined},
true,
{to:['hcg']}
);</code>
</div>
<div class='help'>
<h4 id='valid_strings'>Valid <code>String</code> values for colors include:</h4>
<ul id='color-space-models'>
<li><abbr>RGB</abbr> {red, green, blue} values as:
<ul>
<li>integer byte values (<kbd>0—255</kbd>)</li>
<li>percent ratios (<kbd>0%—100%</kbd> — ¡be sure to use the percent <kbd>%</kbd> symbol with <abbr>RGB</abbr> values!)</li>
</ul>
<p>Each value may be separated by spaces/commas.
You may wrap() or prefix: the values with <kbd>rgb( )</kbd> or <kbd>rgb:</kbd> but that is not necessary.</p></li>
<li><abbr>RGB</abbr> values in hexadecimal (<abbr title='also known as'>a.k.a.</abbr> <abbr>hex</abbr>) with or without the leading <kbd>#</kbd> symbol.</li>
<li>various different color-space models including:
(items marked with <range>✢</range> adapt to the <abbr title='Red, Green, Blue'>RGB</abbr> color-space profile you are using)
(items marked with <range>✓</range> are limited to the <abbr title='standard Red, Green, Blue'>sRGB</abbr> color-space)
(items marked with <range>❇</range> can take you beyond the <abbr title='Red, Green, Blue'>RGB</abbr> color-space profile you are using)
<ul class='range'>
<li><range>✣</range><abbr>CMYK</abbr> {Cyan, Magenta, Yellow, Black}</li>
<li><range>✣</range><abbr>CMY</abbr> {Cyan, Magenta, Yellow}</li>
<li><range>✣</range><abbr>HSV</abbr><br><abbr>HSB</abbr> {Hue, Saturation, Value / Brightness}</li>
<li><range>✣</range><abbr>HSL</abbr> {Hue, Saturation, Lightness}</li>
<li><range>✣</range><abbr>HWB</abbr> {Hue, Whiteness, Blackness}</li>
<li><range>✣</range><abbr>HCG</abbr> {Hue, Chroma∝, Gray} (<strong>¡Not</strong> the Munsell color system!)
<p>Chroma∝ is proportional (<kbd>0%—100%</kbd>) to the maximum chroma for the given Hue in the <abbr>RGB</abbr> color space (profile) you are using.
This is different from the “perceived chroma” (Chroma without the ∝ proportional symbol) of other color spaces.</p></li>
<li><range>✣</range><pseudo>Hue</pseudo> ← define only a <a href='#standardRGB'>▼“standard <abbr>RGB</abbr>”</a>
hue-angle-value and see the full-color (fully chromatic) tone of the hue.</li>
<li><range>✓</range><abbr>HSLᵤᵥ</abbr><br><abbr>HSLuv</abbr> {Hueᵤᵥ, Saturation, Lightnessᵤᵥ}</li>
<li><range>✓</range><abbr>OKHSV</abbr> {OK: Hue, Saturation, Value (Brightness)}</li>
<li><range>✓</range><abbr>OKHSL</abbr> {OK: Hue, Saturation, Lightness}</li>
<li><range>✓</range><abbr>OKHWB</abbr> {OK: Hue, White, Black}</li>
<li><range>✓</range><abbr>OKHCG</abbr> {OK: Hue, Chroma∝, Gray}
<p>See <abbr>HCG</abbr> above↑</p></li>
<li><range>❇</range><abbr>Lab</abbr> {Lightness, a-axis, b-axis}
<aka>(<abbr title='International Commission on Illumination'>CIE</abbr> <abbr>L*a*b*</abbr> color space)</aka>
→ <code>(L,a,b,α) ‖ (<var>illuminant</var>, L,a,b,α)</code>
<specs><code>0 ≤ L ≤ (100‖100%), (-170‖-136%) ≤ (a,b) ≤ (170‖136%)</code>
← where <code>100%=125</code> is the <abbr title='Cascading Style Sheet'>CSS</abbr> standard.</specs>
The alpha (opacity) <code>α</code> value is optional as always;
and the optional <var>illuminant</var> may be <code>D50</code> (the default — as used by <abbr>CSS</abbr>) or <code>D65</code></li>
<li><range>❇</range><abbr>LCh</abbr> {Lightness, Chroma, Hue}
<aka>(<abbr title='International Commission on Illumination'>CIE</abbr> <abbr>LCh</abbr> color space)</aka>
→ <code>(L,C,h,α) ‖ (<var>illuminant</var>, L,C,h,α)</code>
<specs><code>0 ≤ L ≤ (100‖100%), 0 ≤ C ≤ (230‖154%)</code>
← where <code>100%=150</code> is the <abbr title='Cascading Style Sheet'>CSS</abbr> standard.</specs>
The alpha (opacity) <code>α</code> value is optional as always;
and the optional <var>illuminant</var> may be <code>D50</code> (the default — as used by <abbr>CSS</abbr>) or <code>D65</code></li>
<li><range>❇</range><abbr>Luv</abbr> {Lightness, u-axis, v-axis}
<aka>(<abbr title='International Commission on Illumination'>CIE</abbr> <abbr>L*u*v*</abbr> color space)</aka>
<specs><code>0 ≤ L ≤ (1.0‖100%), (-215‖-100%) ≤ (u,v) ≤ (215‖100%)</code></specs>
<p>Color space models based on <abbr>Luv</abbr> have the “ᵤᵥ” or “uv” suffix.</p></li>
<li><range>❇</range><abbr>LChᵤᵥ</abbr><br><abbr>LChuv</abbr> {Lightnessᵤᵥ, Chromaᵤᵥ, Hueᵤᵥ}
<aka>(<abbr title='International Commission on Illumination'>CIE</abbr> <abbr>LChᵤᵥ</abbr> color space)</aka>
<specs><code>0 ≤ L ≤ (1.0‖100%), 0 ≤ C ≤ (304‖100%)</code></specs></li>
<li><range>❇</range><abbr>OKLab</abbr> {OK: Lightness, a-axis, b-axis}
<specs><code>0 ≤ L ≤ (1.0‖100%), (-0.4‖-100%) ≤ (a,b) ≤ (0.4‖100%)</code></specs>
<p>All the “<abbr ok>OK</abbr>” color spaces are based on <abbr>OKLab</abbr></p></li>
<li><range>❇</range><abbr>OKLCh</abbr> {OK: Lightness, Chroma, Hue}
<specs><code>0 ≤ L ≤ (1.0‖100%), 0 ≤ C ≤ (0.5‖125%)</code>
← where <code>100%=0.4</code> is the <abbr title='Cascading Style Sheet'>CSS</abbr> standard</specs></li>
<li><range>❇</range><abbr>Jᶻaᶻbᶻ</abbr><br><abbr>Jzazbz</abbr> {Lightness, az-axis, bz-axis}
<specs><code>0 ≤ Jᶻ ≤ (1.0‖100%), (-0.5‖-50%) ≤ (aᶻ,bᶻ) ≤ (0.5‖50%)</code></specs></li>
<li><range>❇</range><abbr>JᶻCᶻhᶻ</abbr><br><abbr>JzCzhz</abbr> {Lightness, Chroma, Hue}
<specs><code>0 ≤ Jᶻ ≤ (1.0‖100%), 0 ≤ Cᶻ ≤ (≈0.7071‖70.71%)</code> ← √(0.5²+0.5²)</specs></li>
<li><range>❇</range><abbr>ICᵀCᴾ</abbr><br><abbr>ICtCp</abbr> {Intensity, Tritanopia-axis, Protanopia-axis}
<specs><code>0 ≤ I ≤ (1.0‖100%), (-0.5‖-50%) ≤ (Cᵀ,Cᴾ) ≤ (0.5‖50%)</code></specs></li>
<li><range>❇</range><abbr>IChᵀᴾ</abbr><br><abbr>IChtp</abbr> {Intensity, Chromaᵀᴾ, hueᵀᴾ}
<specs><code>0 ≤ I ≤ (1.0‖100%), 0 ≤ Cᵀᴾ ≤ (≈0.7071‖70.71%)</code> ← √(0.5²+0.5²)</specs></li>
<li><range>❇</range><abbr>XYZ</abbr>
<aka>(<abbr title='International Commission on Illumination'>CIE</abbr> <abbr>XYZ</abbr> color space)</aka>
→ <code>(X,Y,Z,α) ‖ (<var>illuminant</var>, X,Y,Z,α) ‖ (<var>RGB-profile</var>, X,Y,Z,α) ‖ (<var>RGB-profile</var>, <var>illuminant</var>, X,Y,Z,α)</code>
<p>I am not sure of the exact limits of the input values, but I <em>think maybe</em> generally
<code>0 ≤ X ≤ 0.950489, 0 ≤ Y ≤ 1, 0 ≤ Z ≤ 1.0883</code> seems to be fair for the <abbr>D65</abbr> illuminant…?</p>
<p>The “<var>illuminant</var>” and/or “<var>RGB-profile</var>” is optional as shown; so is the alpha (opacity) value (α) as it always is.
Currently, only <code>"sRGB"</code> is valid for “<var>RGB-profile</var>”.
There are currently 7 different legal values for “<var>illuminant</var>”
(these values are case <strong>sensitive</strong> and don’t miss the underscores _ ).
When you define an “illuminant”, you are specifying the mathematical matrix that will be used for the conversion,
and the “observer” is implicit with this matrix.
At this time, all supplied matrices use the “2°” observer,
but you can hack and expand the list of available matrices if you need.
<code>"D65"</code> is the default illuminant as this is the same as used for
the <abbr title='standard Red-Green-Blue'>sRGB</abbr> color-space.</p>
<dl id='illuminants'>
<dt><span>D65</span></dt>
<dd><specs><span>(Observer = 2°, Illuminant = D65)</span></specs>
This default value uses the XYZ→RGB matrix provided by the
<a target='XYZ' href='https://www.w3.org/TR/css-color-4/#color-conversion-code'>►World-Wide-Web Consortium</a>.</dd>
<dt><span>D65_2003</span></dt>
<dd><specs><span>(Observer = 2°, Illuminant = D65)</span></specs>
Uses the XYZ→RGB matrix <a target='XYZ' href='https://en.wikipedia.org/wiki/SRGB'>►provided by the
International Electrotechnical Commission</a>.
Wikipedia QUOTE: <q>Amendment 1 to IEC 61966-2-1:1999, approved in 2003 … also recommends a higher-precision XYZ to sRGB matrix</q>.
If you have <abbr title='X-Y-Z color-space'>XYZ</abbr> color data from back in the day,
especially if it was converted <em>from</em> <abbr title='standard Red-Green-Blue color-space'>sRGB</abbr> data,
you might want to use this matrix to convert it back <em>to</em> <abbr title='standard Red-Green-Blue color-space'>sRGB</abbr>.</dd>
<dt><span>D65_classic</span></dt>
<dd><specs><span>(Observer = 2°, Illuminant = D65)</span></specs>
Uses the “old-school” XYZ→RGB matrix that
<a target='XYZ' href='https://en.wikipedia.org/wiki/SRGB'>►Wikipedia says</a> has
<q>… numerical values [which] match those in the official sRGB specification</q>.
The highly referenced site (by others, for many years) <a target='XYZ' href='https://www.easyrgb.com/en/math.php'>►Easy RGB</a>
uses this matrix.
If you have <abbr title='X-Y-Z color-space'>XYZ</abbr> color data from back in the day,
especially if it was converted <em>from</em> <abbr title='standard Red-Green-Blue color-space'>sRGB</abbr> data,
you might want to use this matrix to convert it back <em>to</em> <abbr title='standard Red-Green-Blue color-space'>sRGB</abbr>.</dd>
<dt><span>D65_Lindbloom</span></dt>
<dd><specs><span>(Observer = 2°, Illuminant = D65)</span></specs>
Uses the XYZ→RGB matrix provided by
<a target='XYZ' href="http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html">►Bruce Lindbloom</a>,
a respected color-theory researcher who’s math is supposedly “more correct”.</dd>
<dt><span>D50</span></dt>
<dd><specs><span>(Observer = 2°, Illuminant = D50)</span></specs>
There is no (known) “standard” matrix for this illuminant. We use “D50_Lindbloom” for now.
<dt><span>D50_Lindbloom</span></dt>
<dd><specs><span>(Observer = 2°, Illuminant = D50)</span></specs>
Uses the XYZ→RGB matrix provided by
<a target='XYZ' href="http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html">►Bruce Lindbloom</a>,
a respected color-theory researcher who’s math is supposedly “more correct”.
The “D50” illuminant is the gateway to other <abbr title='Red-Green-Blue'>RGB</abbr> color-spaces
like “ProPhoto RGB” or “Wide Gamut RGB”.
At this time, this is our “default” <code>D50</code> matrix,
and is used internally when calculating values for the
<abbr title='International Commission on Illumination'>CIE</abbr> <abbr>L*a*b*</abbr> color-space model.</dd>
<dt><span>D65_Wickline</span></dt>
<dd><specs><span>(Observer = 2°, Illuminant = D65)</span></specs>
Uses the XYZ→RGB matrix provided by
<a target='XYZ' href="http://colorlab.wickline.org/colorblind/colorlab/engine.js">►Matthew Wickline</a>,
a respected color-theory researcher who created one of the original
color-blind filter algorithms. He uses this high-precision matrix in his calculations.</dd>
</dl>
</li>
</ul>
<p>Use models by wrapping() or prefixing: their given values.
Values are given as percent ratios (<kbd>0%—100%</kbd> with or without the percent sign %);
except as noted, -axis and Chroma (<strong>¡not</strong> Chroma∝<strong>!</strong>)
values are considered “numeric” if they don’t have a percent sign, and they may be more than <kbd>100%</kbd>;
and except Hue values are given in angular values using one of the following units:
(the default unit used when none is specified is found in an <code>RGB_Calc</code> object’s <code>.config.hueAngleUnit</code> property)</p>
<ul>
<li>in degrees (<kbd>0°—360°</kbd> ← post-fixed using the <kbd>°</kbd> symbol or “<kbd>deg</kbd>”).</li>
<li>in radians (<kbd>0ᴿ–2πᴿ≈6.2831853ᴿ</kbd> ← post-fixed using the <kbd>ᴿ</kbd> symbol, the <kbd>ᶜ</kbd> symbol, or “<kbd>rad</kbd>”).</li>
<li>in gradians (<kbd>0ᵍ—400ᵍ</kbd> ← post-fixed using the <kbd>ᵍ</kbd> symbol or “<kbd>grad</kbd>”).</li>
<li>in % of a turn (<kbd>0%—100%</kbd> ← post-fixed using the <kbd>%</kbd> symbol).</li>
<li>of a turn (<kbd>0●—1●</kbd> ← post-fixed using the <kbd>●</kbd> symbol or “<kbd>turn</kbd>”).</li>
</ul></li>
<li>Any of the available <a href='#palettes'>▼named “palette” colors</a>.
Colors should be prefixed: or wrapped() with the appropriate color-palette name;
except <abbr>CSS</abbr> colors do not need to be wrapped or prefixed by default.
(The default color-palette name can be found and changed at <code>SoftMoon.defaultPalette</code>)
“Named color” palettes may have sub-palettes; you may or may not need to include the sub-palette name
in your color-spec, depending on the palette.
Generally, if all the colors in the parent palette and its sub-palettes have different names,
no sub-palette is required in the spec.
<code class='block'>ANSI: 35
ANSI: 8-bit: shades and tones: 35</code>
</li>
</ul>
<p>You may specify opacity (the opposite of transparency) in any of the color space models
by adding an additional factor (0.0—1.0) or percent (0%—100% ← you must use the percent % sign).
This is called the “alpha” (Greek α) channel in technical terms.
The color-space model names may or may not end with an additional “A” (for example, RGB vs. RGBA).
Per CSS4 specifications, the opacity value may also be separated with a <kbd>/</kbd> symbol
that is itself preceded and followed by a space;
for example <kbd>RGBA(0, 153, 255 / 62%)</kbd>
Note the “loose” interpretation of CSS specs allows commas with the <kbd>/</kbd> alpha separator.
Hex-RGB values may have an additional 2 hex digits to specify the alpha;
for example <kbd>#ADDCAD80</kbd>
Named colors may use the same alpha specification for color space models described above,
but it must end with either a semicolon <kbd>;</kbd> or a space followed by <kbd>opacity;</kbd>
For examples:</p>
<ul>
<li><kbd>Green 30%;</kbd></li>
<li><kbd>DodgerBlue, 78%;</kbd></li>
<li><kbd>ANSI: 35 / .84 opacity;</kbd></li>
</ul>
<p>Note that named colors may already have an alpha value, and if you “add on” another alpha value as shown above,
it will be multiplied by the color’s existing one. For example, if a named-color already has
an alpha value of 50%, and you add on another 50% alpha, the final alpha value is 25%.
You can forbid this action using <code>myCalc.config.forbidAddOnAlpha=true;</code>
(or by using <code>myCalc.config.stack({forbidAddOnAlpha:{value:true}});</code>).
You can modify this process through the <code>multiplyAddOnAlpha(α1, α2)</code> method of your calculator.</p>
<h5>Examples:</h5>
<ul>
<li>These all give the same <span style='color: red;'>red</span> color:
<ul>
<li><kbd>255 0 0</kbd></li>
<li><kbd>rgb (255 0 0)</kbd></li>
<li><kbd>rgb(255, 0 0)</kbd></li>
<li><kbd>#FF000</kbd></li>
<li><kbd>ff0000</kbd></li>
<li><kbd>HCG(0deg, 100, 50)</kbd></li>
<li><kbd>HSL: 0°, 100%, 50%</kbd></li>
<li><kbd>HSV: 0° 100% 100</kbd></li>
<li><kbd>red</kbd></li>
<li><kbd>CSS: red</kbd></li>
<li><kbd>X11( RED )</kbd></li>
</ul>
</li>
<li>These all give the same <span style='color: lightSkyBlue;'>blueish</span> color:
<ul>
<li><kbd>135, 206, 250</kbd></li>
<li><kbd>RGB (135, 206, 250)</kbd></li>
<li><kbd>RGB: 135, 206, 250</kbd></li>
<li><kbd>#87cefa</kbd></li>
<li><kbd>87ceFA</kbd></li>
<li><kbd>hcg(202.96deg, 45.098% 96.429%)</kbd></li>
<li><kbd>hsl:56.3768%,92,75.49</kbd></li>
<li><kbd>hsv ( .563768turn 46% 98.039% )</kbd></li>
<li><kbd>lightSkyBlue</kbd></li>
<li><kbd>css (LiGHTSKyBLue)</kbd></li>
<li><kbd>X11:lIghtskYblUE</kbd></li>
</ul>
</li>
</ul>
</div><!-- close help -->
<div class='object'>
<h4>The properties & methods of the <code>RGB_Calc</code> object, and its class instances</h4>
<h3><code>RGB_Calc</code></h3>
<dl>
<dt><code>.config</code></dt>
<dd>holds this calculator’s configuration options.
It is an instance of an extension of the <a href='#ConfigStack'><code>▼ConfigStack</code></a> Class.
“Quick” calculators use the <code>RGB_Calc.definer.quick.ConfigStack</code> Class, and
“auditing” calculators use the <code>RGB_Calc.definer.audit.ConfigStack</code> Class.</dd>
<dt><code>.to</code></dt>
<dd>holds functions converting sRGB to other color-models.</dd>
<dt><code>.from</code></dt>
<dd>holds functions converting from other color-models to sRGB.</dd>
<dt><code>.luminance(<var>color</var>)</code></dt>
<dd>This non-conversion function takes the color you input and calculates its
“average perceived relative Luminance” — the luminance perceived by
the average person viewing the average monitor,
relative to “pure white” as displayed by the same monitor.
See the <a href='https://www.w3.org/TR/WCAG21/#dfn-relative-luminance' target='W3C'>►<abbr>W3C</abbr>’s formula for luminance</a>
except that <code>RGB_Calc</code> also factors in the alpha (opacity) value:
if the color is partially transparent,
its luminance is correspondingly partially reduced.
Luminance is used internally by the <code>.contrastRatio()</code> and <code>.to.contrast()</code> methods.</dd>
<dt><code>.contrastRatio(<var>foreground</var>, <var>background</var>)</code></dt>
<dd>This non-conversion function calculates the contrast ratio between two colors
based on their “average perceived relative Luminance” (as defined above).
See the <a href='https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio' target='W3C'>►<abbr>W3C</abbr>’s formula for contrast</a>
except that <code>RGB_Calc</code> also factors in the alpha (opacity) value of the foreground:
if the foreground color is partially transparent,
its luminance is correspondingly partially reduced
and some of the luminance of the background color is correspondingly added in.
This result will of course ultimately be skewed if the background color is partially transparent also,
based on the (third) color behind it, unless said third color is fully opaque black.</dd>
<dt><code>.install()</code></dd>
<dd>Used to install different conversion functions “on the fly,”
such as when there are two different color-blind filters available, etc.</dd>
<dt class='internal'><code>.γCorrect_linear_RGB()</code></dd>
<dd>Used internally to gamma-correct RGB values from various conversion functions,
and then outputs the values through <code>.ouput_clampedRGB()</code></dd>
<dt class='internal'><code>.linearize_γCorrected_RGB()</code></dd>
<dd>Used internally to prepare standardized (gamma-corrected) RGB values for conversion calculations.</dd>
<dt class='internal'><code>.output_sRGB()</code></dt>
<dd>filters all sRGB output, according to this calculator’s
<code>.config.roundRGB</code> flag and returns the output using the
object-constructor defined by this calculator’s <code>.config.RGBA_Factory</code></dd>
<dt class='internal'><code>.output_RGB()</code></dt>
<dd>for now, the same as <code>.output_sRGB</code>;
eventually it will handle <abbr>P3-RGB</abbr>,
Adobe <abbr>RGB</abbr>, ProPhoto <abbr>RGB</abbr>, Wide-Gamut <abbr>RGB</abbr> (<abbr>UHD</abbr>), etc.</dd>
<dt class='internal'><code>.output_clampedRGB()</code></dt>
<dd>filters all RGB (factors from 0.0—1.0) output by first adjusting the bit-depth,
then verifies that the values are in the gamut of the current RGB profile,
and returns the output through the
object-constructor defined by this calculator’s <code>.config.RGBA_Factory</code>,
or if out-of-gamut, passes the color to <code>.config.clamp_sRGB()</code> for customized clamping.</dd>
<dt class='internal'><code>.getByte()</code></dt>
<dd>filters sRGB input and guarantees results from <kbd>0—255</kbd></dd>
<dt class='internal'><code>.getFactor()</code></dt>
<dd>filters input and returns a factor from <kbd>0—1</kbd>,
or <code>false</code> if the value is out-of-range.
Input may be a string or number, and may be a percent (0-100),
or already a factor if <code>.config.inputAsFactor</code> is true;
but strings with a <code>%</code> qualifier at the end are always considered percents.</dd>
<dt class='internal'><code>.getHueFactor()</code></dt>
<dd>filters input and returns a factor from <kbd>0—1</kbd>;
note hue-angles are circular, so no value is out-of-range.
The conversion factor is determined by <code>.config.hueAngleUnit</code>
or the value may already be a factor if <code>.config.inputAsFactor</code> is true;
but strings with a hue-angle-unit qualifier at the end respect that conversion factor.
If the hue-angle-unit is not recognized, this function returns <code>false</code>.
Note that <code>RGB_Calc</code> uses the hue 360° (2πrad, 400grad, 1turn, 100%, etc.) to specify
that the “color” is a gray-tone (i.e. “all the colors at once”) when it makes a conversion,
whereas usually 360° normalizes to 0° (the “red” hue when using “standard <abbr title='red, green, blue'>RGB</abbr> hues”).
When calculating the hue-factor, it therefore will not normalize this specific hue value;
however, 720° (etc.) normalizes to 0° as usual.
You will only notice this result when using the <code>ColorFactory.createColor()</code> method.
This is useful when creating gradients through hue-based color-spaces,
when a color in the gradient is a gray-scale tone:
you may want to grade the adjacent color straight to the gray tone without changing the hue (use hue 360°),
or you may want to grade to the gray tone while <strong>also</strong> grading through hues (use any hue except 360°).
<p id='standardRGB'>Note that hue-values for different color space models are not all the same.
“Standard <abbr title='red, green, blue'>RGB</abbr>” hues are based on an RGB color space,
with red mapped at 0°, green (CSS: lime) at 120°, and blue at 240°,
and with yellow mixing at 60°, cyan mixing at 180°, and magenta mixing at 300°.
The <abbr>CIE LCh</abbr> (based on <abbr>CIE Lab</abbr>),
<abbr>CIE LChᵤᵥ</abbr> & <abbr>HSLᵤᵥ</abbr> (based on <abbr>CIE Luv</abbr>),
and <abbr>OKLCh</abbr> <abbr>OKHSL</abbr> <abbr>OKHSV</abbr> <abbr>OKHWB</abbr> & <abbr>OKHCG</abbr> (based on <abbr>OKLab</abbr>)
color models use three different hue-mappings, depending on the color space they are based on.</p></dd>
<dt class='internal'><code>.getAxis()</code></dt>
<dd>filters input and returns an axis value (or a chroma value),
or <code>false</code> if the value is out-of-range.
Input may be a string or number, and may be an axis-value or chroma-value number
(value limits depends on the color-model’s input),
or already a factor if <code>.config.inputAsFactor</code> is true <strong><em>and</em></strong> <code>.config.inputAsNumeric</code> is false;
but strings with a <code>%</code> qualifier at the end are always considered percents.</dd>
<dt class='internal'><code>.getAlpha()</code></dt>
<dd>filters input and returns a factor from <kbd>0—1</kbd>,
or <code>false</code> if the value is out-of-range.
Input may be a string or number.
Input values are considered factors from <code>0.0</code>–<code>1.0</code> unless they have <code>%</code> qualifiers.</dd>
<dt class='internal'><code>.factorize()</code></dt>
<dd>filters an <code>Array</code> of values using <code>this.getFactor()</code>,
<code>this.getHueFactor()</code>, and <code>this.getAlpha()</code>,
and returns either:
<ul>
<li>a new <code>Array</code> (with the factorized values) when <code>.config.preserveInputArrays=true</code></li>
<li>the same <code>Array</code> (with the modified values) when <code>.config.preserveInputArrays=false</code></li>
<li><code>false</code> if <code>this.getFactor()</code> or <code>this.getHueFactor()</code> or <code>this.getAlpha()</code>
returns <code>false</code></li>
</ul></dd>
<dt class='internal'><code>.applyAlpha()</code></dt>
<dd>This function applies an alpha value to a given color-object.
The two alpha values are multiplied according to the
formula in <code>multiplyAddOnAlpha()</code> (see below).
It is used when you pass a “named-color” to an “auditing” calculator,
and you specify an “add-on” alpha value to a color that already has an alpha value.
For example: <kbd>skyPalette: clouds / 84% opacity;</kbd>
Suppose this color (<kbd>skyPalette: clouds</kbd>) is a partly transparent blueish-graytone: <kbd>RGB(50%, 55%, 70%, 80%)</kbd>
Then the final alpha result is (by the default formula): <code>80% × 84% = 67.2%</code><br>
If you use your own custom color-objects for <abbr>RGB</abbr> calculator output,
you may need to update or replace this function to work with them,
if they don’t have an <code>.alpha</code> property,
and they are not an <code>Array</code> or a child-class of <code>Array</code>.</dd>
<dt class='internal'><code>.multiplyAddOnAlpha()</code></dt>
<dd>This function takes two alpha values and multiples them according to a specific formula.
You may modify the formula to suit your needs by replacing this function.</dd>
<dt class='internal'><code>.convertColor()</code></dt>
<dd>used by <a href='#auditing'>▲“auditing”</a> <code>.to</code> functions to interpret the given color
using the “catch-all” function (see <code>.$()</code> below)
and convert it to sRGB before further converting to the final format.</dd>
<dt class='internal audit'><code>.$()</code></dt>
<dd>This is only found on <a href='#auditing'>▲“auditing”</a> instances of the <code>RGB_Calc</code> class
and is a mirror of the “catch-all” function that is the central to that class.
In other words:
<code class='block'>var rgb, myCalc = new SoftMoon.WebWare.RGB_Calc();
rgb=myCalc('red') //the easy preferred way
rgb=mycalc.$('red') //the long way
</code>
This allows methods of an “audit” <code>RGB_Calc.to</code> Class instance to access the “catch-all.”</dd>
<dt class='static'><code>.definer</code></dt>
<dd>data-Object (static property of <code>RGB_Calc</code> only).
This is where all the stuff is stored to create a new calculator instance.
Within this Object, you can find goodies such as the
<code>RGB_Calc.definer.quick.ConfigStack</code> and
<code>RGB_Calc.definer.audit.ConfigStack</code> constructors and their prototypes.</dd>
<dt class='static'><code>.hueAngleUnitFactors</code></dt>
<dd>data table (static property of <code>RGB_Calc</code> only)</dd>
<dt class='static external'><code>.colorblindProviders</code></dt>
<dd>table of color-blind filter-functions and their meta-data. (static property of <code>RGB_Calc</code> only,
and only present when an external color-blind filter provider file is present)</dd>
</dl>
</div>
<div class='help'>
<p>In general, only the first 6 listed properties (methods) of <code>RGB_Calc</code> (above)
are used, and in common use, only the first 5 listed.
There are 2 different color-blind filters currently available for the <code>RGB_Calc</code> Class library.
Both install themselves as <code>RGB_Calc.to.colorblind()</code> methods;
but only one can work at a time.
They also install their meta-data in the static <code>RGB_Calc.colorblindProviders</code> property.
You can use <code>RGB_Calc.install('colorblind', 'Rigden')</code>
or <code>RGB_Calc.install('colorblind', 'Wickline')</code>,
and the filter you choose will become the one that is active,
not only in <code>RGB_Calc.to</code> but in all <strong>future</strong> calculators
constructed (using for example <code>myCalc = new RGB_Calc();</code>).
If you use, for example <code>myCalc.install('colorblind', 'Rigden')</code> then
the colorblind filter you install will only take effect on that individual instance
of the <code>RGB_Calc</code> Class.</p>
<p>The <code>RGB_Calc.to</code> and <code>RGB_Calc.from</code> methods are all lowercase,
and the <code>RGB_Calc.from</code> methods <em>must</em> be for
the “catch-all” <code>String</code> filtering function to recognize them.
You may add to them as you wish.
The format makes programming with them simple & easy to de-localize,
allowing, for examples: <code>RGB_Calc.from[model]</code> or <code>myCalc.to[model]</code>.
There are also <code>RGB_Calc.to.contrast()</code> and <code>RGB_Calc.to.shade()</code> methods,
but of course not similar “from” methods.
“Contrast” returns either “black” or “white”, while “shade” either lightens or darkens a given color in contrast to the given color.</p>
<p>The <code>RGB_Calc.to</code> and <code>RGB_Calc.from</code> objects have as their prototype
the calculator they are attached to.
That means that the prototype of <code>RGB_Calc.to</code> or <code>RGB_Calc.from</code> is itself <code>RGB_Calc</code>.
Likewise, when you construct a custom calculator: <code>const myCalc = new RGB_Calc()</code>
the objects <code>myCalc.to</code> and <code>myCalc.from</code> have as their prototypes <code>myCalc</code>.
Therefore, any of the methods of <code>RGB_Calc.to</code>
or <code>RGB_Calc.from</code> (or similar to newly constructed calculators)
can refer to <code>this.config</code> and assess the <code>ConfigStack</code> instance
for the given calculator.</p>
<p>The other <code>RGB_Calc</code> <span class='internal'>methods</span> are all hooks to functions that are used internally.
These hooks are for plug-ins to the <code>RGB_Calc</code> Class to access.
You may use these hooks or hack them as you wish, but generally you need not worry about them.</p>
<p>Finally, the last 3 properties listed above of <code>RGB_Calc</code> are static properties
and are not included with class instances.
They are also available for your hacking or other use, but the <code>ConfigStack</code> constructors
and their <code>.prototype</code>s need special attention. </p>
<h4>Introducing … <code>ConfigStack</code>s</h4>
<p>Every “calculator,” as well as every <code>ColorFactory</code> instance,
gets its own instance of a <code>ConfigStack</code>
constructed object for its <code>.config</code> property,
and every <code>ConfigStack</code> instance is “attached” to its calculator or <code>ColorFactory</code> instance.
<a href='#quick'>▲“Quick calculators”</a> use the <code>SoftMoon.WebWare.RGB_Calc.definer.quick.ConfigStack</code> constructor,
and its prototyped “factories” are all <code>Array</code>s.
<a href='#auditing'>▲“Auditing calculators”</a>
use the <code>SoftMoon.WebWare.RGB_Calc.definer.audit.ConfigStack</code> constructor,
and its prototyped “factories” are all <code>…A_Color</code>s;
and <a href='#ColorFactory'>▼<code>ColorFactory</code> instances</a> extend the
<code>SoftMoon.WebWare.RGB_Calc.definer.audit.ConfigStack</code> even further, and use <code>A_Array</code>s.
Also, every custom “Color <code>Object</code>” (<abbr>a.k.a.</abbr> <code>…A_Color</code>s) (<code>RGBA_Color</code>s, <code>HSLA_Color</code>s, & <code>CMYKA_Color</code>s, etc., etc.)
gets its own <code>ConfigStack</code>, and those stacks each may have different “factory” defaults for each type of custom Color <code>Object</code> and their conversion methods:
<code>…A_Color</code> conversions output an <code>…A_Color</code> by default.
“Color-Arrays” (a.k.a <code>…A_Array</code>s, the parents to <code>…A_Colors</code>) have a shared config-stack in their prototype for each color-model,
and those stacks each may have different “factory” defaults for each type of custom <code>…A_Array Object</code> and their conversion methods:
and <code>…A_Array</code> conversions output an <code>…A_Array</code> by default.
The “ConfigStack” has in its prototype all the default configuration values and special methods.
You can easily change the values in any individual “calculator,” <code>ColorFactory</code> instance, or Color <code>Object</code> without affecting the others,
for example <code>RGB_Calc.config.roundRGB=true;</code>;
but if you change a config value in an <code>…A_Array</code>,
it affects <strong><em>all</em></strong> of the same Class of <code>…A_Array</code> instances:</p>
<code class='block'>my_HSL1=new HSLA_Array([0.2167, 1, 0.4]);
my_HSL2=new HSLA_Array([0.55, 1, 0.7]);
console.log(my_HSL1.toString()); // .config.stringFormat === "self" by default: HSLA_Array(… … …)
my_HSL2.config.stringFormat='CSS'; // ← affects ALL instances of HSLA_Array
console.log(my_HSL1.toString()); // .config.stringFormat === "CSS" now: HSL(… … …)
my_HSL1.config.stack({stringFormat:{value:"self"}}); // still affects ALL instances of HSLA_Array
console.log(my_HSL2.toString()); // .config.stringFormat === "self" now: HSLA_Array(… … …)
my_HSL1.config.cull(); // still affects ALL instances of HSLA_Array
//my_HSL2.config.cull(); // we could do this instead and it still affects ALL instances of HSLA_Array
console.log(my_HSL2.toString()); // .config.stringFormat === back to "CSS" now: HSL(… … …)
</code>
<p>The “ConfigStack” is a 2-dimentional Object-prototype-stack with methods to add to and remove from the stack:
specifically <code>RGB_Calc.config.stack()</code> and <code>RGB_Calc.config.cull()</code>.
When you <code>.stack()</code>, the “Stack” adds another new <code>Object</code>
to its own top-level making itself the prototype of this new <code>Object</code>,
and re-points its calculator’s <code>.config</code> property to this new <code>Object</code>.
(Remember, when JavaScript<abbr tm>™</abbr> looks for a property of an object and doesn’t find it there,
it looks in that object’s prototype and then recursively the prototype’s prototype until it finds the property;
this makes native JavaScript<abbr tm>™</abbr> Objects an ideal container for configuration values!)
Then you can change the configuration values as you like to temporarily suit your needs,
then use <code>.config.cull()</code> to return to the previous configuration values.
To make it even easier, <code>.config.stack()</code> accepts a parameter that is a JavaScript<abbr tm>™</abbr>
Object-Properties-Definer (see a good
<a href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties' target="Mozilla">►JavaScript<abbr tm>™</abbr> reference</a>):
for example <code>myCalc.config.stack({roundRGB:{value:false}, RGBA_Factory:{value:Array}});</code>.
In this way, you can temporarily modify individual configuration value(s) for an individual calculator
and then restore the original value(s), quickly and easily without having to keep track of said original value(s).
You can use <code>.config.stack()</code> multiple times and build the “ConfigStack”
to as many levels as you need; the <code>.config.reset()</code> method will remove
all the <code>Objects</code> stacked for the given calculator’s configuration
and bring it back to its given default values when it was originally constructed.</p>
<p>For any calculator, you don't need to <code>.stack()</code> the <code>.config</code>
to temporarily change the config values if you only use defaults in your calculator instance,
as the defaults are in the prototype. However, if you pass a <code>.config</code> descriptor
object to the <code>RGB_Calc</code> constructor, those values <strong>are</strong>
stored in the top level of your ConfigStack, and modifying the <code>.config</code> directly modifies them.
Using <code>delete</code> as shown below is faster and convenient if you only
want to temporarily change one or maybe two values.
Using it with many values may be slower and clutters your codespace —
that’s why <code>.stack()</code> and <code>.cull()</code> were included.</p>
<code class='block'>const myCalc=new SoftMoon.WebWare.RGB_Calc({hueAngleUnit:'grad'});
myCalc.from.hsv("34, 95, 45"); // input as gradians & percents by this calc’s current default
myCalc.config.inputAsFactor=true;
myCalc.from.hsv("34grad, .95, .45"); // input as gradians & factors by this calc’s current default
delete myCalc.config.inputAsFactor; // now the .config value goes back to the old default, faster than .stack() & .cull()
myCalc.config.hueAngleUnit='rad'; // we can never go back to "grad" - if we delete this value, the prototype value is used
myCalc.config.stack(); // if we did this first (after we created the calculator) all values could be preserved using delete</code>
<p>There is also a flag to <code>.config.resetConfigStackOnThrownError</code> when using the standard
<code>.config.onError()</code> handler.
However, now-a-days it is considered best practice to use a <code>try {…} finally {…}</code>