diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-08-14 17:02:47 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-08-14 17:02:47 +0000 |
| commit | 01fd769e29aa1738b1326d4a50a8f09a6665f242 (patch) | |
| tree | af1754712f0c8c39c9f245f13a41d50674acd406 /src/flood-context.cpp | |
| parent | Fix background tracing in clone tiler dialog (diff) | |
| download | inkscape-01fd769e29aa1738b1326d4a50a8f09a6665f242.tar.gz inkscape-01fd769e29aa1738b1326d4a50a8f09a6665f242.zip | |
Fix paint bucket tool
(bzr r9508.1.66)
Diffstat (limited to 'src/flood-context.cpp')
| -rw-r--r-- | src/flood-context.cpp | 150 |
1 files changed, 73 insertions, 77 deletions
diff --git a/src/flood-context.cpp b/src/flood-context.cpp index b67d180ff..dab0a33fa 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -52,8 +52,7 @@ #include "display/nr-arena.h" #include "display/nr-arena-image.h" #include "display/canvas-arena.h" -#include "libnr/nr-pixops.h" -#include "libnr/nr-pixblock.h" +#include "display/cairo-utils.h" #include <2geom/pathvector.h> #include "sp-item.h" #include "sp-root.h" @@ -199,22 +198,20 @@ static void sp_flood_context_setup(SPEventContext *ec) } } -/** - * \brief Merge a pixel with the background color. - * \param orig The pixel to merge with the background. - * \param bg The background color. - * \param base The pixel to merge the original and background into. - */ -inline static void -merge_pixel_with_background (unsigned char *orig, unsigned char *bg, - unsigned char *base) +inline static guint32 +compose_onto (guint32 px, guint32 bg) { - int precalc_bg_alpha = (255 * (255 - bg[3])) / 255; - - for (int i = 0; i < 3; i++) { - base[i] = precalc_bg_alpha + (bg[i] * bg[3]) / 255; - base[i] = (base[i] * (255 - orig[3])) / 255 + (orig[i] * orig[3]) / 255; - } + EXTRACT_ARGB32(px, ap,rp,gp,bp) + EXTRACT_ARGB32(bg, ab,rb,gb,bb) + guint32 ao,ro,bo,go; + + ao = 255*255 - (255-ap)*(255-bp); ao = (ao + 127) / 255; + ro = (255-ap)*rb + rp; ro = (ro + 127) / 255; + go = (255-ap)*gb + gp; go = (go + 127) / 255; + bo = (255-ap)*bb + bp; bo = (bo + 127) / 255; + + ASSEMBLE_ARGB32(pxout, ao,ro,go,bo) + return pxout; } /** @@ -222,10 +219,10 @@ merge_pixel_with_background (unsigned char *orig, unsigned char *bg, * \param px The pixel buffer. * \param x The X coordinate. * \param y The Y coordinate. - * \param width The width of the pixel buffer. + * \param stride The rowstride of the pixel buffer. */ -inline unsigned char * get_pixel(guchar *px, int x, int y, int width) { - return px + (x + y * width) * 4; +inline guint32 get_pixel(guchar *px, int x, int y, int stride) { + return *reinterpret_cast<guint32*>(px + y * stride + x * 4); } inline unsigned char * get_trace_pixel(guchar *trace_px, int x, int y, int width) { @@ -273,34 +270,44 @@ GList * flood_autogap_dropdown_items_list() { * \param threshold The fill threshold. * \param method The fill method to use as defined in PaintBucketChannels. */ -static bool compare_pixels(unsigned char *check, unsigned char *orig, unsigned char *merged_orig_pixel, unsigned char *dtc, int threshold, PaintBucketChannels method) { +static bool compare_pixels(guint32 check, guint32 orig, guint32 merged_orig_pixel, guint32 dtc, int threshold, PaintBucketChannels method) +{ int diff = 0; - float hsl_check[3], hsl_orig[3]; - + float hsl_check[3] = {0,0,0}, hsl_orig[3] = {0,0,0}; + + EXTRACT_ARGB32(check, ac,rc,gc,bc) + EXTRACT_ARGB32(orig, ao,ro,go,bo) + EXTRACT_ARGB32(dtc, ad,rd,gd,bd) + EXTRACT_ARGB32(merged_orig_pixel, amop,rmop,gmop,bmop) + if ((method == FLOOD_CHANNELS_H) || (method == FLOOD_CHANNELS_S) || (method == FLOOD_CHANNELS_L)) { - sp_color_rgb_to_hsl_floatv(hsl_check, check[0] / 255.0, check[1] / 255.0, check[2] / 255.0); - sp_color_rgb_to_hsl_floatv(hsl_orig, orig[0] / 255.0, orig[1] / 255.0, orig[2] / 255.0); + double dac = ac; + double dao = ao; + sp_color_rgb_to_hsl_floatv(hsl_check, rc / dac, gc / dac, bc / dac); + sp_color_rgb_to_hsl_floatv(hsl_orig, ro / dao, go / dao, bo / dao); } switch (method) { case FLOOD_CHANNELS_ALPHA: - return ((int)abs(check[3] - orig[3]) <= threshold); + return abs(static_cast<int>(ac) - ao) <= threshold; case FLOOD_CHANNELS_R: - return ((int)abs(check[0] - orig[0]) <= threshold); + return abs(static_cast<int>(ac ? unpremul_alpha(rc, ac) : 0) - (ao ? unpremul_alpha(ro, ao) : 0)) <= threshold; case FLOOD_CHANNELS_G: - return ((int)abs(check[1] - orig[1]) <= threshold); + return abs(static_cast<int>(ac ? unpremul_alpha(gc, ac) : 0) - (ao ? unpremul_alpha(go, ao) : 0)) <= threshold; case FLOOD_CHANNELS_B: - return ((int)abs(check[2] - orig[2]) <= threshold); + return abs(static_cast<int>(ac ? unpremul_alpha(bc, ac) : 0) - (ao ? unpremul_alpha(bo, ao) : 0)) <= threshold; case FLOOD_CHANNELS_RGB: - unsigned char merged_check[3]; - - merge_pixel_with_background(check, dtc, merged_check); - - for (int i = 0; i < 3; i++) { - diff += (int)abs(merged_check[i] - merged_orig_pixel[i]); - } + guint32 amc, rmc, bmc, gmc; + amc = 255*255 - (255-ac)*(255-ad); amc = (amc + 127) / 255; + rmc = (255-ac)*rd + rc; rmc = (rmc + 127) / 255; + gmc = (255-ac)*gd + gc; gmc = (gmc + 127) / 255; + bmc = (255-ac)*bd + bc; bmc = (bmc + 127) / 255; + + diff += abs(static_cast<int>(amc ? unpremul_alpha(rmc, amc) : 0) - (amop ? unpremul_alpha(rmop, amop) : 0)); + diff += abs(static_cast<int>(amc ? unpremul_alpha(gmc, amc) : 0) - (amop ? unpremul_alpha(gmop, amop) : 0)); + diff += abs(static_cast<int>(amc ? unpremul_alpha(bmc, amc) : 0) - (amop ? unpremul_alpha(bmop, amop) : 0)); return ((diff / 3) <= ((threshold * 3) / 4)); case FLOOD_CHANNELS_H: @@ -346,11 +353,12 @@ struct bitmap_coords_info { int y_limit; unsigned int width; unsigned int height; + unsigned int stride; unsigned int threshold; unsigned int radius; PaintBucketChannels method; - unsigned char *dtc; - unsigned char *merged_orig_pixel; + guint32 dtc; + guint32 merged_orig_pixel; Geom::Rect bbox; Geom::Rect screen; unsigned int max_queue_size; @@ -366,12 +374,12 @@ struct bitmap_coords_info { * \param orig_color The original selected pixel to use as the fill target color. * \param bci The bitmap_coords_info structure. */ -inline static bool check_if_pixel_is_paintable(guchar *px, unsigned char *trace_t, int x, int y, unsigned char *orig_color, bitmap_coords_info bci) { +inline static bool check_if_pixel_is_paintable(guchar *px, unsigned char *trace_t, int x, int y, guint32 orig_color, bitmap_coords_info bci) { if (is_pixel_paintability_checked(trace_t)) { return is_pixel_paintable(trace_t); } else { - unsigned char *t = get_pixel(px, x, y, bci.width); - if (compare_pixels(t, orig_color, bci.merged_orig_pixel, bci.dtc, bci.threshold, bci.method)) { + guint32 pixel = get_pixel(px, x, y, bci.stride); + if (compare_pixels(pixel, orig_color, bci.merged_orig_pixel, bci.dtc, bci.threshold, bci.method)) { mark_pixel_paintable(trace_t); return true; } else { @@ -550,7 +558,7 @@ inline static bool coords_in_range(unsigned int x, unsigned int y, bitmap_coords * \param bci The bitmap_coords_info structure. * \param original_point_trace_t The original pixel in the trace pixel buffer to check. */ -inline static unsigned int paint_pixel(guchar *px, guchar *trace_px, unsigned char *orig_color, bitmap_coords_info bci, unsigned char *original_point_trace_t) { +inline static unsigned int paint_pixel(guchar *px, guchar *trace_px, guint32 orig_color, bitmap_coords_info bci, unsigned char *original_point_trace_t) { if (bci.radius == 0) { mark_pixel_colored(original_point_trace_t); return PAINT_DIRECTION_ALL; @@ -632,7 +640,7 @@ static void shift_point_onto_queue(std::deque<Geom::Point> *fill_queue, unsigned * \param orig_color The original selected pixel to use as the fill target color. * \param bci The bitmap_coords_info structure. */ -static ScanlineCheckResult perform_bitmap_scanline_check(std::deque<Geom::Point> *fill_queue, guchar *px, guchar *trace_px, unsigned char *orig_color, bitmap_coords_info bci, unsigned int *min_x, unsigned int *max_x) { +static ScanlineCheckResult perform_bitmap_scanline_check(std::deque<Geom::Point> *fill_queue, guchar *px, guchar *trace_px, guint32 orig_color, bitmap_coords_info bci, unsigned int *min_x, unsigned int *max_x) { bool aborted = false; bool reached_screen_boundary = false; bool ok; @@ -816,37 +824,31 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); - guchar *px = g_new(guchar, 4 * width * height); - - NRPixBlock B; - nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, - final_bbox.x0, final_bbox.y0, final_bbox.x1, final_bbox.y1, - px, 4 * width, FALSE, FALSE ); + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + guchar *px = g_new(guchar, stride * height); + cairo_surface_t *s = cairo_image_surface_create_for_data( + px, CAIRO_FORMAT_ARGB32, width, height, stride); + cairo_t *ct = cairo_create(s); + SPNamedView *nv = sp_desktop_namedview(desktop); - unsigned long bgcolor = nv->pagecolor; - - unsigned char dtc[4]; - dtc[0] = NR_RGBA32_R(bgcolor); - dtc[1] = NR_RGBA32_G(bgcolor); - dtc[2] = NR_RGBA32_B(bgcolor); - dtc[3] = NR_RGBA32_A(bgcolor); - - for (unsigned int fy = 0; fy < height; fy++) { - guchar *p = NR_PIXBLOCK_PX(&B) + fy * B.rs; - for (unsigned int fx = 0; fx < width; fx++) { - for (int i = 0; i < 4; i++) { - *p++ = dtc[i]; - } - } - } + guint32 bgcolor = nv->pagecolor; + // bgcolor is 0xrrggbbaa, we need 0xaarrggbb + guint32 dtc = (bgcolor >> 8) | (bgcolor << 24); - nr_arena_item_invoke_render(NULL, root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE ); - nr_pixblock_release(&B); + ink_cairo_set_source_rgba32(ct, bgcolor); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_OVER); + + nr_arena_item_invoke_render(ct, root, &final_bbox, NULL, NR_ARENA_ITEM_RENDER_NO_CACHE ); + + cairo_surface_flush(s); + cairo_destroy(ct); + cairo_surface_destroy(s); // Hide items sp_item_invoke_hide(SP_ITEM(sp_document_root(document)), dkey); - nr_object_unref((NRObject *) arena); guchar *trace_px = g_new(guchar, width * height); @@ -883,6 +885,7 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even bci.y_limit = y_limit; bci.width = width; bci.height = height; + bci.stride = stride; bci.threshold = threshold; bci.method = method; bci.bbox = *bbox; @@ -935,15 +938,8 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even int cx = (int)color_point[Geom::X]; int cy = (int)color_point[Geom::Y]; - unsigned char *orig_px = get_pixel(px, cx, cy, width); - unsigned char orig_color[4]; - for (int i = 0; i < 4; i++) { orig_color[i] = orig_px[i]; } - - unsigned char merged_orig[3]; - - merge_pixel_with_background(orig_color, dtc, merged_orig); - - bci.merged_orig_pixel = merged_orig; + guint32 orig_color = get_pixel(px, cx, cy, stride); + bci.merged_orig_pixel = compose_onto(orig_color, dtc); unsigned char *trace_t = get_trace_pixel(trace_px, cx, cy, width); if (!is_pixel_checked(trace_t) && !is_pixel_colored(trace_t)) { |
