index 1d73f14e1906ec92ff560d18bba0d8fec95cdc8a..0b24649a99a9f1e122dffa8d147a59717329841c 100644 (file)
* feColorMatrix filter primitive renderer
*
* Authors:
- * Felipe CorrĂȘa da Silva Sanches <felipe.sanches@gmail.com>
+ * Felipe CorrĂȘa da Silva Sanches <juca@members.fsf.org>
+ * Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
*
* Copyright (C) 2007 authors
*
#include "libnr/nr-blit.h"
#include <math.h>
-namespace NR {
+namespace Inkscape {
+namespace Filters {
FilterColorMatrix::FilterColorMatrix()
{
}
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);
+ 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 != NR_PIXBLOCK_MODE_R8G8B8A8N) {
+ if (in->mode != out->mode) {
NRPixBlock *original_in = in;
in = new NRPixBlock;
- nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8N,
+ nr_pixblock_setup_fast(in, out->mode,
original_in->area.x0, original_in->area.y0,
original_in->area.x1, original_in->area.y1,
true);
unsigned char *out_data = NR_PIXBLOCK_PX(out);
unsigned char r,g,b,a;
int x,y,x0,y0,x1,y1,i;
- double a00,a01,a02,a10,a11,a12,a20,a21,a22, coshue, sinhue;
x0=in->area.x0;
y0=in->area.y0;
x1=in->area.x1;
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;
- }
- 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] + 255*values[4] );
- out_data[i+1] = CLAMP_D_TO_U8( r*values[5] + g*values[6] + b*values[7] + a*values[8] + 255*values[9] );
- out_data[i+2] = CLAMP_D_TO_U8( r*values[10] + g*values[11] + b*values[12] + a*values[13] + 255*values[14] );
- out_data[i+3] = CLAMP_D_TO_U8( r*values[15] + g*values[16] + b*values[17] + a*values[18] + 255*values[19] );
+ {
+ 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:
- 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*(0.213+0.787*value) + g*(0.715-0.715*value) + b*(0.072-0.072*value) );
- out_data[i+1] = CLAMP_D_TO_U8( r*(0.213-0.213*value) + g*(0.715+0.285*value) + b*(0.072-0.072*value) );
- out_data[i+2] = CLAMP_D_TO_U8( r*(0.213-0.213*value) + g*(0.715-0.715*value) + b*(0.072+0.928*value) );
- out_data[i+3] = a;
+ {
+ 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:
- coshue = cos(value * M_PI/180.0);
- sinhue = sin(value * M_PI/180.0);
- a00 = 0.213 + coshue*( 0.787) + sinhue*(-0.213);
- a01 = 0.715 + coshue*(-0.715) + sinhue*(-0.715);
- a02 = 0.072 + coshue*(-0.072) + sinhue*( 0.928);
- a10 = 0.213 + coshue*(-0.213) + sinhue*( 0.143);
- a11 = 0.715 + coshue*( 0.285) + sinhue*( 0.140);
- a12 = 0.072 + coshue*(-0.072) + sinhue*(-0.283);
- a20 = 0.213 + coshue*(-0.213) + sinhue*(-0.787);
- a21 = 0.715 + coshue*(-0.715) + sinhue*( 0.715);
- a22 = 0.072 + coshue*( 0.928) + sinhue*( 0.072);
-
- 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;
+ {
+ 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;
out_data[i] = 0;
out_data[i+1] = 0;
out_data[i+2] = 0;
- out_data[i+3] = CLAMP_D_TO_U8( r*0.2125 + g*0.7154 + b*0.0721);
+ out_data[i+3] = static_cast<unsigned char>( r*0.2125 + g*0.7154 + b*0.0721 + .5 );
}
}
break;
return 0;
}
-void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Matrix const &/*trans*/)
+void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/)
{
}
values = v;
}
-} /* namespace NR */
+} /* namespace Filters */
+} /* namespace Inkscape */
/*
Local Variables: