00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef FONT_ENGINE_FREETYPE_HPP
00026 #define FONT_ENGINE_FREETYPE_HPP
00027
00028
00029 extern "C"
00030 {
00031 #include <ft2build.h>
00032 #include FT_FREETYPE_H
00033 #include FT_GLYPH_H
00034 }
00035
00036
00037 #include <string>
00038 #include <vector>
00039 #include <map>
00040 #include <iostream>
00041
00042 #include <boost/shared_ptr.hpp>
00043 #include <boost/utility.hpp>
00044 #include <boost/ptr_container/ptr_vector.hpp>
00045 #include <boost/thread/mutex.hpp>
00046
00047 #include <mapnik/color.hpp>
00048 #include <mapnik/utils.hpp>
00049 #include <mapnik/ctrans.hpp>
00050 #include <mapnik/geometry.hpp>
00051
00052 #include <mapnik/text_path.hpp>
00053
00054 namespace mapnik
00055 {
00056 class font_face : boost::noncopyable
00057 {
00058 public:
00059 font_face(FT_Face face)
00060 : face_(face) {}
00061
00062 std::string family_name() const
00063 {
00064 return std::string(face_->family_name);
00065 }
00066
00067 std::string style_name() const
00068 {
00069 return std::string(face_->style_name);
00070 }
00071
00072 unsigned num_glyphs() const
00073 {
00074 return face_->num_glyphs;
00075 }
00076
00077 FT_GlyphSlot glyph() const
00078 {
00079 return face_->glyph;
00080 }
00081
00082 FT_Face get_face() const
00083 {
00084 return face_;
00085 }
00086
00087 bool set_pixel_sizes(unsigned size)
00088 {
00089 if (! FT_Set_Pixel_Sizes( face_, 0, size ))
00090 return true;
00091
00092 return false;
00093 }
00094
00095
00096 ~font_face()
00097 {
00098 #ifdef MAPNIK_DEBUG
00099 std::clog << "clean up face:" << family_name()<<":" << style_name() << std::endl;
00100 #endif
00101 FT_Done_Face(face_);
00102 }
00103
00104 private:
00105 FT_Face face_;
00106 };
00107
00108 typedef boost::shared_ptr<font_face> face_ptr;
00109
00110 class MAPNIK_DECL freetype_engine : public mapnik::singleton<freetype_engine,mapnik::CreateStatic>,
00111 private boost::noncopyable
00112 {
00113 friend class mapnik::CreateStatic<freetype_engine>;
00114 public:
00115
00116 static bool register_font(std::string const& file_name);
00117 static std::vector<std::string> face_names ();
00118 static face_ptr create_face(std::string const& family_name);
00119
00120 private:
00121 freetype_engine();
00122 virtual ~freetype_engine();
00123 static FT_Library library_;
00124 static std::map<std::string,std::string> name2file_;
00125 };
00126
00127 template <typename T>
00128 class MAPNIK_DECL face_manager : private boost::noncopyable
00129 {
00130 typedef T font_engine_type;
00131 typedef std::map<std::string,face_ptr> faces;
00132
00133 public:
00134 face_ptr get_face(std::string const& name)
00135 {
00136 typename faces::iterator itr;
00137 itr = faces_.find(name);
00138 if (itr != faces_.end())
00139 {
00140 return itr->second;
00141 }
00142 else
00143 {
00144 face_ptr face = font_engine_type::instance()->create_face(name);
00145 if (face)
00146 {
00147 faces_.insert(make_pair(name,face));
00148 }
00149 return face;
00150 }
00151 }
00152 private:
00153 faces faces_;
00154 };
00155
00156 template <typename T>
00157 struct text_renderer : private boost::noncopyable
00158 {
00159 struct glyph_t : boost::noncopyable
00160 {
00161 FT_Glyph image;
00162 glyph_t(FT_Glyph image_) : image(image_) {}
00163 ~glyph_t () { FT_Done_Glyph(image);}
00164 };
00165
00166 typedef boost::ptr_vector<glyph_t> glyphs_t;
00167 typedef std::pair<unsigned,unsigned> dimension_t;
00168 typedef T pixmap_type;
00169
00170 text_renderer (pixmap_type & pixmap, face_ptr face)
00171 : pixmap_(pixmap),
00172 face_(face),
00173 fill_(0,0,0),
00174 halo_fill_(255,255,255),
00175 halo_radius_(0) {}
00176
00177 void set_pixel_size(unsigned size)
00178 {
00179 face_->set_pixel_sizes(size);
00180 }
00181
00182 void set_fill(mapnik::Color const& fill)
00183 {
00184 fill_=fill;
00185 }
00186
00187 void set_halo_fill(mapnik::Color const& halo)
00188 {
00189 halo_fill_=halo;
00190 }
00191
00192 void set_halo_radius( int radius=1)
00193 {
00194 halo_radius_=radius;
00195 }
00196
00197 Envelope<double> prepare_glyphs(text_path *path)
00198 {
00199
00200 glyphs_.clear();
00201
00202 FT_Matrix matrix;
00203 FT_Vector pen;
00204 FT_Error error;
00205
00206 FT_Face face = face_->get_face();
00207
00208
00209 FT_BBox bbox;
00210 bbox.xMin = bbox.yMin = 32000;
00211 bbox.xMax = bbox.yMax = -32000;
00212
00213 for (int i = 0; i < path->num_nodes(); i++)
00214 {
00215 int c;
00216 double x, y, angle;
00217
00218 path->vertex(&c, &x, &y, &angle);
00219
00220
00221
00222 FT_BBox glyph_bbox;
00223 FT_Glyph image;
00224
00225 pen.x = int(x * 64);
00226 pen.y = int(y * 64);
00227
00228 matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
00229 matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
00230 matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
00231 matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
00232
00233 FT_Set_Transform (face,&matrix,&pen);
00234
00235 FT_UInt glyph_index = FT_Get_Char_Index( face, unsigned(c));
00236
00237 error = FT_Load_Glyph (face,glyph_index, FT_LOAD_NO_HINTING);
00238 if ( error )
00239 continue;
00240
00241 error = FT_Get_Glyph( face->glyph, &image);
00242 if ( error )
00243 continue;
00244
00245 FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
00246 if (glyph_bbox.xMin < bbox.xMin)
00247 bbox.xMin = glyph_bbox.xMin;
00248 if (glyph_bbox.yMin < bbox.yMin)
00249 bbox.yMin = glyph_bbox.yMin;
00250 if (glyph_bbox.xMax > bbox.xMax)
00251 bbox.xMax = glyph_bbox.xMax;
00252 if (glyph_bbox.yMax > bbox.yMax)
00253 bbox.yMax = glyph_bbox.yMax;
00254
00255 if ( bbox.xMin > bbox.xMax )
00256 {
00257 bbox.xMin = 0;
00258 bbox.yMin = 0;
00259 bbox.xMax = 0;
00260 bbox.yMax = 0;
00261 }
00262
00263
00264 glyphs_.push_back(new glyph_t(image));
00265 }
00266
00267 return Envelope<double>(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax);
00268 }
00269
00270 dimension_t character_dimensions(const unsigned c)
00271 {
00272 FT_Matrix matrix;
00273 FT_Vector pen;
00274 FT_Error error;
00275
00276 FT_Face face = face_->get_face();
00277 FT_GlyphSlot slot = face->glyph;
00278
00279 pen.x = 0;
00280 pen.y = 0;
00281
00282 FT_BBox glyph_bbox;
00283 FT_Glyph image;
00284
00285 matrix.xx = (FT_Fixed)( 1 * 0x10000L );
00286 matrix.xy = (FT_Fixed)( 0 * 0x10000L );
00287 matrix.yx = (FT_Fixed)( 0 * 0x10000L );
00288 matrix.yy = (FT_Fixed)( 1 * 0x10000L );
00289
00290 FT_Set_Transform (face,&matrix,&pen);
00291
00292 FT_UInt glyph_index = FT_Get_Char_Index( face, c);
00293
00294 error = FT_Load_Glyph (face,glyph_index,FT_LOAD_NO_HINTING);
00295 if ( error )
00296 return dimension_t(0, 0);
00297
00298 error = FT_Get_Glyph( face->glyph, &image);
00299 if ( error )
00300 return dimension_t(0, 0);
00301
00302 FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
00303 FT_Done_Glyph(image);
00304 return dimension_t(slot->advance.x >> 6, glyph_bbox.yMax - glyph_bbox.yMin);
00305 }
00306
00307 void get_string_info(std::wstring const& text, string_info *info)
00308 {
00309 unsigned width = 0;
00310 unsigned height = 0;
00311
00312 for (std::wstring::const_iterator i=text.begin();i!=text.end();++i)
00313 {
00314 dimension_t char_dim = character_dimensions(*i);
00315
00316 info->add_info(*i, char_dim.first, char_dim.second);
00317
00318 width += char_dim.first;
00319 height = char_dim.second > height ? char_dim.second : height;
00320
00321 }
00322 info->set_dimensions(width, height);
00323 }
00324
00325 void render(double x0, double y0)
00326 {
00327 FT_Error error;
00328 FT_Vector start;
00329 unsigned height = pixmap_.height();
00330
00331 start.x = static_cast<FT_Pos>(x0 * (1 << 6));
00332 start.y = static_cast<FT_Pos>((height - y0) * (1 << 6));
00333
00334
00335 typename glyphs_t::iterator pos;
00336
00337
00338 if (halo_radius_ > 0 && halo_radius_ < 256)
00339 {
00340
00341 for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
00342 {
00343
00344 FT_Glyph_Transform(pos->image,0,&start);
00345
00346 error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
00347 if ( ! error )
00348 {
00349
00350 FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
00351 render_halo(&bit->bitmap, halo_fill_.rgba(),
00352 bit->left,
00353 height - bit->top,halo_radius_);
00354 }
00355 }
00356 }
00357
00358 for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
00359 {
00360
00361 FT_Glyph_Transform(pos->image,0,&start);
00362
00363 error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
00364 if ( ! error )
00365 {
00366
00367 FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
00368 render_bitmap(&bit->bitmap, fill_.rgba(),
00369 bit->left,
00370 height - bit->top);
00371 }
00372 }
00373 }
00374
00375 private:
00376
00377 void render_halo(FT_Bitmap *bitmap,unsigned rgba,int x,int y,int radius)
00378 {
00379 int x_max=x+bitmap->width;
00380 int y_max=y+bitmap->rows;
00381 int i,p,j,q;
00382
00383 for (i=x,p=0;i<x_max;++i,++p)
00384 {
00385 for (j=y,q=0;j<y_max;++j,++q)
00386 {
00387 int gray = bitmap->buffer[q*bitmap->width+p];
00388 if (gray)
00389 {
00390 for (int n=-halo_radius_; n <=halo_radius_; ++n)
00391 for (int m=-halo_radius_;m <= halo_radius_; ++m)
00392 pixmap_.blendPixel(i+m,j+n,rgba,gray);
00393 }
00394 }
00395 }
00396 }
00397
00398 void render_bitmap(FT_Bitmap *bitmap,unsigned rgba,int x,int y)
00399 {
00400 int x_max=x+bitmap->width;
00401 int y_max=y+bitmap->rows;
00402 int i,p,j,q;
00403
00404 for (i=x,p=0;i<x_max;++i,++p)
00405 {
00406 for (j=y,q=0;j<y_max;++j,++q)
00407 {
00408 int gray=bitmap->buffer[q*bitmap->width+p];
00409 if (gray)
00410 {
00411 pixmap_.blendPixel(i,j,rgba,gray);
00412 }
00413 }
00414 }
00415 }
00416
00417 pixmap_type & pixmap_;
00418 face_ptr face_;
00419 mapnik::Color fill_;
00420 mapnik::Color halo_fill_;
00421 int halo_radius_;
00422 unsigned text_ratio_;
00423 unsigned wrap_width_;
00424 glyphs_t glyphs_;
00425 };
00426 }
00427
00428
00429 #endif // FONT_ENGINE_FREETYPE_HPP