Arduino - 5x8 ISO 8859-2 font

A while ago I took an existing 3x8 font, converted it by hand for use with AdaFruit's graphics library and subsequently modified it to use ISO 8859-2 characters (in a presumably innocent coincidence this popped up in the Adafruit GFX Library a few months later). Anyway, I recently received a request to perform the same modification to the standard 5x8 fonts and only recently got round to looking at this. As a quick reminder, ISO 8859-2 covers ~128 extra characters for alphabets used by Central and Eastern and Southern European languages - these characters look like this:

After a little bit of experimentation I realised that the extra 2 columns aren't really all that useful for adding the extra ligatures (čarky, hačky, umlauts etc) - we're really constrained by vertical space. Many of the existing letters need to be modified or reworked entirely, since they consume the almost entire 8 rows and we need 2 rows for some ligatures. For example Ä is currently implemented as the following:

    0x7D, 0x12, 0x11, 0x12, 0x7D

Which looks like this:

This is visually a little confusing, but more importantly we cannot really re-use it for ISO 8859-2 since some of the ligatures we need to add to the "A" require at least two rows. Instead of having an "A" which jumps around depending on the ligature, I've created a single A for when a ligature is used and left the ungarnished original letter alone.

Just as another example of why this can be tricky the existing ä looks really weird to me, the umlauts are skewed off to the left and look like they're joined to the letter itself. 

I've moved this up into a central position which is the same on all letters involving umlauts. This is purely based on personal taste, but I think it looks better - below is the original style compared to my modified version:

There are similar considerations in some of the other letters that are left as an exercise for the reader - see if you can devise a neat system to fit all the letters below into 3x8 grid in a way that is consistent and legible, it's pretty tricky. I've made an initial stab at this (see GitHub gist below), but after revisiting this I've realised how flakey and error-prone this process of creating fonts is. 



A tiny font ... Eastern European edition

In a previous post I created a little replacement font for the Adafruit Graphics Library, but left the non-ASCII characters (values > 0x7F, 128 in total) completely blank. This is because this area is used to implement the additional symbols necessary for languages other than English, and I had initially just intended to create an English language font for my own purposes.

Obviously you can't represent all of the necessary symbols for all the world's languages in just 128 slots, and this is where ISO 8859 comes in*. There are 16 ISO/IEC 8859 character sets which implement the symbols for loosely related (and sometimes unrelated) languages in the upper 128 bytes.

The most common one is probably ISO 8859-1 which can represent most of the EU's main languages, so it should be a pretty sensible one to implement. However since I live in the Czech Republic and I love Central\Eastern Europe I decided to implement ISO 8859-2 which covers Bosnian, Polish, Croatian, Czech, Slovak, Slovene, Serbian, and Hungarian and looks like the below

Note: the above rendering I picked up someplace on the internet is actually incorrect - when the letters t and d have a caron/haček it actually looks more like an apostrophe - ď and ť.

I only implemented this for my slimmer 3x8 font, but if there's any interest I can quickly put together something for the Adafruit 5x8 one or attempt a different character set so long as it's based based on a latin script. Sadly I'm not sure if my skills are up to the task of creating something tougher like Chinese, Tamil or Thai.

I'm a novice at font design, but looking at the required diacritics it seemed to make sense to reserve the top two rows for things like Haček (e.g. č, ř and ž) and Čarka (e.g. á, ý and é) and the bottom row for anything below the letters - which leaves a 3x5 space in the middle to implement the root of each letter - which I managed to do with a couple of exceptions. Here's a quick visualisation of this:

So for example if we want to create the letter "č" it would look something like this:

With only three columns available there are a number of characters which will look a little weird - the worst of which were Đ, § and ď - and the Albanian characters with the tail (ç, ţ and the like). Here's what the font looks like:

It's a little cramped - with some characters appearing to be joined to those above/below - which is due to the fact that the top rows were previously blank and served as line spacing.

I've pushed this into my fork of the Adafruit GFX Library repo on github - check it out and copy the whole thing into your Arduino libraries folder to install it. Note that the Arduino IDE saves files using UTF-8 encoding, so you can't just throw string literals in and assume they'll work - the simplest way to output a string using this character set is to manually enter the hex values. 

So if we want to have the string representation of a nice little Czech sentence, we'd encode it as follows:

When we pass this to display.write() - not display.print(), which will just output the numeric values - we'll see this:

* = Yes I know that we have unicode to properly address this problem, but it's quite complex and is mercifully not used by the Adafruit Graphics library for simplicity's sake.

A tiny new font for the SSD1306 128x64 OLED screen

The default font for the Adafruit graphics library is a 5x7 font, it looks a little something like this:

It's readable, but I thought it'd be interesting to use a more compact font like "Tom Thumb" by Robey Pointer:

The font currently bundled with the library is in a file called glcdfont.c and is defined as a big byte array:

Each line of that array is 5 bytes and represents a simple monochrome bitmap of a single ascii character, with each byte representing a column. For example example the letter "a" is represented by the following line:

0x20, 0x54, 0x54, 0x78, 0x40,

In binary each of these is:

You can almost see the shape if you twist your head 90 degrees to the right, but to make things a little clearer here's what this actually represents:

If we were to use the Tom Thumb font we could save ourselves two bytes per character, since it is a little slimmer, meaning that "a" could be represented by the following three bytes:

0x68, 0x58, 0x70

Or, in binary:

Which looks like this:

Since there's a bit of wasted space at the top (the top two bits won't get used at all) we could technically save ourselves a little more space, but for simplicity's sake I'm going to sacrifice those two bits. Currently the font can be easily retrieved and manipulated as each column fits neatly into a single byte, however we'd introduce a good deal more complexity by squeezing those additional bits - which would mean substantial changes to the driver itself to compute the correct address to read the bitmap from, and shift/mask the necessary bits.

However even with this tradeoff we can still save 2 bytes per character, which is a pretty impressive 512 bytes over the whole ascii space which is pretty substantial.

The main challenge is creating a separate .c file we can swap glcdfont.c out for. I had trouble dealing with the BDF file Robey shared, but since there's a little bitmap representation of the whole ascii space it wasn't too tough recreating the font by hand ... just extremely tedious! I hacked together a simple little app (source is here) using Processing that let me paint each character by clicking boxes and which spat out the hex values when I hit a key. I'd then copy and paste this into the glcdfont.c. As I said, extremely tedious.

Once I'd produce my file it was time to test it - the beauty of having the 3x6 font means that the entire ascii space could be displayed on a 128x64 screen:

It's actually pretty surprising how much text you can fit on screen.

And just a little reminder of how small this screen is, with a €2 coin for scale

You can see the amount of memory saved in the .text section (where program code lives) by examining binaries GCC has produced - exactly 512 bytes.

My fork of the Adafruit gfx library with the Tom Thumb font is at https://github.com/smcl/Adafruit-GFX-Library and is a drop-in replacement for the existing library (replace the entire library, though, since I made some changes in Adafruit_GFX.cpp. You can switch between the fonts by toggling the #if ... #else condition in glcdfont.h below: