1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-24 18:22:24 -05:00

XEP-0392: Version 0.2

* Move to SHA-1 instead of CRC32
* Use bare JID instead of roster names as input
* Properly reference BT.601 and include constants in text
* Editoral fixes
This commit is contained in:
Jonas Wielicki 2017-10-04 15:25:01 +02:00
parent d158d2037c
commit d21ed8e45c

View File

@ -28,6 +28,17 @@
<email>jonas@wielicki.name</email> <email>jonas@wielicki.name</email>
<jid>jonas@wielicki.name</jid> <jid>jonas@wielicki.name</jid>
</author> </author>
<revision>
<version>0.2</version>
<date>2017-10-04</date>
<initials>jwi</initials>
<remark><p>
Move to SHA-1 as mixing function;
Properly reference BT.601 and include constants in text;
Prefer bare JID over roster name when selecting the hash function input;
Editing.
</p></remark>
</revision>
<revision> <revision>
<version>0.1</version> <version>0.1</version>
<date>2017-09-27</date> <date>2017-09-27</date>
@ -43,6 +54,9 @@
</header> </header>
<section1 topic='Introduction' anchor='intro'> <section1 topic='Introduction' anchor='intro'>
<p>Colors provide a valuable visual cue to recognize text. Recognition of colors works much faster than recognition of text. Together with the length and overall shape of a piece of text (such as a nickname), a color provides a decent amount of entropy to distinguish a reasonable amount of entities.</p> <p>Colors provide a valuable visual cue to recognize text. Recognition of colors works much faster than recognition of text. Together with the length and overall shape of a piece of text (such as a nickname), a color provides a decent amount of entropy to distinguish a reasonable amount of entities.</p>
<p>Clients have been using randomly or deterministically chosen colors for users in multi-user situations for a long time already. However, since there has been no standard for how this is implemented, the experience differs across platforms. The goal of this XEP is to provide a uniform, platform-independent, stateless and easy-to-implement way to map arbitrary bytestrings to colors, as well as give recommendations how this is applied to color names of participants in conversations, roster entries and other pieces of text.</p>
<p>To allow cross-client use, it is important that the color scheme can be adapted to different environments. This specification provides means to adapt colors to different background colors as well as &cvds;.</p>
<p>In no way is the system presented in this specification a replacement for names. It only serves as an additional visual aid.</p>
</section1> </section1>
<section1 topic='Requirements' anchor='reqs'> <section1 topic='Requirements' anchor='reqs'>
<p>The color generation mechanism should provide the following features:</p> <p>The color generation mechanism should provide the following features:</p>
@ -68,23 +82,23 @@
</section2> </section2>
<section2 topic='Adding colors to participants of a conversation' anchor='usecase-nickcolor'> <section2 topic='Adding colors to participants of a conversation' anchor='usecase-nickcolor'>
<p>Implementations may colorize the participants of a conversation with an individual color to make them easier to distinguish.</p> <p>Implementations may colorize the participants of a conversation with an individual color to make them easier to distinguish.</p>
<p>In such cases, the color SHOULD be generated as described in the <link url='#usecase-textcolor'>Generating a color</link> section. The input used SHOULD be, in descending order of preference, (a) the name assigned in the roster, (b) the nickname from the conversation, (c) the bare JID.</p> <p>In such cases, the color SHOULD be generated as described in the <link url='#usecase-textcolor'>Generating a color</link> section. The input used SHOULD be, in descending order of preference, (a) the nickname from the conversation, (b) the bare JID.</p>
</section2> </section2>
<section2 topic='Auto-Generating Avatars' anchor='usecase-avatar'> <section2 topic='Auto-Generating Avatars' anchor='usecase-avatar'>
<p>Implementations may want to show a picture in connection with a contact even if the contact does not have an avatar defined (e.g. via &xep0084;).</p> <p>Implementations may want to show a picture in connection with a contact even if the contact does not have an avatar defined (e.g. via &xep0084;).</p>
<p>In such cases, auto-generating an avatar SHOULD happen as follows:</p> <p>In such cases, auto-generating an avatar SHOULD happen as follows:</p>
<ol> <ol>
<li>Obtain a name for the contact, in descending order of preference, (a) from the roster, (b) by using the nickname from the conversation, (c) by using the bare JID.</li> <li>Obtain a name for the contact, in descending order of preference, (a) by using the actual bare JID of the contact (<em>not</em> the bare JID of the conference in case of a XEP-0045 MUC), (b) by using the nickname from the conversation.</li>
<li>Generate a color as described in the <link url='#usecase-textcolor'>Generating a color</link> section.</li> <li>Generate a color as described in the <link url='#usecase-textcolor'>Generating a color</link> section.</li>
<li>Fill an implementation-defined background shape with that color.</li> <li>Fill an implementation-defined background shape with that color.</li>
<li>Render the first character of the name in white or black centered on the square.</li> <li>Render the first character of the name in white or black centered on the shape.</li>
</ol> </ol>
</section2> </section2>
</section1> </section1>
<section1 topic='Business Rules' anchor='rules'> <section1 topic='Business Rules' anchor='rules'>
<ul> <ul>
<li>Implementations MUST allow the user to turn off any colorization completely.</li> <li>Implementations SHOULD allow the user to turn off any colorization completely.</li>
<li>Implementations MUST implement the &cvd; profiles and MUST allow the user to choose any of these profiles or to disable the correction.</li> <li>Implementations SHOULD implement the &cvd; profiles and SHOULD allow the user to choose any of these profiles or to disable the correction.</li>
<li>Implementations MUST NOT share the &cvd; correction settings with other entities.</li> <li>Implementations MUST NOT share the &cvd; correction settings with other entities.</li>
</ul> </ul>
</section1> </section1>
@ -112,7 +126,7 @@
</section2> </section2>
<section2 topic='CbCr generation' anchor='algorithm-cbcr'> <section2 topic='CbCr generation' anchor='algorithm-cbcr'>
<p>Input: Angle in the CbCr plane, from the previous algorithm.</p> <p>Input: Angle in the CbCr plane, from the previous algorithm.</p>
<p>Output: Values for Cb and Cr in the YCbCr BT.601 color space in the range from -0.5 to 0.5.</p> <p>Output: Values for Cb and Cr in the YCbCr &BT.601; color space in the range from -0.5 to 0.5.</p>
<p>Form a vector from the angle and project it to edges of a quad in 2D space with edge length 1 around (0, 0). The resulting coordinates are Cb and Cr:</p> <p>Form a vector from the angle and project it to edges of a quad in 2D space with edge length 1 around (0, 0). The resulting coordinates are Cb and Cr:</p>
<code><![CDATA[float cr = sin(angle); <code><![CDATA[float cr = sin(angle);
float cb = cos(angle); float cb = cos(angle);
@ -127,7 +141,7 @@ cr = cr * factor;
]]></code> ]]></code>
</section2> </section2>
<section2 topic='CbCr to RGB' anchor='algorithm-rgb'> <section2 topic='CbCr to RGB' anchor='algorithm-rgb'>
<p>Input: Values for Cb and Cr in the YCbCr BT.601 color space in the range from -0.5 to 0.5; Value for Y.</p> <p>Input: Values for Cb and Cr in the YCbCr &BT.601; color space in the range from -0.5 to 0.5; Value for Y.</p>
<p>Output: Values for Red (R), Green (G) and Blue (B) in the RGB color space in the range from 0 to 1.</p> <p>Output: Values for Red (R), Green (G) and Blue (B) in the RGB color space in the range from 0 to 1.</p>
<p>Note: The recommended value for Y is 0.732. See <link url='#impl-gamma'>Gamma Correction</link> for a discussion on the choice of Y.</p> <p>Note: The recommended value for Y is 0.732. See <link url='#impl-gamma'>Gamma Correction</link> for a discussion on the choice of Y.</p>
<ol> <ol>
@ -137,6 +151,7 @@ float g = (y - KR*r - KB*b)/KG;
]]></code></li> ]]></code></li>
<li>Clip the values of r, g and b to the range from 0 to 1.</li> <li>Clip the values of r, g and b to the range from 0 to 1.</li>
</ol> </ol>
<p>See <link url='#constants-ycbcr'>Constants for YCbCr (BT.601)</link> for the values of KR, KG and KB.</p>
</section2> </section2>
<section2 topic='Adapting the Color for specific Background Colors' anchor='algorithm-bg'> <section2 topic='Adapting the Color for specific Background Colors' anchor='algorithm-bg'>
<p>Input: RGB values for the color to adapt (Ri, Gi, Bi) and for the background color to adapt to (Rb, Gb, Bb), in the range from 0 to 1 each.</p> <p>Input: RGB values for the color to adapt (Ri, Gi, Bi) and for the background color to adapt to (Rb, Gb, Bb), in the range from 0 to 1 each.</p>
@ -144,25 +159,26 @@ float g = (y - KR*r - KB*b)/KG;
<ol> <ol>
<li>Invert the background color by subtracting the individual channels from 1 each: <li>Invert the background color by subtracting the individual channels from 1 each:
<code><![CDATA[ <code><![CDATA[
rb = 1-rb; rb_inv = 1-rb;
gb = 1-gb; gb_inv = 1-gb;
bb = 1-bb;]]></code></li> bb_inv = 1-bb;]]></code></li>
<li>Mix the inverted background with the color to adapt, using a mixing factor of 0.2: <li>Mix the inverted background with the color to adapt, using a mixing factor of 0.2:
<code><![CDATA[ <code><![CDATA[
rc = 0.2*rb + 0.8*ri; rc = 0.2*rb_inv + 0.8*ri;
gc = 0.2*gb + 0.8*gi; gc = 0.2*gb_inv + 0.8*gi;
bc = 0.2*bb + 0.8*bi;]]></code></li> bc = 0.2*bb_inv + 0.8*bi;]]></code></li>
</ol> </ol>
</section2> </section2>
<section2 topic='RGB to YCbCr' anchor='algorithm-rgb2cbcr'> <section2 topic='RGB to YCbCr' anchor='algorithm-rgb2cbcr'>
<p>Input: Values for Red (R), Green (G) and Blue (B) in the RGB color space in the range from 0 to 1.</p> <p>Input: Values for Red (R), Green (G) and Blue (B) in the RGB color space in the range from 0 to 1.</p>
<p>Output: Values for Cb and Cr in the YCbCr BT.601 color space in the range from -0.5 to 0.5; Value for Y.</p> <p>Output: Values for Cb and Cr in the YCbCr &BT.601; color space in the range from -0.5 to 0.5; Value for Y.</p>
<p>Calculate Y, Cb and Cr according to BT.601:</p> <p>Calculate Y, Cb and Cr according to BT.601:</p>
<code><![CDATA[ <code><![CDATA[
y = KR*r + (1 - KR - KB)*g + KB*b; y = KR*r + (1 - KR - KB)*g + KB*b;
cb = (b - y) / (1 - KB) / 2 cb = (b - y) / (1 - KB) / 2
cr = (r - y) / (1 - KR) / 2 cr = (r - y) / (1 - KR) / 2
]]></code> ]]></code>
<p>See <link url='#constants-ycbcr'>Constants for YCbCr (BT.601)</link> for the values of KR, KG and KB.</p>
</section2> </section2>
<section2 topic='Conversion of an RGB color palette to a CbCr color palette' anchor='algorithm-genpalette'> <section2 topic='Conversion of an RGB color palette to a CbCr color palette' anchor='algorithm-genpalette'>
<p>Input: A set of RGB colors (each component from 0 to 1).</p> <p>Input: A set of RGB colors (each component from 0 to 1).</p>
@ -190,53 +206,6 @@ cr = (r - y) / (1 - KR) / 2
</ol> </ol>
<p>Note: the distance metric is simply the euclidian distance in the CbCr plane.</p> <p>Note: the distance metric is simply the euclidian distance in the CbCr plane.</p>
</section2> </section2>
<section2 topic='Test Vectors' anchor='algorithm-testvector'>
<p>This section holds test vectors for the different configurations. The test vectors are provided as Comma Separated Values. Strings are enclosed by single quotes (&apos;). The first line contains a header. Each row contains, in that order, the original text, the text encoded as UTF-8 as hexadecimal octets, and the Cb, Cr, Red, Green, and Blue values.</p>
<section3 topic='No &cvd; correction' anchor='algorithm-testvector-no-cvd'>
<code><![CDATA[
text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',2.099189,-0.291880,0.500000,1.000,0.475,0.215
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',5.830846,0.500000,-0.242972,0.391,0.733,1.000
'😺','f09f98ba',4.312757,-0.211180,-0.500000,0.031,1.000,0.358]]></code>
</section3>
<section3 topic='With Red/Green-blindess correction' anchor='algorithm-testvector-cvd-redgreen'>
<code><![CDATA[text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',1.049594,0.287079,0.500000,1.000,0.276,1.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',2.915423,-0.500000,0.115053,0.893,0.822,0.000
'😺','f09f98ba',2.156378,-0.331588,0.500000,1.000,0.489,0.144]]></code>
</section3>
<section3 topic='With Blue-blindess correction' anchor='algorithm-testvector-cvd-blue'>
<code><![CDATA[
text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',2.620391,-0.500000,0.287079,1.000,0.699,0.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',4.486219,-0.115053,-0.500000,0.031,1.000,0.528
'😺','f09f98ba',3.727175,-0.500000,-0.331588,0.267,1.000,0.000]]></code>
</section3>
<section3 topic='Mapping to 216 color palette' anchor='algorithm-testvector-palette'>
<p>The used palette can be generated by sampling the RGB cube evenly with six samples on each axis (resulting in 216 colors). The resulting palette is commonly known as the palette of so-called "Web Safe" colors.</p>
<section4 topic='No &cvd; correction' anchor='algorithm-testvector-palette-no-cvd'>
<code><![CDATA[
text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',2.099189,-0.291880,0.500000,1.000,0.200,0.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',5.830846,0.500000,-0.242972,0.000,0.200,1.000
'😺','f09f98ba',4.312757,-0.211180,-0.500000,0.000,1.000,0.200]]></code>
</section4>
<section4 topic='With Red/Green-blindess correction' anchor='algorithm-testvector-palette-cvd-redgreen'>
<code><![CDATA[
text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',1.049594,0.287079,0.500000,1.000,0.000,0.800
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',2.915423,-0.500000,0.115053,1.000,1.000,0.000
'😺','f09f98ba',2.156378,-0.331588,0.500000,1.000,0.200,0.000]]></code>
</section4>
<section4 topic='With Blue-blindess correction' anchor='algorithm-testvector-palette-cvd-blue'>
<code><![CDATA[
text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',2.620391,-0.500000,0.287079,1.000,0.600,0.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',4.486219,-0.115053,-0.500000,0.000,1.000,0.400
'😺','f09f98ba',3.727175,-0.500000,-0.331588,0.200,1.000,0.000]]></code>
</section4>
</section3>
</section2>
</section1> </section1>
<section1 topic='Implementation Notes' anchor='impl'> <section1 topic='Implementation Notes' anchor='impl'>
<section2 topic='Gamma Correction' anchor='impl-gamma'> <section2 topic='Gamma Correction' anchor='impl-gamma'>
@ -245,7 +214,7 @@ text,hextext,angle,cb,cr,r,g,b
</section2> </section2>
</section1> </section1>
<section1 topic='Accessibility Considerations' anchor='access'> <section1 topic='Accessibility Considerations' anchor='access'>
<p>As outlined above, implementations MUST offer the &rgblind; and &bblind; corrections as defined in the <link url='#algorithm-cvd'>Corrections for &cvds;</link> section. Users MUST be allowed to choose between:</p> <p>As outlined above, implementations SHOULD offer the &rgblind; and &bblind; corrections as defined in the <link url='#algorithm-cvd'>Corrections for &cvds;</link> section. Users SHOULD be allowed to choose between:</p>
<ul> <ul>
<li>disabling all corrections (skip the Corrections for &cvds; step entirely),</li> <li>disabling all corrections (skip the Corrections for &cvds; step entirely),</li>
<li>applying one of the &cvd; correction profiles and</li> <li>applying one of the &cvd; correction profiles and</li>
@ -256,12 +225,12 @@ text,hextext,angle,cb,cr,r,g,b
</section1> </section1>
<section1 topic='Security Considerations' anchor='security'> <section1 topic='Security Considerations' anchor='security'>
<p>This specification extracts a bit more information from an entity and shows it alongside the existing information to the user. As the algorithm is likely to produce different colors for look-alikes (see &xep0165; for examples) in JIDs, it may add additional protection against attacks based on those.</p> <p>This specification extracts a bit more information from an entity and shows it alongside the existing information to the user. As the algorithm is likely to produce different colors for look-alikes (see &xep0165; for examples) in JIDs, it may add additional protection against attacks based on those.</p>
<p>Due to the limited set of distinguishable colors, possible &cvds; and/or use of palettes, entities MUST NOT rely on colors being unique in any context.</p> <p>Due to the limited set of distinguishable colors and only extracting 16 bits of the hash function output, possible &cvds; and/or use of palettes, entities MUST NOT rely on colors being unique in any context.</p>
</section1> </section1>
<section1 topic='Design Considerations' anchor='design'> <section1 topic='Design Considerations' anchor='design'>
<p>This section provides an overview of design considerations made while writing this specification. It shows alternatives which have been considered, and eventually rejected.</p> <p>This section provides an overview of design considerations made while writing this specification. It shows alternatives which have been considered, and eventually rejected.</p>
<section2 topic='Other variants of the YCbCr color space' anchor='design-other-ycbcr'> <section2 topic='Other variants of the YCbCr color space' anchor='design-other-ycbcr'>
<p>The other common YCbCr variants, BT.709 and BT.2020, do not achieve a brightness across the color space as uniform as BT.601 does. Adapting the Y value for uniform luminosity across the range for CbCr would have complicated the algorithm with little or no gain.</p> <p>The other common YCbCr variants, BT.709 and BT.2020, do not achieve a brightness across the color space as uniform as &BT.601; does. Adapting the Y value for uniform luminosity across the range for CbCr would have complicated the algorithm with little or no gain.</p>
</section2> </section2>
<section2 topic='Hue-Saturation-Value/Lightness color space' anchor='design-hsv'> <section2 topic='Hue-Saturation-Value/Lightness color space' anchor='design-hsv'>
<p>The HSV and HSL color spaces fail to provide uniform luminosity with fixed value/lightness and saturation parameters. Adapting those parameters for uniform luminosity across the hue range would have complicated the algorithm with litte to no gain.</p> <p>The HSV and HSL color spaces fail to provide uniform luminosity with fixed value/lightness and saturation parameters. Adapting those parameters for uniform luminosity across the hue range would have complicated the algorithm with litte to no gain.</p>
@ -272,17 +241,76 @@ text,hextext,angle,cb,cr,r,g,b
<p>In addition, more state needs to be taken into account, increasing the complexity of choosing a color.</p> <p>In addition, more state needs to be taken into account, increasing the complexity of choosing a color.</p>
</section2> </section2>
<section2 topic='Choice of mixing function in angle generation' anchor='design-mixing'> <section2 topic='Choice of mixing function in angle generation' anchor='design-mixing'>
<p>This specification needs to collapse an arbitrarily long string into just a few bits (the angle in the CbCr plane). To do so, a CRC32 sum is used.</p> <p>This specification needs to collapse an arbitrarily long string into just a few bits (the angle in the CbCr plane). To do so, SHA-1 (&rfc3174;) is used.</p>
<p>An alternative, which may yield better distribution of colors, would have been to use a cryptographic hash function. However, the performance and implementation cost for a cryptographic hash function is considerable compared with a simple CRC32, especially on small (less than 1 kiB) inputs.</p> <p>CRC32 and Adler32 have been considered as faster alternatives. Downsides of these functions:</p>
<ul>
<li>Bad mixing without additional entropy.</li>
<li>Adler32 is rarely available in standard libraries.</li>
<li>CRC32 is ambiguous: there are multiple polynomials in widespread use (e.g. the Ethernet and the zlib polynomials). Often it is not clear which polynomial is used by a library.</li>
</ul>
<p>SHA-1 is widely available. From a security point of view, the exact choice of hash function does not matter here, since it is truncated to 16 bits. At this length, any cryptographic hash function is weak.</p>
</section2> </section2>
</section1> </section1>
<section1 topic='IANA Considerations' anchor='iana'> <section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with &IANA;. </p> <p>This document requires no interaction with &IANA;. </p>
</section1> </section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'> <section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>This document requires no interaction with the &REGISTRAR;. </p> <p>This document requires no interaction with the &REGISTRAR;. </p>
</section1> </section1>
<section1 topic='Acknowledgements' anchor='acknowledgements'> <section1 topic='Acknowledgements' anchor='acknowledgements'>
<p>Thanks to Daniel Gultsch, Georg Lukas, and Tobias Markmann.</p> <p>Thanks to Daniel Gultsch, Georg Lukas, and Tobias Markmann.</p>
</section1> </section1>
<section1 topic='Test Vectors and Constants' anchor='vectors-and-constants'>
<section2 topic='Constants for YCbCr (BT.601)' anchor='constants-ycbcr'>
<p>Throughout the document, the constants KR, KG and KB are used. They are defined in &BT.601; as:</p>
<code><![CDATA[
KR = 0.299
KG = 0.587
KB = 0.114
]]></code>
</section2>
<section2 topic='Test Vectors' anchor='testvectors-fullrange'>
<p>This section holds test vectors for the different configurations. The test vectors are provided as Comma Separated Values. Strings are enclosed by single quotes (&apos;). The first line contains a header. Each row contains, in that order, the original text, the text encoded as UTF-8 as hexadecimal octets, the angle in radians, and the Cb, Cr, Red, Green, and Blue values.</p>
<section3 topic='No &cvd; correction' anchor='testvectors-fullrange-no-cvd'>
<code><![CDATA[text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',5.711769,0.500000,-0.321484,0.281,0.790,1.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',3.654957,-0.500000,-0.281892,0.337,1.000,0.000
'😺','f09f98ba',5.780607,0.500000,-0.274827,0.347,0.756,1.000]]></code>
</section3>
<section3 topic='With Red/Green-blindess correction' anchor='testvectors-fullrange-cvd-redgreen'>
<code><![CDATA[text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',2.855884,-0.500000,0.146872,0.938,0.799,0.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',1.827478,-0.131236,0.500000,1.000,0.420,0.499
'😺','f09f98ba',2.890304,-0.500000,0.128358,0.912,0.812,0.000]]></code>
</section3>
<section3 topic='With Blue-blindess correction' anchor='testvectors-fullrange-cvd-blue'>
<code><![CDATA[text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',4.426681,-0.146872,-0.500000,0.031,1.000,0.472
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',3.398275,-0.500000,-0.131236,0.548,0.998,0.000
'😺','f09f98ba',4.461100,-0.128358,-0.500000,0.031,1.000,0.505]]></code>
</section3>
</section2>
<section2 topic='Test Vectors for mapping to 216 color palette' anchor='testvectors-palette'>
<p>The used palette can be generated by sampling the RGB cube evenly with six samples on each axis (resulting in 216 colors). The resulting palette is commonly known as the palette of so-called "Web Safe" colors.</p>
<p>The format of the test vectors is the same as in the full range case above.</p>
<section3 topic='No &cvd; correction' anchor='testvectors-palette-no-cvd'>
<code><![CDATA[text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',5.711769,0.500000,-0.321484,0.000,0.400,1.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',3.654957,-0.500000,-0.281892,0.400,1.000,0.000
'😺','f09f98ba',5.780607,0.500000,-0.274827,0.000,0.200,1.000]]></code>
</section3>
<section3 topic='With Red/Green-blindess correction' anchor='testvectors-palette-cvd-redgreen'>
<code><![CDATA[text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',2.855884,-0.500000,0.146872,1.000,1.000,0.000
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',1.827478,-0.131236,0.500000,1.000,0.000,0.000
'😺','f09f98ba',2.890304,-0.500000,0.128358,1.000,1.000,0.000]]></code>
</section3>
<section3 topic='With Blue-blindess correction' anchor='testvectors-palette-cvd-blue'>
<code><![CDATA[text,hextext,angle,cb,cr,r,g,b
'Romeo','526f6d656f',4.426681,-0.146872,-0.500000,0.000,1.000,0.400
'juliet@capulet.lit','6a756c69657440636170756c65742e6c6974',3.398275,-0.500000,-0.131236,0.600,1.000,0.000
'😺','f09f98ba',4.461100,-0.128358,-0.500000,0.000,1.000,0.400]]></code>
</section3>
</section2>
</section1>
</xep> </xep>