TuttleOFX  1
freegil.hpp
Go to the documentation of this file.
00001 // Copyright Tom Brinkman 2008. Distributed under the Boost
00002 // Software License, Version 1.0. (See accompanying
00003 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
00004 
00005 #ifndef _freegil_hpp_
00006 #define _freegil_hpp_
00007 
00008 #include <boost/gil/gil_all.hpp>
00009 #include <ft2build.h>
00010 #include FT_FREETYPE_H
00011 #include FT_GLYPH_H
00012 #include FT_CACHE_H
00013 
00014 #include <blend.hpp>
00015 
00016 namespace layer
00017 {
00018 
00019 struct glyph
00020 {
00021         glyph(char ch, FT_Face face, boost::gil::rgb8_pixel_t pixel) :
00022                 ch(ch), face(face), pixel(pixel){}
00023 
00024         char ch;
00025         FT_Face face;
00026         boost::gil::rgb8_pixel_t pixel;
00027 };
00028 
00029 struct make_metric
00030 {
00031         FT_Glyph_Metrics operator()(glyph& glyph)
00032         {
00033                 BOOST_ASSERT(glyph.face);
00034                 int load_flags = FT_LOAD_DEFAULT;
00035                 int index = FT_Get_Char_Index(glyph.face,glyph.ch);
00036                 FT_Load_Glyph(glyph.face, index, load_flags);
00037                 return glyph.face->glyph->metrics;
00038         }
00039 };
00040 
00041 struct make_width
00042 {
00043         int advance;
00044         int lasbwidth;
00045         int lastadvance;
00046         make_width() : advance(0), lasbwidth(0), lastadvance(0) {}
00047         operator int(){return advance-(lastadvance-lasbwidth);}
00048         void operator()(FT_Glyph_Metrics metrics)
00049         {
00050                 lastadvance = metrics.horiAdvance >> 6; 
00051                 lasbwidth = (metrics.width >> 6);
00052                 advance += lastadvance;
00053         }
00054 };
00055 
00056 struct make_advance_width
00057 {
00058         int advance;
00059         make_advance_width() : advance(0){}
00060         operator int(){return advance;}
00061         void operator()(FT_Glyph_Metrics metrics)
00062         {
00063                 advance += metrics.horiAdvance >> 6;
00064         }
00065 };
00066 
00067 struct make_advance_height
00068 {
00069         int height;
00070         make_advance_height() : height(0){}
00071         operator int(){return height;}
00072         void operator()(FT_Glyph_Metrics metrics)
00073         {
00074                 int advance = (metrics.vertAdvance >> 6);
00075                 height = (std::max)(height,advance);
00076         }
00077 };
00078 
00079 struct make_height
00080 {
00081         int height;
00082         make_height() : height(0){}
00083         operator int(){return height;}
00084         void operator()(FT_Glyph_Metrics metrics)
00085         {
00086                 int h = (metrics.height >> 6);
00087                 height = (std::max)(height,h);
00088         }
00089 };
00090 
00091 struct make_glyph_height
00092 {
00093         int height;
00094         make_glyph_height() : height(0) {} 
00095         operator int(){return height;}
00096         void operator()(FT_Glyph_Metrics metrics)
00097         {
00098                 int n = (metrics.height >> 6) -(metrics.horiBearingY >> 6);
00099                 height = (std::max)(height,n);
00100         }
00101 };
00102 
00103 struct find_last_fitted_glyph
00104 {
00105         int width,x;
00106         find_last_fitted_glyph(int width) : width(width),x(0){}
00107         bool operator()(FT_Glyph_Metrics metric)
00108         {
00109                 int tmp = x + (metric.width >> 6);
00110                 x += (metric.horiAdvance >> 6); 
00111                 return tmp > width;
00112         }
00113 };
00114 
00115 template <typename view_t>
00116 struct render_glyphs
00117 {
00118         int x;
00119         const view_t& view;
00120         render_glyphs(const view_t& view) : view(view), x(0) {} 
00121 
00122         void operator()(glyph& glyph)
00123         {
00124                 using namespace boost::gil;
00125                 
00126                 FT_GlyphSlot glyphslot = glyph.face->glyph; 
00127                 FT_Face face = glyph.face;                      
00128 
00129                 int load_flags = FT_LOAD_DEFAULT;
00130                 int index = FT_Get_Char_Index(face,glyph.ch);
00131                 FT_Load_Glyph(face, index, load_flags);
00132                 FT_Render_Glyph(glyphslot, FT_RENDER_MODE_NORMAL);
00133 
00134                 int y = view.height() - (face->glyph->metrics.horiBearingY >> 6);
00135                 int width = face->glyph->metrics.width >> 6;
00136                 int height = face->glyph->metrics.height >> 6;
00137                 int xadvance = face->glyph->advance.x >> 6;
00138 
00139                 BOOST_ASSERT(view.width());
00140                 BOOST_ASSERT(width == glyphslot->bitmap.width);
00141                 BOOST_ASSERT(height == glyphslot->bitmap.rows);
00142 
00143                 gray8c_view_t gray = interleaved_view(width,height,
00144                         (gray8_pixel_t*)glyphslot->bitmap.buffer,glyphslot->bitmap.width);
00145 
00146                 copy<alpha24_blend>(glyph.pixel,gray,subimage_view(view,x,y,width,height));
00147                 x += xadvance; 
00148         }
00149 };
00150 
00151 static inline FT_Error face_requester(FTC_FaceID id, FT_Library library, void* data, FT_Face* face)
00152 {
00153         char** paths = (char**)data;
00154         char* path = paths[(long)id]; 
00155         return FT_New_Face(library, path, 0, face);
00156 }
00157 
00158 template <typename view_t>
00159 struct text
00160 {
00161         enum 
00162         { 
00163                 left = (0x1 << 0),
00164                 center = (0x1 << 1),
00165                 right = (0x1 << 2),
00166                 top = (0x1 << 3),
00167                 ftop = (0x1 << 4),
00168                 middle = (0x1 << 5),  //when text is aligned adjacent to each other.
00169                 fmiddle = (0x1 << 6), //when the text is all by itself
00170                 bottom = (0x1 << 7),
00171         }; 
00172 
00173         enum
00174         {
00175                 fill = (0x1 << 0),
00176                 clipspecial = (0x1 << 1),
00177                 fillexcess =  (0x1 << 2),
00178         };
00179 
00180         typedef typename view_t::value_type color_t;
00181 
00182         FTC_Manager manager;
00183         std::string str;
00184         int id;
00185         int size;
00186         int align;
00187         int options;
00188         char special;
00189         color_t color;
00190         std::vector<glyph> glyphs;
00191 
00192         text(FTC_Manager manager, std::string str, color_t color, 
00193                 int id, int size, int align = center|middle, int options = 0, char special = '#') : 
00194                         manager(manager), str(str), id(id), size(size), align(align), 
00195                                 color(color), options(options), special(special){}
00196 
00197         text(FTC_Manager manager, color_t color, 
00198                 int id, int size, int align = center|middle, int options = 0, char special = '.') : 
00199                         manager(manager), id(id), size(size), align(align), 
00200                                 color(color), options(options), special(special){}
00201 
00202         void operator()(view_t& view)
00203         {
00204                 FTC_ScalerRec_ scaler;
00205                 scaler.face_id = (FTC_FaceID)id;
00206                 scaler.width = size;
00207                 scaler.height = size;
00208                 scaler.pixel = 1;
00209                 scaler.x_res = 0;
00210                 scaler.y_res = 0;
00211                 
00212                 FT_Size asize;
00213                 FT_Error error = FTC_Manager_LookupSize(manager, &scaler, &asize);
00214                 if (error)
00215                         return;
00216                 
00217                 for (int n = 0; n < str.size(); ++n)
00218                         glyphs.push_back(glyph(str[n],asize->face,color));
00219 
00220                 std::vector<FT_Glyph_Metrics> m;                        
00221                 std::transform(glyphs.begin(),glyphs.end(), std::back_inserter(m), make_metric());              
00222 
00223                 int mwidth = std::for_each(m.begin(), m.end(), make_width());
00224 
00225                 if (options & fill || (options & fillexcess && mwidth > view.width()))
00226                 {
00227                         glyphs.clear();
00228                         for (int n = 0; n < 500; ++n)
00229                                 glyphs.push_back(glyph(special,asize->face,color));
00230 
00231                         m.clear();                      
00232                         std::transform(glyphs.begin(),glyphs.end(),
00233                                 std::back_inserter(m), make_metric());
00234                 }
00235 
00236                 if (options & clipspecial)
00237                 {
00238                         int pos = -1;
00239                         for (pos = 0; pos < glyphs.size(); ++pos)
00240                                 if (glyphs[pos].ch == special)
00241                                         break;
00242                 
00243                         if (pos >= 1 && pos < glyphs.size())
00244                         {
00245                                 std::vector<glyph> front,back;
00246                                 std::copy(glyphs.begin(), glyphs.begin()+pos, std::back_inserter(front));
00247                                 std::copy(glyphs.begin()+pos, glyphs.end(), std::back_inserter(back));
00248                                 glyphs.clear();
00249                 
00250                                 while (true)
00251                                 {
00252                                         std::vector<glyph> glyphs2;
00253                                         std::copy(front.begin(),front.end(), std::back_inserter(glyphs2));      
00254                                         std::copy(back.begin(),back.end(), std::back_inserter(glyphs2));        
00255                 
00256                                         std::vector<FT_Glyph_Metrics> metrics;          
00257                                         std::transform(glyphs2.begin(),glyphs2.end(),
00258                                                 std::back_inserter(metrics), make_metric());
00259                 
00260                                         std::vector<FT_Glyph_Metrics>::iterator it = 
00261                                                 std::find_if(metrics.begin(),metrics.end(),
00262                                                         find_last_fitted_glyph(view.width()));
00263 
00264                                         if (it != metrics.end())
00265                                                 front.pop_back();
00266                                         else
00267                                                 break;
00268                                 }
00269                 
00270                                 std::copy(front.begin(), front.end(), std::back_inserter(glyphs));
00271                                 std::copy(back.begin(), back.end(), std::back_inserter(glyphs));
00272                         }
00273                 }
00274 
00275                 m.clear();              
00276                 std::transform(glyphs.begin(),glyphs.end(), std::back_inserter(m), make_metric());
00277 
00278                 std::vector<FT_Glyph_Metrics>::iterator it = 
00279                         std::find_if(m.begin(), m.end(), find_last_fitted_glyph(view.width()));
00280                 int distance = (int)std::distance(it,m.end());
00281                 glyphs.erase(glyphs.end()-distance,glyphs.end());
00282                 
00283                 m.clear();              
00284                 std::transform(glyphs.begin(),glyphs.end(), std::back_inserter(m), make_metric());
00285 
00286                 mwidth = std::for_each(m.begin(), m.end(), make_width());
00287                 int mheight = std::for_each(m.begin(), m.end(), make_height());
00288                 int gheight = std::for_each(m.begin(), m.end(), make_glyph_height());
00289 
00290                 int x = 0;
00291                 if (align & center)
00292                         x = (view.width()-mwidth)/2;
00293                 else if (align & right)
00294                         x = view.width()-mwidth;
00295         
00296                 int y = 0;
00297                 if (align & middle)
00298                         y = (view.height()-mheight-gheight)/2;
00299                 else if (align & fmiddle)
00300                         y = (view.height()-mheight)/2;
00301                 else if (align & bottom)
00302                         y = view.height()-mheight;
00303 
00304                 BOOST_ASSERT(!glyphs.empty());
00305                 view = subimage_view(view,x,y,mwidth,mheight);
00306                 std::for_each(glyphs.begin(), glyphs.end(), render_glyphs<view_t>(view));
00307         }
00308 };
00309 
00310 template <typename view_t>
00311 struct elipsed_layer
00312 {
00313         typedef typename view_t::value_type color_t;
00314 
00315         FTC_Manager manager;
00316         std::string sfront;
00317         std::string sback;
00318         int id;
00319         int size;
00320         color_t color;
00321         static const int dwidth = 30;
00322 
00323         elipsed_layer(FTC_Manager manager, std::string sfront, std::string sback, color_t color, int id, int size) : 
00324                         manager(manager), sfront(sfront), sback(sback), id(id), size(size), color(color){}
00325 
00326         void operator()(view_t& view)
00327         {
00328                 typedef text<view_t> text_t;
00329 
00330                 text_t lback(manager,sback,color,id,size,
00331                         text_t::right|text_t::bottom);
00332                 view_t vback = view;
00333                 lback(vback);
00334                 
00335                 text_t lfront(manager,sfront,color,id,size,
00336                         text_t::left|text_t::bottom);
00337                 int width = view.width()-vback.width()-dwidth;
00338                 view_t vfront = subimage_view(view,0,0,width,view.height());
00339                 lfront(vfront);
00340 
00341                 text_t ldots(manager,color,id,size,     
00342                         text_t::center|text_t::bottom,text_t::fill,'.');
00343                 width = view.width()-vfront.width()-vback.width();
00344                 view_t vdots = subimage_view(view,vfront.width(),0,width,view.height());                
00345                 ldots(vdots);
00346         }       
00347 };
00348 
00349 }
00350 
00351 #endif