added font_engine impl - work in progress:)

This commit is contained in:
Artem Pavlenko 2006-02-21 19:55:24 +00:00
parent 897341e042
commit bd173527a0
11 changed files with 579 additions and 28 deletions

View file

@ -24,8 +24,8 @@ opts = Options()
opts.Add('PREFIX', 'The install path "prefix"', '/usr/local')
opts.Add(PathOption('BOOST_INCLUDES', 'Search path for boost include files', '/usr/include'))
opts.Add(PathOption('BOOST_LIBS', 'Search path for boost library files', '/usr/lib'))
opts.Add(PathOption('FREETYPE_INCLUDES', 'Search path for FreeType include files', '/usr/include'))
opts.Add(PathOption('FREETYPE_LIBS', 'Search path for FreeType library files', '/usr/lib'))
opts.Add(PathOption('FREETYPE_INCLUDES', 'Search path for FreeType include files', '/opt/freetype/include/freetype2'))
opts.Add(PathOption('FREETYPE_LIBS', 'Search path for FreeType library files', '/opt/freetype/lib'))
opts.Add(PathOption('PNG_INCLUDES', 'Search path for libpng include files', '/usr/include'))
opts.Add(PathOption('PNG_LIBS', 'Search path for libpng include files', '/usr/lib'))
opts.Add(PathOption('JPEG_INCLUDES', 'Search path for libjpeg include files', '/usr/include'))
@ -63,6 +63,7 @@ C_LIBSHEADERS = [
['tiff', 'tiff.h', True],
['z', 'zlib.h', True],
['jpeg', ['stdio.h','jpeglib.h'], True],
#['freetype', 'ft2build.h', True],
['pq', 'libpq-fe.h', False]
]

View file

@ -23,6 +23,8 @@
#include "feature_style_processor.hpp"
#include <boost/utility.hpp>
//#include "agg_font_freetype.h"
#include "font_engine_freetype.hpp"
namespace mapnik
{
@ -31,6 +33,10 @@ namespace mapnik
private boost::noncopyable
{
agg_renderer(Map const& m, T & pixmap);
void start_map_processing();
void end_map_processing();
void start_layer_processing();
void end_layer_processing();
void process(point_symbolizer const& sym,Feature const& feature);
void process(line_symbolizer const& sym,Feature const& feature);
void process(line_pattern_symbolizer const& sym,Feature const& feature);
@ -41,6 +47,7 @@ namespace mapnik
private:
T & pixmap_;
CoordTransform t_;
face_manager<freetype_engine> font_manager_;
};
}

View file

@ -68,7 +68,7 @@ namespace mapnik
}
std::string to_string() const
{
return value_.to_string();
return value_.to_expression_string();
}
~literal() {}
private:
@ -88,8 +88,6 @@ namespace mapnik
property(property const& other)
: expression<FeatureT>(),
name_(other.name_)
//index_(other.index_),
//valid_(other.valid_)
{}
value get_value(FeatureT const& feature) const
@ -108,11 +106,7 @@ namespace mapnik
{
return name_;
}
void set_index(size_t index)
{
//index_=index;
//valid_=true;
}
std::string to_string() const
{
return "["+name_+"]";
@ -120,8 +114,7 @@ namespace mapnik
~property() {}
private:
std::string name_;
//size_t index_;
//bool valid_;
};
}

View file

