TuttleOFX
1
|
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