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; } } } }
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(); }
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; }
void VectorParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/) { set_and_write_new_values( origin * postmul, vector * postmul.without_translation() ); }