FreeType2 Usage Notes

The motivation of this page is that the FreeType2 tutorial doesn’t
give you complete working code. Lots of people complain about the lack
of very short simple working example. I too felt that was lacking, so I
posted up my first simple program.

See: text2text

This program should compile on linux, Irix, or solaris. Minor Makefile
adjustments may be needed if files don’t appear in the same locations
for you as the do me. Last tested on Irix w/ MIPSpro, RHEL3, Ubuntu
Warty Warthog, and Solaris9 w/ SunStudio. Solaris with GCC will require
you adjusting your system so cc invokes gcc.

Anyway, the program demonstrates simple usage of freetype2.

Below is the main piece. It opens the library, loads the font file,
sets the text size, then renders out the characters. As written, it
just assumes the canvas will be large enough for the text.

If you extrapolate as it is written, you would have to render the
text twice if you want to create a canvas that is sure to hold the
string (say because you want to render to a picture). Also, the code
below offers no method for dealing with ligatures.

error = FT_Init_FreeType( &library );
if ( error )
{
  printf("an error occured\n");
  exit(-1);
} 

error = FT_New_Face( library, fileName, 0, &face );
if ( error == FT_Err_Unknown_File_Format )
{
  //... the font file could be opened and read, but it appears
  //... that its font format is unsupported
  printf("Face error\n");
  exit(-1);
}
else if ( error )
{
  //... another error code means that the font file could not
  //... be opened or read, or simply that it is broken...
  printf("other Face error\n"); 
  exit(-1);
}

error = FT_Set_Char_Size( face, /* handle to face object */
0, /* char_width in 1/64th of points */
48*64, /* char_height in 1/64th of points */
40, /* horizontal device resolution */
18 ); /* vertical device resolution */

slot = face->glyph; /* a small shortcut */

pen_x = 0;
pen_y = 0;
for ( n = 0; n < num_chars; n++ )
{
  unsigned char * buf;

  /* load glyph image into the slot (erase previous one) */
  error = FT_Load_Char( face, text[n], FT_LOAD_DEFAULT );
  if ( error ) continue; /* ignore errors */

  /* convert to an anti-aliased bitmap */
  //FT_RENDER_MODE_MONO
  error = FT_Render_Glyph( face->glyph,  FT_RENDER_MODE_NORMAL );
  if ( error ) continue; /* now, draw to our target surface */

  buf = slot->bitmap.buffer;

  for(j=0; jbitmap.rows; j++)
  {
    for(i=0; ibitmap.width ; i++)
    {
      int index = (j*slot->bitmap.width)+(i);
      unsigned char c;
      //printf("index: %d offset %d\n", index/8, index%8);
      c=buf[index];

      pen_y = height -3-slot->bitmap_top;

       if (c>0 && c<128) output[(j+pen_y)*width+(i+pen_x)] = '.';
       if (c>127) output[(j+pen_y)*width+(i+pen_x)] = 'x';
    }
  }

  /* increment pen position */
  pen_x += slot->bitmap.width+2;
}

The big change I’m working on is making it use an array FT_Glyph
structures to be able to hold the string of glyphs. In
psuedo code, that would look something like this:

FT_Glyph * glyphs;
int width=0;
//setup array.

for (/*each char in char string*/)
{
  error = FT_Load_Char( face, string[i], FT_LOAD_NORMAL );
  error = FT_Get_Glyph( face->glyph, &(glyph[i]));
  error = FT_Render_Glyph( &(glyph[i]),  FT_RENDER_MODE_NORMAL );
  width += glyph[i]->bitmap.width + SPACE_BETWEEN_CHARS;
}

//create canvase

for (/*each char in char string*/)
{
  //do something with each render'd glyphs bitmap to copy to destination

  FT_Done_Glyph(glyphs[i]);
}

free(glyphs);

Keep in mind that is incomplete code. It hasn’t really been written
up and tested yet.

And I still don’t know how to deal with ligatures, kerning, and all
sorts of other features. However, if I implement the pseudo code above,
I expect I’ll have everything I need for now.

 

C/C++ Message Passing

Note: For C++ users, find an update at http://blog.jdboyd.net/2010/11/small-revisit-of-cc-message-passing-in-a-threaded-program/

My favorite approach to threaded programming is message passing, holding the shared memory for things that need it for performance reasons.

eCos has a handy general purpose message passing system, but C/C++ do not. Posix does have some methods that can be used for this. There are pipes or System V message queues. My problem with these is that they are meant for interprocess work, and thus have un-needed overhead for talking between threads. Also, those two methods are byte stream oriented.

What eCos has and what I wanted was the ability to pass pointers to a messages struct. Basically, a thread safe queue that pushes void* in and pops void* out, without invoking syscalls, which sap performance. I typically use this with a struct. Either all of the structs in the queue are the same type, or else in every struct used, the first item in the struct is an int indicating what struct to coerce the pointer to.

Anyway, here are the files:

Tested on Linux with GCC 3.2 and Solaris with Sun C++ 5.5. On Solaris, the test program for the queue returns two warnings, but functions fine. The test program is C++ for reasons that aren’t really relevant. This should be fixed at some point.

This is meant to be written to be acceptable for use in realtime systems. Obviously, if those systems don’t support posix threads, one will need to substitute the OS’s form of Mutex’s and Conds.