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

Text antialiasing can’t be disabled #25

Open
gc opened this issue Jul 11, 2021 · 6 comments
Open

Text antialiasing can’t be disabled #25

gc opened this issue Jul 11, 2021 · 6 comments
Labels
enhancement New feature or request

Comments

@gc
Copy link

gc commented Jul 11, 2021

I'm looking at migrating from node-canvas, and I've noticed a difference between the text drawing which is a big problem for me because I use several small/pixel-art fonts, I don't know if its a bug or just I'm not using something correctly - please let me know! Thanks

image

Code / Minimal reproduction (used to generate that image^): https://github.com/gc/skia-canvas-test

@Brooooooklyn
Copy link

@gc hey, I'm the original author of the rust-skia project, maybe you can try this https://github.com/Brooooooklyn/canvas project, which aim to provide zero system dependencies and high performance of canvas implementation for Node.js.

@samizdatco I just noticed your heavy work on this project! This is amazing. I start skr-canvas from scrach instead of rust-skia because the build steps of rust-skia is too complex, I need Linux musl support and build skia without fontconfig, which is complex for rust-skia. It seems the arm/arm64 issues already appeared: #24

/cc @pragmatrix

@samizdatco
Copy link
Owner

I'm looking at migrating from node-canvas, and I've noticed a difference between the text drawing which is a big problem for me because I use several small/pixel-art fonts, I don't know if its a bug or just I'm not using something correctly - please let me know! Thanks

As far as I know, the canvas standard doesn't provide a way to disable antialiasing/smoothing beyond the specific case of resizing bitmap images (whether in a drawImage() call or when using an image-based CanvasPattern). For instance, here's a magnified version of the browser's text rendering even with imageSmoothingEnabled set to false: https://jsfiddle.net/6r7ktuhn/

All of which is to say, it's the node-canvas behavior that's actually unexpected here. But it also seems like a genuinely useful thing to be able to control, especially for pixel-art use cases like yours. It might make more sense to turn it into a separate fontSmoothingEnabled property rather than conflating it with image-smoothing though...

@samizdatco samizdatco added the enhancement New feature or request label Jul 12, 2021
@samizdatco samizdatco changed the title Blurry (anti-aliased?) text Text antialiasing can’t be disabled Jul 12, 2021
@gc
Copy link
Author

gc commented Jul 12, 2021

the canvas standard doesn't provide a way to disable antialiasing/smoothing beyond the specific case of resizing bitmap images (whether in a drawImage() call or when using an image-based CanvasPattern). For instance, here's a magnified version of the browser's text rendering even with imageSmoothingEnabled set to false: https://jsfiddle.net/6r7ktuhn/

Yep. It is impossible to fillText with no anti-aliasing in any major browser, I know this because I spent hours trying to figure out a way around the issue. Ultimately the best solution I came up with, is just raw pixel manipulation, having a matrix of 0's and 1's for each letter, paint each pixel of each letter manually. I read that the 'canvas standard' doesn't specify anything about text anti-aliasing, but its just a thing browsers do by themself, because text in 99.99% of cases would look bad without it, so ofcourse they implement that.

The way I see it, it comes down to: is it possible for you to control anti-aliasing, so you can implement a thing like fontSmoothingEnabled? If its possible, that would be a really nice thing to add, I dont see any reason not too. You would just default it to anti-alias everything , so theres no breaking change and it matches the browsers.

@samizdatco
Copy link
Owner

So it actually looks like the antialiasing setting may be inaccessible since fillText() uses an SkParagraph-based typesetter. This issue from last year makes it sound like Skia itself is assigning the antialias-mode value internally. So for now at least, it doesn't seem like a fontSmoothing flag is in the offing.

However, I think you can achieve the hard-edged-characters effect you want by using the newly added outlineText() method to convert your text to a Path2D before drawing it.

For instance:

  FontLibrary.use('./osrs-font-compact.otf');
  ctx.font = '16px OSRSFontCompact';
  ctx.fillStyle = 'black';

  // blurry
  ctx.fillText("It's dangerous to go alone! Take this.", 10, 16)

  // sharp edged
  let textPath = ctx.outlineText('You are likely to be eaten by a grue.')
  ctx.fill(textPath.offset(10, 32))

text-as-path

@gc
Copy link
Author

gc commented Jul 23, 2021

I improved my test case so it tries out one of the other fonts I use, and for some reason this second font (osrs-font-bold.ttf) doesnt work in skia-canvas (but works in node-canvas), in either method of fillText or outlineText. Is this a mistake on my side or a potential bug? https://github.com/gc/skia-canvas-test

@samizdatco
Copy link
Owner

Seems fine to me:

  FontLibrary.use(['osrs-font-compact.otf','./osrs-font-bold.ttf']);
  ctx.font = '16px "RuneScape Bold 12"';
  ctx.fillStyle = 'black';

  // blurry
  ctx.fillText("It's dangerous to go alone! Take this.", 10, 16)

  // sharp edged
  let textPath = ctx.outlineText('You are likely to be eaten by a grue.')
  ctx.fill(textPath.offset(10, 32))

out

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

No branches or pull requests

3 participants