Using Bitmap Fonts with Android

In this part I will try to explain what I understand on good game design elements. I will use droids in the examples and I will script a basic fight simulator to see how they behave.

Android is an OS running on many types of devices with different screen sizes. Because of that it is pretty difficult to address font related issues regarding both size and appearance on these platforms.

To use a consistent font face across devices I have used bitmap fonts. That is, each character is represented by a bitmap.

We can create an image for each letter in the alphabet and number for example and whenever we want to display a text, we draw the images of the characters from the string at the given position.

But wait! Isn’t loading an image for every character overkill? Yes it is. We can use android’s utilities for manipulating bitmaps to our advantage.

All we need is a bitmap containing all the characters we want to use and slice it up into individual bitmaps. To do this the easy way we will use a monospaced font. A monospaced font is a font whose letters and characters occupy the same horizontal space. In other words, the characters have the same width.

A simple character map can look like this.

Character Map

Character Map

Note that the background is transparent.

The above character map is arranged in a grid. The width of a character is 8 pixels. The height is 12 pixels. Note that the second row starts at 15 pixels so there is a gap between the rows. It’s just a choice and also how Photoshop broke the lines and I didn’t bother to change them.

Transparent Background

Transparent Background

The above image shows the beginning of the first row and how the characters are organised into cells.

Following this it is easy to slice it up. A simple for iteration will do the trick. To keep things simple I have created a map of only the English alphabet, digits and a few punctuation marks. You can extend it as you wish. Use a monospaced font in Photoshop or Gimp or whatever image editor you fancy and create your own sheet.

Here are plenty of bitmap fonts to choose from.

How can we use this? My idea to display text onto the screen is to create a drawString method that takes the text to be displayed as a parameter along with the position where we want to display it.

Something like this will do it:

void drawString(Canvas canvas, String text, int x, int y)

I also pass the canvas object in, onto which I want to draw the text. This is just for simplicity. In case of an OpenGL renderer we will have to use billboards (squares with textures). But for the purpose of slicing images and displaying fonts let’s stick with this approach.

Create a simple Android project that use simple 2D canvas. We will draw onto that.

I implemented the SurfaceView to hold my canvas and called it DrawingPanel.

In its constructor I simply register it to receive events when touching the surface and load the resources. The resources are in fact just the images of the glyphs/characters.

Download the following image file and drag it into your eclipse’s projects resource folder under: /res/drawable-mdpi for ADP to generate the id for the resource.



Create the DrawingPanel class.

public class DrawingPanel extends SurfaceView implements SurfaceHolder.Callback {


    private Canvas canvas;      // the canvas to draw on

    private Glyphs glyphs;      // the glyphs


