00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "freetypeFont.h"
00016
00017 #ifdef HAVE_FREETYPE
00018
00019 #include "config_pnmtext.h"
00020 #include "config_util.h"
00021 #include "config_express.h"
00022 #include "virtualFileSystem.h"
00023
00024
00025
00026
00027 const PN_stdfloat FreetypeFont::_points_per_unit = 10.0f;
00028
00029
00030 const PN_stdfloat FreetypeFont::_points_per_inch = 72.0f;
00031
00032
00033
00034
00035
00036
00037 FreetypeFont::
00038 FreetypeFont() {
00039 _face = NULL;
00040
00041 _point_size = text_point_size;
00042 _requested_pixels_per_unit = text_pixels_per_unit;
00043 _tex_pixels_per_unit = text_pixels_per_unit;
00044 _requested_scale_factor = text_scale_factor;
00045 _scale_factor = text_scale_factor;
00046 _native_antialias = text_native_antialias;
00047
00048 _line_height = 1.0f;
00049 _space_advance = 0.25f;
00050
00051 _char_size = 0;
00052 _dpi = 0;
00053 _pixel_width = 0;
00054 _pixel_height = 0;
00055 }
00056
00057
00058
00059
00060
00061
00062 FreetypeFont::
00063 FreetypeFont(const FreetypeFont ©) :
00064 Namable(copy),
00065 _point_size(copy._point_size),
00066 _requested_pixels_per_unit(copy._requested_pixels_per_unit),
00067 _tex_pixels_per_unit(copy._tex_pixels_per_unit),
00068 _requested_scale_factor(copy._requested_scale_factor),
00069 _scale_factor(copy._scale_factor),
00070 _native_antialias(copy._native_antialias),
00071 _line_height(copy._line_height),
00072 _space_advance(copy._space_advance),
00073 _face(copy._face),
00074 _char_size(copy._char_size),
00075 _dpi(copy._dpi),
00076 _pixel_width(copy._pixel_width),
00077 _pixel_height(copy._pixel_height)
00078 {
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 bool FreetypeFont::
00090 load_font(const Filename &font_filename, int face_index) {
00091 unload_font();
00092 _face = new FreetypeFace;
00093 if (!_face->_ft_ok) {
00094 pnmtext_cat.error()
00095 << "Unable to read font " << font_filename
00096 << ": FreeType library not initialized properly.\n";
00097 unload_font();
00098 return false;
00099 }
00100
00101 bool exists = false;
00102 int error;
00103 Filename path(font_filename);
00104 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00105 vfs->resolve_filename(path, get_model_path());
00106 exists = vfs->read_file(path, _face->_font_data, true);
00107 if (exists) {
00108 FT_Face face;
00109 error = FT_New_Memory_Face(_face->_ft_library,
00110 (const FT_Byte *)_face->_font_data.data(),
00111 _face->_font_data.length(),
00112 face_index, &face);
00113 _face->set_face(face);
00114 }
00115
00116 bool okflag = false;
00117 if (!exists) {
00118 pnmtext_cat.error()
00119 << "Unable to find font file " << font_filename << "\n";
00120 } else {
00121 if (error == FT_Err_Unknown_File_Format) {
00122 pnmtext_cat.error()
00123 << "Unable to read font " << font_filename << ": unknown file format.\n";
00124 } else if (error) {
00125 pnmtext_cat.error()
00126 << "Unable to read font " << font_filename << ": invalid.\n";
00127
00128 } else {
00129 okflag = reset_scale();
00130 }
00131 }
00132
00133 if (!okflag) {
00134 unload_font();
00135 }
00136
00137 return okflag;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147 bool FreetypeFont::
00148 load_font(const char *font_data, int data_length, int face_index) {
00149 unload_font();
00150 _face = new FreetypeFace;
00151
00152 if (!_face->_ft_ok) {
00153 pnmtext_cat.error()
00154 << "Unable to read font: FreeType library not initialized properly.\n";
00155 unload_font();
00156 return false;
00157 }
00158
00159 int error;
00160 FT_Face face;
00161 error = FT_New_Memory_Face(_face->_ft_library,
00162 (const FT_Byte *)font_data, data_length,
00163 face_index, &face);
00164 _face->set_face(face);
00165
00166 bool okflag = false;
00167 if (error == FT_Err_Unknown_File_Format) {
00168 pnmtext_cat.error()
00169 << "Unable to read font: unknown file format.\n";
00170 } else if (error) {
00171 pnmtext_cat.error()
00172 << "Unable to read font: invalid.\n";
00173
00174 } else {
00175 okflag = reset_scale();
00176 }
00177
00178 if (!okflag) {
00179 unload_font();
00180 }
00181
00182 return okflag;
00183 }
00184
00185
00186
00187
00188
00189
00190 void FreetypeFont::
00191 unload_font() {
00192 _face = NULL;
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202 bool FreetypeFont::
00203 load_glyph(FT_Face face, int glyph_index, bool prerender) {
00204 int flags = FT_LOAD_RENDER;
00205 if (!_native_antialias) {
00206 flags |= FT_LOAD_MONOCHROME;
00207 }
00208
00209 if (!prerender) {
00210
00211
00212 flags = 0;
00213 }
00214
00215 int error = FT_Load_Glyph(face, glyph_index, flags);
00216 if (error) {
00217 pnmtext_cat.error()
00218 << "Unable to render glyph " << glyph_index << "\n";
00219 return false;
00220 }
00221 return true;
00222 }
00223
00224
00225
00226
00227
00228
00229
00230 void FreetypeFont::
00231 copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image) {
00232 if (bitmap.pixel_mode == ft_pixel_mode_grays &&
00233 bitmap.num_grays == (int)image.get_maxval() + 1) {
00234
00235
00236 unsigned char *buffer_row = bitmap.buffer;
00237 for (int yi = 0; yi < bitmap.rows; yi++) {
00238 for (int xi = 0; xi < bitmap.width; xi++) {
00239 image.set_gray_val(xi, yi, buffer_row[xi]);
00240 }
00241 buffer_row += bitmap.pitch;
00242 }
00243
00244 } else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
00245
00246
00247 unsigned char *buffer_row = bitmap.buffer;
00248 for (int yi = 0; yi < bitmap.rows; yi++) {
00249 xelval maxval = image.get_maxval();
00250 int bit = 0x80;
00251 unsigned char *b = buffer_row;
00252 for (int xi = 0; xi < bitmap.width; xi++) {
00253 if (*b & bit) {
00254 image.set_gray_val(xi, yi, maxval);
00255 } else {
00256 image.set_gray_val(xi, yi, 0);
00257 }
00258 bit >>= 1;
00259 if (bit == 0) {
00260 ++b;
00261 bit = 0x80;
00262 }
00263 }
00264
00265 buffer_row += bitmap.pitch;
00266 }
00267
00268
00269 } else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
00270
00271
00272 unsigned char *buffer_row = bitmap.buffer;
00273 for (int yi = 0; yi < bitmap.rows; yi++) {
00274 for (int xi = 0; xi < bitmap.width; xi++) {
00275 image.set_gray(xi, yi, (PN_stdfloat)buffer_row[xi] / (bitmap.num_grays - 1));
00276 }
00277 buffer_row += bitmap.pitch;
00278 }
00279
00280 } else {
00281 pnmtext_cat.error()
00282 << "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
00283 }
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
00293 bool FreetypeFont::
00294 reset_scale() {
00295 if (_face == NULL) {
00296 return false;
00297 }
00298
00299
00300
00301 FT_Face face = _face->acquire_face(0, 0, 0, 0);
00302
00303
00304
00305
00306 _tex_pixels_per_unit = _requested_pixels_per_unit;
00307 _scale_factor = _requested_scale_factor;
00308 _font_pixels_per_unit = _tex_pixels_per_unit * _scale_factor;
00309
00310 _pixel_height = 0;
00311 _pixel_width = 0;
00312 PN_stdfloat units_per_inch = (_points_per_inch / _points_per_unit);
00313 _dpi = (int)(_font_pixels_per_unit * units_per_inch);
00314 _char_size = (int)(_point_size * 64);
00315
00316 int error = FT_Set_Char_Size(face, _char_size, _char_size, _dpi, _dpi);
00317 if (error) {
00318
00319
00320
00321
00322 int desired_height = (int)(_font_pixels_per_unit * _point_size / _points_per_unit + 0.5f);
00323 int best_size = -1;
00324 int largest_size = -1;
00325 if (face->num_fixed_sizes > 0) {
00326 largest_size = 0;
00327 int best_diff = 0;
00328 for (int i = 0; i < face->num_fixed_sizes; i++) {
00329 int diff = face->available_sizes[i].height - desired_height;
00330 if (diff > 0 && (best_size == -1 || diff < best_diff)) {
00331 best_size = i;
00332 best_diff = diff;
00333 }
00334 if (face->available_sizes[i].height > face->available_sizes[largest_size].height) {
00335 largest_size = i;
00336 }
00337 }
00338 }
00339 if (best_size < 0) {
00340 best_size = largest_size;
00341 }
00342
00343 if (best_size >= 0) {
00344 _pixel_height = face->available_sizes[best_size].height;
00345 _pixel_width = face->available_sizes[best_size].width;
00346 error = FT_Set_Pixel_Sizes(face, _pixel_width, _pixel_height);
00347 if (!error) {
00348 _font_pixels_per_unit = _pixel_height * _points_per_unit / _point_size;
00349 _scale_factor = _font_pixels_per_unit / _tex_pixels_per_unit;
00350
00351 if (_scale_factor < 1.0) {
00352
00353 _scale_factor = 1.0;
00354 _tex_pixels_per_unit = _font_pixels_per_unit;
00355 }
00356 }
00357 }
00358 }
00359
00360 if (error) {
00361 pnmtext_cat.warning()
00362 << "Unable to set " << get_name()
00363 << " to " << _point_size << "pt at " << _dpi << " dpi.\n";
00364 _line_height = 1.0f;
00365 _face->release_face(face);
00366 return false;
00367 }
00368
00369 _line_height = face->size->metrics.height / (_font_pixels_per_unit * 64.0f);
00370
00371
00372 error = FT_Load_Char(face, ' ', FT_LOAD_DEFAULT);
00373 if (error) {
00374
00375 _space_advance = 0.25f * _line_height;
00376
00377 } else {
00378 _space_advance = face->glyph->advance.x / (_font_pixels_per_unit * 64.0f);
00379 }
00380
00381 _face->release_face(face);
00382 return true;
00383 }
00384
00385 #endif // HAVE_FREETYPE