index c1b534b7705addcb019e8ceb45800ffe9f26e9b0..d80782d2009bb7687a11ac811f02558feeee1e7a 100644 (file)
* bulia byak
* Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
*
- * Copyright (C) 2006 authors
+ * Copyright (C) 2006-2008 authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "display/nr-filter-units.h"
#include "libnr/nr-blit.h"
#include "libnr/nr-pixblock.h"
-#include "libnr/nr-matrix.h"
-#include "libnr/nr-matrix-fns.h"
+#include <2geom/matrix.h>
#include "util/fixed_point.h"
#include "preferences.h"
+#ifndef INK_UNUSED
+#define INK_UNUSED(x) ((void)(x))
+#endif
+
// IIR filtering method based on:
// L.J. van Vliet, I.T. Young, and P.W. Verbeek, Recursive Gaussian Derivative Filters,
// in: A.K. Jain, S. Venkatesh, B.C. Lovell (eds.),
static size_t const N = 3;
template<typename InIt, typename OutIt, typename Size>
-void copy_n(InIt beg_in, Size N, OutIt beg_out) {
+inline void copy_n(InIt beg_in, Size N, OutIt beg_out) {
std::copy(beg_in, beg_in+N, beg_out);
}
return round_cast<Tt>(v);
}
-namespace NR {
+namespace Inkscape {
+namespace Filters {
FilterGaussian::FilterGaussian()
{
{
#if HAVE_OPENMP
#pragma omp parallel for num_threads(num_threads)
+#else
+ INK_UNUSED(num_threads);
#endif // HAVE_OPENMP
for ( int c2 = 0 ; c2 < n2 ; c2++ ) {
#if HAVE_OPENMP
#if HAVE_OPENMP
#pragma omp parallel for num_threads(num_threads) private(history)
+#else
+ INK_UNUSED(num_threads);
#endif // HAVE_OPENMP
for ( int c2 = 0 ; c2 < n2 ; c2++ ) {
@@ -531,48 +539,64 @@ upsample(PT *const dst, int const dstr1, int const dstr2, unsigned int const dn1
int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
{
- /* in holds the input pixblock */
- NRPixBlock *in = slot.get(_input);
- if (!in) {
- g_warning("Missing source image for feGaussianBlur (in=%d)", _input);
- return 1;
- }
+ // TODO: Meaningful return values? (If they're checked at all.)
- Matrix trans = units.get_matrix_primitiveunits2pb();
+ /* in holds the input pixblock */
+ NRPixBlock *original_in = slot.get(_input);
/* If to either direction, the standard deviation is zero or
* input image is not defined,
* a transparent black image should be returned. */
- if (_deviation_x <= 0 || _deviation_y <= 0 || in == NULL) {
- NRPixBlock *out = new NRPixBlock;
- if (in == NULL) {
+ if (_deviation_x <= 0 || _deviation_y <= 0 || original_in == NULL) {
+ NRPixBlock *src = original_in;
+ if (src == NULL) {
+ g_warning("Missing source image for feGaussianBlur (in=%d)", _input);
// A bit guessing here, but source graphic is likely to be of
// right size
- in = slot.get(NR_FILTER_SOURCEGRAPHIC);
+ src = slot.get(NR_FILTER_SOURCEGRAPHIC);
}
- nr_pixblock_setup_fast(out, in->mode, in->area.x0, in->area.y0,
- in->area.x1, in->area.y1, true);
- if (out->data.px != NULL) {
+ NRPixBlock *out = new NRPixBlock;
+ nr_pixblock_setup_fast(out, src->mode, src->area.x0, src->area.y0,
+ src->area.x1, src->area.y1, true);
+ if (out->size != NR_PIXBLOCK_SIZE_TINY && out->data.px != NULL) {
out->empty = false;
slot.set(_output, out);
}
return 0;
}
+ // Gaussian blur is defined to operate on non-premultiplied color values.
+ // So, convert the input first it uses non-premultiplied color values.
+ // And please note that this should not be done AFTER resampling, as resampling a non-premultiplied image
+ // does not simply yield a non-premultiplied version of the resampled premultiplied image!!!
+ NRPixBlock *in = original_in;
+ if (in->mode == NR_PIXBLOCK_MODE_R8G8B8A8N) {
+ in = nr_pixblock_new_fast(NR_PIXBLOCK_MODE_R8G8B8A8P,
+ original_in->area.x0, original_in->area.y0,
+ original_in->area.x1, original_in->area.y1,
+ false);
+ if (!in) {
+ // ran out of memory
+ return 0;
+ }
+ nr_blit_pixblock_pixblock(in, original_in);
+ }
+
+ Geom::Matrix trans = units.get_matrix_primitiveunits2pb();
+
// Some common constants
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int const width_org = in->area.x1-in->area.x0, height_org = in->area.y1-in->area.y0;
- double const deviation_x_org = _deviation_x * NR::expansionX(trans);
- double const deviation_y_org = _deviation_y * NR::expansionY(trans);
+ double const deviation_x_org = _deviation_x * trans.expansionX();
+ double const deviation_y_org = _deviation_y * trans.expansionY();
int const PC = NR_PIXBLOCK_BPP(in);
#if HAVE_OPENMP
- int const NTHREADS = std::max(1,std::min(8,prefs->getInt("/options/threading/numthreads",omp_get_num_procs())));
+ int const NTHREADS = std::max(1,std::min(8, Inkscape::Preferences::get()->getInt("/options/threading/numthreads", omp_get_num_procs())));
#else
int const NTHREADS = 1;
#endif // HAVE_OPENMP
// Subsampling constants
- int const quality = prefs->getInt("/options/blurquality/value");
+ int const quality = slot.get_blurquality();
int const x_step_l2 = _effect_subsample_step_log2(deviation_x_org, quality);
int const y_step_l2 = _effect_subsample_step_log2(deviation_y_org, quality);
int const x_step = 1<<x_step_l2;
in->area.x0/x_step+width, in->area.y0/y_step+height, true);
if (out->size != NR_PIXBLOCK_SIZE_TINY && out->data.px == NULL) {
// alas, we've accomplished a lot, but ran out of memory - so abort
+ if (in != original_in) nr_pixblock_free(in);
+ delete out;
return 0;
}
// Temporary storage for IIR filter
for(int i=0; i<NTHREADS; i++) {
tmpdata[i] = new IIRValue[std::max(width,height)*PC];
if (tmpdata[i] == NULL) {
+ if (in != original_in) nr_pixblock_free(in);
nr_pixblock_release(out);
while(i-->0) {
delete[] tmpdata[i];
case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
downsample<unsigned char,3>(NR_PIXBLOCK_PX(out), 3, out->rs, width, height, NR_PIXBLOCK_PX(in), 3, in->rs, width_org, height_org, x_step_l2, y_step_l2);
break;
- case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- downsample<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, width, height, NR_PIXBLOCK_PX(in), 4, in->rs, width_org, height_org, x_step_l2, y_step_l2);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
+ //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
+ // downsample<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, width, height, NR_PIXBLOCK_PX(in), 4, in->rs, width_org, height_org, x_step_l2, y_step_l2);
+ // break;
+ case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
downsample<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, width, height, NR_PIXBLOCK_PX(in), 4, in->rs, width_org, height_org, x_step_l2, y_step_l2);
break;
default:
case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
filter2D_IIR<unsigned char,3,false>(NR_PIXBLOCK_PX(out), 3, out->rs, NR_PIXBLOCK_PX(ssin), 3, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
break;
- case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
+ //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
+ // filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
+ // break;
+ case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
filter2D_IIR<unsigned char,4,true >(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, b, M, tmpdata, NTHREADS);
break;
default:
case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
filter2D_FIR<unsigned char,3>(NR_PIXBLOCK_PX(out), 3, out->rs, NR_PIXBLOCK_PX(ssin), 3, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
break;
- case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
+ //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
+ // filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
+ // break;
+ case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), 4, out->rs, NR_PIXBLOCK_PX(ssin), 4, ssin->rs, width, height, kernel, scr_len_x, NTHREADS);
break;
default:
case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
filter2D_IIR<unsigned char,3,false>(NR_PIXBLOCK_PX(out), out->rs, 3, NR_PIXBLOCK_PX(out), out->rs, 3, height, width, b, M, tmpdata, NTHREADS);
break;
- case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, b, M, tmpdata, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
+ //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
+ // filter2D_IIR<unsigned char,4,false>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, b, M, tmpdata, NTHREADS);
+ // break;
+ case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
filter2D_IIR<unsigned char,4,true >(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, b, M, tmpdata, NTHREADS);
break;
default:
case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
filter2D_FIR<unsigned char,3>(NR_PIXBLOCK_PX(out), out->rs, 3, NR_PIXBLOCK_PX(out), out->rs, 3, height, width, kernel, scr_len_y, NTHREADS);
break;
- case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, kernel, scr_len_y, NTHREADS);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
+ //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
+ // filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, kernel, scr_len_y, NTHREADS);
+ // break;
+ case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
filter2D_FIR<unsigned char,4>(NR_PIXBLOCK_PX(out), out->rs, 4, NR_PIXBLOCK_PX(out), out->rs, 4, height, width, kernel, scr_len_y, NTHREADS);
break;
default:
in->area.x1, in->area.y1, true);
if (finalout->size != NR_PIXBLOCK_SIZE_TINY && finalout->data.px == NULL) {
// alas, we've accomplished a lot, but ran out of memory - so abort
+ if (in != original_in) nr_pixblock_free(in);
nr_pixblock_release(out);
delete out;
return 0;
case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB
upsample<unsigned char,3>(NR_PIXBLOCK_PX(finalout), 3, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 3, out->rs, width, height, x_step_l2, y_step_l2);
break;
- case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
- upsample<unsigned char,4>(NR_PIXBLOCK_PX(finalout), 4, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 4, out->rs, width, height, x_step_l2, y_step_l2);
- break;
- case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
+ //case NR_PIXBLOCK_MODE_R8G8B8A8N: ///< Normal 8 bit RGBA
+ // upsample<unsigned char,4>(NR_PIXBLOCK_PX(finalout), 4, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 4, out->rs, width, height, x_step_l2, y_step_l2);
+ // break;
+ case NR_PIXBLOCK_MODE_R8G8B8A8P: ///< Premultiplied 8 bit RGBA
upsample<unsigned char,4>(NR_PIXBLOCK_PX(finalout), 4, finalout->rs, width_org, height_org, NR_PIXBLOCK_PX(out), 4, out->rs, width, height, x_step_l2, y_step_l2);
break;
default:
slot.set(_output, finalout);
}
+ if (in != original_in) nr_pixblock_free(in);
+
return 0;
}
-void FilterGaussian::area_enlarge(NRRectL &area, Matrix const &trans)
+void FilterGaussian::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
{
- int area_x = _effect_area_scr(_deviation_x * NR::expansionX(trans));
- int area_y = _effect_area_scr(_deviation_y * NR::expansionY(trans));
+ int area_x = _effect_area_scr(_deviation_x * trans.expansionX());
+ int area_y = _effect_area_scr(_deviation_y * trans.expansionY());
// maximum is used because rotations can mix up these directions
// TODO: calculate a more tight-fitting rendering area
int area_max = std::max(area_x, area_y);
}
}
-} /* namespace NR */
+} /* namespace Filters */
+} /* namespace Inkscape */
/*
Local Variables: