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

Disable browser interpolation of <canvas> #10

Open
FWeinb opened this issue Oct 15, 2015 · 16 comments
Open

Disable browser interpolation of <canvas> #10

FWeinb opened this issue Oct 15, 2015 · 16 comments

Comments

@FWeinb
Copy link

FWeinb commented Oct 15, 2015

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

@hrj
Copy link
Member

hrj commented Oct 15, 2015

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?

@FWeinb
Copy link
Author

FWeinb commented Oct 15, 2015

I am on a retina MBP and I can notice the difference. See:

Without pixelated
Without pixelated

With 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?

hrj added a commit that referenced this issue Oct 15, 2015
@hrj
Copy link
Member

hrj commented Oct 15, 2015

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.

@FWeinb
Copy link
Author

FWeinb commented Oct 15, 2015

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.

@hrj
Copy link
Member

hrj commented Oct 15, 2015

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.

@hrj
Copy link
Member

hrj commented Oct 16, 2015

@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)?

@blixt
Copy link

blixt commented Oct 21, 2015

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).

screen shot 2015-10-21 at 11 33 50 am

@blixt
Copy link

blixt commented Oct 21, 2015

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

@hrj
Copy link
Member

hrj commented Oct 21, 2015

On Wed, Oct 21, 2015 at 9:19 PM, Blixt notifications@github.com 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!

@hrj
Copy link
Member

hrj commented Oct 21, 2015

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.

@hrj
Copy link
Member

hrj commented Oct 21, 2015

For future reference, I found another article.

@blixt
Copy link

blixt commented Oct 21, 2015

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).

@blixt
Copy link

blixt commented Oct 21, 2015

As requested, here are two unchanged screenshots with and without image-rendering: pixelated on the PNG.

screen shot 2015-10-21 at 1 31 46 pm
screen shot 2015-10-21 at 1 31 18 pm

@hrj
Copy link
Member

hrj commented Oct 21, 2015

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.

hrj added a commit that referenced this issue Oct 25, 2015
@hrj
Copy link
Member

hrj commented Oct 25, 2015

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).

@hrj
Copy link
Member

hrj commented Apr 30, 2017

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.

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

No branches or pull requests

3 participants