diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-07-21 16:37:38 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-07-21 16:37:38 +0000 |
| commit | dd78fe909d51f28f7d2e42dcc17ffcb45eb39b23 (patch) | |
| tree | 2c331954debb4c2bc08181f16b0c6b0eb88690e3 /src/display | |
| parent | Fix type mismatch of std::min args in ColorMatrixMatrix constructor (diff) | |
| download | inkscape-dd78fe909d51f28f7d2e42dcc17ffcb45eb39b23.tar.gz inkscape-dd78fe909d51f28f7d2e42dcc17ffcb45eb39b23.zip | |
Add unpremul_alpha utility function. Some preparations
(bzr r9508.1.26)
Diffstat (limited to 'src/display')
| -rw-r--r-- | src/display/cairo-templates.h | 104 | ||||
| -rw-r--r-- | src/display/cairo-utils.h | 9 | ||||
| -rw-r--r-- | src/display/nr-filter-colormatrix.cpp | 12 | ||||
| -rw-r--r-- | src/display/nr-filter-convolve-matrix.cpp | 7 |
4 files changed, 125 insertions, 7 deletions
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h index efbd9c094..871d5c867 100644 --- a/src/display/cairo-templates.h +++ b/src/display/cairo-templates.h @@ -268,6 +268,110 @@ void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter cairo_surface_mark_dirty(out); } +template <typename Synth> +void ink_cairo_surface_synthesize(cairo_surface_t *out, Synth synth) +{ + // ASSUMPTIONS + // 1. Cairo ARGB32 surface strides are always divisible by 4 + // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces + + int w = cairo_image_surface_get_width(out); + int h = cairo_image_surface_get_height(out); + int strideout = cairo_image_surface_get_stride(out); + int bppout = cairo_image_surface_get_format(out) == CAIRO_FORMAT_A8 ? 1 : 4; + int limit = w * h; + // NOTE: fast path is not used, because we would need 2 divisions to get pixel indices + + guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out); + + #if HAVE_OPENMP + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int num_threads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); + #endif + + if (bppout == 4) { + #if HAVE_OPENMP + #pragma omp parallel for num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint32 *out_p = out_data + i * strideout/4; + for (int j = 0; j < w; ++j) { + *out_p = synth(j, i); + ++out_p; + } + } + } else { + // bppout == 1 + #if HAVE_OPENMP + #pragma omp parallel for num_threads(num_threads) + #endif + for (int i = 0; i < h; ++i) { + guint8 *out_p = reinterpret_cast<guint8*>(out_data) + i * strideout; + for (int j = 0; j < w; ++j) { + guint32 out_px = synth(j, i); + *out_p = out_px >> 24; + ++out_p; + } + } + } + cairo_surface_mark_dirty(out); +} + +// simple pixel accessor for image surface that handles different edge wrapping modes +class PixelAccessor { +public: + typedef PixelAccessor self; + enum EdgeMode { + EDGE_PAD, + EDGE_WRAP, + EDGE_ZERO + }; + + PixelAccessor(cairo_surface_t *s, EdgeMode e) + : _surface(s) + , _px(cairo_image_surface_get_data(s)) + , _x(0), _y(0) + , _w(cairo_image_surface_get_width(s)) + , _h(cairo_image_surface_get_height(s)) + , _stride(cairo_image_surface_get_stride(s)) + , _edge_mode(e) + , _alpha(cairo_image_surface_get_format(s) == CAIRO_FORMAT_A8) + {} + + guint32 pixelAt(int x, int y) { + // This is a lot of ifs for a single pixel access. However, branch prediction + // should help us a lot, as the result of ifs is always the same for a single image. + int real_x = x, real_y = y; + switch (_edge_mode) { + case EDGE_PAD: + real_x = CLAMP(x, 0, _w-1); + real_y = CLAMP(y, 0, _h-1); + break; + case EDGE_WRAP: + real_x %= _w; + real_y %= _h; + break; + case EDGE_ZERO: + default: + if (x < 0 || x >= _w || y < 0 || y >= _h) + return 0; + break; + } + if (_alpha) { + return *(_px + real_y*_stride + real_x) << 24; + } else { + guint32 *px = reinterpret_cast<guint32*>(_px +real_y*_stride + real_x*4); + return *px; + } + } +private: + cairo_surface_t *_surface; + guint8 *_px; + int _x, _y, _w, _h, _stride; + EdgeMode _edge_mode; + bool _alpha; +}; + // Some helpers for pixel manipulation G_GNUC_CONST inline gint32 diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index 02bfe0f73..12fcd8b3d 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -98,11 +98,18 @@ void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs); void convert_pixbuf_normal_to_argb32(GdkPixbuf *); void convert_pixbuf_argb32_to_normal(GdkPixbuf *); -inline guint32 premul_alpha(guint32 color, guint32 alpha) +G_GNUC_CONST inline guint32 +premul_alpha(guint32 color, guint32 alpha) { guint32 temp = alpha * color + 128; return (temp + (temp >> 8)) >> 8; } +G_GNUC_CONST inline guint32 +unpremul_alpha(guint32 color, guint32 alpha) +{ + // NOTE: you must check for alpha != 0 yourself. + return (255 * color + alpha/2) / alpha; +} // TODO: move those to 2Geom void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Matrix trans, Geom::OptRect area, bool optimize_stroke, double stroke_width); diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp index 8b7956833..7ab606182 100644 --- a/src/display/nr-filter-colormatrix.cpp +++ b/src/display/nr-filter-colormatrix.cpp @@ -51,9 +51,9 @@ struct ColorMatrixMatrix { // we need to un-premultiply alpha values for this type of matrix // TODO: unpremul can be ignored if there is an identity mapping on the alpha channel if (a != 0) { - r = (r * 255 + a/2) / a; - b = (b * 255 + a/2) / a; - g = (g * 255 + a/2) / a; + r = unpremul_alpha(r, a); + g = unpremul_alpha(g, a); + b = unpremul_alpha(b, a); } gint32 ro = r*_v[0] + g*_v[1] + b*_v[2] + a*_v[3] + _v[4]; @@ -141,9 +141,9 @@ struct ColorMatrixLuminanceToAlpha { EXTRACT_ARGB32(in, a, r, g, b) // unpremultiply color values if (a != 0) { - r = (r * 255 + a/2) / a; - b = (b * 255 + a/2) / a; - g = (g * 255 + a/2) / a; + r = unpremul_alpha(r, a); + g = unpremul_alpha(g, a); + b = unpremul_alpha(b, a); } guint32 ao = r*54 + g*182 + b*18; return ((ao + 127) / 255) << 24; diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp index fc88102d8..0119736cf 100644 --- a/src/display/nr-filter-convolve-matrix.cpp +++ b/src/display/nr-filter-convolve-matrix.cpp @@ -140,6 +140,13 @@ static void convolve2D(unsigned char *const out_data, unsigned char const *const } } +/* +void FilterConvolveMatrix::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_identical(input); +}*/ + int FilterConvolveMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) { NRPixBlock *in = slot.get(_input); if (!in) { |
