Brooooooklyn / canvas

High performance skia binding to Node.js. Zero system dependencies and pure npm packages without any postinstall scripts nor node-gyp.
https://vercel.skia.rs
MIT License
1.78k stars 76 forks source link

Expose Low-Level Skia and Harfbuzz APIs #681

Open Danielku15 opened 1 year ago

Danielku15 commented 1 year ago

I am currently looking for a good library providing skia bindings for rendering images. Having a Canvas-like API is nice and would partially fit my needs, but I would actually prefer to have the low-level Skia and Harfbuzz function calls available too.

Do you think it would be feasable to expose (more or less) the full Skia APIs in your library as a 1:1 mapping? Additionally for proper text drawing having access to Harfbuzz would also be great.

Alternatively, if it is also in your interest, I could also try to adjust your canvas implementation to directly fit the rendering of Chrome. The differences I see seem to be mostly in the text rendering and with my experience on the other libraries I could likely fix those differences.

My background is following:

I am making a cross platform library (web, node, .net, android,...) and try to rely on Skia on all platforms when it comes to testing for visual bugs.

I want to get the exact visual output like in Chrome and for this it is important to use Skia exactly the same as they do. When making the exact same drawing calls in Chrome the results are significantly different to this library.With SkiaSharp I managed to get outputs matching almost the ones in Chrome.

When using this library as rendering backend almost all my tests fail while with Chrome, SkiaSharp and Skija I can get outputs similar enough to allow me testing for visual regression problems.

References: https://github.com/CoderLine/alphaTab/blob/develop/src.csharp/AlphaTab/Platform/CSharp/SkiaCanvas.cs https://github.com/CoderLine/alphaTab/blob/develop/src.kotlin/alphaTab/alphaTab/src/androidTest/kotlin/alphaTab/visualTests/SkiaCanvas.kt https://github.com/mono/SkiaSharp/issues/1253

yisibl commented 1 year ago

Thanks for looking into this, so what are the main reasons for these differences?

Danielku15 commented 1 year ago

The two reasons are:

  1. Harfbuzz does the placement of the glyphs different than the default shaper. This results in different spacing between the individual characters. When I was discussing the same topic with the folks from SkiaSharp I was doing various tests. Here one example how the spacing can be different. See here and here
  2. The second important setting the scaling factor for mapping between harfbuzz and skia. This affects heavily on sub-pixel level how the anti aliasing is then applied. See here and here

To achieve the correct rendering I need this library would need to provide a range of new APIs unless internally it directly does the drawing as my library also needs it:

  1. The Harfbuzz APIs to create a font object and scale it as this is one main input for harfbuzz on shaping.
  2. The shaping API is needed which places all the glyphs so we can get all positions we need.
  3. The Skia APIs for building a text blob is needed to create a text blob and set the glyph positions as computed by harfbuzz.
  4. The Skia APIs for drawing a text blob is needed to effectively render the text.
  5. The Skia APIs for accessing typeface metadata is needed to adjust the positions for text alignment and text baseline settings.

I am not sure if my code covers all text rendering scenarios which skia supports (multi line, emojis, RTL etc.) but it works perfectly for my usecase of single line text rendering.