@ -0,0 +1,395 @@
/* This file is part of Mapnik (c++ mapping toolkit)
* Copyright (C) 2005 Artem Pavlenko
*
* Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//$Id$
#if !defined FONT_ENGINE_FREETYPE_HPP
#define FONT_ENGINE_FREETYPE_HPP
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/thread/mutex.hpp>
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <color.hpp>
#include <utils.hpp>
namespace mapnik
{
class font_face : boost::noncopyable
{
public:
font_face(FT_Face face)
: face_(face) {}
std::string family_name() const
{
return std::string(face_->family_name);
}
std::string style_name() const
{
return std::string(face_->style_name);
}
unsigned num_glyphs() const
{
return face_->num_glyphs;
}
FT_GlyphSlot glyph() const
{
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_;
}
bool set_pixel_sizes(unsigned size)
{
if (! FT_Set_Pixel_Sizes( face_, 0, size ))
return true;
return false;
}
~font_face()
{
std::cout << "clean up face:" << family_name()<<":" << style_name() << std::endl;
FT_Done_Face(face_);
}
private:
FT_Face face_;
};
typedef boost::shared_ptr<font_face> face_ptr;
class freetype_engine : public mapnik::singleton<freetype_engine,mapnik::CreateStatic>,
private boost::noncopyable
{
friend class mapnik::CreateStatic<freetype_engine>;
public:
static bool register_font(std::string const& file_name)
{
mutex::scoped_lock lock(mapnik::singleton<freetype_engine,
mapnik::CreateStatic>::mutex_);
FT_Face face;
FT_Error error = FT_New_Face (library_,file_name.c_str(),0,&face);
if ( !error )
{
std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
name2file_.insert(std::make_pair(name,file_name));
FT_Done_Face(face );
return true;
}
return false;
}
static std::vector<std::string> face_names ()
{
std::vector<std::string> names;
std::map<std::string,std::string>::const_iterator itr;
for (itr = name2file_.begin();itr!=name2file_.end();++itr)
{
names.push_back(itr->first);
}
return names;
}
static face_ptr create_face(std::string const& family_name)
{
mutex::scoped_lock lock(mapnik::singleton<freetype_engine,
mapnik::CreateStatic>::mutex_);
std::map<std::string,std::string>::iterator itr;
itr = name2file_.find(family_name);
if (itr != name2file_.end())
{
FT_Face face;
FT_Error error = FT_New_Face (library_,itr->second.c_str(),0,&face);
if (!error)
{
return face_ptr (new font_face(face));
}
}
return face_ptr();
}
private:
freetype_engine()
{
FT_Error error = FT_Init_FreeType( &library_ );
if (error)
{
throw std::runtime_error("can not load FreeType2 library");
}
}
virtual ~freetype_engine()
{
FT_Done_FreeType(library_);
}
static FT_Library library_;
static std::map<std::string,std::string> name2file_;
};
template <typename T>
class face_manager : private boost::noncopyable
{
typedef T font_engine_type;
typedef std::map<std::string,face_ptr> faces;
public:
face_ptr get_face(std::string const& name)
{
typename faces::iterator itr;
itr = faces_.find(name);
if (itr != faces_.end())
{
return itr->second;
}
else
{
face_ptr face = font_engine_type::instance()->create_face(name);
if (face)
{
faces_.insert(make_pair(name,face));
}
return face;
}
}
private:
faces faces_;
};
template <typename T>
struct text_renderer : private boost::noncopyable
{
typedef T pixmap_type;
text_renderer (pixmap_type & pixmap, face_ptr face)
: pixmap_(pixmap),
face_(face),
fill_(0,0,0),
halo_fill_(255,255,255),
halo_radius_(0),
angle_(0.0) {}
void set_pixel_size(unsigned size)
{
face_->set_pixel_sizes(size);
}
void set_angle(float angle)
{
angle_=angle;
}
void set_fill(mapnik::Color const& fill)
{
fill_=fill;
}
void set_halo_fill(mapnik::Color const& halo)
{
halo_fill_=halo;
}
void set_halo_radius( int radius=1)
{
halo_radius_=radius;
}
void render(std::string const& text, double x0, double y0)
{
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;
unsigned height = pixmap_.height();
origin.x = 0;
origin.y = 0;
pen.x = unsigned(x0 * 64);
pen.y = unsigned((height - y0) * 64);
use_kerning = FT_HAS_KERNING(face);
//unsigned count=1;
for (std::string::const_iterator i=text.begin();i!=text.end();++i)
{
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, *i );
if ( use_kerning && previous && glyph_index)
{
FT_Vector delta;
FT_Get_Kerning(face,previous,glyph_index,
FT_KERNING_DEFAULT,&delta);
pen.x += delta.x;
pen.y += delta.y;
std::cout<< "use kerning "<< std::endl;
}
error = FT_Load_Glyph (face,glyph_index,FT_LOAD_DEFAULT);
if ( error )
continue;
error = FT_Get_Glyph( face->glyph, &glyph );
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_)
{
render_halo(&bit->bitmap, halo_fill_.rgba(),
bit->left,
height - bit->top,halo_radius_);
}
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++);
}
}
private:
void render_halo(FT_Bitmap *bitmap,unsigned rgba,int x,int y,int radius)
{
int x_max=x+bitmap->width;
int y_max=y+bitmap->rows;
int i,p,j,q;
for (i=x,p=0;i<x_max;++i,++p)
{
for (j=y,q=0;j<y_max;++j,++q)
{
int gray = bitmap->buffer[q*bitmap->width+p];
if (gray)
{
for (int n=-halo_radius_; n <=halo_radius_; ++n)
for (int m=-halo_radius_;m <= halo_radius_; ++m)
pixmap_.blendPixel(i+m,j+n,rgba,gray);
}
}
}
}
void render_bitmap(FT_Bitmap *bitmap,unsigned rgba,int x,int y)
{
int x_max=x+bitmap->width;
int y_max=y+bitmap->rows;
int i,p,j,q;
for (i=x,p=0;i<x_max;++i,++p)
{
for (j=y,q=0;j<y_max;++j,++q)
{
int gray=bitmap->buffer[q*bitmap->width+p];
if (gray)
{
pixmap_.blendPixel(i,j,rgba,gray);
}
}
}
}
pixmap_type & pixmap_;
face_ptr face_;
mapnik::Color fill_;
mapnik::Color halo_fill_;
int halo_radius_;
float angle_;
};
}
#endif // FONT_ENGINE_FREETYPE_HPP

View file

@ -95,13 +95,30 @@ namespace mapnik
return 0xff << 24 | r << 16 | g << 8 | b;
}
inline void blendPixel(int x,int y,unsigned int rgba,int t)
inline void blendPixel(int x,int y,unsigned int rgba1,int t)
{
if (checkBounds(x,y))
{
int bg=data_(x,y);
int nc=blendColor(rgba,bg,t);
data_(x,y)=nc;
unsigned rgba0 = data_(x,y);
unsigned a1 = t;//(rgba1 >> 24) & 0xff;
if (a1 == 0) return;
unsigned r1 = rgba1 & 0xff;
unsigned g1 = (rgba1 >> 8 ) & 0xff;
unsigned b1 = (rgba1 >> 16) & 0xff;
unsigned a0 = (rgba0 >> 24) & 0xff;
unsigned r0 = (rgba0 & 0xff) * a0;
unsigned g0 = ((rgba0 >> 8 ) & 0xff) * a0;
unsigned b0 = ((rgba0 >> 16) & 0xff) * a0;
a0 = ((a1 + a0) << 8) - a0*a1;
r0 = ((((r1 << 8) - r0) * a1 + (r0 << 8)) / a0);
g0 = ((((g1 << 8) - g0) * a1 + (g0 << 8)) / a0);
b0 = ((((b1 << 8) - b0) * a1 + (b0 << 8)) / a0);
a0 = a0 >> 8;
data_(x,y)= (a0 << 24)| (b0 << 16) | (g0 << 8) | (r0) ;
}
}

View file

@ -27,15 +27,22 @@
namespace mapnik
{
enum label_placement_e {
point_placement=1,
line_placement=2
};
struct text_symbolizer
{
{
text_symbolizer(std::string const& name,Color const& fill)
: name_(name),
fill_(fill) {}
fill_(fill),
label_p_(point_placement){}
text_symbolizer(text_symbolizer const& rhs)
: name_(rhs.name_),
fill_(rhs.fill_) {}
fill_(rhs.fill_),
label_p_(rhs.label_p_) {}
~text_symbolizer()
{
@ -45,9 +52,25 @@ namespace mapnik
{
return name_;
}
Color const& get_fill() const
{
return fill_;
}
void set_label_placement(label_placement_e label_p)
{
label_p_ = label_p;
}
label_placement_e get_label_placement() const
{
return label_p_;
}
private:
std::string name_;
Color fill_;
Color fill_;
label_placement_e label_p_;
};
}

View file

@ -313,6 +313,21 @@ namespace mapnik {
};
struct to_string : public boost::static_visitor<std::string>
{
template <typename T>
std::string operator() (T val) const
{
std::stringstream ss;
ss << val;
return ss.str();
}
std::string const& operator() (std::string const& val) const
{
return val;
}
};
struct to_expression_string : public boost::static_visitor<std::string>
{
template <typename T>
std::string operator() (T val) const
@ -390,7 +405,12 @@ namespace mapnik {
*this = boost::apply_visitor(impl::div<value>(),*this,other);
return *this;
}
std::string to_expression_string() const
{
return boost::apply_visitor(impl::to_expression_string(),*this);
}
std::string to_string() const
{
return boost::apply_visitor(impl::to_string(),*this);

View file

@ -24,6 +24,8 @@ Import('env')
prefix = env['PREFIX']
libraries = ['agg'] + env['LIBS']
libraries += ['freetype']
linkflags = '-Wl,-rpath-link,. -Wl,-soname,libmapnik.so'
source = Split(
@ -47,6 +49,7 @@ source = Split(
point_symbolizer.cpp
polygon_pattern_symbolizer.cpp
line_pattern_symbolizer.cpp
font_engine_freetype.cpp
"""
)
#render.cpp

View file

@ -51,7 +51,6 @@
#include "agg_renderer_outline_image.h"
#include <boost/utility.hpp>
#include <iostream>
namespace mapnik
@ -89,6 +88,31 @@ namespace mapnik
pixmap_.setBackground(bg);
std::cout << "scale="<<m.scale()<<std::endl;
}
template <typename T>
void agg_renderer<T>::start_map_processing()
{
std::cout << "start map processing" << std::endl;
}
template <typename T>
void agg_renderer<T>::end_map_processing()
{
std::cout << "end map processing" << std::endl;
}
template <typename T>
void agg_renderer<T>::start_layer_processing()
{
std::cout << "start layer processing" << std::endl;
}
template <typename T>
void agg_renderer<T>::end_layer_processing()
{
std::cout << "end layer processing" << std::endl;
}
template <typename T>
void agg_renderer<T>::process(polygon_symbolizer const& sym,Feature const& feature)
{
@ -356,10 +380,51 @@ namespace mapnik
template <typename T>
void agg_renderer<T>::process(text_symbolizer const& sym ,Feature const& feature)
{
//TODO - implement text
//std::cout << feature << std::endl;
std::cout << sym.get_name() <<":" << feature[sym.get_name()] << std::endl;
typedef coord_transform<CoordTransform,geometry_type> path_type;
geometry_ptr const& geom=feature.get_geometry();
if (geom)
{
double angle = 0.0;
if (sym.get_label_placement() == line_placement &&
geom->num_points() > 1)
{
path_type path(t_,*geom);
double x0,y0,x1,y1;
path.vertex(&x0,&y0);
path.vertex(&x1,&y1);
double dx = x1 - x0;
double dy = y1 - y0;
angle = atan( dx/ dy ) - 0.5 * 3.1459;
//TODO!!!!!!!!!!!!!!!!!!!!
}
std::string text = feature[sym.get_name()].to_string();
if (text.length() > 0)
{
Color const& fill = sym.get_fill();
double x;
double y;
geom->label_position(&x,&y);
t_.forward_x(&x);
t_.forward_y(&y);
face_ptr face = font_manager_.get_face("Bitstream Vera Sans Roman");//TODO
if (face)
{
text_renderer<mapnik::Image32> ren(pixmap_,face);
ren.set_pixel_size(12);
ren.set_fill(fill);
ren.set_halo_radius(1);
ren.set_angle(angle);
ren.render(text,x,y);
}
}
}
}
template class agg_renderer<Image32>;
}

View file

@ -0,0 +1,27 @@
/* This file is part of Mapnik (c++ mapping toolkit)
* Copyright (C) 2006 Artem Pavlenko
*
* Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//$Id$
#include "font_engine_freetype.hpp"
namespace mapnik
{
FT_Library freetype_engine::library_;
std::map<std::string,std::string> freetype_engine::name2file_;
}

View file

@ -69,7 +69,7 @@ namespace mapnik
}
template <class PixBuffer>
void TextRasterizer<PixBuffer>::render_bitmap(FT_Bitmap *bitmap,int x,int y)
void TextRasterizer<PixBuffer>::render_bitmap(FT_Bitmap *bitmap,int x,int y)
{
int x_max=x+bitmap->width;
int y_max=y+bitmap->rows;