summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-07-17 23:31:07 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2010-07-17 23:31:07 +0000
commit73150a4a03282c19b4b04bd2e3b5ff02fb15952e (patch)
tree034937d8a365f03d65ce995c5792f0627185c828 /src
parentColor matrix filter. Fix arithmetic operator in feComposite (diff)
downloadinkscape-73150a4a03282c19b4b04bd2e3b5ff02fb15952e.tar.gz
inkscape-73150a4a03282c19b4b04bd2e3b5ff02fb15952e.zip
Component transfer filter
(bzr r9508.1.24)
Diffstat (limited to 'src')
-rw-r--r--src/display/cairo-templates.h1
-rw-r--r--src/display/cairo-utils.cpp7
-rw-r--r--src/display/cairo-utils.h6
-rw-r--r--src/display/nr-filter-colormatrix.cpp176
-rw-r--r--src/display/nr-filter-colormatrix.h7
-rw-r--r--src/display/nr-filter-component-transfer.cpp426
-rw-r--r--src/display/nr-filter-component-transfer.h9
7 files changed, 283 insertions, 349 deletions
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h
index c64ad78c1..efbd9c094 100644
--- a/src/display/cairo-templates.h
+++ b/src/display/cairo-templates.h
@@ -265,6 +265,7 @@ void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter
}
}
}
+ cairo_surface_mark_dirty(out);
}
// Some helpers for pixel manipulation
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index c46caa7be..a05d28170 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -448,13 +448,6 @@ ink_cairo_surface_get_height(cairo_surface_t *surface)
return cairo_image_surface_get_height(surface);
}
-// taken from Cairo sources
-static inline guint32 premul_alpha(guint32 color, guint32 alpha)
-{
- guint32 temp = alpha * color + 128;
- return (temp + (temp >> 8)) >> 8;
-}
-
/**
* @brief Convert pixel data from GdkPixbuf format to ARGB.
* This will convert pixel data from GdkPixbuf format to Cairo's native pixel format.
diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h
index 1406636d0..02bfe0f73 100644
--- a/src/display/cairo-utils.h
+++ b/src/display/cairo-utils.h
@@ -98,6 +98,12 @@ void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs);
void convert_pixbuf_normal_to_argb32(GdkPixbuf *);
void convert_pixbuf_argb32_to_normal(GdkPixbuf *);
+inline guint32 premul_alpha(guint32 color, guint32 alpha)
+{
+ guint32 temp = alpha * color + 128;
+ return (temp + (temp >> 8)) >> 8;
+}
+
// TODO: move those to 2Geom
void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Matrix trans, Geom::OptRect area, bool optimize_stroke, double stroke_width);
void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv);
diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp
index d0926ebcc..94459e3aa 100644
--- a/src/display/nr-filter-colormatrix.cpp
+++ b/src/display/nr-filter-colormatrix.cpp
@@ -15,8 +15,7 @@
#include "display/cairo-templates.h"
#include "display/cairo-utils.h"
#include "display/nr-filter-colormatrix.h"
-#include "display/nr-filter-units.h"
-#include "display/nr-filter-utils.h"
+#include "display/nr-filter-slot.h"
namespace Inkscape {
namespace Filters {
@@ -32,173 +31,6 @@ FilterPrimitive * FilterColorMatrix::create() {
FilterColorMatrix::~FilterColorMatrix()
{}
-#if 0
-int FilterColorMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) {
- NRPixBlock *in = slot.get(_input);
- if (!in) {
- g_warning("Missing source image for feColorMatrix (in=%d)", _input);
- return 1;
- }
-
- NRPixBlock *out = new NRPixBlock;
- if ((type==COLORMATRIX_SATURATE || type==COLORMATRIX_HUEROTATE) && in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N) {
- // saturate and hueRotate do not touch the alpha channel and are linear (per-pixel) operations, so no premultiplied -> non-premultiplied operation is necessary
- nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P,
- in->area.x0, in->area.y0, in->area.x1, in->area.y1,
- true);
- } else {
- nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N,
- in->area.x0, in->area.y0, in->area.x1, in->area.y1,
- true);
- }
-
- // this primitive is defined for non-premultiplied RGBA values,
- // thus convert them to that format
- // However, since not all operations care, the input is only transformed if necessary.
- bool free_in_on_exit = false;
- if (in->mode != out->mode) {
- NRPixBlock *original_in = in;
- in = new NRPixBlock;
- nr_pixblock_setup_fast(in, out->mode,
- original_in->area.x0, original_in->area.y0,
- original_in->area.x1, original_in->area.y1,
- true);
- nr_blit_pixblock_pixblock(in, original_in);
- free_in_on_exit = true;
- }
-
- unsigned char *in_data = NR_PIXBLOCK_PX(in);
- unsigned char *out_data = NR_PIXBLOCK_PX(out);
- unsigned char r,g,b,a;
- int x,y,x0,y0,x1,y1,i;
- x0=in->area.x0;
- y0=in->area.y0;
- x1=in->area.x1;
- y1=in->area.y1;
-
- switch(type){
- case COLORMATRIX_MATRIX:
- {
- if (values.size()!=20) {
- g_warning("ColorMatrix: values parameter error. Wrong size: %i.", static_cast<int>(values.size()));
- return -1;
- }
- double a04 = 255*values[4];
- double a14 = 255*values[9];
- double a24 = 255*values[14];
- double a34 = 255*values[19];
- for (x=x0;x<x1;x++){
- for (y=y0;y<y1;y++){
- i = ((x-x0) + (x1-x0)*(y-y0))*4;
- r = in_data[i];
- g = in_data[i+1];
- b = in_data[i+2];
- a = in_data[i+3];
- out_data[i] = CLAMP_D_TO_U8( r*values[0] + g*values[1] + b*values[2] + a*values[3] + a04 ); // CLAMP includes rounding!
- out_data[i+1] = CLAMP_D_TO_U8( r*values[5] + g*values[6] + b*values[7] + a*values[8] + a14 );
- out_data[i+2] = CLAMP_D_TO_U8( r*values[10] + g*values[11] + b*values[12] + a*values[13] + a24 );
- out_data[i+3] = CLAMP_D_TO_U8( r*values[15] + g*values[16] + b*values[17] + a*values[18] + a34 );
- }
- }
- }
- break;
- case COLORMATRIX_SATURATE:
- {
- double v = std::max(0.0,std::min(1.0,value)); // The standard says it should be between 0 and 1, and clamping it here makes it unnecessary to clamp the color values.
- double a00 = 0.213+0.787*v, a01 = 0.715-0.715*v, a02 = 0.072-0.072*v;
- double a10 = 0.213-0.213*v, a11 = 0.715+0.285*v, a12 = 0.072-0.072*v;
- double a20 = 0.213-0.213*v, a21 = 0.715-0.715*v, a22 = 0.072+0.928*v;
- for (x=x0;x<x1;x++){
- for (y=y0;y<y1;y++){
- i = ((x-x0) + (x1-x0)*(y-y0))*4;
- r = in_data[i];
- g = in_data[i+1];
- b = in_data[i+2];
- a = in_data[i+3];
- out_data[i] = static_cast<unsigned char>( r*a00 + g*a01 + b*a02 + .5 );
- out_data[i+1] = static_cast<unsigned char>( r*a10 + g*a11 + b*a12 + .5 );
- out_data[i+2] = static_cast<unsigned char>( r*a20 + g*a21 + b*a22 + .5 );
- out_data[i+3] = a;
- }
- }
- }
- break;
- case COLORMATRIX_HUEROTATE:
- {
- double coshue = cos(value * M_PI/180.0);
- double sinhue = sin(value * M_PI/180.0);
- double a00 = 0.213 + coshue*( 0.787) + sinhue*(-0.213);
- double a01 = 0.715 + coshue*(-0.715) + sinhue*(-0.715);
- double a02 = 0.072 + coshue*(-0.072) + sinhue*( 0.928);
- double a10 = 0.213 + coshue*(-0.213) + sinhue*( 0.143);
- double a11 = 0.715 + coshue*( 0.285) + sinhue*( 0.140);
- double a12 = 0.072 + coshue*(-0.072) + sinhue*(-0.283);
- double a20 = 0.213 + coshue*(-0.213) + sinhue*(-0.787);
- double a21 = 0.715 + coshue*(-0.715) + sinhue*( 0.715);
- double a22 = 0.072 + coshue*( 0.928) + sinhue*( 0.072);
- if (in->mode==NR_PIXBLOCK_MODE_R8G8B8A8P) {
- // Although it does not change the alpha channel, it can give "out-of-bound" results, and in this case the bound is determined by the alpha channel
- for (x=x0;x<x1;x++){
- for (y=y0;y<y1;y++){
- i = ((x-x0) + (x1-x0)*(y-y0))*4;
- r = in_data[i];
- g = in_data[i+1];
- b = in_data[i+2];
- a = in_data[i+3];
-
- out_data[i] = static_cast<unsigned char>(std::max(0.0,std::min((double)a, r*a00 + g*a01 + b*a02 + .5 )));
- out_data[i+1] = static_cast<unsigned char>(std::max(0.0,std::min((double)a, r*a10 + g*a11 + b*a12 + .5 )));
- out_data[i+2] = static_cast<unsigned char>(std::max(0.0,std::min((double)a, r*a20 + g*a21 + b*a22 + .5 )));
- out_data[i+3] = a;
- }
- }
- } else {
- for (x=x0;x<x1;x++){
- for (y=y0;y<y1;y++){
- i = ((x-x0) + (x1-x0)*(y-y0))*4;
- r = in_data[i];
- g = in_data[i+1];
- b = in_data[i+2];
- a = in_data[i+3];
-
- out_data[i] = CLAMP_D_TO_U8( r*a00 + g*a01 + b*a02);
- out_data[i+1] = CLAMP_D_TO_U8( r*a10 + g*a11 + b*a12);
- out_data[i+2] = CLAMP_D_TO_U8( r*a20 + g*a21 + b*a22);
- out_data[i+3] = a;
- }
- }
- }
- }
- break;
- case COLORMATRIX_LUMINANCETOALPHA:
- for (x=x0;x<x1;x++){
- for (y=y0;y<y1;y++){
- i = ((x-x0) + (x1-x0)*(y-y0))*4;
- r = in_data[i];
- g = in_data[i+1];
- b = in_data[i+2];
- out_data[i] = 0;
- out_data[i+1] = 0;
- out_data[i+2] = 0;
- out_data[i+3] = static_cast<unsigned char>( r*0.2125 + g*0.7154 + b*0.0721 + .5 );
- }
- }
- break;
- case COLORMATRIX_ENDTYPE:
- break;
- }
-
- if (free_in_on_exit) {
- nr_pixblock_release(in);
- delete in;
- }
-
- out->empty = FALSE;
- slot.set(_output, out);
- return 0;
-}
-#endif
-
struct ColorMatrixMatrix {
ColorMatrixMatrix(std::vector<double> const &values) {
unsigned limit = std::min(20ul, values.size());
@@ -214,12 +46,6 @@ struct ColorMatrixMatrix {
}
}
- static inline guint32 premul_alpha(guint32 color, guint32 alpha)
- {
- guint32 temp = alpha * color + 128;
- return (temp + (temp >> 8)) >> 8;
- }
-
guint32 operator()(guint32 in) {
EXTRACT_ARGB32(in, a, r, g, b)
// we need to un-premultiply alpha values for this type of matrix
diff --git a/src/display/nr-filter-colormatrix.h b/src/display/nr-filter-colormatrix.h
index e3beb943d..c95c84568 100644
--- a/src/display/nr-filter-colormatrix.h
+++ b/src/display/nr-filter-colormatrix.h
@@ -12,14 +12,15 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <vector>
+#include <2geom/forward.h>
#include "display/nr-filter-primitive.h"
-#include "display/nr-filter-slot.h"
-#include "display/nr-filter-units.h"
-#include<vector>
namespace Inkscape {
namespace Filters {
+class FilterSlot;
+
enum FilterColorMatrixType {
COLORMATRIX_MATRIX,
COLORMATRIX_SATURATE,
diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp
index ab9990360..05795d670 100644
--- a/src/display/nr-filter-component-transfer.cpp
+++ b/src/display/nr-filter-component-transfer.cpp
@@ -10,13 +10,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "display/nr-filter-component-transfer.h"
-#include "display/nr-filter-units.h"
-#include "display/nr-filter-utils.h"
-#include "libnr/nr-pixblock.h"
-#include "libnr/nr-blit.h"
-#include "libnr/nr-pixops.h"
#include <math.h>
+#include "display/cairo-templates.h"
+#include "display/cairo-utils.h"
+#include "display/nr-filter-component-transfer.h"
+#include "display/nr-filter-slot.h"
namespace Inkscape {
namespace Filters {
@@ -32,170 +30,278 @@ FilterPrimitive * FilterComponentTransfer::create() {
FilterComponentTransfer::~FilterComponentTransfer()
{}
-int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units*/) {
- NRPixBlock *in = slot.get(_input);
+struct ComponentTransfer {
+ ComponentTransfer(guint32 color)
+ : _shift(color * 8)
+ , _mask(0xff << _shift)
+ {}
+protected:
+ guint32 _shift;
+ guint32 _mask;
+};
+
+template <bool alpha>
+struct ComponentTransferTable;
+
+template <>
+struct ComponentTransferTable<false> : public ComponentTransfer {
+ ComponentTransferTable(guint32 color, std::vector<double> const &values)
+ : ComponentTransfer(color)
+ , _v(values.size())
+ {
+ for (unsigned i = 0; i< values.size(); ++i) {
+ _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255);
+ }
+ }
+ guint32 operator()(guint32 in) {
+ guint32 component = (in & _mask) >> _shift;
+ guint32 alpha = (in & 0xff000000) >> 24;
+ if (alpha == 0) return in;
+
+ component = (255 * component + alpha/2) / alpha;
+ guint32 k = (_v.size() - 1) * component;
+ guint32 dx = k % 255; k /= 255;
+ component = _v[k]*255 + (_v[k+1] - _v[k])*dx;
+ component = (component + 127) / 255;
+ component = premul_alpha(component, alpha);
+ return (in & ~_mask) | (component << _shift);
+ }
+private:
+ std::vector<guint32> _v;
+};
+
+template <>
+struct ComponentTransferTable<true> {
+ ComponentTransferTable(std::vector<double> const &values)
+ : _v(values.size())
+ {
+ for (unsigned i = 0; i< values.size(); ++i) {
+ _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255);
+ }
+ }
+ guint32 operator()(guint32 in) {
+ guint32 alpha = (in & 0xff000000) >> 24;
+ if (alpha == 0) return in;
+
+ guint32 k = (_v.size() - 1) * alpha;
+ guint32 dx = k % 255; k /= 255;
+ alpha = _v[k]*255 + (_v[k+1] - _v[k])*dx;
+ alpha = (alpha + 127) / 255;
+ return (in & 0x00ffffff) | (alpha << 24);
+ }
+private:
+ std::vector<guint32> _v;
+};
+
+template <bool alpha>
+struct ComponentTransferDiscrete;
+
+template <>
+struct ComponentTransferDiscrete<false> : public ComponentTransfer {
+ ComponentTransferDiscrete(guint32 color, std::vector<double> const &values)
+ : ComponentTransfer(color)
+ , _v(values.size())
+ {
+ for (unsigned i = 0; i< values.size(); ++i) {
+ _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255);
+ }
+ }
+ guint32 operator()(guint32 in) {
+ guint32 component = (in & _mask) >> _shift;
+ guint32 alpha = (in & 0xff000000) >> 24;
+ if (alpha == 0) return in;
+
+ component = (255 * component + alpha/2) / alpha;
+ guint32 k = (_v.size() - 1) * component / 255;
+ component = _v[k];
+ component = premul_alpha(component, alpha);
+ return (in & ~_mask) | (component << _shift);
+ }
+private:
+ std::vector<guint32> _v;
+};
+
+template <>
+struct ComponentTransferDiscrete<true> {
+ ComponentTransferDiscrete(std::vector<double> const &values)
+ : _v(values.size())
+ {
+ for (unsigned i = 0; i< values.size(); ++i) {
+ _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255);
+ }
+ }
+ guint32 operator()(guint32 in) {
+ guint32 alpha = (in & 0xff000000) >> 24;
+ if (alpha == 0) return in;
+
+ guint32 k = (_v.size() - 1) * alpha / 255;
+ alpha = _v[k];
+ return (in & 0x00ffffff) | (alpha << 24);
+ }
+private:
+ std::vector<guint32> _v;
+};
+
+template <bool alpha>
+struct ComponentTransferLinear;
+
+template <>
+struct ComponentTransferLinear<false> : public ComponentTransfer {
+ ComponentTransferLinear(guint32 color, double intercept, double slope)
+ : ComponentTransfer(color)
+ , _intercept(round(intercept*255*255))
+ , _slope(round(slope*255))
+ {}
+ guint32 operator()(guint32 in) {
+ gint32 component = (in & _mask) >> _shift;
+ guint32 alpha = (in & 0xff000000) >> 24;
+ if (alpha == 0) return 0;
- if (!in) {
- g_warning("Missing source image for feComponentTransfer (in=%d)", _input);
- return 1;
+ // TODO: this can probably be reduced to something simpler
+ component = (255 * component + alpha/2) / alpha;
+ component = pxclamp(_slope * component + _intercept, 0, 255*255);
+ component = (component + 127) / 255;
+ component = premul_alpha(component, alpha);
+ return (in & ~_mask) | (component << _shift);
}
+private:
+ gint32 _intercept;
+ gint32 _slope;
+};
- int x0=in->area.x0;
- int x1=in->area.x1;
- int y0=in->area.y0;
- int y1=in->area.y1;
-
- // this primitive is defined for RGBA values,
- // thus convert them to that format before blending
- bool free_in_on_exit = false;
- if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && in->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
- NRPixBlock *original_in = in;
- in = new NRPixBlock;
- nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8N,
- original_in->area.x0, original_in->area.y0,
- original_in->area.x1, original_in->area.y1,
- false);
- nr_blit_pixblock_pixblock(in, original_in);
- free_in_on_exit = true;
+template <>
+struct ComponentTransferLinear<true> {
+ ComponentTransferLinear(double intercept, double slope)
+ : _intercept(round(intercept*255*255))
+ , _slope(round(slope*255))
+ {}
+ guint32 operator()(guint32 in) {
+ gint32 alpha = (in & 0xff000000) >> 24;
+ alpha = pxclamp(_slope * alpha + _intercept, 0, 255*255);
+ alpha = (alpha + 127) / 255;
+ return (in & 0x00ffffff) | (alpha << 24);
}
- bool premultiplied = in->mode == NR_PIXBLOCK_MODE_R8G8B8A8P;
-
- NRPixBlock *out = new NRPixBlock;
- nr_pixblock_setup_fast(out, in->mode, x0, y0, x1, y1, true);
-
- unsigned char *in_data = NR_PIXBLOCK_PX(in);
- unsigned char *out_data = NR_PIXBLOCK_PX(out);
-
- (void)in_data;
- (void)out_data;
-
- int size = 4 * (y1-y0) * (x1-x0);
- int i;
-
- int color=4;
- while(color-->0) {
- int _vsize = tableValues[color].size();
- double _intercept = intercept[color];
- double _slope = slope[color];
- double _amplitude = amplitude[color];
- double _exponent = exponent[color];
- double _offset = offset[color];
- switch(type[color]){
- case COMPONENTTRANSFER_TYPE_IDENTITY:
- for(i=color;i<size;i+=4){
- out_data[i]=in_data[i];
- }
- break;
- case COMPONENTTRANSFER_TYPE_TABLE:
- if (_vsize<=1){
- if (_vsize==1) {
- g_warning("A component transfer table has to have at least two values.");
- }
- for(i=color;i<size;i+=4){
- out_data[i]=in_data[i];
- }
- } else {
- if (!premultiplied || color==3) {
- std::vector<gdouble> _tableValues(tableValues[color]);
- // Scale by 255 and add .5 to avoid having to add it later for rounding purposes
- // Note that this means that CLAMP_D_TO_U8 cannot be used here (as it includes rounding!)
- for(i=0;i<_vsize;i++) {
- _tableValues[i] = std::max(0.,std::min(255.,255*_tableValues[i])) + .5;
- }
- for(i=color;i<size;i+=4){
- int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
- double dx = ((_vsize-1) * in_data[i])/255.0 - k;
- out_data[i] = static_cast<unsigned char>(_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k]));
- }
- } else {
- std::vector<gdouble> _tableValues(tableValues[color]);
- for(i=0;i<_vsize;i++) {
- _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i]));
- }
- for(i=color;i<size;i+=4){
- if (in_data[i+3-color]==0) continue;
- int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color];
- double dx = ((_vsize-1) * in_data[i]) / (double)in_data[i+3-color] - k;
- out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * (_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k])), out_data[i+3-color]); // CLAMP includes rounding!
- }
- }
- }
- break;
- case COMPONENTTRANSFER_TYPE_DISCRETE:
- if (_vsize==0){
- for(i=color;i<size;i+=4){
- out_data[i] = in_data[i];
- }
- } else {
- if (!premultiplied || color==3) {
- std::vector<unsigned char> _tableValues(_vsize);
- // Convert to unsigned char
- for(i=0;i<_vsize;i++) {
- _tableValues[i] = CLAMP_D_TO_U8(255*tableValues[color][i]);
- }
- for(i=color;i<size;i+=4){
- int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
- out_data[i] = _tableValues[k];
- }
- } else {
- std::vector<gdouble> _tableValues(tableValues[color]);
- for(i=0;i<_vsize;i++) {
- _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i]));
- }
- for(i=color;i<size;i+=4){
- if (in_data[i+3-color]==0) continue;
- int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color];
- out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * _tableValues[k], out_data[i+3-color]);
- }
- }
- }
- break;
- case COMPONENTTRANSFER_TYPE_LINEAR:
- if (!premultiplied || color==3) {
- _intercept = 255*_intercept;
- for(i=color;i<size;i+=4){
- out_data[i] = CLAMP_D_TO_U8(_slope * in_data[i] + _intercept); // CLAMP includes rounding!
- }
- } else {
- for(i=color;i<size;i+=4){
- if (in_data[i+3-color]==0) continue;
- double out = _slope * in_data[i] / in_data[i+3-color] + _intercept;
- out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * out, out_data[i+3-color]);
- }
- }
- break;
- case COMPONENTTRANSFER_TYPE_GAMMA:
- if (!premultiplied || color==3) {
- _amplitude *= pow(255.0, -_exponent+1); // The input should be divided by 255, then exponentiated and then multiplied by 255 again, instead the amplitude is modified accordingly.
- _offset = 255*_offset;
- for(i=color;i<size;i+=4){
- out_data[i] = CLAMP_D_TO_U8(_amplitude * pow((double)in_data[i], _exponent) + _offset);
- }
- } else {
- for(i=color;i<size;i+=4){
- if (in_data[i+3-color]==0) continue;
- double out = _amplitude * pow((double)in_data[i] / in_data[i+3-color], _exponent) + _offset;
- out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * out, out_data[i+3-color]);
- }
- }
- break;
- case COMPONENTTRANSFER_TYPE_ERROR:
- //TODO: report an error here
- g_warning("Component tranfer type \"error\".");
- break;
- default:
- g_warning("Invalid tranfer type %d.", type[color]);
+private:
+ gint32 _intercept;
+ gint32 _slope;
+};
+
+template <bool alpha>
+struct ComponentTransferGamma;
+
+template <>
+struct ComponentTransferGamma<false> : public ComponentTransfer {
+ ComponentTransferGamma(guint32 color, double amplitude, double exponent, double offset)
+ : ComponentTransfer(color)
+ , _amplitude(amplitude)
+ , _exponent(exponent)
+ , _offset(offset)
+ {}
+ guint32 operator()(guint32 in) {
+ double component = (in & _mask) >> _shift;
+ guint32 alpha = (in & 0xff000000) >> 24;
+ if (alpha == 0) return 0;
+
+ double alphaf = alpha;
+ component /= alphaf;
+ component = _amplitude * pow(component, _exponent) + _offset;
+ guint32 cpx = pxclamp(component * alphaf, 0, 255);
+ return (in & ~_mask) | (cpx << _shift);
+ }
+private:
+ double _amplitude;
+ double _exponent;
+ double _offset;
+};
+
+template <>
+struct ComponentTransferGamma<true> {
+ ComponentTransferGamma(double amplitude, double exponent, double offset)
+ : _amplitude(amplitude)
+ , _exponent(exponent)
+ , _offset(offset)
+ {}
+ guint32 operator()(guint32 in) {
+ double alpha = (in & 0xff000000) >> 24;
+ alpha /= 255.0;
+ alpha = _amplitude * pow(alpha, _exponent) + _offset;
+ guint32 cpx = pxclamp(alpha * 255.0, 0, 255);
+ return (in & 0x00ffffff) | (cpx << 24);
+ }
+private:
+ double _amplitude;
+ double _exponent;
+ double _offset;
+};
+
+void FilterComponentTransfer::render_cairo(FilterSlot &slot)
+{
+ cairo_surface_t *input = slot.getcairo(_input);
+ cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA);
+ //cairo_surface_t *outtemp = ink_cairo_surface_create_identical(out);
+ ink_cairo_surface_blit(input, out);
+
+ // parameters: R = 0, G = 1, B = 2, A = 3
+ // Cairo: R = 2, G = 1, B = 0, A = 3
+ for (unsigned i = 0; i < 3; ++i) {
+ guint32 color = 2 - i;
+ switch (type[i]) {
+ case COMPONENTTRANSFER_TYPE_TABLE:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferTable<false>(color, tableValues[i]));
+ break;
+ case COMPONENTTRANSFER_TYPE_DISCRETE:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferDiscrete<false>(color, tableValues[i]));
+ break;
+ case COMPONENTTRANSFER_TYPE_LINEAR:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferLinear<false>(color, intercept[i], slope[i]));
+ break;
+ case COMPONENTTRANSFER_TYPE_GAMMA:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferGamma<false>(color, amplitude[i], exponent[i], offset[i]));
+ break;
+ case COMPONENTTRANSFER_TYPE_ERROR:
+ case COMPONENTTRANSFER_TYPE_IDENTITY:
+ default:
+ break;
}
+ //ink_cairo_surface_blit(out, outtemp);
}
- if (free_in_on_exit) {
- nr_pixblock_release(in);
- delete in;
+ // fast paths for alpha channel
+ switch (type[3]) {
+ case COMPONENTTRANSFER_TYPE_TABLE:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferTable<true>(tableValues[3]));
+ break;
+ case COMPONENTTRANSFER_TYPE_DISCRETE:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferDiscrete<true>(tableValues[3]));
+ break;
+ case COMPONENTTRANSFER_TYPE_LINEAR:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferLinear<true>(intercept[3], slope[3]));
+ break;
+ case COMPONENTTRANSFER_TYPE_GAMMA:
+ ink_cairo_surface_filter(out, out,
+ ComponentTransferGamma<true>(amplitude[3], exponent[3], offset[3]));
+ break;
+ case COMPONENTTRANSFER_TYPE_ERROR:
+ case COMPONENTTRANSFER_TYPE_IDENTITY:
+ default:
+ break;
}
- out->empty = FALSE;
slot.set(_output, out);
- return 0;
+ cairo_surface_destroy(out);
+ //cairo_surface_destroy(outtemp);
+}
+
+bool FilterComponentTransfer::can_handle_affine(Geom::Matrix const &)
+{
+ return true;
}
void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/)
diff --git a/src/display/nr-filter-component-transfer.h b/src/display/nr-filter-component-transfer.h
index eb76bd543..1e69deb15 100644
--- a/src/display/nr-filter-component-transfer.h
+++ b/src/display/nr-filter-component-transfer.h
@@ -12,14 +12,14 @@
* 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 <vector>
+#include "display/nr-filter-primitive.h"
namespace Inkscape {
namespace Filters {
+class FilterSlot;
+
enum FilterComponentTransferType {
COMPONENTTRANSFER_TYPE_IDENTITY,
COMPONENTTRANSFER_TYPE_TABLE,
@@ -35,7 +35,8 @@ public:
static FilterPrimitive *create();
virtual ~FilterComponentTransfer();
- virtual int render(FilterSlot &slot, FilterUnits const &units);
+ virtual void render_cairo(FilterSlot &slot);
+ virtual bool can_handle_affine(Geom::Matrix const &);
virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans);
FilterComponentTransferType type[4];