1 #define __SP_PIXBUF_OPS_C__
3 /*
4 * Helpers for SPItem -> gdk_pixbuf related stuff
5 *
6 * Authors:
7 * John Cliff <simarilius@yahoo.com>
8 *
9 * Copyright (C) 2008 John Cliff
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
18 #include <interface.h>
19 #include <libnr/nr-pixops.h>
20 #include <glib.h>
21 #include <glib/gmessages.h>
22 #include <png.h>
23 #include "png-write.h"
24 #include <display/nr-arena-item.h>
25 #include <display/nr-arena.h>
26 #include <document.h>
27 #include <sp-item.h>
28 #include <sp-root.h>
29 #include <sp-defs.h>
30 #include "unit-constants.h"
32 #include "libnr/nr-matrix-translate-ops.h"
33 #include "libnr/nr-scale-ops.h"
34 #include "libnr/nr-scale-translate-ops.h"
35 #include "libnr/nr-translate-matrix-ops.h"
36 #include "libnr/nr-translate-scale-ops.h"
38 #include "pixbuf-ops.h"
40 /**
41 * Hide all items that are not listed in list, recursively, skipping groups and defs.
42 */
43 static void
44 hide_other_items_recursively(SPObject *o, GSList *list, unsigned dkey)
45 {
46 if ( SP_IS_ITEM(o)
47 && !SP_IS_DEFS(o)
48 && !SP_IS_ROOT(o)
49 && !SP_IS_GROUP(o)
50 && !g_slist_find(list, o) )
51 {
52 sp_item_invoke_hide(SP_ITEM(o), dkey);
53 }
55 // recurse
56 if (!g_slist_find(list, o)) {
57 for (SPObject *child = sp_object_first_child(o) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
58 hide_other_items_recursively(child, list, dkey);
59 }
60 }
61 }
64 // The following is a mutation of the flood fill code, the marker preview, and random other samplings.
65 // The dpi settings dont do anything yet, but I want them to, and was wanting to keep reasonably close
66 // to the call for the interface to the png writing.
68 bool
69 sp_export_jpg_file(SPDocument *doc, gchar const *filename,
70 double x0, double y0, double x1, double y1,
71 unsigned width, unsigned height, double xdpi, double ydpi,
72 unsigned long bgcolor, double quality,GSList *items)
74 {
77 GdkPixbuf* pixbuf;
78 pixbuf = sp_generate_internal_bitmap(doc, filename, x0, y0, x1, y1,
79 width, height, xdpi, ydpi,
80 bgcolor, items );
83 gchar c[32];
84 g_snprintf(c, 32, "%f", quality);
85 gboolean saved = gdk_pixbuf_save (pixbuf, filename, "jpeg", NULL, "quality", c, NULL);
86 g_free(c);
87 gdk_pixbuf_unref (pixbuf);
88 if (saved) return true;
89 else return false;
90 }
92 GdkPixbuf*
93 sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/,
94 double x0, double y0, double x1, double y1,
95 unsigned width, unsigned height, double xdpi, double ydpi,
96 unsigned long bgcolor,
97 GSList *items_only)
99 {
101 GdkPixbuf* pixbuf = NULL;
102 /* Create new arena for offscreen rendering*/
103 NRArena *arena = NRArena::create();
104 nr_arena_set_renderoffscreen(arena);
105 unsigned dkey = sp_item_display_key_new(1);
107 sp_document_ensure_up_to_date (doc);
109 Geom::Rect screen=Geom::Rect(Geom::Point(x0,y0), Geom::Point(x1, y1));
111 double padding = 1.0;
113 Geom::Point origin(screen.min()[Geom::X],
114 sp_document_height(doc) - screen[Geom::Y].extent() - screen.min()[Geom::Y]);
116 origin[Geom::X] = origin[Geom::X] + (screen[Geom::X].extent() * ((1 - padding) / 2));
117 origin[Geom::Y] = origin[Geom::Y] + (screen[Geom::Y].extent() * ((1 - padding) / 2));
119 Geom::Scale scale( (xdpi / PX_PER_IN), (ydpi / PX_PER_IN));
120 Geom::Matrix affine = scale * Geom::Translate(-origin * scale);
122 /* Create ArenaItems and set transform */
123 NRArenaItem *root = sp_item_invoke_show(SP_ITEM(sp_document_root(doc)), arena, dkey, SP_ITEM_SHOW_DISPLAY);
124 nr_arena_item_set_transform(NR_ARENA_ITEM(root), affine);
126 NRGC gc(NULL);
127 gc.transform.setIdentity();
129 // We show all and then hide all items we don't want, instead of showing only requested items,
130 // because that would not work if the shown item references something in defs
131 if (items_only) {
132 hide_other_items_recursively(sp_document_root(doc), items_only, dkey);
133 }
135 NRRectL final_bbox;
136 final_bbox.x0 = 0;
137 final_bbox.y0 = 0;//row;
138 final_bbox.x1 = width;
139 final_bbox.y1 = height;//row + num_rows;
141 nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
143 guchar *px = NULL;
144 guint64 size = 4L * (guint64)width * (guint64)height;
145 if(size < (guint64)G_MAXSIZE) {
146 // g_try_new is limited to g_size type which is defined as unisgned int. Need to test for very large nubers
147 px = g_try_new(guchar, size);
148 }
150 if(px != NULL)
151 {
153 NRPixBlock B;
154 //g_warning("sp_generate_internal_bitmap: nr_pixblock_setup_extern.");
155 nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N,
156 final_bbox.x0, final_bbox.y0, final_bbox.x1, final_bbox.y1,
157 px, 4 * width, FALSE, FALSE );
159 unsigned char dtc[4];
160 dtc[0] = NR_RGBA32_R(bgcolor);
161 dtc[1] = NR_RGBA32_G(bgcolor);
162 dtc[2] = NR_RGBA32_B(bgcolor);
163 dtc[3] = NR_RGBA32_A(bgcolor);
165 for (gsize fy = 0; fy < height; fy++) {
166 guchar *p = NR_PIXBLOCK_PX(&B) + fy * (gsize)B.rs;
167 for (unsigned int fx = 0; fx < width; fx++) {
168 for (int i = 0; i < 4; i++) {
169 *p++ = dtc[i];
170 }
171 }
172 }
175 nr_arena_item_invoke_render(NULL, root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE );
177 pixbuf = gdk_pixbuf_new_from_data(px, GDK_COLORSPACE_RGB,
178 TRUE,
179 8, width, height, width * 4,
180 (GdkPixbufDestroyNotify)g_free,
181 NULL);
182 }
183 else
184 {
185 g_warning("sp_generate_internal_bitmap: not enough memory to create pixel buffer. Need %lld.", size);
186 }
187 sp_item_invoke_hide (SP_ITEM(sp_document_root(doc)), dkey);
188 nr_object_unref((NRObject *) arena);
190 // gdk_pixbuf_save (pixbuf, "C:\\temp\\internal.jpg", "jpeg", NULL, "quality","100", NULL);
192 return pixbuf;
193 }
195 /*
196 Local Variables:
197 mode:c++
198 c-file-style:"stroustrup"
199 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
200 indent-tabs-mode:nil
201 fill-column:99
202 End:
203 */
204 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :