One of the features most glaringly missing from CanvasPaint is text support. Quite a lot of the images saved online contain scrawly, hand-drawn text. Proper font support would obviously greatly improve the efficiency of spamming some website’s url and/or the word “dick” 50 times in a row. Unfortunately, the canvas spec does not address writing text to a canvas apart from the following comment:
// drawing text is not supported in this version of the API // (there is no way to predict what metrics the fonts will have, // which makes fonts very hard to use for painting)
On the Mozilla wiki, there has been some inconclusive discussion about adding text rendering functionality, but it appears to have stalled.
So let’s explore some other options. The first thought is to somehow make use of the browser’s built-in perfect font handling capabilities (kerning/hinting, right-to-left, etc.), letting it render the font by itself and then somehow importing it into the canvas:
1. Overlaying HTML
One obvious technique that does this is simply layering divs with “real” text on top of a canvas. The nicest implementation of this principle is Oliver Steele’s TextCanvas library. This approach works well enough, but of course the text is not actually rendered to the canvas and thus can’t be transformed, drawn over (unless you layer another canvas on top) or saved when you call toDataURL(), so it’s not a suitable solution for CanvasPaint.
2. Rendering HTML with drawWindow()
Mozilla supports a proprietary drawWindow() method, which would enable one to render some HTML text from a (potentially hidden) iframe to the canvas. However, that method is only accessible from chrome – ie. for extensions, where it is used to great effect for creating/displaying screenshots of web pages (TabPreview, etc). There’s a bug advocating allowing websites to access it as well, but that too appears to be in hibernation.
So using the browser’s font rendering doesn’t seem to be working well enough. “No problem,” I hear you say, “then let’s reimplement it all from scratch!”. Alright, if you insist…
3. Bitmap fonts with drawImage()
A bitmap font is simply an image containing all characters of a font, which is then selectively drawn to the canvas. → Try it out.
This works fairly well, but to make it look really nice, we’d need to create one such image per font size we’re intending to use.
Benjamin Joffe has written a helpful bitmap font generator to facilitate this task. For most canvas projects this is probably the way to go, even though it feels rather tedious and inflexible.
4. Vector fonts
That finally leaves us with parsing actual vector font files. The two most commonly used formats are TrueType and PostScript Type1 – both complex binary file formats, which we’ll hardly be able to parse in JavaScript.
Thankfully a little tool called TTF2PT1 allows us to convert a TrueType file into an ASCII Type1 (T1A) font. Suddenly, everthing becomes readable. Now the instructions for drawing Arial’s capital I look like so:
/I {
[...]
93 hmoveto
95 hlineto
716 vlineto
-95 hlineto
-716 vlineto
closepath
endchar }
It turns out to be quite easy to convert those lines for use with canvas with some simple hackish search/replace/turn-PS-stack-operators-into-JS-function-calls. We’ll just load the T1A file using AJAX and parse it in real time: → Try it out.
Some issues remain: At 150-200KB, those T1A files are pretty huge. To save on filesize and processing time, one could possibly pre-parse those into some made-up canvas font format, or at least remove all the lines the simple parser skips anyway.
Most quality fonts include very specific and complex hinting information to optimize their display at small font sizes where simple antialiasing causes pixels to tend to smudge and run together. A reference implementation of how to handle hints might be FreeType’s Autohinter (or possibly Ghostscript or T1Lib?) Replicating all that in JavaScript would be quite a task… any volunteers?
Additionally, there are most likely licensing issues with putting font data online like that, if you’re not just planning on using open source fonts. I suspect this is one of the reasons the efforts to enable embedding fonts in regular HTML (the DRM’ed EOT and PFR, as well as CSS2’s liberal @font-face) never caught on.
So what to implement in CanvasPaint? I’m leaning towards a pre-parsed “canvasfont” version of Vera Sans… another entry for the todo list. Soon, important messages like these should be easier to create:
[One final idea would be rendering the text server side with ImageMagick or the like, and loading that into the canvas... but that'd be, like, totally lame, right?]
Update: The RhinoCanvas project has an in-depth suggestion for a drawString() method.


February 28th, 2007 at 23:0
[...] The very cool CanvasPaint project went nuts and implemented vector fonts in canvas! (more info here. [...]
April 3rd, 2007 at 16:1
Hi,
I’ve extended the features of S5 1.3 (aka Reloaded) with dynamically generated, scalable pie charts in canvas objects through parsing html tables. I needed text for the percentage strings (0123456789%.).
I’ve tested html-, image- and stroke-text.
The implementation of vector fonts is the wrong way because of the complexity. But integrating the very simple stroke fonts from CAD programs is much more interesting.
Example:
######################### start snip ########################
Canvas Stroke Font Sample
#demo { border: 1px solid black; padding: 1em; }
canvas { border: 4px solid #FFFF99; }
function deg2rad(degrees) {
return Math.PI *degrees/180;
}
function drawString(ctx, txt, col, fh, tx, ty) {
var fw = fh*0.666666; var lw = fh*0.125;
var ls = lw/2; var xp = 0; var cr = ls;
ctx.lineCap = “round”; ctx.lineJoin = “round”
ctx.lineWidth = lw; ctx.strokeStyle = col;
for (var i = 0; i
The following is a demonstration of how to render text on a canvas element
through a simple, fixed width stroke font, which I created [only numbers, point
and percentage] (example font-sizes: 64, 48, 32, 16, 14, 12, 10, 9, 8, 7, 6
– font-aspect-ratio: 1:2 — font-lineWidth: font-height/8).
######################### end snip ########################
April 3rd, 2007 at 16:1
Sorry the source has been cutted.
Here is the sample link:
http://www.netzgesta.de/S5/canvas-text.html
April 3rd, 2007 at 16:1
That is pretty awesome — hats off!
April 23rd, 2007 at 02:1
Here are 20+ vector fonts samples. This is a bit of a cheat, but it works. have fun.
http://www.gnpti.com/website/WebCharts50/canvasFont/index.jsp
June 15th, 2007 at 20:1
I implemented the printable 7 bit ascii character set portion of the sans serif Hershey fonts in Javascript. It is compact and fast, if not gorgeous.
http://core.federated.com/~jim/canvastext/
August 27th, 2007 at 10:1
How about writing your text in a div overlay.
When you exit the typetool, you send an ajax request and let php add the text to the image (dataurl wise).
All changes, while waiting for the new image are placed on a stack and redrawn once the new image arrives. Refresh canvas.
I don’t think that vectortext with javascript will work. You need kerningtables, anti-alias stuff and all that. It takes a fontdesigner over a year to make a decent font, don’t expect to do the same with javascript in a few days :)
Great work, love where this is going.
October 3rd, 2007 at 06:1
Thanks for showing that this is possible, but there are several problems with your approach.
First of all, you’re rounding the advance positions in hsbw. That rounding leads to the terrible layout of text you see at small sizes. You’re better off just letting the horizontal advance happen freely, which will let antialiasing do a much better job. Besides, if you want to hint the fonts, you need to keep track of the exact on-screen pixel position, and you’d basically have to shadow every canvas translate, rotate and scale operation so you could invert them.
Second, at least according to Apple and Cairo’s documentation, canvas uses the nonzero rounding rule for filling, which means you shouldn’t have to play with composite operations at all.
Also, you’re right about it being better to preprocess the font. One approach would be to create a javascript array with one entry for each glyph. Each glyph would have some data (metrics, kerning, etc.) and also an actual function that would render the outline. That way, you could just eval() the whole thing.
You’d have a loop that looked something like this for rendering text:
let prev_char = null
for each character c in the text:
canvas.translate(
font.getKern(prev_char, c),
0)
let g = font.getGlyph(c)
g.render(canvas)
canvas.translate(g.x_advance, 0)
prev_char = c
How you get the font array isn’t important. (Javascript people seem to place too much emphasis on ajax-this and ajax-that; it’s just one way of getting information into a document.)
February 5th, 2008 at 15:0
I have made a sans-serif multiple master single line stroke font library for use with canvas and vml. I took over some ideas and the font format grid from Jim Studt’s “canvastext.js”. Here is the sample link:
http://www.netzgesta.de/dev/text/
May 19th, 2008 at 17:1
How is the code in the demo licensed?
October 20th, 2008 at 05:1
[...] run into problems, however, when I began to look into displaying text on a canvas tag. There are a few alternatives, and maybe something that doesn’t work in Firefox yet, but all seem to involve [...]