summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJasper van de Gronde <jasper.vandegronde@gmail.com>2009-04-08 12:03:17 +0000
committerjaspervdg <jaspervdg@users.sourceforge.net>2009-04-08 12:03:17 +0000
commitf9b48a2902266bee5c387088edbbf2b62844a2b6 (patch)
tree30dc8eba2b30980f25641b05f3482b12d9d88f03 /src
parentSwap iterations over x and y coordinate to be more cache friendly (so the inn... (diff)
downloadinkscape-f9b48a2902266bee5c387088edbbf2b62844a2b6.tar.gz
inkscape-f9b48a2902266bee5c387088edbbf2b62844a2b6.zip
Fix feConvolveMatrix to use premultiplied color values (and semi-properly use bias).
(bzr r7666)
Diffstat (limited to 'src')
-rw-r--r--src/display/nr-filter-convolve-matrix.cpp84
1 files changed, 59 insertions, 25 deletions
diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp
index fc279df4c..47978edd6 100644
--- a/src/display/nr-filter-convolve-matrix.cpp
+++ b/src/display/nr-filter-convolve-matrix.cpp
@@ -27,14 +27,6 @@ FilterPrimitive * FilterConvolveMatrix::create() {
FilterConvolveMatrix::~FilterConvolveMatrix()
{}
-static bool inside_area(int px, int py, int w, int h){
- if (px<0) return false;
- if (py<0) return false;
- if (px>w) return false;
- if (py>h) return false;
- return true;
-}
-
int FilterConvolveMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) {
NRPixBlock *in = slot.get(_input);
if (!in) {
@@ -42,6 +34,15 @@ int FilterConvolveMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/)
return 1;
}
+ if (bias!=0) {
+ g_warning("It is unknown whether Inkscape's implementation of bias in feConvolveMatrix is correct!");
+ // The SVG specification implies that feConvolveMatrix is defined for premultiplied colors (which makes sense).
+ // It also says that bias should simply be added to the result for each color (without taking the alpha into account)
+ // However, it also says that one purpose of bias is "to have .5 gray value be the zero response of the filter".
+ // It seems sensible to indeed support the latter behaviour instead of the former, but this does appear to go against the standard.
+ // Note that Batik simply does not support bias!=0
+ }
+
NRPixBlock *out = new NRPixBlock;
nr_pixblock_setup_fast(out, in->mode,
@@ -59,15 +60,15 @@ int FilterConvolveMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/)
unsigned int index;
unsigned int kernel_index;
- for (x=targetX; x < width - (orderX - targetX); x++){
+ if (in->mode==NR_PIXBLOCK_MODE_R8G8B8A8P) {
for (y=targetY; y < height - (orderY - targetY); y++){
- result_R = 0;
- result_G = 0;
- result_B = 0;
- result_A = 0;
- for (i=0; i < orderY; i++){
- for (j=0; j < orderX; j++){
- if (inside_area(x - targetX + j, y - targetY + i, width, height)){
+ for (x=targetX; x < width - (orderX - targetX); x++){
+ result_R = 0;
+ result_G = 0;
+ result_B = 0;
+ result_A = 0;
+ for (i=0; i < orderY; i++){
+ for (j=0; j < orderX; j++){
index = 4*( x - targetX + j + width*(y - targetY + i) );
kernel_index = orderX-j-1 + orderX*(orderY-i-1);
result_R += ( (double) in_data[index++] * kernelMatrix[kernel_index] );
@@ -76,16 +77,49 @@ int FilterConvolveMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/)
result_A += ( (double) in_data[index] * kernelMatrix[kernel_index] );
}
}
+ unsigned int out_index = 4*( x + width*y );
+ if( preserveAlpha ) {
+ out_data[out_index+3] = in_data[out_index+3];
+ } else {
+ out_data[out_index+3] = CLAMP_D_TO_U8(result_A / divisor + 255*bias);
+ }
+ out_data[out_index+0] = CLAMP_D_TO_U8_ALPHA(result_R / divisor + out_data[out_index+3]*bias, out_data[out_index+3]); // CLAMP includes rounding!
+ out_data[out_index+1] = CLAMP_D_TO_U8_ALPHA(result_G / divisor + out_data[out_index+3]*bias, out_data[out_index+3]);
+ out_data[out_index+2] = CLAMP_D_TO_U8_ALPHA(result_B / divisor + out_data[out_index+3]*bias, out_data[out_index+3]);
}
- unsigned int out_index = 4*( x + width*y );
- out_data[out_index++] = CLAMP_D_TO_U8(result_R / divisor + bias); // CLAMP includes rounding!
- out_data[out_index++] = CLAMP_D_TO_U8(result_G / divisor + bias);
- out_data[out_index++] = CLAMP_D_TO_U8(result_B / divisor + bias);
-
- if( preserveAlpha ) {
- out_data[out_index] = in_data[out_index];
- } else {
- out_data[out_index] = CLAMP_D_TO_U8(result_A / divisor + bias);
+ }
+ } else {
+ for (y=targetY; y < height - (orderY - targetY); y++){
+ for (x=targetX; x < width - (orderX - targetX); x++){
+ result_R = 0;
+ result_G = 0;
+ result_B = 0;
+ result_A = 0;
+ for (i=0; i < orderY; i++){
+ for (j=0; j < orderX; j++){
+ index = 4*( x - targetX + j + width*(y - targetY + i) );
+ kernel_index = orderX-j-1 + orderX*(orderY-i-1);
+ result_R += ( (double) in_data[index+0] * in_data[index+3] * kernelMatrix[kernel_index] );
+ result_G += ( (double) in_data[index+1] * in_data[index+3] * kernelMatrix[kernel_index] );
+ result_B += ( (double) in_data[index+2] * in_data[index+3] * kernelMatrix[kernel_index] );
+ result_A += ( (double) in_data[index+3] * kernelMatrix[kernel_index] );
+ }
+ }
+ unsigned int out_index = 4*( x + width*y );
+ if( preserveAlpha ) {
+ out_data[out_index+3] = in_data[out_index+3];
+ } else {
+ out_data[out_index+3] = CLAMP_D_TO_U8(result_A / divisor + 255*bias);
+ }
+ if (out_data[out_index+3]==0) {
+ out_data[out_index+0] = 0;
+ out_data[out_index+1] = 0;
+ out_data[out_index+2] = 0;
+ } else {
+ out_data[out_index+0] = CLAMP_D_TO_U8(result_R / (divisor*out_data[out_index+3]) + 255*bias); // CLAMP includes rounding!
+ out_data[out_index+1] = CLAMP_D_TO_U8(result_G / (divisor*out_data[out_index+3]) + 255*bias);
+ out_data[out_index+2] = CLAMP_D_TO_U8(result_B / (divisor*out_data[out_index+3]) + 255*bias);
+ }
}
}
}