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 }