diff --git a/c++/freetype/src/freetypeview.cpp b/c++/freetype/src/freetypeview.cpp index 856321e..db5c464 100644 --- a/c++/freetype/src/freetypeview.cpp +++ b/c++/freetype/src/freetypeview.cpp @@ -12,6 +12,25 @@ #include "freetypeview.h" +static void +fill_rect( + Surface &surface, + const IntPair2 &rect, + const Color &color ) +{ + const IntPair2 b = rect + & IntPair2( IntVector2(0, 0), IntVector2(surface.width(), surface.height()) ); + if (b.empty()) + return; + const IntVector2 size = b.size(); + const int pitch = surface.pitch(); + const int step = pitch - size.x; + for(Color *p = &surface[b.p0.y][b.p0.x], *end = p + pitch*size.y; p != end; p += step) + for(Color *row_end = p + size.x; p < row_end; ++p) + *p = color; +} + + FreeTypeView::FreeTypeView(): p0(new View::Point( Vector2(0, 0) )), px(new View::Point( Vector2(1, 0) )), @@ -38,6 +57,7 @@ FreeTypeView::FreeTypeView(): params.hinting = false; params.antialiasing = true; + params.invert = true; params.matrix = Matrix().translation(Vector2(15.5, 18.4)); params.color = Color(1, 1, 0, 1); @@ -106,6 +126,11 @@ FreeTypeView::update_surface() { IntVector2(width, height) ); if (int_bounds.empty()) return; + + // prepare surface + DataSurface surface(width, height); + if (params.invert) + fill_rect(surface, int_bounds, params.color.get_mult_alpha()); const Vector2 spacing( params.spacing.x > real_precision ? params.spacing.x : 1, @@ -172,7 +197,6 @@ FreeTypeView::update_surface() { if (!(bounds & dst_rect).empty()) { // create renderer - DataSurface surface(width, height); LabPangoRendererParams rp; rp.surface = &surface; rp.bounds = IntPair2( IntVector2( (int)floor(bounds.p0.x + real_precision), @@ -186,6 +210,7 @@ FreeTypeView::update_surface() { rp.color = params.color; rp.hinting = params.hinting; rp.antialiasing = params.antialiasing; + rp.eraze = params.invert; PangoRenderer *renderer = lab_pango_renderer_new(&rp); // render line by line @@ -215,8 +240,6 @@ FreeTypeView::update_surface() { pango_renderer_deactivate(renderer); g_object_unref(renderer); - - this->surface = surface.to_cairo_surface(true); } // free pango @@ -225,6 +248,8 @@ FreeTypeView::update_surface() { g_object_unref(font); g_object_unref(context); g_object_unref(font_map); + + this->surface = surface.to_cairo_surface(true); } void diff --git a/c++/freetype/src/freetypeview.h b/c++/freetype/src/freetypeview.h index 6530e9e..2c22826 100644 --- a/c++/freetype/src/freetypeview.h +++ b/c++/freetype/src/freetypeview.h @@ -25,6 +25,7 @@ public: Vector2 origin; Matrix matrix; Color color; + bool invert; std::string text; @@ -37,7 +38,8 @@ public: alignment(), justify(), wrap_width(), - alignment_by_origin() + alignment_by_origin(), + invert() { } }; diff --git a/c++/freetype/src/labpangorenderer.cpp b/c++/freetype/src/labpangorenderer.cpp index fe01c72..f5d3f83 100644 --- a/c++/freetype/src/labpangorenderer.cpp +++ b/c++/freetype/src/labpangorenderer.cpp @@ -30,74 +30,51 @@ static inline int floor_ft_int(int x) { return (x & -64)/64; } static inline int ceil_ft_int(int x) { return ((x-1) & -64)/64 + 1; } +template static void put_ft_bitmap( Surface &surface, const IntPair2 &bounds, const FT_Bitmap &bitmap, - int x, - int y, + const IntVector2 &offset, const Color &color ) { const IntPair2 b = bounds & IntPair2( IntVector2(0, 0), IntVector2(surface.width(), surface.height()) ) - & IntPair2( IntVector2(x, y), IntVector2(x + bitmap.width, y + bitmap.rows) ); + & IntPair2( offset, IntVector2(offset.x + bitmap.width, offset.y + bitmap.rows) ); if (b.empty()) return; const IntVector2 size = b.size(); - const IntVector2 sp0 = b.p0 - IntVector2(x, y); + const IntVector2 sp0 = b.p0 - offset; const int pitch = surface.pitch(); Color *dp = &surface[b.p0.y][b.p0.x]; const int dstep = pitch - size.x; - const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch + sp0.x; - const int sstep = bitmap.pitch - size.x; - - for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep) { - for(const Color *row_end = dp + size.x; dp < row_end; ++dp, ++sp) { - const Real a = *sp * (1/255.0); - *dp = *dp*(1-a) + color*a; + if (antialiasing) { + const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch + sp0.x; + const int sstep = bitmap.pitch - size.x; + for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep) { + for(const Color *row_end = dp + size.x; dp < row_end; ++dp, ++sp) { + const Real a = *sp * (1/255.0); + if (eraze) *dp *= 1 - a; + else *dp = *dp*(1-a) + color*a; + } } + } else { + const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch; + const int sstep = bitmap.pitch; + const int sp1x = sp0.x + size.x; + for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep) + for(int bit = sp0.x; bit < sp1x; ++dp, ++bit) + if (sp[bit/8] & (128 >> (bit%8))) + *dp = eraze ? Color() : color; } } static void -put_ft_bitmap_mono( - Surface &surface, - const IntPair2 &bounds, - const FT_Bitmap &bitmap, - int x, - int y, - const Color &color ) -{ - const IntPair2 b = bounds - & IntPair2( IntVector2(0, 0), IntVector2(surface.width(), surface.height()) ) - & IntPair2( IntVector2(x, y), IntVector2(bitmap.width, bitmap.rows) ); - if (b.empty()) - return; - - const IntVector2 size = b.size(); - const IntVector2 sp0 = b.p0 - IntVector2(x, y); - const int pitch = surface.pitch(); - - Color *dp = &surface[b.p0.y][b.p0.x]; - const int dstep = pitch - size.x; - - const unsigned char *sp = bitmap.buffer + sp0.y*bitmap.pitch; - const int sstep = bitmap.pitch; - const int sp1x = sp0.x + size.x; - - for(const Color *end = dp + pitch*size.y; dp != end; dp += dstep, sp += sstep) - for(int bit = sp0.x; bit < sp1x; ++dp, ++bit) - if (sp[bit/8] & (128 >> (bit%8))) - *dp = color; -} - - -static void lab_pango_renderer_draw_glyph( PangoRenderer *renderer, PangoFont *font, @@ -160,22 +137,23 @@ lab_pango_renderer_draw_glyph( ceil_ft_int(-metrics.horiBearingY + metrics.height) + iy )); if (!(params.bounds & glyph_bounds).empty()) { if (!FT_Render_Glyph(face->glyph, params.antialiasing ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO)) { + const IntVector2 offset( + face->glyph->bitmap_left + ix, + iy - face->glyph->bitmap_top ); if (params.antialiasing) { - put_ft_bitmap( - *params.surface, - surface_bounds, - face->glyph->bitmap, - face->glyph->bitmap_left + ix, - iy - face->glyph->bitmap_top, - params.color ); + if (params.eraze) + put_ft_bitmap( + *params.surface, surface_bounds, face->glyph->bitmap, offset, params.color ); + else + put_ft_bitmap( + *params.surface, surface_bounds, face->glyph->bitmap, offset, params.color ); } else { - put_ft_bitmap_mono( - *params.surface, - surface_bounds, - face->glyph->bitmap, - face->glyph->bitmap_left + ix, - iy - face->glyph->bitmap_top, - params.color ); + if (params.eraze) + put_ft_bitmap( + *params.surface, surface_bounds, face->glyph->bitmap, offset, params.color ); + else + put_ft_bitmap( + *params.surface, surface_bounds, face->glyph->bitmap, offset, params.color ); } } } diff --git a/c++/freetype/src/labpangorenderer.h b/c++/freetype/src/labpangorenderer.h index 7f5b40c..b44637e 100644 --- a/c++/freetype/src/labpangorenderer.h +++ b/c++/freetype/src/labpangorenderer.h @@ -30,8 +30,9 @@ struct LabPangoRendererParams { Color color; bool hinting; bool antialiasing; + bool eraze; LabPangoRendererParams(): - surface(), hinting(), antialiasing() { } + surface(), hinting(), antialiasing(), eraze() { } };