Esempio n. 1
0
static void sp_tspan_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/)
{
    // find out the ancestor text which holds our layout
    SPObject *parent_text = SP_OBJECT(item);
    for (; parent_text != NULL && !SP_IS_TEXT(parent_text); parent_text = SP_OBJECT_PARENT (parent_text)){};
    if (parent_text == NULL) return;

    // get the bbox of our portion of the layout
    SP_TEXT(parent_text)->layout.getBoundingBox(bbox, transform, sp_text_get_length_upto(parent_text, item), sp_text_get_length_upto(item, NULL) - 1);

    // Add stroke width
    SPStyle* style=SP_OBJECT_STYLE (item);
    if (!style->stroke.isNone()) {
        double const scale = transform.descrim();
        if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord
            double const width = MAX(0.125, style->stroke_width.computed * scale);
            if ( fabs(bbox->x1 - bbox->x0) > -0.00001 && fabs(bbox->y1 - bbox->y0) > -0.00001 ) {
                bbox->x0-=0.5*width;
                bbox->x1+=0.5*width;
                bbox->y0-=0.5*width;
                bbox->y1+=0.5*width;
            }
        }
    }
}
Esempio n. 2
0
static Geom::Matrix
sp_line_set_transform (SPItem *item, Geom::Matrix const &xform)
{
	SPLine *line = SP_LINE (item);
	Geom::Point points[2];

	points[0] = Geom::Point(line->x1.computed, line->y1.computed);
	points[1] = Geom::Point(line->x2.computed, line->y2.computed);

	points[0] *= xform;
	points[1] *= xform;

	line->x1.computed = points[0][Geom::X];
	line->y1.computed = points[0][Geom::Y];
	line->x2.computed = points[1][Geom::X];
	line->y2.computed = points[1][Geom::Y];

	sp_item_adjust_stroke(item, xform.descrim());

	SP_OBJECT (item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);

	return Geom::identity();
}
Esempio n. 3
0
void transform_bicubic(NRPixBlock *to, NRPixBlock *from, Geom::Matrix const &trans)
{
    if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) {
        g_warning("A non-32-bpp image passed to transform_bicubic: scaling aborted.");
        return;
    }

    bool free_from_on_exit = false;
    if (from->mode != to->mode){
        NRPixBlock *o_from = from;
        from = new NRPixBlock;
        nr_pixblock_setup_fast(from, to->mode, o_from->area.x0, o_from->area.y0, o_from->area.x1, o_from->area.y1, false);
        nr_blit_pixblock_pixblock(from, o_from);
        free_from_on_exit = true;
    }

    if (from->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
        // TODO: Fix this... (The problem is that for interpolation non-premultiplied colors should be premultiplied...)
        g_warning("transform_bicubic does not properly support non-premultiplied images");
    }
    
    // Precalculate sizes of source and destination pixblocks
    int from_width = from->area.x1 - from->area.x0;
    int from_height = from->area.y1 - from->area.y0;
    int to_width = to->area.x1 - to->area.x0;
    int to_height = to->area.y1 - to->area.y0;

    Geom::Matrix itrans = trans.inverse();

    // Loop through every pixel of destination image, a line at a time
    for (int to_y = 0 ; to_y < to_height ; to_y++) {
        for (int to_x = 0 ; to_x < to_width ; to_x++) {
            double from_x = itrans[0] * (to_x + 0.5 + to->area.x0)
                + itrans[2] * (to_y + 0.5 + to->area.y0)
                + itrans[4] - from->area.x0;
            double from_y = itrans[1] * (to_x + 0.5 + to->area.x0)
                + itrans[3] * (to_y + 0.5 + to->area.y0)
                + itrans[5] - from->area.y0;

            if (from_x < 0 || from_x >= from_width ||
                from_y < 0 || from_y >= from_height) {
                continue;
            }

            RGBA line[4];

            int from_line[4];
            for (int i = 0 ; i < 4 ; i++) {
                int fy_line = (int)round(from_y) + i - 2;
                if (fy_line >= 0) {
                    if (fy_line < from_height) {
                        from_line[i] = fy_line * from->rs;
                    } else {
                        from_line[i] = (from_height - 1) * from->rs;
                    }
                } else {
                    from_line[i] = 0;
                }                
            }

            for (int i = 0 ; i < 4 ; i++) {
                int k = (int)round(from_x) + i - 2;
                if (k < 0) k = 0;
                if (k >= from_width) k = from_width - 1;
                k *= 4;
                _check_index(from, from_line[0] + k, __LINE__);
                _check_index(from, from_line[1] + k, __LINE__);
                _check_index(from, from_line[2] + k, __LINE__);
                _check_index(from, from_line[3] + k, __LINE__);
                line[i].r = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k],
                                   NR_PIXBLOCK_PX(from)[from_line[1] + k],
                                   NR_PIXBLOCK_PX(from)[from_line[2] + k],
                                   NR_PIXBLOCK_PX(from)[from_line[3] + k],
                                   from_y);
                line[i].g = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 1],
                                   NR_PIXBLOCK_PX(from)[from_line[1] + k + 1],
                                   NR_PIXBLOCK_PX(from)[from_line[2] + k + 1],
                                   NR_PIXBLOCK_PX(from)[from_line[3] + k + 1],
                                   from_y);
                line[i].b = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 2],
                                   NR_PIXBLOCK_PX(from)[from_line[1] + k + 2],
                                   NR_PIXBLOCK_PX(from)[from_line[2] + k + 2],
                                   NR_PIXBLOCK_PX(from)[from_line[3] + k + 2],
                                   from_y);
                line[i].a = sample(NR_PIXBLOCK_PX(from)[from_line[0] + k + 3],
                                   NR_PIXBLOCK_PX(from)[from_line[1] + k + 3],
                                   NR_PIXBLOCK_PX(from)[from_line[2] + k + 3],
                                   NR_PIXBLOCK_PX(from)[from_line[3] + k + 3],
                                   from_y);
            }
            RGBA result;
            result.r = round(sample(line[0].r, line[1].r, line[2].r, line[3].r,
                                    from_x));
            result.g = round(sample(line[0].g, line[1].g, line[2].g, line[3].g,
                                    from_x));
            result.b = round(sample(line[0].b, line[1].b, line[2].b, line[3].b,
                                    from_x));
            result.a = round(sample(line[0].a, line[1].a, line[2].a, line[3].a,
                                    from_x));

            using Inkscape::Filters::clamp;
            using Inkscape::Filters::clamp_alpha;
            _check_index(to, to_y * to->rs + to_x * 4, __LINE__);
            if (to->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
                /* Make sure, none of the RGB channels exceeds 100% intensity
                 * in premultiplied output */
                int const alpha = clamp((int)result.a);
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] = 
                    clamp_alpha((int)result.r, alpha);
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] = 
                    clamp_alpha((int)result.g, alpha);
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] = 
                    clamp_alpha((int)result.b, alpha);
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = alpha;
            } else {
                /* Clamp the output to unsigned char range */
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4]
                    = clamp((int)result.r);
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1]
                    = clamp((int)result.g);
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2]
                    = clamp((int)result.b);
                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3]
                    = clamp((int)result.a);
            }
        }
    }
    if (free_from_on_exit) {
        nr_pixblock_release(from);
        delete from;
    }
}
static gint sp_dropper_context_root_handler(SPEventContext *event_context, GdkEvent *event)
{
    SPDropperContext *dc = (SPDropperContext *) event_context;
    int ret = FALSE;
    SPDesktop *desktop = event_context->desktop;
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    int pick = prefs->getInt("/tools/dropper/pick", SP_DROPPER_PICK_VISIBLE);
    bool setalpha = prefs->getBool("/tools/dropper/setalpha", true);

    switch (event->type) {
	case GDK_BUTTON_PRESS:
            if (event->button.button == 1 && !event_context->space_panning) {
                dc->centre = Geom::Point(event->button.x, event->button.y);
                dc->dragging = TRUE;
                ret = TRUE;
            }
            break;
	case GDK_MOTION_NOTIFY:
            if (event->motion.state & GDK_BUTTON2_MASK) {
                // pass on middle-drag
                ret = FALSE;
                break;
            } else if (!event_context->space_panning) {
                // otherwise, constantly calculate color no matter is any button pressed or not

                double rw = 0.0;
                double W(0), R(0), G(0), B(0), A(0);

                if (dc->dragging) {
                    // calculate average

                    // radius
                    rw = std::min(Geom::L2(Geom::Point(event->button.x, event->button.y) - dc->centre), 400.0);

                    if (rw == 0) { // happens sometimes, little idea why...
                        break;
                    }

                    Geom::Point const cd = desktop->w2d(dc->centre);
                    Geom::Matrix const w2dt = desktop->w2d();
                    const double scale = rw * w2dt.descrim();
                    Geom::Matrix const sm( Geom::Scale(scale, scale) * Geom::Translate(cd) );
                    sp_canvas_item_affine_absolute(dc->area, sm);
                    sp_canvas_item_show(dc->area);

                    /* Get buffer */
                    const int x0 = (int) floor(dc->centre[Geom::X] - rw);
                    const int y0 = (int) floor(dc->centre[Geom::Y] - rw);
                    const int x1 = (int) ceil(dc->centre[Geom::X] + rw);
                    const int y1 = (int) ceil(dc->centre[Geom::Y] + rw);

                    if ((x1 > x0) && (y1 > y0)) {
                        NRPixBlock pb;
                        nr_pixblock_setup_fast(&pb, NR_PIXBLOCK_MODE_R8G8B8A8P, x0, y0, x1, y1, TRUE);
                        /* fixme: (Lauris) */
                        sp_canvas_arena_render_pixblock(SP_CANVAS_ARENA(sp_desktop_drawing(desktop)), &pb);
                        for (int y = y0; y < y1; y++) {
                            const unsigned char *s = NR_PIXBLOCK_PX(&pb) + (y - y0) * pb.rs;
                            for (int x = x0; x < x1; x++) {
                                const double dx = x - dc->centre[Geom::X];
                                const double dy = y - dc->centre[Geom::Y];
                                const double w = exp(-((dx * dx) + (dy * dy)) / (rw * rw));
                                W += w;
                                R += w * s[0];
                                G += w * s[1];
                                B += w * s[2];
                                A += w * s[3];
                                s += 4;
                            }
                        }
                        nr_pixblock_release(&pb);

                        R = (R + 0.001) / (255.0 * W);
                        G = (G + 0.001) / (255.0 * W);
                        B = (B + 0.001) / (255.0 * W);
                        A = (A + 0.001) / (255.0 * W);

                        R = CLAMP(R, 0.0, 1.0);
                        G = CLAMP(G, 0.0, 1.0);
                        B = CLAMP(B, 0.0, 1.0);
                        A = CLAMP(A, 0.0, 1.0);
                    }

                } else {
                    // pick single pixel
                    NRPixBlock pb;
                    int x = (int) floor(event->button.x);
                    int y = (int) floor(event->button.y);
                    nr_pixblock_setup_fast(&pb, NR_PIXBLOCK_MODE_R8G8B8A8P, x, y, x+1, y+1, TRUE);
                    sp_canvas_arena_render_pixblock(SP_CANVAS_ARENA(sp_desktop_drawing(desktop)), &pb);
                    const unsigned char *s = NR_PIXBLOCK_PX(&pb);

                    R = s[0] / 255.0;
                    G = s[1] / 255.0;
                    B = s[2] / 255.0;
                    A = s[3] / 255.0;
                }

                if (pick == SP_DROPPER_PICK_VISIBLE) {
                    // compose with page color
                    guint32 bg = sp_desktop_namedview(desktop)->pagecolor;
                    R = R + (SP_RGBA32_R_F(bg)) * (1 - A);
                    G = G + (SP_RGBA32_G_F(bg)) * (1 - A);
                    B = B + (SP_RGBA32_B_F(bg)) * (1 - A);
                    A = 1.0;
                } else {
                    // un-premultiply color channels
                    if (A > 0) {
                        R /= A;
                        G /= A;
                        B /= A;
                    }
                }

                if (fabs(A) < 1e-4) {
                    A = 0; // suppress exponentials, CSS does not allow that
                }

                // remember color
                dc->R = R;
                dc->G = G;
                dc->B = B;
                dc->alpha = A;

                // status message
                double alpha_to_set = setalpha? dc->alpha : 1.0;
                guint32 c32 = SP_RGBA32_F_COMPOSE(R, G, B, alpha_to_set);

                gchar c[64];
                sp_svg_write_color(c, sizeof(c), c32);

                // alpha of color under cursor, to show in the statusbar
                // locale-sensitive printf is OK, since this goes to the UI, not into SVG
                gchar *alpha = g_strdup_printf(_(" alpha %.3g"), alpha_to_set);
                // where the color is picked, to show in the statusbar
                gchar *where = dc->dragging ? g_strdup_printf(_(", averaged with radius %d"), (int) rw) : g_strdup_printf(_(" under cursor"));
                // message, to show in the statusbar
                const gchar *message = dc->dragging ? _("<b>Release mouse</b> to set color.") : _("<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard");
                event_context->defaultMessageContext()->setF(
                    Inkscape::NORMAL_MESSAGE,
                    "<b>%s%s</b>%s. %s", c,
                    (pick == SP_DROPPER_PICK_VISIBLE)? "" : alpha,
                    where, message
                    );

                g_free(where);
                g_free(alpha);

                ret = TRUE;
            }
            break;
	case GDK_BUTTON_RELEASE:
            if (event->button.button == 1 && !event_context->space_panning)
            {
                sp_canvas_item_hide(dc->area);
                dc->dragging = FALSE;

                double alpha_to_set = setalpha? dc->alpha : 1.0;

                // do the actual color setting
                sp_desktop_set_color(desktop,
                                     (event->button.state & GDK_MOD1_MASK)?
                                     ColorRGBA(1 - dc->R, 1 - dc->G, 1 - dc->B, alpha_to_set) : ColorRGBA(dc->R, dc->G, dc->B, alpha_to_set),
                                     false,  !(event->button.state & GDK_SHIFT_MASK));

                // REJON: set aux. toolbar input to hex color!


                if (!(sp_desktop_selection(desktop)->isEmpty())) {
                    sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_DROPPER, 
                                     _("Set picked color"));
                }

                ret = TRUE;
            }
            break;
	case GDK_KEY_PRESS:
            switch (get_group0_keyval(&event->key)) {
		case GDK_Up:
		case GDK_Down:
		case GDK_KP_Up:
		case GDK_KP_Down:
                    // prevent the zoom field from activation
                    if (!MOD__CTRL_ONLY) {
                        ret = TRUE;
                    }
                    break;
		case GDK_Escape:
                    sp_desktop_selection(desktop)->clear();
		default:
                    break;
            }
            break;
	default:
            break;
    }

    if (!ret) {
        if (((SPEventContextClass *) parent_class)->root_handler) {
            ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event);
        }
    }

    return ret;
}
Esempio n. 5
0
void
VectorParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/)
{
        set_and_write_new_values( origin * postmul, vector * postmul.without_translation() );
}