New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 712844 link

Starred by 6 users

Issue metadata

Status: Available
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac
Pri: 2
Type: Bug



Sign in to add a comment

createImageBitmap resizeQuality option broken

Reported by vit...@rcdesign.ru, Apr 18 2017

Issue description

UserAgent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0

Steps to reproduce the problem:
1. Enable experimental canvas extension flag
2. Go to resizer demo http://nodeca.github.io/pica/demo/

3.1 Set unsharp amount to 0, toggle "use createImageBitmap" checkbox and compare quality with javascript Lancos3 implementation.

3.2 Move "quality" slider, and see that result of createImageBitmap is the same for: pixelated <-> low, medium <-> high.

What is the expected behavior?
Expected quality to be as in Skia filters:

1. Box (pixelated)
2. Hanning (low)
3. Lanczos2 (medium)
3. Lanczos3 (high)

What went wrong?
Real quality seems to be:

1. Box (pixelated)
2. Box (low)
3. Lanczos2 (medium)
4. Lanczos2 (high)

Did this work before? No 

Does this work in other browsers? Yes

Chrome version: 57.0.2987.133  Channel: stable
OS Version: ubuntu 14.04
Flash Version: 

1. I digged Skia sources when implemented javascript resizer math, and i think i can see quality difference between existing filters.

My guess is that createImageBitmap resize use "filter number / 2" due some mistake.

2. Please, recheck result rounding of Skia convolver in similar place https://github.com/nodeca/pica/blob/3.0.3/lib/mathlib/resize_convolve_js.js#L63-L66

As far as i remember, Skia uses "result >> 14" instead of "(result + (1 << 13)) >> 14". That cause broken rounding and energy loss. See details in https://github.com/nodeca/pica/commit/f384be97723c97a14f88f0cc1e2c091feaeebedd
 
Labels: OS-Android OS-Chrome OS-Mac OS-Windows
Cc: junov@chromium.org
Owner: xidac...@chromium.org
Status: Assigned (was: Unconfirmed)
Will investigate.
Cc: fmalita@chromium.org
OK, here is my investigation.

I used a small script ("test.html"), with the "test.png", and produce results with 4 different kinds of resizing filter options.

fmalita@ pointed out that in the downscaling case, the result of high == medium, which is indicated in the attached files. The difference between medium and low is quite obvious. Now if you compare low vs pixelated, focus on the text on the orange and black circle disk, I believe you will notice the difference. I think in your original test case, the image is too small after resizing and the difference is really subtle.
test.html
493 bytes View Download
test.png
11.1 MB View Download
high.png
1.6 MB View Download
medium.png
1.6 MB View Download
low.png
1.6 MB View Download
pixelated.png
1.6 MB View Download
Status: WontFix (was: Assigned)

Comment 5 by vit...@rcdesign.ru, May 10 2017

Ok, let me rephrase problem: it's impossible to create good thumbnails via createImageBitmap(), because quality is horrible even in "high" mode.

See attached screenshots of http://nodeca.github.io/pica/demo/ from macbook pro retina + ubuntu 14.04 + Chrome 58.

Pay attention to white paper with "Ubuntu". I think it's obvious, that createImageBitmap() produces very blurred result.

Can you see difference and reproduce it on your side?
cib.png
2.7 MB View Download
wasm_manual.png
2.8 MB View Download

Comment 6 by vit...@rcdesign.ru, May 10 2017

@xidac..., your investigation shows, that difference between quality modes exists. Ok. But it does not provide rating of best quality, because does not have alternate source to compare.

In my investigation, i compare best result of createImageBitbap() with best result of Lanczos3 implemented in js/wasm (those are binary equal).

"My" Lanczos3 algorythm is ~ the same as in Skia with 2 minor differences:
- no interleaving for horizontal + vertical passes
- may be, better result rounding in convolvers ( "(result + (1 << 13)) >> 14" instead of "result >> 14" )

I understand, it may be subjective to say "another program do resize better than your one", but:
1. Difference is really big.
2. Math is ~ the same. That's not battle about filters and theory.
I tried on Linux, Windows and Mac and cannot repro what you have. Please refer to the attached images.

