diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2013-09-26 22:42:32 +0000 |
|---|---|---|
| committer | Krzysztof Kosiński <tweenk.pl@gmail.com> | 2013-09-26 22:42:32 +0000 |
| commit | 81209cb6fe83ccf8cb1244fe63f93361f68cc7c0 (patch) | |
| tree | 8edcd48c973f702e091b1e8bcd1887c0023fdee7 /src | |
| parent | The downscaling fix is already in Cairo trunk. (diff) | |
| download | inkscape-81209cb6fe83ccf8cb1244fe63f93361f68cc7c0.tar.gz inkscape-81209cb6fe83ccf8cb1244fe63f93361f68cc7c0.zip | |
Use Cairo 1.10 blend operators to render feBlend
(bzr r12600)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/nr-filter-blend.cpp | 164 |
1 files changed, 30 insertions, 134 deletions
diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index a08191f67..bff7405b7 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -1,6 +1,6 @@ -/* +/** @file * SVG feBlend renderer - * + *//* * "This filter composites two objects together using commonly used * imaging software blending modes. It performs a pixel-wise combination * of two input images." @@ -9,6 +9,7 @@ * Authors: * Niko Kiirala <niko@kiirala.com> * Jasper van de Gronde <th.v.d.gronde@hccnet.nl> + * Krzysztof Kosiński <tweenk.pl@gmail.com> * * Copyright (C) 2007-2008 authors * @@ -30,20 +31,6 @@ namespace Inkscape { namespace Filters { -/* - * From http://www.w3.org/TR/SVG11/filters.html#feBlend - * - * For all feBlend modes, the result opacity is computed as follows: - * qr = 1 - (1-qa)*(1-qb) - * - * For the compositing formulas below, the following definitions apply: - * cr = Result color (RGB) - premultiplied - * qa = Opacity value at a given pixel for image A - * qb = Opacity value at a given pixel for image B - * ca = Color (RGB) at a given pixel for image A - premultiplied - * cb = Color (RGB) at a given pixel for image B - premultiplied - */ - FilterBlend::FilterBlend() : _blend_mode(BLEND_NORMAL), _input2(NR_FILTER_SLOT_NOT_SET) @@ -56,91 +43,6 @@ FilterPrimitive * FilterBlend::create() { FilterBlend::~FilterBlend() {} -// cr = (1-qa)*cb + (1-qb)*ca + ca*cb -struct BlendMultiply { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = (255-aa)*rb + (255-ab)*ra + ra*rb; ro = (ro + 127) / 255; - guint32 go = (255-aa)*gb + (255-ab)*ga + ga*gb; go = (go + 127) / 255; - guint32 bo = (255-aa)*bb + (255-ab)*ba + ba*bb; bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -// cr = cb + ca - ca * cb -struct BlendScreen { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = 255*(rb + ra) - ra * rb; ro = (ro + 127) / 255; - guint32 go = 255*(gb + ga) - ga * gb; go = (go + 127) / 255; - guint32 bo = 255*(bb + ba) - ba * bb; bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -struct BlendDarken { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = std::min((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255; - guint32 go = std::min((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255; - guint32 bo = std::min((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb) -struct BlendLighten { - guint32 operator()(guint32 in1, guint32 in2) - { - EXTRACT_ARGB32(in1, aa, ra, ga, ba) - EXTRACT_ARGB32(in2, ab, rb, gb, bb) - - guint32 ao = 255*255 - (255-aa)*(255-ab); ao = (ao + 127) / 255; - guint32 ro = std::max((255-aa)*rb + 255*ra, (255-ab)*ra + 255*rb); ro = (ro + 127) / 255; - guint32 go = std::max((255-aa)*gb + 255*ga, (255-ab)*ga + 255*gb); go = (go + 127) / 255; - guint32 bo = std::max((255-aa)*bb + 255*ba, (255-ab)*ba + 255*bb); bo = (bo + 127) / 255; - - ASSEMBLE_ARGB32(pxout, ao, ro, go, bo) - return pxout; - } -}; - -/* -struct BlendAlpha -static inline void blend_alpha(guint32 in1, guint32 in2, guint32 *out) -{ - EXTRACT_ARGB32(in1, a1, a2, a3, a4); - EXTRACT_ARGB32(in2, b1, b2, b3, b4); - - guint32 o1 = 255*255 - (255-a1)*(255-b1); o1 = (o1+127) / 255; - guint32 o2 = 255*255 - (255-a2)*(255-b2); o2 = (o2+127) / 255; - guint32 o3 = 255*255 - (255-a3)*(255-b3); o3 = (o3+127) / 255; - guint32 o4 = 255*255 - (255-a4)*(255-b4); o4 = (o4+127) / 255; - - ASSEMBLE_ARGB32(pxout, o1, o2, o3, o4); - *out = pxout; -} -*/ - void FilterBlend::render_cairo(FilterSlot &slot) { cairo_surface_t *input1 = slot.getcairo(_input); @@ -161,41 +63,35 @@ void FilterBlend::render_cairo(FilterSlot &slot) cairo_surface_t *out = ink_cairo_surface_create_output(input1, input2); set_cairo_surface_ci( out, ci_fp ); - cairo_content_t ct1 = cairo_surface_get_content(input1); - cairo_content_t ct2 = cairo_surface_get_content(input2); - if ((ct1 == CAIRO_CONTENT_ALPHA && ct2 == CAIRO_CONTENT_ALPHA) - || _blend_mode == BLEND_NORMAL) - { - ink_cairo_surface_blit(input2, out); - cairo_t *out_ct = cairo_create(out); - cairo_set_source_surface(out_ct, input1, 0, 0); - cairo_paint(out_ct); - cairo_destroy(out_ct); - } else { - // blend mode != normal and at least 1 surface is not pure alpha - - // TODO: convert to Cairo blending operators once we start using the 1.10 series - switch (_blend_mode) { - case BLEND_MULTIPLY: - ink_cairo_surface_blend(input1, input2, out, BlendMultiply()); - break; - case BLEND_SCREEN: - ink_cairo_surface_blend(input1, input2, out, BlendScreen()); - break; - case BLEND_DARKEN: - ink_cairo_surface_blend(input1, input2, out, BlendDarken()); - break; - case BLEND_LIGHTEN: - ink_cairo_surface_blend(input1, input2, out, BlendLighten()); - break; - case BLEND_NORMAL: - default: - // this was handled before - g_assert_not_reached(); - break; - } + ink_cairo_surface_blit(input2, out); + cairo_t *out_ct = cairo_create(out); + cairo_set_source_surface(out_ct, input1, 0, 0); + + // All of the blend modes are implemented in Cairo as of 1.10. + // For a detailed description, see: + // http://cairographics.org/operators/ + switch (_blend_mode) { + case BLEND_MULTIPLY: + cairo_set_operator(out_ct, CAIRO_OPERATOR_MULTIPLY); + break; + case BLEND_SCREEN: + cairo_set_operator(out_ct, CAIRO_OPERATOR_SCREEN); + break; + case BLEND_DARKEN: + cairo_set_operator(out_ct, CAIRO_OPERATOR_DARKEN); + break; + case BLEND_LIGHTEN: + cairo_set_operator(out_ct, CAIRO_OPERATOR_LIGHTEN); + break; + case BLEND_NORMAL: + default: + cairo_set_operator(out_ct, CAIRO_OPERATOR_OVER); + break; } + cairo_paint(out_ct); + cairo_destroy(out_ct); + slot.set(_output, out); cairo_surface_destroy(out); } |
