Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

FTRenderer.cc

Go to the documentation of this file.
00001 /*
00002     File:       FTRenderer.cc
00003 
00004     Function:   Render text into images using FreeType
00005                 (http://www.freetype.org)
00006 
00007     Author:     Andrew Willmott
00008 
00009     Notes:      
00010 */
00011 
00012 #include "gcl/FTRenderer.h"
00013 
00014 #include <stdlib.h>
00015 
00016 FTRenderer::FTRenderer() : glyphs(0)
00017 {
00018     dpi = 96;
00019     pointSize = 24;
00020     hinted = 1;
00021     smooth = 1;
00022     border = 0;
00023     Init();
00024 }
00025 
00026 FTRenderer::~FTRenderer() 
00027 {
00028     Free();
00029 }
00030 
00031 Void FTRenderer::SetPointSize(Int size)
00032 {
00033     pointSize = size;
00034 }
00035 
00036 Void FTRenderer::SetupGlyphTable()
00037 {
00038     TT_UShort   i, n;
00039     TT_UShort   platform, encoding;
00040 
00041     /* First, look for a Unicode charmap */
00042 
00043     noCharMap = true;
00044     n = TT_Get_CharMap_Count(face);
00045 
00046     for (i = 0; i < n; i++)
00047     {
00048         TT_Get_CharMap_ID(face, i, &platform, &encoding);
00049         if ((platform == 3 && encoding == 1) ||
00050                 (platform == 0 && encoding == 0))
00051         {
00052             TT_Get_CharMap(face, i, &charMap);
00053             noCharMap = false;
00054             break;
00055         }
00056     }
00057 
00058     if (i == n)
00059     {
00060         TT_Face_Properties properties;
00061 
00062         TT_Get_Face_Properties(face, &properties);
00063 
00064         numGlyphs = properties.num_Glyphs;
00065     }
00066 
00067     /* Second, allocate the array */
00068 
00069     glyphs = new TT_Glyph[256];
00070     for (i = 0; i < 256; i++)
00071         glyphs[i].z = 0;
00072 }
00073 
00074 Void FTRenderer::FreeGlyphTable()
00075 {
00076     Int i;
00077 
00078     if (!glyphs)
00079         return;
00080 
00081     for (i = 0; i < 256; ++i)
00082         TT_Done_Glyph(glyphs[i]);
00083 
00084     delete[] glyphs;
00085 
00086     glyphs = 0;
00087 }
00088 
00089 Void FTRenderer::LoadGlyphs(StrConst txt, Int txtlen)
00090 // make sure all glyphs in the string are loaded
00091 {
00092     TT_UShort   i, n;
00093     Int         code, load_flags;
00094     TT_Error    error;
00095 
00096     load_flags = TTLOAD_SCALE_GLYPH;
00097     if (hinted)
00098         load_flags |= TTLOAD_HINT_GLYPH;
00099 
00100     for (i = 0; i < txtlen; ++i)
00101     {
00102         unsigned char j = txt[i];
00103 
00104         // already loaded?
00105         if (glyphs[j].z)
00106             continue;
00107 
00108         if (noCharMap)
00109         {
00110             code = j - ' ' + 1;
00111             if (code < 0 || code >= numGlyphs)
00112                 code = 0;
00113         }
00114         else
00115         {
00116             code = TT_Char_Index(charMap, j);
00117             if (code < 0)
00118                 code = 0;   /* FIXME! default code */
00119         }
00120 
00121         (void)
00122         (
00123             (error = TT_New_Glyph(face, &glyphs[j])) ||
00124             (error = TT_Load_Glyph(instance, glyphs[j], code, load_flags))
00125         );
00126         if (error)
00127             _Warning(String().Printf("ERROR: cannot allocate and load glyph: %d\n", error));
00128     }
00129 }
00130 
00131 
00132 Void FTRenderer::SetFace(StrConst filename)
00133 {
00134     TT_Error error;
00135 
00136     if (faceSet)
00137         FreeFace();
00138 
00139     /* load the typeface */
00140 
00141     error = TT_Open_Face(engine, filename, &face);
00142     if (error)
00143     {
00144         if (error == TT_Err_Could_Not_Open_File)
00145             _Error(String().Printf("ERROR: could not find/open %s\n", filename));
00146         else
00147             _Error(String().Printf("ERROR: while opening %s, error code = %x\n", filename, error));
00148     }
00149 
00150     /* create and initialize instance */
00151 
00152     (void)
00153     (
00154         (error = TT_New_Instance(face, &instance)) ||
00155         (error = TT_Set_Instance_Resolutions(instance, dpi, dpi)) ||
00156         (error = TT_Set_Instance_CharSize(instance, pointSize * 64))
00157     );
00158     if (error)
00159         _Error(String().Printf("ERROR: could not create and initialize instance: %d\n",
00160                 error));
00161 
00162     faceSet = true;
00163     SetupGlyphTable();
00164 }
00165 
00166 Void FTRenderer::FreeFace()
00167 {
00168     FreeGlyphTable();
00169     TT_Done_Instance(instance);
00170     TT_Close_Face(face);
00171 }
00172 
00173 Void FTRenderer::SetupImage(StrConst txt, Int txtlen)
00174 {
00175     Int                     i, upm, ascent, descent;
00176     TT_Face_Properties      properties;
00177     TT_Instance_Metrics     imetrics;
00178     TT_Glyph_Metrics        gmetrics;
00179     Int                     width, height;
00180     TT_F26Dot6              widthx;
00181     
00182     /* allocate the large bitmap */
00183 
00184     TT_Get_Face_Properties( face, &properties );
00185     TT_Get_Instance_Metrics( instance, &imetrics );
00186 
00187     upm = properties.header->Units_Per_EM;
00188     ascent = ( properties.horizontal->Ascender * imetrics.y_ppem ) / upm;
00189     descent = ( properties.horizontal->Descender * imetrics.y_ppem ) / upm;
00190 
00191     width = 2 * border;
00192     height = 2 * border + ascent - descent;
00193     widthx = 64 * width;
00194     
00195     for (i = 0; i < txtlen; i++)
00196     {
00197         unsigned char j = txt[i];
00198 
00199         if (!glyphs[j].z)
00200             continue;
00201 
00202         TT_Get_Glyph_Metrics(glyphs[j], &gmetrics);
00203         widthx += gmetrics.advance;
00204     }
00205 
00206     width = (widthx + 63) / 64;
00207     width = (width + 3) & ~0x3;
00208     image.SetSize(width, height);
00209     image.Clear(cWhite);
00210 
00211     pixmap.rows = height;
00212     pixmap.width = width;
00213     pixmap.flow = TT_Flow_Up;
00214     pixmap.cols = width;
00215     pixmap.size = width * height;
00216     pixmap.bitmap = image.ByteData();
00217 
00218     xShift = border;
00219     yShift = border - descent;
00220 }
00221 
00222 
00223 Void FTRenderer::RenderGlyph(TT_Glyph glyph, TT_F26Dot6 x_off, TT_F26Dot6 y_off,
00224                               TT_Glyph_Metrics *gmetrics)
00225 {
00226     if (!smooth)
00227     {
00228         TT_Get_Glyph_Bitmap(glyph, &pixmap, x_off, y_off);
00229     }
00230     else
00231     {
00232         TT_F26Dot6 xmin, ymin, xmax, ymax;
00233 
00234         xmin = gmetrics->bbox.xMin & ~0x3F;
00235         ymin = gmetrics->bbox.yMin & ~0x3F;
00236         xmax = (gmetrics->bbox.xMax + 63) & ~0x3F;
00237         ymax = (gmetrics->bbox.yMax + 63) & ~0x3F;
00238 
00239         TT_Get_Glyph_Pixmap(glyph, &pixmap, x_off, y_off);
00240     }
00241 }
00242 
00243 Void FTRenderer::RenderAllGlyphs(StrConst txt, Int txtlen)
00244 {
00245     Int                 i;
00246     TT_F26Dot6          x, y;
00247     TT_Glyph_Metrics    gmetrics;
00248 
00249     x = xShift * 64;
00250     y = yShift * 64;
00251 
00252     for (i = 0; i < txtlen; i++)
00253     {
00254         unsigned char j = txt[i];
00255 
00256         if (!glyphs[j].z)
00257             continue;
00258 
00259         TT_Get_Glyph_Metrics(glyphs[j], &gmetrics);
00260 
00261         RenderGlyph(glyphs[j], x, y, &gmetrics);
00262 
00263         x += gmetrics.advance;
00264     }
00265 }
00266 
00267 Void FTRenderer::Init()
00268 {
00269     TT_Error    error;
00270     TT_Byte     palette[5] = 
00271                 {
00272                     255,
00273                     192,
00274                     128,
00275                     64,
00276                     0
00277                 };
00278 
00279     error = TT_Init_FreeType(&engine);
00280     if (error)
00281         _Error(String().Printf("ERROR: While initializing engine, code = %d\n", error));
00282 
00283     TT_Set_Raster_Gray_Palette(engine, palette);
00284 
00285     faceSet = false;
00286 }
00287 
00288 Void FTRenderer::Free()
00289 {
00290     if (faceSet)
00291         FreeFace();
00292 
00293     TT_Done_FreeType(engine);
00294 }
00295 
00296 Void FTRenderer::RenderText(StrConst txt)
00297 {
00298     if (!faceSet)
00299         _Error("(FTRenderer) No font set yet");
00300     Int txtlen = txt.Length();
00301     LoadGlyphs(txt, txtlen);
00302     SetupImage(txt, txtlen);
00303     RenderAllGlyphs(txt, txtlen);
00304 }

Generated at Sat Aug 5 00:16:58 2000 for Graphics Class Library by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000