webdriver icon indicating copy to clipboard operation
webdriver copied to clipboard

Guidance on rounding floating-point coordinates for Take Element Screenshot

Open mtrea opened this issue 6 years ago • 4 comments

In chapter 17. Screen capture, section 17.2 Take Element Screenshot:

The Take Element Screenshot command takes a screenshot of the visible region encompassed by the bounding rectangle of an element.

"bounding rectangle" links to https://w3c.github.io/webdriver/#dfn-bounding-rectangle which indicates that x, y, width, and height are of type "double".

The returned screenshot must be a PNG. However, per the PNG spec on Data Representation: http://www.libpng.org/pub/png/spec/1.1/pngext-1.1.0-pdg.html "The core of PNG does not use floating-point numbers anywhere".

Therefore, the implementation must convert the coordinates to be integers, and there is not currently any guidance on how this should be done. Should mathematical rounding be applied? Should values be truncated? Should clients round "out" such that the image is always at least as big as the floating-point-defined rect?

mtrea avatar Dec 06 '19 19:12 mtrea

CSS pixels can be fractional but are not necessarily equal to the “real” device pixels drawn on the screen.

CSS pixels values are given in pixel units, not in as absolute physical measurements. One pixel unit, or 1px, is thought to be the visual viewing angle of a single pixel on the device with a density of 96dpi measured at an arm’s length’s distance:

For a nominal arm’s length of 28 inches, the visual angle is therefore about 0.0213 degrees. For reading at arm’s length, 1px thus corresponds to about 0.26 mm (1/96 inch).

This is known as the reference pixel, which means that CSS pixel units are modulated by the media’s device pixel ratio and density.

The example CSS-VALUES-3 uses to illustrate this effect is that while an area of 1px by 1px will be covered by a single dot in a low-resolution device, the same area may be covered by more dots in higher resolution devices, such as laser printers or on high-DPI screen monitors.

WebDriver uses CSS pixels to mark the location of the web element to capture, but the actual computed image file will be represented in absolute device pixels, in integer.

To give an example: when you have an area of 1px by 1px CSS pixels on an Apple Retina display, depending on the scaling factor, the produced screenshot might have a dimension of 2px by 2px due to the screen’s pixel ratio (see window.devicePixelRatio).

andreastt avatar Dec 06 '19 22:12 andreastt

Thanks for the clarification, Andreas. Perhaps I oversimplified in my initial post. I agree that the device pixel ratio is also relevant. Given that CSS pixels can be fractional and image files must be represented in absolute device pixels, some kind of conversion needs to happen between the two. To my knowledge, there isn't any formal guidance on how exactly this conversion should be done.

I think one could reasonably argue in favor of a couple different implementations, though I'm most in favor of rounding "out" such that the bounds of the final image are greater than or equal to that of the initial image, such that you avoid cropping any content.

mtrea avatar Dec 10 '19 17:12 mtrea

WebDriver paints the framebuffer into a <canvas> element, and the device pixel ratio is taken into consideration when its internal bitmap representation is serialised as a file.

This is what HTML has to say about rounding:

The image file's pixel data must be the bitmap's pixel data scaled to one image pixel per coordinate space unit, and if the file format used supports encoding resolution metadata, the resolution must be given as 96dpi (one image pixel per CSS pixel).

WebDriver doesn’t put any restrictions on what it means to draw a region of the framebuffer, saying the implementation must take implementation-defined steps. This means that the scaling of the screenshot is undefined, but that the resulting PNG should always well-formed due to the way <canvas> serialisation (HTMLCanvasElement.toDataURL) is handled.

andreastt avatar Dec 11 '19 13:12 andreastt

see also #1251

gsnedders avatar Jan 29 '20 15:01 gsnedders