1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Helpers for SPItem -> gdk_pixbuf related stuff
*
* Authors:
* John Cliff <simarilius@yahoo.com>
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
*
* Copyright (C) 2008 John Cliff
*
* Released under GNU GPL v2+, read the file 'COPYING' for more information.
*/
#include <2geom/transforms.h>
#include <gdk/gdk.h>
#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<SPItem *> 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 :
|