implement color bitmap extraction/scaling/compositing into target pixmap

This commit is contained in:
artemp 2017-02-28 15:04:49 +01:00
parent 639dcae83f
commit 1b67779290
2 changed files with 95 additions and 20 deletions

View file

@ -28,6 +28,7 @@
#include <mapnik/image_compositing.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/pixel_position.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
@ -51,8 +52,13 @@ struct glyph_t
{
FT_Glyph image;
detail::evaluated_format_properties const& properties;
glyph_t(FT_Glyph image_, detail::evaluated_format_properties const& properties_)
: image(image_), properties(properties_) {}
pixel_position pos;
double size;
glyph_t(FT_Glyph image_, detail::evaluated_format_properties const& properties_, pixel_position const& pos_, double size_)
: image(image_),
properties(properties_),
pos(pos_),
size(size_) {}
};
class text_renderer : private util::noncopyable

View file

@ -25,6 +25,8 @@
#include <mapnik/grid/grid.hpp>
#include <mapnik/text/text_properties.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/image_scaling.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image_any.hpp>
@ -66,8 +68,35 @@ void text_renderer::prepare_glyphs(glyph_positions const& positions)
for (auto const& glyph_pos : positions)
{
glyph_info const& glyph = glyph_pos.glyph;
glyph.face->set_character_sizes(glyph.format->text_size * scale_factor_); //TODO: Optimize this?
FT_Int32 load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
FT_Face face = glyph.face->get_face();
if (glyph.face->is_color())
{
load_flags |= FT_LOAD_COLOR ;
if (face->num_fixed_sizes > 0)
{
int scaled_size = static_cast<int>(glyph.format->text_size * scale_factor_);
int best_match = 0;
int diff = std::abs(scaled_size - face->available_sizes[0].width);
for (int i = 1; i < face->num_fixed_sizes; ++i)
{
int ndiff = std::abs(scaled_size - face->available_sizes[i].height);
if (ndiff < diff)
{
best_match = i;
diff = ndiff;
}
}
error = FT_Select_Size(face, best_match);
}
}
else
{
glyph.face->set_character_sizes(glyph.format->text_size * scale_factor_);
}
double size = glyph.format->text_size * scale_factor_;
matrix.xx = static_cast<FT_Fixed>( glyph_pos.rot.cos * 0x10000L);
matrix.xy = static_cast<FT_Fixed>(-glyph_pos.rot.sin * 0x10000L);
matrix.yx = static_cast<FT_Fixed>( glyph_pos.rot.sin * 0x10000L);
@ -77,17 +106,13 @@ void text_renderer::prepare_glyphs(glyph_positions const& positions)
pen.x = static_cast<FT_Pos>(pos.x * 64);
pen.y = static_cast<FT_Pos>(pos.y * 64);
FT_Face face = glyph.face->get_face();
FT_Set_Transform(face, &matrix, &pen);
error = FT_Load_Glyph(face, glyph.glyph_index, FT_LOAD_NO_HINTING);
error = FT_Load_Glyph(face, glyph.glyph_index, load_flags);
if (error) continue;
FT_Glyph image;
error = FT_Get_Glyph(face->glyph, &image);
if (error) continue;
glyphs_.emplace_back(image, *glyph.format);
glyphs_.emplace_back(image, *glyph.format, pos, size);
}
}
@ -101,7 +126,7 @@ void composite_bitmap(T & pixmap, FT_Bitmap *bitmap, unsigned rgba, int x, int y
{
for (int j = y, q = 0; j < y_max; ++j, ++q)
{
unsigned gray=bitmap->buffer[q*bitmap->width+p];
unsigned gray = bitmap->buffer[q * bitmap->width + p];
if (gray)
{
mapnik::composite_pixel(pixmap, comp_op, i, j, rgba, gray, opacity);
@ -110,6 +135,31 @@ void composite_bitmap(T & pixmap, FT_Bitmap *bitmap, unsigned rgba, int x, int y
}
}
template <typename T>
void composite_color_bitmap(T & pixmap, FT_Bitmap *bitmap, int x, int y, double size, double opacity, composite_mode_e comp_op)
{
image_rgba8 image(bitmap->width, bitmap->rows);
for (unsigned i = 0, p = 0; i < bitmap->width; ++i, p += 4)
{
for (unsigned j = 0, q = 0; j < bitmap->rows; ++j, ++q)
{
std::uint8_t b = bitmap->buffer[q * bitmap->width * 4 + p];
std::uint8_t g = bitmap->buffer[q * bitmap->width * 4 + p + 1];
std::uint8_t r = bitmap->buffer[q * bitmap->width * 4 + p + 2];
std::uint8_t a = bitmap->buffer[q * bitmap->width * 4 + p + 3];
unsigned c = static_cast<unsigned>((a << 24) | (b << 16) | (g << 8) | (r));
image(i, j) = c;
}
}
double scale = size/image.height();
int scaled_width = bitmap->width * scale;
int scaled_height = bitmap->rows * scale;
image_rgba8 scaled_image(scaled_width, scaled_height);
scale_image_agg(scaled_image, image , SCALING_BILINEAR , scale, scale, 0.0, 0.0, 1.0, 0);
composite(pixmap, scaled_image, comp_op, opacity, x, y);
}
template <typename T>
agg_text_renderer<T>::agg_text_renderer (pixmap_type & pixmap,
halo_rasterizer_e rasterizer,
@ -211,18 +261,38 @@ void agg_text_renderer<T>::render(glyph_positions const& pos)
{
fill = glyph.properties.fill.rgba();
text_opacity = glyph.properties.text_opacity;
FT_Glyph_Transform(glyph.image, &matrix, &start);
error = FT_Glyph_To_Bitmap(&glyph.image ,FT_RENDER_MODE_NORMAL, 0, 1);
if (!error)
error = 0;
if ( glyph.image->format != FT_GLYPH_FORMAT_BITMAP )
{
error = FT_Glyph_To_Bitmap(&glyph.image ,FT_RENDER_MODE_NORMAL, 0, 1);
}
if (error == 0)
{
FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(glyph.image);
composite_bitmap(pixmap_,
&bit->bitmap,
fill,
bit->left,
height - bit->top,
text_opacity,
comp_op_);
int pixel_mode = bit->bitmap.pixel_mode;
if (pixel_mode == 7)
{
int x = (start.x >> 6) + glyph.pos.x;
int y = height - (start.y >> 6) + glyph.pos.y;
composite_color_bitmap(pixmap_,
&bit->bitmap,
x,y, glyph.size,
text_opacity,
comp_op_);
}
else
{
composite_bitmap(pixmap_,
&bit->bitmap,
fill,
bit->left,
height - bit->top,
text_opacity,
comp_op_);
}
}
FT_Done_Glyph(glyph.image);
}
@ -257,7 +327,6 @@ void grid_text_renderer<T>::render(glyph_positions const& pos, value_integer fea
error = FT_Glyph_To_Bitmap(&glyph.image, FT_RENDER_MODE_NORMAL, 0, 1);
if (!error)
{
FT_BitmapGlyph bit = reinterpret_cast<FT_BitmapGlyph>(glyph.image);
render_halo_id(&bit->bitmap,
feature_id,