-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Changes from 9 commits
1214d64
4b127c0
a7ceae5
2e36881
76fbc56
72d43ce
8c9cb50
62311e1
f13e1e3
2bbf985
9ee37bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60360,7 +60360,7 @@ interface <dfn>Path2D</dfn> { | |
<div w-nodev> | ||
|
||
<p>A <code>CanvasRenderingContext2D</code> object has an <dfn>output bitmap</dfn> that | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can't have normative definitions inside non-normative notes. Is the intention here to provide a normative definition, or just a discussion? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is intended to be a normative definition--should I just move it outside of the note? I'm not very sure where to put this definition, actually. Right now, it's defined just before its first usage, but maybe there's somewhere better to put it. The only "somewhere better" I could think of is the CSS Compositing and Blending spec, and I think putting it there would result in scope creep as that spec would likely then have to be updated/clarified as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking into this more (tangentially), there seem to be only two passing references to premultiplied alpha in CSS Compositing and Blending, and none in CSS Color. Are there any other specifications to look at, or is all of this just implicit currently? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect it's all implicit currently, although we could try to loop in the relevant CSS folks to be sure. I like your idea of stepping back and finding a better location for this. (Note that in general there's no need to define before use; we have hyperlinks 😊.) I'm currently thinking maybe it deserves its own section, as a sibling to https://html.spec.whatwg.org/#colour-spaces-and-colour-correction ? Or, I guess, if we want to keep it 2D context specific, as a sibling of https://html.spec.whatwg.org/#drawing-model ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've created a new section for premultiplied alpha, and moved the "output bitmap must be premultiplied" part into it. In the future, it may be good to move the "what does premultiplied alpha mean conceptually" part into one of the CSS specs, but that would involve a lot more rewriting. |
||
is initialized when the object is created.</p> | ||
is initialized when the object is created.</p> | ||
|
||
<!--ADD-TOPIC:Security--> | ||
<p>The <span>output bitmap</span> has an <span | ||
|
@@ -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 | ||
|
@@ -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 | ||
|
@@ -65740,6 +65741,116 @@ interface <dfn>OffscreenCanvasRenderingContext2D</dfn> { | |
|
||
</div> | ||
|
||
<div w-nodev> | ||
<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="note"> | ||
<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="Completely-opaque orange"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, I don't think that would give a good experience. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added alt text. |
||
<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="Halfway-opaque yellow"> | ||
<tr> | ||
<td>Unrepresentable | ||
<td>255, 127, 0, 127 | ||
<td>Unrepresentable | ||
<td>Additive halfway-opaque orange | ||
<td><img src="images/premultiplied-example-3.png" width="96" height="96" alt="Additive halfway-opaque orange"> | ||
<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="Additive fully-transparent orange"> | ||
<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="Fully-transparent ("invisible") orange"> | ||
<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="Fully-transparent ("invisible") turquoise"> | ||
</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> | ||
|
||
<div 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>. | ||
</div> | ||
</div> | ||
|
||
<h3 split-filename="custom-elements" id="custom-elements">Custom elements</h3> | ||
|
||
<h4 id="custom-elements-intro">Introduction</h4> | ||
|
@@ -94710,7 +94821,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> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "are premultiplied by its alpha channel" in the sense of "this is the form that the output will take", not "this is the operation that we will perform on the input". |
||
|
||
<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> | ||
|
@@ -95150,14 +95261,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> | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an extremely long note, and seems to include an example inside of it. Perhaps it'd be best as a statement of fact (not inside a note wrapper), plus an example (div class=example)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed