Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify premultiplication #6500

Merged
merged 11 commits into from
Apr 5, 2021
Binary file added images/premultiplied-example-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/premultiplied-example-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/premultiplied-example-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/premultiplied-example-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/premultiplied-example-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 103 additions & 11 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -64025,7 +64025,7 @@ try {
data-x=""><var>sy</var>+<var>sh</var></span>), (<var>sx</var>,
<var>sy</var>+<var>sh</var>), in the bitmap's coordinate space units.
Pixels outside the <span>output bitmap</span> must be set to <span>transparent black</span>. Pixel
values must not be premultiplied by alpha.</p>
values must not be <span data-x="concept-premultiplied-alpha">premultiplied by alpha</span>.</p>

<p>When the user agent is required to <dfn>create an <code>ImageData</code> object</dfn>, given a
positive integer number of rows <var>rows</var>, a positive integer number of pixels per row
Expand Down Expand Up @@ -64167,10 +64167,11 @@ try {
in the rendering context's <span>output bitmap</span>.</p></li>
</ol>

<p class="note">Due to the lossy nature of converting to and from premultiplied alpha color
values, pixels that have just been set using <code
data-x="dom-context-2d-putImageData">putImageData()</code> might be returned to an equivalent
<code data-x="dom-context-2d-getImageData">getImageData()</code> as different values.</p>
<p class="note">Due to the lossy nature of converting to and from <span
data-x="concept-premultiplied-alpha">premultiplied alpha</span> color values, pixels that have
just been set using <code data-x="dom-context-2d-putImageData">putImageData()</code>, and are not
completely opaque, might be returned to an equivalent <code
data-x="dom-context-2d-getImageData">getImageData()</code> as different values.</p>

<p>The current path, <span data-x="dom-context-2d-transformation">transformation matrix</span>,
<span data-x="shadows">shadow attributes</span>, <span data-x="dom-context-2d-globalAlpha">global
Expand Down Expand Up @@ -65740,6 +65741,96 @@ interface <dfn>OffscreenCanvasRenderingContext2D</dfn> {

</div>

<h5>Premultiplied alpha and the 2D rendering context</h5>

<p><dfn data-x="concept-premultiplied-alpha">Premultiplied alpha</dfn> refers to one way of
representing transparency in an image, the other being non-premultiplied alpha.</p>

<p>Under non-premultiplied alpha, the red, green, and blue channels of a pixel represent that
pixel's color, and its alpha channel represents that pixel's opacity.</p>

<p>Under premultiplied alpha, however, the red, green, and blue channels of a pixel represent the
amounts of color that the pixel adds to the image, and its alpha channel represents the amount
that the pixel obscures whatever is behind it.</p>

<div class="example">
<p>For instance, assuming the color channels range from 0 (off) to 255 (full intensity), these
example colors are represented in the following ways:</p>

<table>
<thead>
<tr>
<th>CSS color representation
<th>Premultiplied representation
<th>Non-premultiplied representation
<th>Description of color
<th>Image of color blended above other content
<tbody>
<tr>
<td>rgba(255, 127, 0, 1)
<td>255, 127, 0, 255
<td>255, 127, 0, 255
<td>Completely-opaque orange
<td><img src="images/premultiplied-example-1.png" width="96" height="96" alt="An opaque orange circle sits atop a background">
<tr>
<td>rgba(255, 255, 0, 0.5)
<td>127, 127, 0, 127
<td>255, 255, 0, 127
<td>Halfway-opaque yellow
<td><img src="images/premultiplied-example-2.png" width="96" height="96" alt="A yellow circle, halfway transparent, sits atop a background">
<tr>
<td>Unrepresentable
<td>255, 127, 0, 127
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't good alt text, as it just repeats what's nearby. Can you give a more detailed description for non-sighted users, per the guidelines in https://html.spec.whatwg.org/#alt ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea how to textually describe these images in a meaningful way. Should I just make the alt-text blank?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't think that would give a good experience.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added alt text.

<td>Unrepresentable
<td>Additive halfway-opaque orange
<td><img src="images/premultiplied-example-3.png" width="96" height="96" alt="An orange circle somewhat brightens the background that it sits atop">
<tr>
<td>Unrepresentable
<td>255, 127, 0, 0
<td>Unrepresentable
<td>Additive fully-transparent orange
<td><img src="images/premultiplied-example-4.png" width="96" height="96" alt="An orange circle completely brightens the background that it sits atop">
<tr>
<td>rgba(255, 127, 0, 0)
<td>0, 0, 0, 0
<td>255, 127, 0, 0
<td>Fully-transparent ("invisible") orange
<td><img src="images/premultiplied-example-5.png" width="96" height="96" alt="An empty background with nothing atop it">
<tr>
<td>rgba(0, 127, 255, 0)
<td>0, 0, 0, 0
<td>255, 127, 0, 0
<td>Fully-transparent ("invisible") turquoise
<td><img src="images/premultiplied-example-5.png" width="96" height="96" alt="An empty background with nothing atop it">
</table>
</div>

<p><dfn data-x="convert-to-premultiplied">Converting a color value from a non-premultiplied
representation to a premultiplied one</dfn> involves multiplying the color's red, green, and
blue channels by its alpha channel (remapping the range of the alpha channel such that "fully
transparent" is 0, and "fully opaque" is 1).</p>

<p><dfn data-x="convert-from-premultiplied">Converting a color value from a premultiplied
representation to a non-premultiplied one</dfn> involves the inverse: dividing the color's red,
green, and blue channels by its alpha channel.</p>

<p>As certain colors can only be represented under premultiplied alpha (for instance, additive
colors), and others can only be represented under non-premultiplied alpha (for instance,
"invisible" colors which hold certain red, green, and blue values even with no opacity); and
division and multiplication on 8-bit integers (which is how canvas' colors are currently stored)
entails a loss of precision, converting between premultiplied and non-premultiplied alpha is a
lossy operation on colors that are not fully opaque.</p>

<p>A <code>CanvasRenderingContext2D</code>'s <span>output bitmap</span> and an
<code>OffscreenCanvasRenderingContext2D</code>'s <span data-x="offscreencontext2d-bitmap"
>bitmap</span> must use premultiplied alpha to represent transparent colors.</p>

<p class="note">It is important for canvas bitmaps to represent colors using premultiplied alpha
because it affects the range of representable colors. While additive colors cannot currently be
drawn onto canvases directly because CSS colors are non-premultiplied and cannot represent them,
it is still possible to, for instance, draw additive colors onto a WebGL canvas and then draw that
WebGL canvas onto a 2D canvas via <code data-x="dom-context-2d-drawImage">drawImage()</code>.</p>

<h3 split-filename="custom-elements" id="custom-elements">Custom elements</h3>

<h4 id="custom-elements-intro">Introduction</h4>
Expand Down Expand Up @@ -94710,7 +94801,7 @@ dictionary <dfn>ImageBitmapOptions</dfn> {
if the <code data-x="dom-ImageBitmapOptions-premultiplyAlpha">premultiplyAlpha</code>
option is set to "<code data-x="dom-PremultiplyAlpha-premultiply">premultiply</code>",
the <span data-x="concept-ImageBitmap-bitmap-data">bitmap data</span>'s color channels are
premultiplied by its alpha channel.
<span data-x="concept-premultiplied-alpha">premultiplied by its alpha channel</span>.</p>

<p>Rejects the promise with an <span>"<code>InvalidStateError</code>"</span>
<code>DOMException</code> if the source image is not in a valid state (e.g., an <code>img</code>
Expand Down Expand Up @@ -95150,14 +95241,15 @@ dictionary <dfn>ImageBitmapOptions</dfn> {
optimal for drawing images onto the canvas.</p></li>

<li><p>If <var>val</var> is "<dfn enum-value for="PremultiplyAlpha"><code
data-x="dom-PremultiplyAlpha-premultiply">premultiply</code></dfn>", the <var>output</var>
that is not premultiplied by alpha must have its color components multiplied by alpha and
that is premultiplied by alpha must be left untouched.</p></li>
data-x="dom-PremultiplyAlpha-premultiply">premultiply</code></dfn>", the <var>output</var> that
is not premultiplied by alpha must have its color components <span
data-x="convert-to-premultiplied">multiplied by alpha</span> and that is premultiplied by alpha
must be left untouched.</p></li>

<li><p>If <var>val</var> is "<dfn enum-value for="PremultiplyAlpha"><code
data-x="dom-PremultiplyAlpha-none">none</code></dfn>", the <var>output</var> that is not
premultiplied by alpha must be left untouched and that is premultiplied by alpha must have
its color components divided by alpha.</p></li>
premultiplied by alpha must be left untouched and that is premultiplied by alpha must have its
color components <span data-x="convert-from-premultiplied">divided by alpha</span>.</p></li>
</ol>
</li>

Expand Down