updated text symboilizer
fixed memory leak in FT_Glyph
This commit is contained in:
parent
06da5f14eb
commit
0f3fcc7f34
4 changed files with 177 additions and 84 deletions
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/ptr_container/ptr_vector.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <string>
|
||||
|
@ -66,34 +67,6 @@ namespace mapnik
|
|||
return face_->glyph;
|
||||
}
|
||||
|
||||
/*
|
||||
unsigned glyph_index(unsigned charcode) const
|
||||
{
|
||||
return FT_Get_Char_Index(face_, charcode );
|
||||
}
|
||||
|
||||
void set_transform (FT_Matrix * m,FT_Vector *v)
|
||||
{
|
||||
FT_Set_Transform(face_,m,v);
|
||||
}
|
||||
|
||||
bool render_glyph (unsigned charcode) const
|
||||
{
|
||||
unsigned glyph_index = FT_Get_Char_Index(face_, charcode );
|
||||
FT_Error error;
|
||||
error = FT_Load_Glyph(face_,glyph_index,FT_LOAD_DEFAULT);
|
||||
if (error == 0 )
|
||||
{
|
||||
error = FT_Render_Glyph(face_->glyph, FT_RENDER_MODE_NORMAL );
|
||||
if (error == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
FT_Face get_face() const
|
||||
{
|
||||
return face_;
|
||||
|
@ -273,6 +246,16 @@ namespace mapnik
|
|||
template <typename T>
|
||||
struct text_renderer : private boost::noncopyable
|
||||
{
|
||||
|
||||
struct glyph_t : boost::noncopyable
|
||||
{
|
||||
FT_Glyph image;
|
||||
glyph_t(FT_Glyph image_) : image(image_) {}
|
||||
~glyph_t () { FT_Done_Glyph(image);}
|
||||
};
|
||||
|
||||
typedef boost::ptr_vector<glyph_t> glyphs_t;
|
||||
typedef std::pair<unsigned,unsigned> dimension_t;
|
||||
typedef T pixmap_type;
|
||||
|
||||
text_renderer (pixmap_type & pixmap, face_ptr face)
|
||||
|
@ -308,32 +291,34 @@ namespace mapnik
|
|||
halo_radius_=radius;
|
||||
}
|
||||
|
||||
void render(std::string const& text, double x0, double y0)
|
||||
dimension_t prepare_glyphs(std::string const& text)
|
||||
{
|
||||
//clear glyphs
|
||||
glyphs_.clear();
|
||||
|
||||
FT_Matrix matrix;
|
||||
FT_Vector origin;
|
||||
FT_Vector pen;
|
||||
FT_Error error;
|
||||
FT_Glyph glyph;
|
||||
|
||||
FT_Face face = face_->get_face();
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
FT_UInt glyph_index;
|
||||
FT_Bool use_kerning;
|
||||
FT_UInt previous = 0;
|
||||
FT_UInt previous;
|
||||
|
||||
unsigned height = pixmap_.height();
|
||||
|
||||
origin.x = 0;
|
||||
origin.y = 0;
|
||||
pen.x = unsigned(x0 * 64);
|
||||
pen.y = unsigned((height - y0) * 64);
|
||||
pen.x = 0;
|
||||
pen.y = 0;
|
||||
|
||||
use_kerning = FT_HAS_KERNING(face);
|
||||
|
||||
std::string::const_iterator i;
|
||||
for (i=text.begin();i!=text.end();++i)
|
||||
FT_BBox bbox;
|
||||
bbox.xMin = bbox.yMin = 32000;
|
||||
bbox.xMax = bbox.yMax = -32000; //hmm??
|
||||
|
||||
for (std::string::const_iterator i=text.begin();i!=text.end();++i)
|
||||
{
|
||||
FT_BBox glyph_bbox;
|
||||
FT_Glyph image;
|
||||
|
||||
matrix.xx = (FT_Fixed)( cos( angle_ ) * 0x10000L );
|
||||
matrix.xy = (FT_Fixed)(-sin( angle_ ) * 0x10000L );
|
||||
matrix.yx = (FT_Fixed)( sin( angle_ ) * 0x10000L );
|
||||
|
@ -341,7 +326,8 @@ namespace mapnik
|
|||
|
||||
FT_Set_Transform (face,&matrix,&pen);
|
||||
|
||||
glyph_index = FT_Get_Char_Index( face, unsigned(*i) & 0xff );
|
||||
FT_UInt glyph_index = FT_Get_Char_Index( face, unsigned(*i) & 0xff );
|
||||
|
||||
if ( use_kerning && previous && glyph_index)
|
||||
{
|
||||
FT_Vector delta;
|
||||
|
@ -355,37 +341,89 @@ namespace mapnik
|
|||
if ( error )
|
||||
continue;
|
||||
|
||||
error = FT_Get_Glyph( face->glyph, &glyph );
|
||||
error = FT_Get_Glyph( face->glyph, &image);
|
||||
if ( error )
|
||||
continue;
|
||||
|
||||
//FT_Glyph_Transform(glyph,&matrix,&pen);
|
||||
FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
|
||||
if (glyph_bbox.xMin < bbox.xMin)
|
||||
bbox.xMin = glyph_bbox.xMin;
|
||||
if (glyph_bbox.yMin < bbox.yMin)
|
||||
bbox.yMin = glyph_bbox.yMin;
|
||||
if (glyph_bbox.xMax > bbox.xMax)
|
||||
bbox.xMax = glyph_bbox.xMax;
|
||||
if (glyph_bbox.yMax > bbox.yMax)
|
||||
bbox.yMax = glyph_bbox.yMax;
|
||||
|
||||
error = FT_Glyph_To_Bitmap( &glyph,FT_RENDER_MODE_NORMAL,0,1);
|
||||
if ( error )
|
||||
continue;
|
||||
|
||||
FT_BitmapGlyph bit = (FT_BitmapGlyph)glyph;
|
||||
if (halo_radius_)
|
||||
if ( bbox.xMin > bbox.xMax )
|
||||
{
|
||||
render_halo(&bit->bitmap, halo_fill_.rgba(),
|
||||
bit->left,
|
||||
height - bit->top,halo_radius_);
|
||||
bbox.xMin = 0;
|
||||
bbox.yMin = 0;
|
||||
bbox.xMax = 0;
|
||||
bbox.yMax = 0;
|
||||
}
|
||||
|
||||
render_bitmap(&bit->bitmap, fill_.rgba(),
|
||||
bit->left,
|
||||
height - bit->top);
|
||||
|
||||
FT_Done_Glyph(glyph);
|
||||
pen.x += slot->advance.x;
|
||||
pen.y += slot->advance.y;
|
||||
|
||||
previous = glyph_index;
|
||||
// take ownership of the glyph
|
||||
glyphs_.push_back(new glyph_t(image));
|
||||
}
|
||||
|
||||
//angle_ = sin ( 0.1 * count++);
|
||||
unsigned string_width = (bbox.xMax - bbox.xMin);
|
||||
unsigned string_height = (bbox.yMax - bbox.yMin);
|
||||
return dimension_t(string_width,string_height);
|
||||
}
|
||||
|
||||
void render(double x0, double y0)
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Vector start;
|
||||
unsigned height = pixmap_.height();
|
||||
|
||||
start.x = unsigned(x0 * (1 << 6));
|
||||
start.y = unsigned((height - y0) * (1 << 6));
|
||||
// now render transformed glyphs
|
||||
typename glyphs_t::iterator pos;
|
||||
|
||||
if (halo_radius_ > 0)
|
||||
{
|
||||
//render halo
|
||||
for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
|
||||
{
|
||||
|
||||
FT_Glyph_Transform(pos->image,0,&start);
|
||||
|
||||
error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
|
||||
if ( ! error )
|
||||
{
|
||||
|
||||
FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
|
||||
render_halo(&bit->bitmap, halo_fill_.rgba(),
|
||||
bit->left,
|
||||
height - bit->top,halo_radius_);
|
||||
}
|
||||
}
|
||||
}
|
||||
//render actual text
|
||||
for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
|
||||
{
|
||||
|
||||
FT_Glyph_Transform(pos->image,0,&start);
|
||||
|
||||
error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
|
||||
if ( ! error )
|
||||
{
|
||||
|
||||
FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
|
||||
render_bitmap(&bit->bitmap, fill_.rgba(),
|
||||
bit->left,
|
||||
height - bit->top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void render_halo(FT_Bitmap *bitmap,unsigned rgba,int x,int y,int radius)
|
||||
|
@ -434,6 +472,7 @@ namespace mapnik
|
|||
mapnik::Color halo_fill_;
|
||||
int halo_radius_;
|
||||
float angle_;
|
||||
glyphs_t glyphs_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <boost/ptr_container/ptr_vector.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <vector>
|
||||
#include <mapnik/envelope.hpp>
|
||||
#include "envelope.hpp"
|
||||
|
||||
|
||||
namespace mapnik
|
||||
|
|
|
@ -30,14 +30,20 @@ namespace mapnik
|
|||
|
||||
struct text_symbolizer
|
||||
{
|
||||
text_symbolizer(std::string const& name,Color const& fill)
|
||||
text_symbolizer(std::string const& name,unsigned size,Color const& fill)
|
||||
: name_(name),
|
||||
size_(size),
|
||||
fill_(fill),
|
||||
halo_fill_(Color(255,255,255)),
|
||||
halo_radius_(0),
|
||||
label_p_(point_placement) {}
|
||||
|
||||
text_symbolizer(text_symbolizer const& rhs)
|
||||
: name_(rhs.name_),
|
||||
size_(rhs.size_),
|
||||
fill_(rhs.fill_),
|
||||
halo_fill_(rhs.halo_fill_),
|
||||
halo_radius_(rhs.halo_radius_),
|
||||
label_p_(rhs.label_p_) {}
|
||||
|
||||
~text_symbolizer()
|
||||
|
@ -48,11 +54,37 @@ namespace mapnik
|
|||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
unsigned get_text_size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
Color const& get_fill() const
|
||||
{
|
||||
return fill_;
|
||||
}
|
||||
|
||||
void set_halo_fill(Color const& fill)
|
||||
{
|
||||
halo_fill_ = fill;
|
||||
}
|
||||
|
||||
Color const& get_halo_fill() const
|
||||
{
|
||||
return halo_fill_;
|
||||
}
|
||||
|
||||
void set_halo_radius(unsigned radius)
|
||||
{
|
||||
halo_radius_ = radius;
|
||||
}
|
||||
|
||||
unsigned get_halo_radius() const
|
||||
{
|
||||
return halo_radius_;
|
||||
}
|
||||
|
||||
void set_label_placement(label_placement_e label_p)
|
||||
{
|
||||
label_p_ = label_p;
|
||||
|
@ -65,7 +97,10 @@ namespace mapnik
|
|||
|
||||
private:
|
||||
std::string name_;
|
||||
unsigned size_;
|
||||
Color fill_;
|
||||
Color halo_fill_;
|
||||
unsigned halo_radius_;
|
||||
label_placement_e label_p_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace mapnik
|
|||
: feature_style_processor<agg_renderer>(m),
|
||||
pixmap_(pixmap),
|
||||
t_(m.getWidth(),m.getHeight(),m.getCurrentExtent()),
|
||||
detector_(Envelope<double>(0,0,m.getWidth(),m.getHeight()))
|
||||
detector_(Envelope<double>(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64))
|
||||
{
|
||||
Color const& bg=m.getBackground();
|
||||
pixmap_.setBackground(bg);
|
||||
|
@ -401,7 +401,8 @@ namespace mapnik
|
|||
path.vertex(&x0,&y0);
|
||||
path.vertex(&x1,&y1);
|
||||
double dx = x1 - x0;
|
||||
double dy = y1 - y0;
|
||||
double dy = ( y1 - y0 > 1e-7 ) ? y1 - y0 : 1.0;
|
||||
|
||||
angle = atan( dx/ dy ) - 0.5 * 3.1459;
|
||||
|
||||
//TODO!!!!!!!!!!!!!!!!!!!!
|
||||
|
@ -418,16 +419,34 @@ namespace mapnik
|
|||
t_.forward_x(&x);
|
||||
t_.forward_y(&y);
|
||||
|
||||
//x += 6; //TODO!!!
|
||||
//y += 6; //TODO!!!
|
||||
|
||||
face_ptr face = font_manager_.get_face("Bitstream Vera Sans Roman");//TODO
|
||||
//face_ptr face = font_manager_.get_face("Times New Roman Regular");//TODO
|
||||
if (face)
|
||||
{
|
||||
text_renderer<mapnik::Image32> ren(pixmap_,face);
|
||||
ren.set_pixel_size(12);
|
||||
ren.set_pixel_size(sym.get_text_size());
|
||||
ren.set_fill(fill);
|
||||
ren.set_halo_radius(1);
|
||||
ren.set_halo_fill(sym.get_halo_fill());
|
||||
ren.set_halo_radius(sym.get_halo_radius());
|
||||
ren.set_angle(angle);
|
||||
ren.render(text,x+6,y+6);
|
||||
|
||||
std::pair<unsigned,unsigned> dim = ren.prepare_glyphs(text);
|
||||
Envelope<double> text_box(x - 0.5*dim.first,y - 0.5 * dim.second ,
|
||||
x + 0.5*dim.first,y + 0.5 * dim.second);
|
||||
|
||||
if (sym.get_halo_radius() > 0)
|
||||
{
|
||||
text_box.width(text_box.width() + sym.get_halo_radius()*2);
|
||||
text_box.height(text_box.height() + sym.get_halo_radius()*2);
|
||||
}
|
||||
|
||||
if (detector_.has_placement(text_box))
|
||||
{
|
||||
ren.render(x - 0.5 * dim.first,y - 0.5 * dim.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue