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

pixel fonts not rendered properly #18

Closed
quinton-ashley opened this issue Nov 29, 2023 · 2 comments
Closed

pixel fonts not rendered properly #18

quinton-ashley opened this issue Nov 29, 2023 · 2 comments
Labels
bug Something isn't working

Comments

@quinton-ashley
Copy link
Collaborator

quinton-ashley commented Nov 29, 2023

Yeah... this is a bit of a rabbit hole! 🐰

q5.js currently can't render pixel fonts (very small sized fonts made of just a few pixels) at a pixel perfect level (sharp and blocky) because q5 uses native canvas rendering. Every browser's canvas.fillText implementation seems to do anti-aliasing and the ctx.textRendering property doesn't seem to change that, at least not in Chromium based browsers. Also Safari does not have this feature. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textRendering

p5.js can sometimes render pixel fonts correctly, if the font is the right size and at a correct position (not always integer coordinates!). p5 does not use native canvas rendering for true type and open type fonts, it uses OpenType rendering. My guess is that this decision was made because around the time p5.js was created, browser's native canvas implementations for font rendering were not so good. Nowadays though, in any other case besides pixel fonts, q5's native canvas rendering with canvas.fillText definitely looks better and probably runs faster than p5's OpenType based method. Which I noted here:
https://discourse.processing.org/t/why-is-text-not-centered-properly-with-textalign-center-center/43322/8

However, in the case of pixel fonts, using OpenType to render text as primitive canvas shapes actually works great because pixel fonts are just made out of a few pixels (squares). So OpenType rendering could be used for pixel fonts and native for everything else? Well things are not so simple.

Take a look at this demo with a font called Bit Potion, the creator says it's best to use it in 16px intervals. I made this demo which uses p5.js and shows text displayed with the pixel font at 16px and 32px.

https://editor.p5js.org/quinton-ashley/sketches/fhr7cLd3R

Clicking the mouse in the demo will switch the text from being rendered at integer coordinates to half pixel coordinates (0.5). For some reason, at any even multiple of 16px, such as 32px, text only looks good at integer coordinates. At any odd multiple of 16 such as 48px or 16px, text only looks good at half pixel coordinates and only without letters that hang under the baseline like "p".

Why is that? Well I found this old stack overflow post where a user says "the canvas coordinate system defines the start of a pixel from the pixel's center" https://stackoverflow.com/questions/22976031/html5-canvas-without-anti-aliasing?rq=3

This sucks for users. Displaying pixel fonts shouldn't be a difficult guessing game. Users should just be able to put in any random coordinates and as long as the font is the right size, q5 should be able to draw it with pixel precision (sharpness).

But how could such a generalized solution be achieved? I don't know yet.

One idea is to add a feature to p5 and q5 where users could define the optimal size of a font. Then when the text function was used with the font, there could be some code that could adjust the position given by the user to make the font display well.

Another totally differnt idea I had was that p5play users could import a pixel font as a spritesheet animation, provided the font offer an image containing all the font's symbols. Then text could be displayed using the Tiles constructor. However, this has many obvious limitations. It'd only work for monospace fonts, not for the "Bit Potion" font. Also this method is untenable for non-English text with accented letters. Also it'd make using the Tiles constructor for anything else pretty much impossible. Yet, this approach could be decent for English text as long as it was implemented as a separate system to not conflict with p5play's Tiles system.

But I also noticed the Bit Potion font is offered as an old bitmap .fnt windows font file. I wonder if there's any canvas library for rendering them? This could be a good solution. I will research this more.

@quinton-ashley
Copy link
Collaborator Author

quinton-ashley commented Nov 30, 2023

Found this stack overflow post: https://gamedev.stackexchange.com/questions/183179/completely-pixelated-font-in-javascript-canvas/183207#183207?newreg=cab3501f3c1144d9b582acb17c458634

Setting this CSS property -webkit-font-smoothing to "none" solves the problem in q5! But only on macOS in Safari (so sad)
https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth

@quinton-ashley quinton-ashley added the bug Something isn't working label Jan 21, 2024
@quinton-ashley quinton-ashley changed the title [bug] pixel fonts not rendered properly pixel fonts not rendered properly Jan 21, 2024
@quinton-ashley quinton-ashley moved this to Todo in q5 Sep 25, 2024
@quinton-ashley
Copy link
Collaborator Author

Working on adding this to p5play:

quinton-ashley/p5play#334

@github-project-automation github-project-automation bot moved this from Todo to Done in q5 Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: Done
Development

No branches or pull requests

1 participant