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

Editorial: putImageData: Clarify that the operation is not a memcpy #11042

Merged
merged 4 commits into from
Feb 20, 2025

Conversation

ccameron-chromium
Copy link
Contributor

@ccameron-chromium ccameron-chromium commented Feb 18, 2025

Ensure that it be clear that putImage will convert from the source ImageData's color space and pixel format to the output bitmap's color space and pixel format.

Also rename dirtyX,dirtyY,dirtyWidth,dirtyHeight to sx,sy,sw,sh. The original names reflect the use case where content is being rendered into an ImageData by JavaScript and that one wishes to copy the "dirty" part of the source ImageData to the destination canvas. This can be confusing because this process will "dirty" the destination canvas. Change this to use the same source and destination parameter names that are used by drawImage and related functions.


/canvas.html ( diff )

@@ -65537,7 +65537,7 @@ interface mixin <dfn interface>CanvasImageData</dfn> {
<span>ImageData</span> <span data-x="dom-context-2d-createImageData-imagedata">createImageData</span>(<span>ImageData</span> imagedata);
<span>ImageData</span> <span data-x="dom-context-2d-getImageData">getImageData</span>([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh, optional <span>ImageDataSettings</span> settings = {});
undefined <span data-x="dom-context-2d-putImageData">putImageData</span>(<span>ImageData</span> imagedata, [EnforceRange] long dx, [EnforceRange] long dy);
undefined <span data-x="dom-context-2d-putImageData">putImageData</span>(<span>ImageData</span> imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight);
undefined <span data-x="dom-context-2d-putImageData">putImageData</span>(<span>ImageData</span> imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh);
Copy link
Member

Choose a reason for hiding this comment

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

We should probably do this separately, but I think it would be good to use non-abbreviated parameter names here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, removed it. And I agree it should stay as the current names. It's an extremely bizarre API.

Copy link
Member

Choose a reason for hiding this comment

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

I was not suggesting the current names necessarily, but destinationX and sourceX would be better than dx and sx. Maybe we can fix imagedata -> imageData now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, it's such a strange behavior (I didn't realize the details of it until editing the spec here!) that I don't want to mess with the "dirty" variable names in this patch.

But imagedata to imageData is safe. I updated that throughout the full spec.

Copy link
Member

Choose a reason for hiding this comment

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

And I agree it should stay as the current names. It's an extremely bizarre API.

Yes, from the top comment I was going to say "beware! these are not the same!" and I agree dirtyX et al. are super weird. Every time I face them, I have to check again some old answer of mine onstackoverflow to remember what these represent exactly. I don't think we can touch it now, but "dirty" seems quite à-propos.

But all of sx, sy, sw, and sh in getImageData, and, dx and dy in putImageData can indeed be changed to sourceX, sourceY, sourceWidth, sourceHeight, destinationX, and destinationY. But maybe that's worth its own PR since drawImage would also need to be updated.

source Outdated
Comment on lines 70234 to 70244
<p>The <dfn method for="CanvasImageData"><code
data-x="dom-context-2d-putImageData">putImageData()</code></dfn> method writes data from
<code>ImageData</code> structures back to the rendering context's <span>output bitmap</span>. Its
arguments are: <var>imagedata</var>, <var>dx</var>, <var>dy</var>, <var>dirtyX</var>,
<var>dirtyY</var>, <var>dirtyWidth</var>, and <var>dirtyHeight</var>.</p>
data-x="dom-context-2d-putImageData">putImageData()</code></dfn> method converts and copies data
from <code>ImageData</code> structures to the rendering context's <span>output bitmap</span>. Its
arguments are: <var>imagedata</var>, <var>dx</var>, <var>dy</var>, <var>sx</var>,
<var>sy</var>, <var>sw</var>, and <var>sh</var>.</p>

<p>When the last four arguments to this method are omitted, they must be assumed to have the
values 0, 0, the <code data-x="dom-imagedata-width">width</code> member of the <var>imagedata</var> structure, and the <code data-x="dom-imagedata-height">height</code>
member of the <var>imagedata</var> structure, respectively.</p>
<p>Then last four arguments to this method indicate the source rectangle for the copy. When they
are omitted, they must be assumed to have the values 0, 0, the
<code data-x="dom-imagedata-width">width</code> member of the <var>imagedata</var> structure, and
the <code data-x="dom-imagedata-height">height</code> member of the <var>imagedata</var>
structure, respectively.</p>
Copy link
Member

Choose a reason for hiding this comment

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

Can we modernize this to

The putImageData(imageData, dx, dy, ...) method steps are:

and since there's an overload I guess we need that intro twice and then they both call into a shared algorithm. That would also remove the need for this weird "if they are omitted" language.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it to a common algorithm (modernized) with both methods documented separately and calling the common algorithm.

@ccameron-chromium ccameron-chromium force-pushed the put_image_data branch 3 times, most recently from 3086f9a to ec10c44 Compare February 19, 2025 09:22
@@ -65537,7 +65537,7 @@ interface mixin <dfn interface>CanvasImageData</dfn> {
<span>ImageData</span> <span data-x="dom-context-2d-createImageData-imagedata">createImageData</span>(<span>ImageData</span> imagedata);
<span>ImageData</span> <span data-x="dom-context-2d-getImageData">getImageData</span>([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh, optional <span>ImageDataSettings</span> settings = {});
undefined <span data-x="dom-context-2d-putImageData">putImageData</span>(<span>ImageData</span> imagedata, [EnforceRange] long dx, [EnforceRange] long dy);
undefined <span data-x="dom-context-2d-putImageData">putImageData</span>(<span>ImageData</span> imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight);
undefined <span data-x="dom-context-2d-putImageData">putImageData</span>(<span>ImageData</span> imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh);
Copy link
Member

Choose a reason for hiding this comment

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

I was not suggesting the current names necessarily, but destinationX and sourceX would be better than dx and sx. Maybe we can fix imagedata -> imageData now?

arguments are: <var>imagedata</var>, <var>dx</var>, <var>dy</var>, <var>dirtyX</var>,
<var>dirtyY</var>, <var>dirtyWidth</var>, and <var>dirtyHeight</var>.</p>
data-x="dom-context-2d-putImageData-short">putImageData(<var>imagedata</var>,
<var>dx</var>, <var>dy</var>)</code></dfn> method will
Copy link
Member

Choose a reason for hiding this comment

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

The format is:

The X(...) method steps are to ...

you also want to supply the arguments in the same order and not rely on the reader to do some argument name mapping. That also means you don't set dirtyWidth to something but instead you'd pass imageData's width. (Though ideally not the public API for that, but maybe we only have public API at this point. Another thing to fix in due course.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed this to do the "steps are to [algorithm name], given [params]" format.

Ensure that it be clear that putImage will convert from the source
ImageData's color space and pixel format to the output bitmap's color
space and pixel format.

Also document the two separate putImageData methods as separate methods
with a common algorithm, rather than a single method with optional
parameters.
Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

Thanks! Very close now. @Kaiido want to do a pass as well?

<var>dx</var>, <var>dy</var>)</code></dfn> method steps are to
<span data-x="dom-context2d-putImageData-common">put pixels from an
<code>ImageData</code> onto a bitmap</span>, given
<var>imageData</var>, the <span>output bitmap</span> of the rendering context,
Copy link
Member

Choose a reason for hiding this comment

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

We can make the second argument <span>this</span>'s <span>output bitmap</span>, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, done.

Copy link
Member

@Kaiido Kaiido left a comment

Choose a reason for hiding this comment

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

LGTM, modulo a small nit.
Though I'd have expected to see something about alpha-multiplication in the algo, but that's already an improvement. Thanks.

in the rendering context's <span>output bitmap</span>.</p></li>
data-x=""><var>dirtyY</var>+<var>dirtyHeight</var></span></span>,
set the pixel with coordinate (<span data-x=""><var>dx</var>+<var>x</var></span>,
<var>dy</var>+<var>y</var>) in <var>bitmap</var> to the color at coordinate
Copy link
Member

Choose a reason for hiding this comment

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

https://html.spec.whatwg.org/multipage/canvas.html#canvas-pixel-arraybuffer doesn't talk at all about "color" but really represents values in an ArrayBuffer, so maybe "to the color of the pixel at coordinate"?.
Also, this is not new, but maybe the alpha: false special case should be handled here explicitly? Though since here we're not in the correct CanvasSettings interface, that might be complex...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated it to read "to the color of the pixel at coordinate".

I can follow up with a patch that indicates the alpha behavior (and for that patch I'll need to include new WPT tests, since it doesn't look like that behavior is tested yet).

@annevk annevk merged commit 6a3787f into whatwg:main Feb 20, 2025
2 checks passed
@annevk
Copy link
Member

annevk commented Feb 20, 2025

Thanks @ccameron-chromium!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants