poly-flif
poly-flif copied to clipboard
Disable browser interpolation of <canvas>
Currently the browser is doing some interpolation to the canvas that will affect the quality of the decoded image and will affect the perception of the flif image format. To disable this across browsers you would need to add:
canvas {
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
image-rendering: -webkit-optimize-contrast; /* Safari */
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
image-rendering: pixelated; /* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor; /* IE */
}
via StackOverflow
Thanks for the heads up. I am not sure this is applicable here though. This code is drawing pixels using putImageData()
which is writing pixels directly to the canvas.
Are you suggesting this based on observation, or just as a general precaution?
I am on a retina MBP and I can notice the difference. See:
Without pixelated
With pixelated
These are 1:1 screenshots from my display (sorry that they are not the same size)
I would say that the pixelated version is much closer to the intent than the blurry one.
Is the drawing via putImageData()
accounting for the pixel density of the display?
Cool, thanks! I have pushed the changes to the CSS. Can you please refresh the demo page and confirm if it is fixed? I don't notice any difference in my display.
Is the drawing via putImageData() accounting for the pixel density of the display?
Nope.
For my eye this looks better but not quite 100% right after playing with it a bit. The problem seams to be that on a retina screen the canvas will draw 4pixel for 1pixel on the canvas. The browser is doing a better job scaling the images, than scaling the canvas.
Maybe something like this could work:
- Draw the FLIF to a canvas via
putImageData()
- Get a PNG from the canvas via
toDataURL("image/png");
- Draw that PNG via a
<img>
-Tag
The resulting image should receive the same post processing a normal image is.
but not quite 100% right after playing with it a bit.
How did you compare? Did you try decoding to PNG using the native flif
binary?
Your idea of drawing via browser native graphics is nice though. I would do it slightly differently:
- After decoding the FLIF, encode to BMP format (it's mostly just a pixel array with some headers).
- Get a blob URL for the BMP
- Draw either on the canvas, or via img tag. Advantage of canvas is that we can support animations properly.
@FWeinb Are your screenshots for a truncated FLIF or for the full FLIF? And what are you comparing against (original image / same-sized PNG / same-size JPG)?
Here's a comparison (2_webp_ll) with "0% truncation" vs. "original image" on a MacBook Pro retina (1:2 pixel ratio). I manually upscaled the screenshot with nearest neighbor to make the different more pronounced (and to avoid the effect being reapplied twice since I took the screenshot on a retina screen).
With image-rendering: pixelated;
(Chrome and Firefox) on the #pngImg
element, here's the comparison again:
![screen shot 2015-10-21 at 11 52 12 am](https://cloud.githubusercontent.com/assets/158591/10642130/53a54370-77ea-11e5-8ecd-5c1197272b5f.png)
On Wed, Oct 21, 2015 at 9:19 PM, Blixt [email protected] wrote:
I manually upscaled the screenshot with nearest neighbor to make the different more pronounced
Can you upload it without upscaling? It is quite confusing. Thanks!
Here is a longish article explaining the problem and a (partial?) solution. I can't fix this myself because I don't have such an exotic display. PRs welcome.
In my opinion, the best approach might be to create a blob image and use canvas.drawImage()
, instead of drawing individual pixels onto the canvas. It would degrade performance for animations (because browser would have to decode the image repeatedly) but I guess it'd be good enough for a poly-fill.
I also hope to design the API such that the decoding of the FLIF and its rendering are two separate functions; allowing independent improvements to them in the future.
For future reference, I found another article.
You don't need to do any of those things, those articles are outdated to work around image rendering. So the thing happening is that your canvas is pixelated (not upsampled), while the PNG is upsampled (not pixelated).
All you need to do is to make the PNG pixelated as well (using #pngImg { image-rendering: pixelated; }
plus all the browser-specific versions) and the two will match for both retina and non-retina (as in my second screenshot).
As requested, here are two unchanged screenshots with and without image-rendering: pixelated
on the PNG.
All you need to do is to make the PNG pixelated as well
That seems fair for the purpose of comparison. I will do that soon.
I have pushed an update with "pixelation" enabled on the right side comparison view, so that the comparison with FLIF is fair on high-resolution displays. Please let me know if it doesn't work.
I still need to figure out how to handle this as a library (for standalone viewing of FLIFs).
I tested the current demo with a virtual screen having 192 DPI, with Chromium. The current CSS rules are working fine for the demo. Both the left side canvas (containing decoded FLIF pixels) and the right side image (containing decoded PNG or JPEG pixels) appear similarly pixelated on a higher DPI screen.
As for the library, dealing with arbitrary images, either the image or the API would need to specify the original resolution of the image. Then the library could scale the canvas (or underlying image buffer) accordingly, to match the screen resolution.