viliusle / miniPaint

online image editor
http://viliusle.github.io/miniPaint/
Other
2.6k stars 607 forks source link

Improve image rendering in browser canvas (lots of pixilation compared to other online image editors) #244

Closed JordanMagnuson closed 2 years ago

JordanMagnuson commented 3 years ago

miniPaint rendering of images in the browser canvas shows lots of pixilation compared to the exported png/jpg, and also compared to other online image editors (e.g. photopea.com)

Here is a clear example of what I'm talking about: the same PNG image opened in minPaint vs Photopea, side by side, in the same web browser (Google Chrome): https://www.flickr.com/photos/pixelscrapper/51101178957/in/dateposted-public/

View that image at 100% zoom, and you can see the difference in rendering is fairly extreme: in Photopea the image looks smooth (much like the original PNG does, if you open it in the browser or in a photo editor), but in miniPaint there is a lot of pixilation, and the image quality appears poor (though again, the PNG that is exported from miniPaint is fine--it does not show the same pixilation).

Here is a detail from the comparison image:

image

Here is the reference file: PNG reference file .json project file

And thank you once again for this wonderful open source image editor!

Giwayume commented 3 years ago

I'm going to guess since you have a 4k monitor, your browser or operating system is scaling the logical resolution of the webpage to something like 1920x1080 so font sizes aren't extremely small. I've mentioned this before here https://github.com/viliusle/miniPaint/issues/167#issuecomment-708092355

Minipaint needs to take window.devicePixelRatio into account when sizing the canvas as well as calculating canvas coordinates from mouse position.

https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio

viliusle commented 3 years ago

Giwayume is probably right. I need to look at this.

@JordanMagnuson Can you open browser console and paste "window.devicePixelRatio", What does it returns? I guess its 2...

Giwayume commented 3 years ago

It's easy to test in the mobile emulator in chrome, for example the iPhone X preset has devicePixelRatio of 3

image

Only thing is you won't be able to see the difference physically unless you're on an actual phone. Can also use display scaling in Windows https://www.windowscentral.com/how-set-custom-display-scaling-setting-windows-10

JordanMagnuson commented 3 years ago

Yes, I should have mentioned that: the monitor those screenshots were taken on is a 4k monitor with window.devicePixelRatio = 1.25.

Unfortunately, the underlying rendering issue seems to be present even on a 1080p monitor with window.devicePixelRatio = 1.

Here is a screenshot from the 1080p monitor (PR = 1, both image editors open side by side in Chrome, at about 60% scale): https://i.imgur.com/rah0rkk.png

Obviously there is subjectivity involved in terms of what constitutes the "best" or "most accurate" rendering of an image (especially when it comes to smoothing the image at different scales). But the Photopea rendering at various scales is much closer to what you get if you open the PNG directly in Chrome (or an image editor like Photoshop). The miniPaint rendering is excessively pixelated by comparison (though some scales do look better than others--notably 100% looks less pixelated than other scales).

Giwayume commented 3 years ago

@JordanMagnuson you say Chrome, what operating system? I'm not seeing such a significant difference on a 1080p monitor with no scaling.

image

Giwayume commented 3 years ago

Hmm I think Photopea is cheating a little bit here. If I switch between imageSmoothingEnabled true/false depending on the zoom level it will look good or bad. Ideally when you're zoomed way in you'll want to see pixels clearly for detailed pixel work, so imageSmoothingEnabled should be false, but when zoomed out in some zoom levels it looks better with imageSmoothingEnabled true.

I say "cheating" in the sense that Photopea doesn't let you set a custom zoom percentage, they probably have a mapping of what the imageSmoothingEnabled value should be based on the current zoom preset and only zoom in to specific levels where it will look best.

Or it could be simple as if zoom < 100% / devicePixelRatio then imageSmoothingEnabled true if zoom >= 100% / devicePixelRatio then imageSmoothingEnabled false

JordanMagnuson commented 3 years ago

@Giwayume I am on Windows 10. Does the screenshot you took have the miniPaint canvas zoom set at 100%? As I noted in my last comment, it does look okay at 100% when devicePixelRatio = 1 -- it's at other zoom levels (and/or other devicePixelRatioo values) where there is a noticeable difference.

Or it could be simple as if zoom < 100% / devicePixelRatio then imageSmoothingEnabled true if zoom >= 100% / devicePixelRatio then imageSmoothingEnabled false

That's an interesting idea. It's possible that it might actually be as simple as that... I'll try to mess around with that a bit.

Giwayume commented 3 years ago

It was 60 or 70%. It was hard to match up because Photopea doesn't show percentage so far as I can tell.

Giwayume commented 3 years ago

Another option if you really care about quality below 100% zoom (this will be way beyond what Photopea does) is use the 'hermite-resize' module at the very end of each draw step to scale down the final draw result then stretch it back up to the canvas size. That module is pretty fast but obviously it's a tiny additional performance overhead.

You can see this looks much better than what Photopea offers when zoomed way out.

http://jsfiddle.net/zxLtj3nr/

JordanMagnuson commented 3 years ago

It was 60 or 70%. It was hard to match up because Photopea doesn't show percentage so far as I can tell.

That's interesting. And this is Google Chrome, Windows 10? I've tested on two computers (Chrome + Windows 10), and seen the same pixilation on both. I just tried resetting Chrome to factory settings, and still getting the same result.

Interestingly, Firefox is showing a smoother image on those same computers (this is with devicePixelRatio = 1): https://i.imgur.com/WuGQRAz.jpg

Microsoft Edge looks about the same as Chrome (bad).

viliusle commented 3 years ago

Or it could be simple as if zoom < 100% / devicePixelRatio then imageSmoothingEnabled true if zoom >= 100% / devicePixelRatio then imageSmoothingEnabled false

It is also possible to create new user setting "canvas Smoothing" with 3 options: off [default], only when zoomed in, on. So use will be able to change.

p.s. right now imageSmoothingEnabled is activeted in multiple places (JSS, CSS) p.s.s. I belive using hermite resize on every rendering frame would be too much....

Giwayume commented 3 years ago

Wasn't suggesting hermite on every frame, I notice a lot of photo viewers run quick resampling algorithms when zooming but a split second after the zoom ends it runs the more expensive and nicer looking algorithm.

JordanMagnuson commented 2 years ago

Wow, the changes you made look much better!