    public DrawingPanel(Context context) {


        // adding the panel to handle events



        // initialise resources



        // making the Panel focusable so it can handle events




    /** Loads the images of the glyphs */

    private void loadResources() {

        this.glyphs = new Glyphs(BitmapFactory.decodeResource(getResources(), R.drawable.glyphs_green));

        Log.d(TAG, "Green glyphs loaded");



I omitted the other methods that need to be implemented as they are just stubs.

The canvas variable is used to draw the text onto and is obtained at every touch event. You’ll see later in the onTouchEvent method.

The most interesting class is the Glyphs class which holds the association of characters with images. The glyphs variable is instantiated in the loadResources() method. It calls the constructor of the Glyphs class with the character sheet image copied earlier.

Check out the Glyphs class:

package net.obviam.fonts;


import java.util.HashMap;

import java.util.Map;




import android.util.Log;



 * @author impaler



public class Glyphs {


    private static final String TAG = Glyphs.class.getSimpleName();

    private Bitmap bitmap;  // bitmap containing the character map/sheet


    // Map to associate a bitmap to each character

    private Map<Character, Bitmap> glyphs = new HashMap<Character, Bitmap>(62);


    private int width;  // width in pixels of one character

    private int height; // height in pixels of one character


    // the characters in the English alphabet

    private char[] charactersL = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g',

            'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',

            'u', 'v', 'w', 'x', 'y', 'z' };

    private char[] charactersU = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',

            'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',

            'U', 'V', 'W', 'X', 'Y', 'Z' };

    private char[] numbers = new char[] { '1', '2', '3', '4', '5', '6', '7',

            '8', '9', '0' };


    public Glyphs(Bitmap bitmap) {


        this.bitmap = bitmap;

        this.width = 8;

        this.height = 12;

        // Cutting up the glyphs

        // Starting with the first row - lower cases

        for (int i = 0; i < 26; i++) {

            glyphs.put(charactersL[i], Bitmap.createBitmap(bitmap,

                    0 + (i * width), 0, width, height));


        Log.d(TAG, "Lowercases initialised");


        // Continuing with the second row - upper cases

        // Note that the row starts at 15px - hardcoded

        for (int i = 0; i < 26; i++) {

            glyphs.put(charactersU[i], Bitmap.createBitmap(bitmap,

                    0 + (i * width), 15, width, height));


        // row 3 for numbers

        Log.d(TAG, "Uppercases initialised");

        for (int i = 0; i < 10; i++) {

            glyphs.put(numbers[i], Bitmap.createBitmap(bitmap,

                    0 + (i * width), 30, width, height));


        Log.d(TAG, "Numbers initialised");


        // TODO - 4th row for punctuation



    public Bitmap getBitmap() {

        return bitmap;




     * Draws the string onto the canvas at <code>x</code> and <code>y</code>

     * @param text


    public void drawString(Canvas canvas, String text, int x, int y) {

        if (canvas == null) {

            Log.d(TAG, "Canvas is null");


        for (int i = 0; i < text.length(); i++) {

            Character ch = text.charAt(i);

            if (glyphs.get(ch) != null) {

                canvas.drawBitmap(glyphs.get(ch), x + (i * width), y, null);





The line

private Map<Character, Bitmap> glyphs = new HashMap<Character, Bitmap>(62);

creates the map which associates a bitmap to each character.

To load this up we need the bitmaps for each character. I have created 3 arrays for the characters for which I have bitmaps.

charactersL[] holds the lower case letters of the English alphabet, charactersU[] the upper case letters and numbers[] holds the numbers. As an exercise add the punctuation array as this one is missing.

Note that the order of the characters is the same as in the character sheet.

For convenience I have created an array for each row from the image. To associate the images with the characters I will iterate through them and cut out the respective image from the sheet based on the index. Having a fixed width for the characters, makes all this dead easy. Examine carefully and understand the constructor. It does the slicing and association.

The drawString(Canvas canvas, String text, int x, int y) method does the drawing. It takes the position where to draw, iterates through the passed in text and draws every character progressively. It is easy to calculate the horizontal offset as each character has the same width.

That is it. To try it out add the following method to the DrawingPanel:

public boolean onTouchEvent(MotionEvent event) {

    // draw text at touch

    try {

        canvas = getHolder().lockCanvas();

        synchronized (getHolder()) {

            if (event.getAction() == MotionEvent.ACTION_DOWN

                    || event.getAction() == MotionEvent.ACTION_MOVE) {

                // clear the screen


                // draw glyphs

                glyphs.drawString(canvas, "Drawing string at "

                        + (int) event.getX() + " " + (int) event.getY(),

                        (int) event.getX(), (int) event.getY());


            if (event.getAction() == MotionEvent.ACTION_UP) {


                glyphs.drawString(canvas, "Drawn string at "

                        + (int) event.getX() + " " + (int) event.getY(),

                        (int) event.getX(), (int) event.getY());



    } finally {

        if (canvas != null) {




    // event was handled

    return true;


Every time we touch the screen, we try to get hold of the canvas to be able to draw onto it. In case of a touch or drag we simply clear the canvas and draw the string onto it.

When we stopped touching the screen we display a slightly different text at the last position.

Finally we release the canvas. Make sure you return true to signal that the event was handled.

That is it. One last thing needed is to set the DrawingPanel to be our view. This one is done in the activity created with the project. I have also disabled the title.

public class PrintingActivity extends Activity {

    /** Called when the activity is first created. */


    public void onCreate(Bundle savedInstanceState) {


        // turn off title


        setContentView(new DrawingPanel(this));



The resulting application should look like this:

Resulting App

Resulting App

To do this with OpenGL follow the same principle and use the bitmaps for textures. I will publish an OpenGL version of this article at some point so stay tuned.

Download the code here (TBD).