diff options
| author | Jasper van de Gronde <jasper.vandegronde@gmail.com> | 2008-12-28 12:36:13 +0000 |
|---|---|---|
| committer | jaspervdg <jaspervdg@users.sourceforge.net> | 2008-12-28 12:36:13 +0000 |
| commit | d1097f76c834b9eeb4036e97b3c214550ed23706 (patch) | |
| tree | a13a131d2389ba1c2e44dd24af1684973444c73d /src | |
| parent | Eliminate unnecessary premultiplied boolean from nr-filter-colormatrix (diff) | |
| download | inkscape-d1097f76c834b9eeb4036e97b3c214550ed23706.tar.gz inkscape-d1097f76c834b9eeb4036e97b3c214550ed23706.zip | |
Makes sure a Gaussian filter is applied to premultiplied data.
(bzr r7028)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/nr-filter-gaussian.cpp | 101 | ||||
| -rw-r--r-- | src/libnr/nr-pixblock.cpp | 31 | ||||
| -rw-r--r-- | src/libnr/nr-pixblock.h | 1 |
3 files changed, 93 insertions, 40 deletions
diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index ce81df811..4e4c3ee63 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -8,7 +8,7 @@ * 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 */ @@ -538,34 +538,51 @@ 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.) - Geom::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; @@ -606,6 +623,8 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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 @@ -616,6 +635,7 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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]; @@ -636,10 +656,10 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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: @@ -673,10 +693,10 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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: @@ -695,10 +715,10 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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: @@ -734,10 +754,10 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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: @@ -756,10 +776,10 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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: @@ -782,6 +802,7 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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; @@ -795,10 +816,10 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) 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: @@ -814,6 +835,8 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) slot.set(_output, finalout); } + if (in != original_in) nr_pixblock_free(in); + return 0; } diff --git a/src/libnr/nr-pixblock.cpp b/src/libnr/nr-pixblock.cpp index 8d2e930ef..6b2b12b7b 100644 --- a/src/libnr/nr-pixblock.cpp +++ b/src/libnr/nr-pixblock.cpp @@ -5,6 +5,7 @@ * * Authors: * (C) 1999-2002 Lauris Kaplinski <lauris@kaplinski.com> + * 2008, Jasper van de Gronde <th.v.d.gonde@hccnet.nl> * * This code is in the Public Domain */ @@ -213,7 +214,7 @@ nr_pixblock_release (NRPixBlock *pb) * * \return Pointer to fresh pixblock. * Calls g_new() and nr_pixblock_setup(). -FIXME: currently unused, delete? +FIXME: currently unused, delete? JG: Should be used more often! (To simplify memory management.) */ NRPixBlock * nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear) @@ -221,13 +222,41 @@ nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool cle NRPixBlock *pb; pb = g_new (NRPixBlock, 1); + if (!pb) return 0; nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear); + if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) { + g_free(pb); + return 0; + } return pb; } /** + * Allocates NRPixBlock and sets it up. + * + * \return Pointer to fresh pixblock. + * Calls g_new() and nr_pixblock_setup(). + */ +NRPixBlock * +nr_pixblock_new_fast (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear) +{ + NRPixBlock *pb; + + pb = g_new (NRPixBlock, 1); + if (!pb) return 0; + + nr_pixblock_setup_fast (pb, mode, x0, y0, x1, y1, clear); + if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) { + g_free(pb); + return 0; + } + + return pb; +} + +/** * Frees all memory taken by pixblock. * * \return NULL diff --git a/src/libnr/nr-pixblock.h b/src/libnr/nr-pixblock.h index c9ccb4fc6..bda32c436 100644 --- a/src/libnr/nr-pixblock.h +++ b/src/libnr/nr-pixblock.h @@ -70,6 +70,7 @@ void nr_pixblock_setup_extern (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, in void nr_pixblock_release (NRPixBlock *pb); NRPixBlock *nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear); +NRPixBlock *nr_pixblock_new_fast (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear); NRPixBlock *nr_pixblock_free (NRPixBlock *pb); unsigned char *nr_pixelstore_4K_new (bool clear, unsigned char val); |
