diff options
| author | Jasper van de Gronde <jasper.vandegronde@gmail.com> | 2008-12-22 17:19:13 +0000 |
|---|---|---|
| committer | jaspervdg <jaspervdg@users.sourceforge.net> | 2008-12-22 17:19:13 +0000 |
| commit | 3a6e93b38a94d64e1adfceed8c555044c3d963fd (patch) | |
| tree | d55d609ccc35835841bf259de24f9781df2dddde /src | |
| parent | fix crash bug 310206 (diff) | |
| download | inkscape-3a6e93b38a94d64e1adfceed8c555044c3d963fd.tar.gz inkscape-3a6e93b38a94d64e1adfceed8c555044c3d963fd.zip | |
Some accuracy improvements for nr-filter-colormatrix (including some changes to let it use premultiplied colors if possible) + author entry I forgot to add in revision 20391.
(bzr r7023)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/nr-filter-colormatrix.cpp | 156 | ||||
| -rw-r--r-- | src/display/nr-filter-component-transfer.cpp | 1 |
2 files changed, 100 insertions, 57 deletions
diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp index 10181a16e..e640ce4fb 100644 --- a/src/display/nr-filter-colormatrix.cpp +++ b/src/display/nr-filter-colormatrix.cpp @@ -3,6 +3,7 @@ * * Authors: * Felipe CorrĂȘa da Silva Sanches <felipe.sanches@gmail.com> + * Jasper van de Gronde <th.v.d.gronde@hccnet.nl> * * Copyright (C) 2007 authors * @@ -37,17 +38,28 @@ int FilterColorMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) { 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); + bool premultiplied; + 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); + premultiplied = true; + } else { + nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, + in->area.x0, in->area.y0, in->area.x1, in->area.y1, + true); + premultiplied = false; + } // 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); @@ -59,7 +71,6 @@ int FilterColorMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) { 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; @@ -67,64 +78,95 @@ int FilterColorMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) { 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] + .5; + double a14 = 255*values[9] + .5; + double a24 = 255*values[14] + .5; + double a34 = 255*values[19] + .5; + 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 ); + 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 (premultiplied) { + // 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 + .5 ); + out_data[i+1] = CLAMP_D_TO_U8( r*a10 + g*a11 + b*a12 + .5 ); + out_data[i+2] = CLAMP_D_TO_U8( r*a20 + g*a21 + b*a22 + .5 ); + out_data[i+3] = a; + } + } } } break; @@ -138,7 +180,7 @@ int FilterColorMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) { 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; diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp index dbf5c44ed..caf053bcf 100644 --- a/src/display/nr-filter-component-transfer.cpp +++ b/src/display/nr-filter-component-transfer.cpp @@ -3,6 +3,7 @@ * * Authors: * Felipe CorrĂȘa da Silva Sanches <felipe.sanches@gmail.com> + * Jasper van de Gronde <th.v.d.gronde@hccnet.nl> * * Copyright (C) 2007 authors * |
