From c853ffb5b2f75f5a889ed2e3ef89b818a736e87a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 13:50:49 +0200 Subject: Adding upstream version 1.3+ds. Signed-off-by: Daniel Baumann --- src/helper/pixbuf-ops.cpp | 131 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/helper/pixbuf-ops.cpp (limited to 'src/helper/pixbuf-ops.cpp') diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp new file mode 100644 index 0000000..82d85e9 --- /dev/null +++ b/src/helper/pixbuf-ops.cpp @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Helpers for SPItem -> gdk_pixbuf related stuff + * + * Authors: + * John Cliff + * Jon A. Cruz + * Abhishek Sharma + * + * Copyright (C) 2008 John Cliff + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <2geom/transforms.h> +#include + +#include "helper/pixbuf-ops.h" +#include "helper/png-write.h" +#include "display/cairo-utils.h" +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "document.h" +#include "object/sp-root.h" +#include "object/sp-defs.h" +#include "object/sp-use.h" +#include "util/units.h" +#include "util/scope_exit.h" +#include "inkscape.h" + +/** + Generates a bitmap from given items. The bitmap is stored in RAM and not written to file. + @param document Inkscape document. + @param area Export area in document units. + @param dpi Resolution. + @param items Vector of pointers to SPItems to export. Export all items if empty. + @param opaque Set items opacity to 1 (used by Cairo renderer for filtered objects rendered as bitmaps). + @return The created GdkPixbuf structure or nullptr if rendering failed. +*/ +Inkscape::Pixbuf *sp_generate_internal_bitmap(SPDocument *document, + Geom::Rect const &area, + double dpi, + std::vector items, + bool opaque, + uint32_t const *checkerboard_color, + double device_scale) +{ + // Geometry + if (area.hasZeroArea()) { + return nullptr; + } + + Geom::Point origin = area.min(); + double scale_factor = Inkscape::Util::Quantity::convert(dpi, "px", "in"); + Geom::Affine affine = Geom::Translate(-origin) * Geom::Scale (scale_factor, scale_factor); + + int width = std::ceil(scale_factor * area.width()); + int height = std::ceil(scale_factor * area.height()); + + // Document + document->ensureUpToDate(); + unsigned dkey = SPItem::display_key_new(1); + + // Drawing + Inkscape::Drawing drawing; // New drawing for offscreen rendering. + drawing.setRoot(document->getRoot()->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY)); + auto invoke_hide_guard = scope_exit([&] { document->getRoot()->invoke_hide(dkey); }); + drawing.root()->setTransform(affine); + drawing.setExact(); // Maximum quality for blurs. + + // Hide all items we don't want, instead of showing only requested items, + // because that would not work if the shown item references something in defs. + if (!items.empty()) { + document->getRoot()->invoke_hide_except(dkey, items); + } + + auto final_area = Geom::IntRect::from_xywh(0, 0, width, height); + drawing.update(final_area); + + if (opaque) { + // Required by sp_asbitmap_render(). + for (auto item : items) { + if (item->get_arenaitem(dkey)) { + item->get_arenaitem(dkey)->setOpacity(1.0); + } + } + } + + // Rendering + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { + long long size = (long long)height * (long long)cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + g_warning("sp_generate_internal_bitmap: not enough memory to create pixel buffer. Need %lld.", size); + cairo_surface_destroy(surface); + return nullptr; + } + + Inkscape::DrawingContext dc(surface, Geom::Point(0, 0)); + + if (checkerboard_color) { + auto pattern = ink_cairo_pattern_create_checkerboard(*checkerboard_color); + dc.save(); + dc.transform(Geom::Scale(device_scale)); + dc.setOperator(CAIRO_OPERATOR_SOURCE); + dc.setSource(pattern); + dc.paint(); + dc.restore(); + cairo_pattern_destroy(pattern); + } + + // render items + drawing.render(dc, final_area, Inkscape::DrawingItem::RENDER_BYPASS_CACHE); + + if (device_scale != 1.0) { + cairo_surface_set_device_scale(surface, device_scale, device_scale); + } + + return new Inkscape::Pixbuf(surface); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3