You mentioned that you are trying this on chrome 57, so maybe try to update it to 58?
linux-1.png
1.1 MB View Download
linux-2.png
1.1 MB View Download
linux-about.png
69.2 KB View Download
mac-1.png
1.5 MB View Download
mac-2.png
1.5 MB View Download
mac-about.png
116 KB View Download
windows-1.png
1.6 MB View Download
windows-2.png
1.6 MB View Download
windows-about.png
100 KB View Download

Comment 8 by vit...@rcdesign.ru, May 10 2017

You forgot to enable "experimantal canvas extensions" chrome://flags/#enable-experimental-canvas-features, to enable resize support.

Without that flag, pica fallback to "manual" implementation, but does not show this in text. Take a look at resize time. If resize use CIB, it take < 10ms (as on my screenshots). If JS/WASM used, that takes 150-400 ms.

PS. I now uses Chrome 58 and Chromium 58, bug is reproduceable there.
Status: Assigned (was: WontFix)
reopen, yes, I see that it is blurry with the flag enabled.

Comment 10 by vit...@rcdesign.ru, May 10 2017

Great!

Kick me, if you need any help about pica's code. I understand you should not trust it, but i swear it should do exactly the same math as Skia, with only 1 difference in result rounding (if not fixed in Skia yet). But this difference should not cause such a big blur.

What is desired in the end:

IMHO, it will be ideal, if result of createImageBitmap(with_resize) and pica.resize() will be binary equal (= math & implementation will be predictable).


createImageBitmap internally does use skia's resize logic. I have attached a test case. If you run the "test.html", and compare the result with the one produced by skia fiddle:
https://fiddle.skia.org/c/f540048f57161c870b86008be48d9c01

You can see that they are the same.

You have mentioned that this is Skia's resizing logic:
https://github.com/nodeca/pica/blob/3.0.3/lib/mathlib/resize_convolve_js.js#L63-L66

I briefly looked at it, and I think the way it works (please correct me if I am wrong) is for each destination pixel, look at the pixel data from the source image, and apply a filter on the source data.

fmalita@: is this how skia's resizing works? My understanding is that skia directly draws an image into SkCanvas to do the resizing, is that wrong?
skia-test.png
603 KB View Download
test.html
441 bytes View Download

Comment 12 by vit...@rcdesign.ru, May 10 2017

> You have mentioned that this is Skia's resizing logic:
> https://github.com/nodeca/pica/blob/3.0.3/lib/mathlib/resize_convolve_js.js#L63-L66

Let's separate things to avoid confusion.

1. Resize is done via separable concolver. I used Skia sources to learn theory, and tried to implement exactly the same math. Minor difference in filters packing & removed interleaving are technical and do not affect math/precision.

2. The link to pica lines, provided by me, are to show that pica probably has more proper convolver result rounding. Skia used "(result >> 14)" - just dropped fractional part:

254,9 => 254

That can cause brightness loss. I had this bug in pica but did not tested Skia. This test should help to reproduce issue https://github.com/nodeca/pica/blob/master/test/brightness.js. May be, i did not understand something. So i don't insist, just ask if someone experienced could check this place in Skia.

3. That's not implemented in Skia/pica, but if anyone in google is interested, read this http://www.imagemagick.org/Usage/filter/nicolas/#short. Nicolas Robidoux says, that in separable Lanczos3 filter intermediate result should not be rounded to 8 bits:

> I do not recommend tensor (-resize) Lanczos filtering unless you use an HDRI Version of ImageMagick.

That's not related directly to this bug, but may be useful if someone decide to polish Skia's math.
I had a discussion with junov@ and fmalita@, so in skia, Lanczos3 is used when upscaling. For downscaling, it uses mipmapping, not Lanczos3. That's probably why it is different.

Comment 14 by vit...@rcdesign.ru, May 10 2017

Got it. I did not expected mipmapping at all. But i hope you agree, that existing downscale with "high" quality is very far from perfect.

Let me say well-known things:

1. Lancsoz is NOT recommended for upscale. Mitchel is preferable.
2. Lanczos3 is common choice for downscale when high quality required.

IMHO, existing chrome's downscale is not useable when high quality expected. But formally, there is no exact definition of "high quality". Need your decision.

Comment 15 by junov@chromium.org, May 24 2017

I think a good quality/performance compromise would be to use a lanczos fileter for mipmap generation.
Owner: zakerinasab@chromium.org
Cc: bsalomon@chromium.org brianosman@chromium.org
Cc: -junov@chromium.org
Owner: ----
Status: Available (was: Assigned)

Sign in to add a comment