Code

remove memory boundries on bitmap renderer, optimize memory usage
[inkscape.git] / src / helper / pixbuf-ops.cpp
1 /*
2  * Helpers for SPItem -> gdk_pixbuf related stuff
3  *
4  * Authors:
5  *   John Cliff <simarilius@yahoo.com>
6  *   Jon A. Cruz <jon@joncruz.org>
7  *   Abhishek Sharma
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-use.h>
30 #include <sp-defs.h>
31 #include "unit-constants.h"
33 #include "libnr/nr-matrix-translate-ops.h"
34 #include "libnr/nr-scale-ops.h"
35 #include "libnr/nr-scale-translate-ops.h"
36 #include "libnr/nr-translate-matrix-ops.h"
37 #include "libnr/nr-translate-scale-ops.h"
39 #include "pixbuf-ops.h"
41 // TODO look for copy-n-past duplication of this function:
42 /**
43  * Hide all items that are not listed in list, recursively, skipping groups and defs.
44  */
45 static void hide_other_items_recursively(SPObject *o, GSList *list, unsigned dkey)
46 {
47     if ( SP_IS_ITEM(o)
48          && !SP_IS_DEFS(o)
49          && !SP_IS_ROOT(o)
50          && !SP_IS_GROUP(o)
51          && !SP_IS_USE(o)
52          && !g_slist_find(list, o) )
53     {
54         SP_ITEM(o)->invoke_hide(dkey);
55     }
57     // recurse
58     if (!g_slist_find(list, o)) {
59         for ( SPObject *child = o->firstChild() ; child; child = child->getNext() ) {
60             hide_other_items_recursively(child, list, dkey);
61         }
62     }
63 }
66 // The following is a mutation of the flood fill code, the marker preview, and random other samplings.
67 // The dpi settings dont do anything yet, but I want them to, and was wanting to keep reasonably close
68 // to the call for the interface to the png writing.
70 bool
71 sp_export_jpg_file(SPDocument *doc, gchar const *filename,
72                    double x0, double y0, double x1, double y1,
73                    unsigned width, unsigned height, double xdpi, double ydpi,
74                    unsigned long bgcolor, double quality,GSList *items)
76 {
79       GdkPixbuf* pixbuf;
80       pixbuf = sp_generate_internal_bitmap(doc, filename, x0, y0, x1, y1,
81                                          width, height, xdpi, ydpi,
82                                          bgcolor, items );
85      gchar c[32];
86      g_snprintf(c, 32, "%f", quality);
87      gboolean saved = gdk_pixbuf_save (pixbuf, filename, "jpeg", NULL, "quality", c, NULL);
88      g_free(c);
89      gdk_pixbuf_unref (pixbuf);
90      if (saved) return true;
91      else return false;
92 }
94 /**
95     generates a bitmap from given items
96     the bitmap is stored in RAM and not written to file
97     @param x0
98     @param y0
99     @param x1
100     @param y1
101     @param width
102     @param height
103     @param xdpi
104     @param ydpi
105     @return the created GdkPixbuf structure or NULL if no memory is allocable
106 */
107 GdkPixbuf*
108 sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/,
109                             double x0, double y0, double x1, double y1,
110                             unsigned width, unsigned height, double xdpi, double ydpi,
111                             unsigned long bgcolor,
112                             GSList *items_only)
116      GdkPixbuf* pixbuf = NULL;
117      /* Create new arena for offscreen rendering*/
118      NRArena *arena = NRArena::create();
119      nr_arena_set_renderoffscreen(arena);
120      unsigned dkey = SPItem::display_key_new(1);
122      doc->ensureUpToDate();
124      Geom::Rect screen=Geom::Rect(Geom::Point(x0,y0), Geom::Point(x1, y1));
126      double padding = 1.0;
128      Geom::Point origin(screen.min()[Geom::X],
129                       doc->getHeight() - screen[Geom::Y].extent() - screen.min()[Geom::Y]);
131      origin[Geom::X] = origin[Geom::X] + (screen[Geom::X].extent() * ((1 - padding) / 2));
132      origin[Geom::Y] = origin[Geom::Y] + (screen[Geom::Y].extent() * ((1 - padding) / 2));
134      Geom::Scale scale( (xdpi / PX_PER_IN),   (ydpi / PX_PER_IN));
135      Geom::Matrix affine = scale * Geom::Translate(-origin * scale);
137      /* Create ArenaItems and set transform */
138      NRArenaItem *root = SP_ITEM(doc->getRoot())->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY);
139      nr_arena_item_set_transform(NR_ARENA_ITEM(root), affine);
141      NRGC gc(NULL);
142      gc.transform.setIdentity();
144      // We show all and then hide all items we don't want, instead of showing only requested items,
145      // because that would not work if the shown item references something in defs
146      if (items_only) {
147          hide_other_items_recursively(doc->getRoot(), items_only, dkey);
148      }
150      NRRectL final_bbox;
151      final_bbox.x0 = 0;
152      final_bbox.y0 = 0;//row;
153      final_bbox.x1 = width;
154      final_bbox.y1 = height;//row + num_rows;
156      nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
158     guchar *px = NULL;
159     guint64 size = 4L * (guint64)width * (guint64)height;
160     if(size < (guint64)G_MAXSIZE) {
161         // g_try_new is limited to g_size type which is defined as unisgned int. Need to test for very large nubers
162         px = g_try_new(guchar, size);
163     }
165     if(px != NULL)
166     {
168          NRPixBlock B;
169          //g_warning("sp_generate_internal_bitmap: nr_pixblock_setup_extern.");
170          nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N,
171                                    final_bbox.x0, final_bbox.y0, final_bbox.x1, final_bbox.y1,
172                                    px, 4 * width, FALSE, FALSE );
174          unsigned char dtc[4];
175          dtc[0] = NR_RGBA32_R(bgcolor);
176          dtc[1] = NR_RGBA32_G(bgcolor);
177          dtc[2] = NR_RGBA32_B(bgcolor);
178          dtc[3] = NR_RGBA32_A(bgcolor);
180          // fill pixelblock using background colour
181          for (gsize fy = 0; fy < height; fy++) {
182              guchar *p = NR_PIXBLOCK_PX(&B) + fy * (gsize)B.rs;
183              for (unsigned int fx = 0; fx < width; fx++) {
184                  for (int i = 0; i < 4; i++) {
185                      *p++ = dtc[i];
186                  }
187              }
188          }
191          nr_arena_item_invoke_render(NULL, root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE );
193          pixbuf = gdk_pixbuf_new_from_data(px, GDK_COLORSPACE_RGB,
194                                               TRUE,
195                                               8, width, height, width * 4,
196                                               (GdkPixbufDestroyNotify)g_free,
197                                               NULL);
198     }
199     else
200     {
201         g_warning("sp_generate_internal_bitmap: not enough memory to create pixel buffer. Need %lld.", size);
202     }
203      SP_ITEM(doc->getRoot())->invoke_hide(dkey);
204      nr_object_unref((NRObject *) arena);
206 //    gdk_pixbuf_save (pixbuf, "C:\\temp\\internal.jpg", "jpeg", NULL, "quality","100", NULL);
208     return pixbuf;
211 /*
212   Local Variables:
213   mode:c++
214   c-file-style:"stroustrup"
215   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
216   indent-tabs-mode:nil
217   fill-column:99
218   End:
219 */
220 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :