diff --git a/include/mapnik/text/renderer.hpp b/include/mapnik/text/renderer.hpp index 9d480f4c9..267a1bae5 100644 --- a/include/mapnik/text/renderer.hpp +++ b/include/mapnik/text/renderer.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #pragma GCC diagnostic push #include @@ -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 diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index cace1e258..32e57f3ba 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -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(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( glyph_pos.rot.cos * 0x10000L); matrix.xy = static_cast(-glyph_pos.rot.sin * 0x10000L); matrix.yx = static_cast( glyph_pos.rot.sin * 0x10000L); @@ -77,17 +106,13 @@ void text_renderer::prepare_glyphs(glyph_positions const& positions) pen.x = static_cast(pos.x * 64); pen.y = static_cast(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 +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((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 agg_text_renderer::agg_text_renderer (pixmap_type & pixmap, halo_rasterizer_e rasterizer, @@ -211,18 +261,38 @@ void agg_text_renderer::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(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::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(glyph.image); render_halo_id(&bit->bitmap, feature_id,