Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I need to convert some X11 bitmap fonts to an array in C for a 128x64 OLED Display.

I saw some fonts like /usr/share/fonts/X11/misc/9x15-ISO8859-1.pcf.gz

The result should look like

/* Standard ASCII 6x8 font */
const char PROGMEM font6x8[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// sp
  0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,// !
  0x00, 0x00, 0x07, 0x00, 0x07, 0x00,// "

Are the tools for converting a pcf font to an array of chars in C? Where are good resources for bitmap fonts?

Is there anything else I have missed?

share|improve this question
1  
I'm interested in this myself. If you do come across an answer, please share your solution here. –  WhiteHotLoveTiger Apr 21 at 17:44
    
Why need to convert. Do you want to store the file in an array? –  totti May 31 at 14:24
    
@totti: the why is already included in the Q: for a 128x64 OLED Display. –  user55518 Jun 4 at 18:52

2 Answers 2

up vote 2 down vote accepted

You can use convert as shown here: C header file with bitmapped fonts

Probably there are a lot of commands to convert fonts to bitmap, but the freetype API is easy enough to write your own with not much code.

Using the freetype example I wrote something you can use as a start, it output an .xbm file (is a c file but you can use graphics programs like gimp to view/edit it).

Notiche that gimp also support export to .xbm with different bytes per pixel.

The .xbm exported by the example is a 1 bit per pixel format (1 black, 0 white), you need to edit the code in order to handle more colors (the freetype normally use a 8 bit gray scale bitmap buffer to render, if render mode is FT_RENDER_MODE_NORMAL, you may also need to remove the step with the temporary bitmap used to align the FT buffer to 1 byte).

The to_bitmap function is where the conversion from the FT buffer to the destination bitmap is done,

To build the example the freetype dev package is needed, on Debian (maybe also Ubuntu) use:

sudo apt-get install libfreetype6-dev

Simply make to build it.

Use the command with the font path as argument, the output is on stdout

./font2c /usr/share/fonts/X11/misc/9x15-ISO8859-1.pcf.gz >c-bmp-font.xbm

Makefile:

CFLAGS += -O2 -Wall 
CFLAGS += $(shell freetype-config --cflags)
LIBS += $(shell freetype-config --libs)

font2c: font2c.c
    $(CC) $(CFLAGS) -o $@ $^ $(LIBS)

clean:
    -rm -f font2c

font2c.c:

#include <stdio.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include <ftbitmap.h>

#define WIDTH   640
#define BYTEWIDTH (WIDTH)/8
#define HEIGHT  480

static unsigned char image[HEIGHT][BYTEWIDTH];

static FT_Library library;
static FT_Face face;
static FT_Error err;
static FT_Bitmap tempbitmap;

static void to_bitmap( FT_Bitmap*  bitmap, FT_Int x, FT_Int y) {

    FT_Int  i, j, p, q;
    FT_Int  x_max = x + bitmap->width;
    FT_Int  y_max = y + bitmap->rows;

    for ( i = x, p = 0; i < x_max; i++, p++ ) {
        for ( j = y, q = 0; j < y_max; j++, q++ ) {
            if ( (i < 0) || (j < 0) || (i >= WIDTH || j >= HEIGHT) )
                continue;
            image[j][i >> 3] |= (bitmap->buffer[q * bitmap->width + p]) << (i & 7);
        }
    }
}

static void draw_glyph(unsigned char glyph, int *x, int *y) {
    FT_UInt  glyph_index;
    FT_GlyphSlot  slot = face->glyph;

    glyph_index = FT_Get_Char_Index( face, glyph );

    if ((err = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ))) {
        fprintf( stderr, "warning: failed FT_Load_Glyph 0x%x %d\n", glyph, err);
        return;
    }

    if ((err = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_MONO ))) {
        fprintf( stderr, "warning: failed FT_Render_Glyph 0x%x %d\n", glyph, err);
        return;
    }

    FT_Bitmap_New(&tempbitmap);
    FT_Bitmap_Convert( library, &slot->bitmap, &tempbitmap, 1);

    to_bitmap( &tempbitmap, *x, *y );

    FT_Bitmap_Done( library, &tempbitmap );

    *x += slot->advance.x >> 6;
}

static void out_xbm(int w, int h) {
    int x, y;
    printf("#define BMP_width %d\n", WIDTH);
    printf("#define BMP_height %d\n", h);
    printf("static char BMP_bits[] = {\n");
    for (y=0; y < h; y++) {
        printf("\t");
        for (x=0; x < w; x++) {
            printf("0x%x, ", image[y][x]);
        }
        printf("\n");
    }
    printf("\n}\n");
}

int main(int argc, char **argv) {
    char *filename;
    int x = 0, y = 0;
    int g;

    memset (image, 0, BYTEWIDTH*HEIGHT);

    if (argc < 2) {
        fprintf( stderr, "usage: font2c [font]\n");
        exit(1);
    }
    filename = argv[1];

    if ((err = FT_Init_FreeType( &library ))) {
        fprintf( stderr, "error: Init_Freetype failed %d\n", err);
        exit(1);
    }
    if ((err = FT_New_Face( library, filename, 0, &face ))) {
        fprintf( stderr, "error: FT_New_Face failed %d\n", err);
        exit(1);
    }

    for (g = 0; g < 256; g++) {
        if (x+8 >= WIDTH) {
                x = 0;
                y += 15; // FIXME get ascender
        }
        draw_glyph(g, &x, &y);
    }

    out_xbm(BYTEWIDTH, HEIGHT);

    FT_Done_Face( face );
    FT_Done_FreeType( library );

    return 0;

}
share|improve this answer
    
very nice, thank you. –  user55518 Jun 4 at 18:11
    
You're welcome. Added to github with autotools support and facilities to generate the .deb package, maybe I'll make some improvement in the future (having enough free time) –  Alex Jun 4 at 19:03

You have *.pcf.gz file and you want to create array in C, right?

You should try to open the file, read it and convert bytes to hexadecimal format.

share|improve this answer
    
I don't think this is sufficient because you need to know the metrics to be able to distinguish a 8x8 from 8x6 font and obviously gunzip a file before processing. –  user55518 Jun 4 at 18:10
    
yes, thanks for your feedback. that was just suggestion ;-) –  Cockootec Jun 4 at 22:21

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.