From 9edca8fe56eed686ef3d83c7caba23c82348efee Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 14 Jul 2010 08:42:21 +0200 Subject: Flood and merge filters (bzr r9508.1.17) --- src/display/cairo-utils.cpp | 8 ++ src/display/cairo-utils.h | 1 + src/display/nr-filter-blend.cpp | 153 ------------------------------------ src/display/nr-filter-blend.h | 3 - src/display/nr-filter-flood.cpp | 77 +++++++++--------- src/display/nr-filter-flood.h | 10 +-- src/display/nr-filter-gaussian.cpp | 1 + src/display/nr-filter-gaussian.h | 6 +- src/display/nr-filter-merge.cpp | 101 +++++++----------------- src/display/nr-filter-merge.h | 7 +- src/display/nr-filter-primitive.cpp | 2 +- src/display/nr-filter-primitive.h | 16 ++-- 12 files changed, 91 insertions(+), 294 deletions(-) (limited to 'src/display') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 36202f42e..ce56c21f5 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -367,6 +367,14 @@ ink_cairo_surface_create_identical(cairo_surface_t *s) return ns; } +cairo_surface_t * +ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c) +{ + cairo_surface_t *ns = cairo_surface_create_similar(s, c, + ink_cairo_surface_get_width(s), ink_cairo_surface_get_height(s)); + return ns; +} + /** @brief Extract the alpha channel into a new surface. * Creates a surface with a content type of CAIRO_CONTENT_ALPHA that contains * the alpha values of pixels from @a s. */ diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index cfd33330b..3845d5ebb 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -86,6 +86,7 @@ void ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, do cairo_surface_t *ink_cairo_surface_copy(cairo_surface_t *s); cairo_surface_t *ink_cairo_surface_create_identical(cairo_surface_t *s); +cairo_surface_t *ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c); cairo_surface_t *ink_cairo_extract_alpha(cairo_surface_t *s); cairo_surface_t *ink_cairo_surface_unshare(cairo_surface_t *s); int ink_cairo_surface_get_width(cairo_surface_t *surface); diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index 4ce37ae3b..758b49fe4 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -21,14 +21,9 @@ #include "display/cairo-utils.h" #include "display/nr-filter-blend.h" -#include "display/nr-filter-pixops.h" #include "display/nr-filter-primitive.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-types.h" -#include "display/nr-filter-units.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixops.h" #include "preferences.h" namespace Inkscape { @@ -48,77 +43,6 @@ namespace Filters { * cb = Color (RGB) at a given pixel for image B - premultiplied */ -/* - * These blending equations given in SVG standard are for color values - * in the range 0..1. As these values are stored as unsigned char values, - * they need some reworking. An unsigned char value can be thought as - * 0.8 fixed point representation of color value. This is how I've - * ended up with these equations here. - */ - -// Set alpha / opacity. This line is same for all the blending modes, -// so let's save some copy-pasting. -#define SET_ALPHA r[3] = NR_NORMALIZE_21((255 * 255) - (255 - a[3]) * (255 - b[3])) - -// cr = (1 - qa) * cb + ca -inline void -blend_normal(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_COMPOSEPPP_1111(a[0],a[3],b[0]); - r[1] = NR_COMPOSEPPP_1111(a[1],a[3],b[1]); - r[2] = NR_COMPOSEPPP_1111(a[2],a[3],b[2]); - SET_ALPHA; -} - -// cr = (1-qa)*cb + (1-qb)*ca + ca*cb -inline void -blend_multiply(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21((255 - a[3]) * b[0] + (255 - b[3]) * a[0] - + a[0] * b[0]); - r[1] = NR_NORMALIZE_21((255 - a[3]) * b[1] + (255 - b[3]) * a[1] - + a[1] * b[1]); - r[2] = NR_NORMALIZE_21((255 - a[3]) * b[2] + (255 - b[3]) * a[2] - + a[2] * b[2]); - SET_ALPHA; -} - -// cr = cb + ca - ca * cb -inline void -blend_screen(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21((b[0] + a[0]) * 255 - a[0] * b[0]); - r[1] = NR_NORMALIZE_21((b[1] + a[1]) * 255 - a[1] * b[1]); - r[2] = NR_NORMALIZE_21((b[2] + a[2]) * 255 - a[2] * b[2]); - SET_ALPHA; -} - -// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -inline void -blend_darken(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(std::min(NR_COMPOSEPPP_1112(a[0],a[3],b[0]), - NR_COMPOSEPPP_1112(b[0],b[3],a[0]))); - r[1] = NR_NORMALIZE_21(std::min(NR_COMPOSEPPP_1112(a[1],a[3],b[1]), - NR_COMPOSEPPP_1112(b[1],b[3],a[1]))); - r[2] = NR_NORMALIZE_21(std::min(NR_COMPOSEPPP_1112(a[2],a[3],b[2]), - NR_COMPOSEPPP_1112(b[2],b[3],a[2]))); - SET_ALPHA; -} - -// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -inline void -blend_lighten(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = NR_NORMALIZE_21(std::max(NR_COMPOSEPPP_1112(a[0],a[3],b[0]), - NR_COMPOSEPPP_1112(b[0],b[3],a[0]))); - r[1] = NR_NORMALIZE_21(std::max(NR_COMPOSEPPP_1112(a[1],a[3],b[1]), - NR_COMPOSEPPP_1112(b[1],b[3],a[1]))); - r[2] = NR_NORMALIZE_21(std::max(NR_COMPOSEPPP_1112(a[2],a[3],b[2]), - NR_COMPOSEPPP_1112(b[2],b[3],a[2]))); - SET_ALPHA; -} - FilterBlend::FilterBlend() : _blend_mode(BLEND_NORMAL), _input2(NR_FILTER_SLOT_NOT_SET) @@ -372,83 +296,6 @@ void FilterBlend::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -int FilterBlend::render(FilterSlot &slot, FilterUnits const & /*units*/) { - NRPixBlock *in1 = slot.get(_input); - NRPixBlock *in2 = slot.get(_input2); - NRPixBlock *original_in1 = in1; - NRPixBlock *original_in2 = in2; - NRPixBlock *out; - - // Bail out if either one of source images is missing - if (!in1 || !in2) { - g_warning("Missing source image for feBlend (in=%d in2=%d)", _input, _input2); - return 1; - } - - out = new NRPixBlock; - NRRectL out_area; - nr_rect_l_union(&out_area, &in1->area, &in2->area); - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, - out_area.x0, out_area.y0, out_area.x1, out_area.y1, - true); - - // Blending modes are defined for premultiplied RGBA values, - // thus convert them to that format before blending - if (in1->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in1 = new NRPixBlock; - nr_pixblock_setup_fast(in1, NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in1->area.x0, original_in1->area.y0, - original_in1->area.x1, original_in1->area.y1, - false); - nr_blit_pixblock_pixblock(in1, original_in1); - } - if (in2->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in2 = new NRPixBlock; - nr_pixblock_setup_fast(in2, NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in2->area.x0, original_in2->area.y0, - original_in2->area.x1, original_in2->area.y1, - false); - nr_blit_pixblock_pixblock(in2, original_in2); - } - - /* pixops_mix is defined in display/nr-filter-pixops.h - * It mixes the two input images with the function given as template - * and places the result in output image. - */ - switch (_blend_mode) { - case BLEND_MULTIPLY: - pixops_mix(*out, *in1, *in2); - break; - case BLEND_SCREEN: - pixops_mix(*out, *in1, *in2); - break; - case BLEND_DARKEN: - pixops_mix(*out, *in1, *in2); - break; - case BLEND_LIGHTEN: - pixops_mix(*out, *in1, *in2); - break; - case BLEND_NORMAL: - default: - pixops_mix(*out, *in1, *in2); - break; - } - - if (in1 != original_in1) { - nr_pixblock_release(in1); - delete in1; - } - if (in2 != original_in2) { - nr_pixblock_release(in2); - delete in2; - } - - out->empty = FALSE; - slot.set(_output, out); - - return 0; -} - bool FilterBlend::can_handle_affine(Geom::Matrix const &) { // blend is a per-pixel primitive and is immutable under transformations diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h index 45da07f27..94c782156 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -18,8 +18,6 @@ */ #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" namespace Inkscape { namespace Filters { @@ -40,7 +38,6 @@ public: virtual ~FilterBlend(); virtual void render_cairo(FilterSlot &slot); - virtual int render(FilterSlot &slot, FilterUnits const &units); virtual bool can_handle_affine(Geom::Matrix const &); virtual void set_input(int slot); diff --git a/src/display/nr-filter-flood.cpp b/src/display/nr-filter-flood.cpp index fd0600cdb..7afd25e2d 100644 --- a/src/display/nr-filter-flood.cpp +++ b/src/display/nr-filter-flood.cpp @@ -13,10 +13,12 @@ # include "config.h" #endif +#include "display/cairo-utils.h" #include "display/nr-filter-flood.h" -#include "display/nr-filter-utils.h" +#include "display/nr-filter-slot.h" #include "svg/svg-icc-color.h" #include "svg/svg-color.h" +#include "color.h" namespace Inkscape { namespace Filters { @@ -31,48 +33,39 @@ FilterPrimitive * FilterFlood::create() { FilterFlood::~FilterFlood() {} -int FilterFlood::render(FilterSlot &slot, FilterUnits const &/*units*/) { -//g_message("rendering feflood"); - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feFlood (in=%d)", _input); - return 1; - } - - int i; - int in_w = in->area.x1 - in->area.x0; - int in_h = in->area.y1 - in->area.y0; - - NRPixBlock *out = new NRPixBlock; - - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - - unsigned char *out_data = NR_PIXBLOCK_PX(out); - unsigned char r,g,b,a; - - - r = CLAMP_D_TO_U8((color >> 24) % 256); - g = CLAMP_D_TO_U8((color >> 16) % 256); - b = CLAMP_D_TO_U8((color >> 8) % 256); - a = CLAMP_D_TO_U8(opacity*255); - -#if ENABLE_LCMS - icc_color_to_sRGB(icc, &r, &g, &b); -//g_message("result: r:%d g:%d b:%d", r, g, b); -#endif //ENABLE_LCMS - - for(i=0; i < 4*in_h*in_w; i+=4){ - out_data[i]=r; - out_data[i+1]=g; - out_data[i+2]=b; - out_data[i+3]=a; - } - - out->empty = FALSE; +void FilterFlood::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + + double r, g, b, a; + r = SP_RGBA32_R_F(color); + g = SP_RGBA32_G_F(color); + b = SP_RGBA32_B_F(color); + a = opacity; + + #if ENABLE_LCMS + guchar ru, gu, bu; + icc_color_to_sRGB(icc, &ru, &gu, &bu); + r = SP_COLOR_U_TO_F(ru); + g = SP_COLOR_U_TO_F(gu); + b = SP_COLOR_U_TO_F(bu); + #endif + + cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + cairo_t *ct = cairo_create(out); + cairo_set_source_rgba(ct, r, g, b, a); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + slot.set(_output, out); - return 0; + cairo_surface_destroy(out); +} + +bool FilterFlood::can_handle_affine(Geom::Matrix const &) +{ + // flood is a per-pixel primitive and is immutable under transformations + return true; } void FilterFlood::set_color(guint32 c) { diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h index 98c374bbd..6f2e5b5d5 100644 --- a/src/display/nr-filter-flood.h +++ b/src/display/nr-filter-flood.h @@ -13,9 +13,8 @@ */ #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" -#include "svg/svg-color.h" + +class SVGICCColor; namespace Inkscape { namespace Filters { @@ -25,11 +24,12 @@ public: FilterFlood(); static FilterPrimitive *create(); virtual ~FilterFlood(); - + + virtual void render_cairo(FilterSlot &slot); + virtual bool can_handle_affine(Geom::Matrix const &); virtual void set_opacity(double o); virtual void set_color(guint32 c); virtual void set_icc(SVGICCColor *icc_color); - virtual int render(FilterSlot &slot, FilterUnits const &units); virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); private: double opacity; diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 1e59748c4..fbaa9eaa5 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -32,6 +32,7 @@ #include "display/nr-filter-gaussian.h" #include "display/nr-filter-types.h" #include "display/nr-filter-units.h" +#include "display/nr-filter-slot.h" #include <2geom/matrix.h> #include "util/fixed_point.h" #include "preferences.h" diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h index 01ce9efcb..ebc0f8f52 100644 --- a/src/display/nr-filter-gaussian.h +++ b/src/display/nr-filter-gaussian.h @@ -14,12 +14,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" -#include "libnr/nr-pixblock.h" #include <2geom/forward.h> -#include "libnr/nr-rect-l.h" +#include "display/nr-filter-primitive.h" enum { BLUR_QUALITY_BEST = 2, diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp index b913e2cd7..406f74c9e 100644 --- a/src/display/nr-filter-merge.cpp +++ b/src/display/nr-filter-merge.cpp @@ -9,28 +9,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include #include - -#include "2geom/isnan.h" -#include "filters/merge.h" +#include "display/cairo-utils.h" #include "display/nr-filter-merge.h" -#include "display/nr-filter-pixops.h" #include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" #include "display/nr-filter-utils.h" -#include "libnr/nr-blit.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-pixops.h" - -inline void -composite_over(unsigned char *r, unsigned char const *a, unsigned char const *b) -{ - r[0] = a[0] + NR_NORMALIZE_21(b[0] * (255 - a[3])); - r[1] = a[1] + NR_NORMALIZE_21(b[1] * (255 - a[3])); - r[2] = a[2] + NR_NORMALIZE_21(b[2] * (255 - a[3])); - r[3] = a[3] + NR_NORMALIZE_21(b[3] * (255 - a[3])); -} namespace Inkscape { namespace Filters { @@ -46,70 +29,42 @@ FilterPrimitive * FilterMerge::create() { FilterMerge::~FilterMerge() {} -int FilterMerge::render(FilterSlot &slot, FilterUnits const &/*units*/) { - NRPixBlock *in[_input_image.size()]; - NRPixBlock *original_in[_input_image.size()]; - - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - in[i] = slot.get(_input_image[i]); - original_in[i] = in[i]; - } - - NRPixBlock *out; - - // Bail out if one of source images is missing - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - bool missing = false; - if (!in[i]) { - g_warning("Missing source image for feMerge (number=%d slot=%d)", i, _input_image[i]); - missing = true; - } - if (missing) return 1; - } - - out = new NRPixBlock; - NRRectL out_area = in[0]->area; - for (unsigned int i = 1 ; i < _input_image.size() ; i++) { - nr_rect_l_union(&out_area, &out_area, &in[i]->area); - } - nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, - out_area.x0, out_area.y0, out_area.x1, out_area.y1, - true); - - // Merge is defined for premultiplied RGBA values, thus convert them to - // that format before blending - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - if (in[i]->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - in[i] = new NRPixBlock; - nr_pixblock_setup_fast(in[i], NR_PIXBLOCK_MODE_R8G8B8A8P, - original_in[i]->area.x0, - original_in[i]->area.y0, - original_in[i]->area.x1, - original_in[i]->area.y1, - false); - nr_blit_pixblock_pixblock(in[i], original_in[i]); +void FilterMerge::render_cairo(FilterSlot &slot) +{ + if (_input_image.size() == 0) return; + + // output is RGBA if at least one input is RGBA + bool rgba32 = false; + cairo_surface_t *out = NULL; + for (std::vector::iterator i = _input_image.begin(); i != _input_image.end(); ++i) { + cairo_surface_t *in = slot.getcairo(*i); + if (cairo_surface_get_content(in) == CAIRO_CONTENT_COLOR_ALPHA) { + out = ink_cairo_surface_create_identical(in); + rgba32 = true; + break; } } - /* pixops_mix is defined in display/nr-filter-pixops.h - * It mixes the two input images with the function given as template - * and places the result in output image. - */ - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - pixops_mix(*out, *in[i], *out); + if (!rgba32) { + out = ink_cairo_surface_create_identical(slot.getcairo(_input_image[0])); } + cairo_t *out_ct = cairo_create(out); - for (unsigned int i = 0 ; i < _input_image.size() ; i++) { - if (in[i] != original_in[i]) { - nr_pixblock_release(in[i]); - delete in[i]; - } + for (std::vector::iterator i = _input_image.begin(); i != _input_image.end(); ++i) { + cairo_surface_t *in = slot.getcairo(*i); + cairo_set_source_surface(out_ct, in, 0, 0); + cairo_paint(out_ct); } - out->empty = FALSE; + cairo_destroy(out_ct); slot.set(_output, out); + cairo_surface_destroy(out); +} - return 0; +bool FilterMerge::can_handle_affine(Geom::Matrix const &) +{ + // Merge is a per-pixel primitive and is immutable under transformations + return true; } void FilterMerge::set_input(int slot) { diff --git a/src/display/nr-filter-merge.h b/src/display/nr-filter-merge.h index b7737e347..a7871641b 100644 --- a/src/display/nr-filter-merge.h +++ b/src/display/nr-filter-merge.h @@ -13,11 +13,7 @@ */ #include - -#include "filters/merge.h" #include "display/nr-filter-primitive.h" -#include "display/nr-filter-slot.h" -#include "display/nr-filter-units.h" namespace Inkscape { namespace Filters { @@ -28,7 +24,8 @@ public: static FilterPrimitive *create(); virtual ~FilterMerge(); - virtual int render(FilterSlot &slot, FilterUnits const &units); + virtual void render_cairo(FilterSlot &); + virtual bool can_handle_affine(Geom::Matrix const &); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index 31e314055..c81afb874 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -12,8 +12,8 @@ */ #include "display/nr-filter-primitive.h" +#include "display/nr-filter-slot.h" #include "display/nr-filter-types.h" -#include "libnr/nr-pixblock.h" #include "svg/svg-length.h" namespace Inkscape { diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h index 89927fdbd..1205b1d30 100644 --- a/src/display/nr-filter-primitive.h +++ b/src/display/nr-filter-primitive.h @@ -1,6 +1,3 @@ -#ifndef __NR_FILTER_PRIMITIVE_H__ -#define __NR_FILTER_PRIMITIVE_H__ - /* * SVG filters rendering * @@ -11,15 +8,20 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SEEN_NR_FILTER_PRIMITIVE_H +#define SEEN_NR_FILTER_PRIMITIVE_H -#include "display/nr-filter-slot.h" -#include "libnr/nr-pixblock.h" -#include "libnr/nr-rect-l.h" +#include <2geom/forward.h> #include "svg/svg-length.h" +struct NRRectL; + namespace Inkscape { namespace Filters { +class FilterSlot; +class FilterUnits; + /* * Different filter effects need different types of inputs. This is what * traits are used for: one can specify, what special restrictions @@ -112,7 +114,7 @@ public: /** @brief Indicate whether the filter primitive can handle the given affine. * * Results of some filter primitives depend on the coordinate system used when rendering. - * A gaussian blur will equal x and y deviation will remain unchanged by rotations. + * A gaussian blur with equal x and y deviation will remain unchanged by rotations. * Per-pixel filters like color matrix and blend will not change regardless of * the transformation. * -- cgit v1.2.3