[whatwg] Proposal: ImageData constructor or factory method with preexisting data

Kenneth Russell kbr at google.com
Tue Mar 12 15:03:25 PDT 2013


On Tue, Mar 12, 2013 at 2:04 PM, Rik Cabanier <cabanier at gmail.com> wrote:
>
>
> On Tue, Mar 12, 2013 at 11:40 AM, Kenneth Russell <kbr at google.com> wrote:
>>
>> On Tue, Mar 12, 2013 at 11:15 AM, Rik Cabanier <cabanier at gmail.com> wrote:
>> > sounds good!
>> > I think this is a convenient and useful addition.
>>
>> Great.
>>
>> > do you want to keep doubles to define the dimensions instead of
>> > integers? If
>> > so, the size should probably  4 * ceil(sw) * ceil(sh)
>>
>> I would prefer to use integers, and only used doubles to be consistent
>> with the other APIs like getImageData and createImageData. In this
>> case it would make more sense to use integers, since the width and
>> height are simply being used to interpret preexisting data in the
>> Uint8ClampedArray.
>
>
> The current canvas spec doesn't specifically state what happens with partial
> pixels. What happens today?
> (Also is there a definition somewhere that states when a pixel is considered
> filled?)

Safari, Firefox and Chrome all round the double arguments to
putImageData to integers using the "truncate" rounding mode and then
draw the source ImageData pixel-for-pixel. For example, passing 64.5
or 64.99 for the dx or dy arguments is equivalent to passing 64.
Here's a test case.

<canvas id="canvas" width="256" height="256"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
ctx.fillRect(0, 0, width, height);
var imageData = ctx.createImageData(width / 2, height / 2);
for (var ii = 0; ii < imageData.data.length; ii += 4) {
  imageData.data[ii + 0] = 0;
  imageData.data[ii + 1] = 255;
  imageData.data[ii + 2] = 0;
  imageData.data[ii + 3] = 255;
}
// Try passing 64.5, 64.99, or 65 for one or both of these arguments
and see the results
ctx.putImageData(imageData, 64, 64);
</script>

In other words, the source ImageData would not be rendered into the
canvas at a half-pixel offset if ctx.putImageData(imageData, 64.5,
64.5) were called.


>> I don't think it is necessary to provide a createImageDataHD in this
>> interface. The caller will know the devicePixelRatio and determine
>> whether to generate high-DPI data.
>
> That probably won't work since it results in code that executes differently
> on devices that are HD.

I think it works. The application will call the new ImageData
constructor and pass it to either putImageData or putImageDataHD.
These interpret the incoming ImageData differently depending on the
devicePixelRatio.

In contrast, CanvasRenderingContext2D's existing createImageDataHD and
getImageDataHD methods will create an ImageData that may have a
different width and height from those passed in. The reason for this
is that these methods are referring to the canvas's backing store. For
this new constructor which simply wraps existing pixel data, the
application knows exactly how many pixels are contained in the array,
so it makes the most sense to take the incoming width and height
verbatim. I don't see any advantage to having an alternate "high-DPI"
constructor which would multiply the width and height by the
devicePixelRatio behind the scenes.

-Ken


>>
>>
>> > On Tue, Mar 12, 2013 at 10:50 AM, Kenneth Russell <kbr at google.com>
>> > wrote:
>> >>
>> >> It should simply reference the Uint8ClampedArray, not copy it or do
>> >> anything else esoteric. The only way to display an ImageData in the 2D
>> >> canvas context is via the putImageData API. I am not proposing
>> >> changing those semantics.
>> >>
>> >> -Ken
>> >>
>> >>
>> >>
>> >> On Mon, Mar 11, 2013 at 5:00 PM, Rik Cabanier <cabanier at gmail.com>
>> >> wrote:
>> >> > Do you expect that createImageData creates an internal copy of the
>> >> > Uint8ClampedArray object or is it live?
>> >> >
>> >> >
>> >> > On Mon, Mar 11, 2013 at 4:28 PM, Kenneth Russell <kbr at google.com>
>> >> > wrote:
>> >> >>
>> >> >> It would be useful to be able to create an ImageData [1] object with
>> >> >> preexisting data. The main use case is to display arbitrary data in
>> >> >> the 2D canvas context with no data copies.
>> >> >>
>> >> >> Proposed IDL:
>> >> >>
>> >> >> [NoInterfaceObject]
>> >> >> interface ImageDataFactories {
>> >> >>   ImageData createImageData(Uint8ClampedArray data, double sw,
>> >> >> double
>> >> >> sh);
>> >> >> };
>> >> >> Window implements ImageDataFactories;
>> >> >> WorkerGlobalScope implements ImageDataFactories;
>> >> >>
>> >> >> createImageData would throw an exception if the length of the
>> >> >> Uint8ClampedArray was not equal to 4 * floor(sw) * floor(sh), or at
>> >> >> least, if the length of the array was less than this value. (Similar
>> >> >> wording would be used to that of CanvasRenderingContext2D's
>> >> >> createImageData.)
>> >> >>
>> >> >> I don't think it is necessary to provide a createImageDataHD in this
>> >> >> interface. The caller will know the devicePixelRatio and determine
>> >> >> whether to generate high-DPI data.
>> >> >>
>> >> >> [1]
>> >> >>
>> >> >>
>> >> >> http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata
>> >> >>
>> >> >> Comments?
>> >> >>
>> >> >> Thanks,
>> >> >>
>> >> >> -Ken
>> >> >
>> >> >
>> >
>> >
>
>



More information about the whatwg mailing list