From: jaspervdg Date: Sun, 28 Dec 2008 12:36:13 +0000 (+0000) Subject: Makes sure a Gaussian filter is applied to premultiplied data. X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=b8346b59f65f93ecaece3be77f5faae8c642810b;p=inkscape.git Makes sure a Gaussian filter is applied to premultiplied data. --- 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 * - * 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; i0) { delete[] tmpdata[i]; @@ -636,10 +656,10 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units) case NR_PIXBLOCK_MODE_R8G8B8: ///< 8 bit RGB downsample(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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 + * 2008, Jasper van de Gronde * * 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,12 +222,40 @@ 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. * 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);