updated text symboilizer

fixed memory leak in FT_Glyph
This commit is contained in:
Artem Pavlenko 2006-03-01 15:16:45 +00:00
parent 06da5f14eb
commit 0f3fcc7f34
4 changed files with 177 additions and 84 deletions

View file

@ -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>
@ -65,34 +66,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
{
@ -273,8 +246,18 @@ 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)
: pixmap_(pixmap),
face_(face),
@ -307,41 +290,44 @@ 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_Error error;
FT_Face face = face_->get_face();
FT_GlyphSlot slot = face->glyph;
FT_UInt glyph_index;
FT_Bool use_kerning;
FT_UInt previous = 0;
unsigned height = pixmap_.height();
origin.x = 0;
origin.y = 0;
pen.x = unsigned(x0 * 64);
pen.y = unsigned((height - y0) * 64);
FT_UInt previous;
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 );
matrix.yy = (FT_Fixed)( cos( angle_ ) * 0x10000L );
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;
@ -350,42 +336,94 @@ namespace mapnik
pen.x += delta.x;
pen.y += delta.y;
}
error = FT_Load_Glyph (face,glyph_index,FT_LOAD_DEFAULT);
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);
error = FT_Glyph_To_Bitmap( &glyph,FT_RENDER_MODE_NORMAL,0,1);
if ( error )
continue;
FT_BitmapGlyph bit = (FT_BitmapGlyph)glyph;
if (halo_radius_)
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;
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;
//angle_ = sin ( 0.1 * count++);
// take ownership of the glyph
glyphs_.push_back(new glyph_t(image));
}
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_;
};
}

View file

@ -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

View file

@ -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),
label_p_(point_placement){}
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_;
};
}

View file

@ -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!!!!!!!!!!!!!!!!!!!!
@ -417,17 +418,35 @@ namespace mapnik
geom->label_position(&x,&y);
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);
}
}
}
}