index 69848e9a6995350c909a1989977df0709a07e13a..d3fe2771ff8d07970153b3b1427879a0d08a0977 100644 (file)
--- a/src/helper/png-write.cpp
+++ b/src/helper/png-write.cpp
-#define __SP_PNG_WRITE_C__
-
/*
* PNG file format utilities
*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Whoever wrote this example in libpng documentation
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
*
* Copyright (C) 1999-2002 authors
*
#include <interface.h>
#include <libnr/nr-pixops.h>
#include <libnr/nr-translate-scale-ops.h>
+#include <2geom/rect.h>
#include <glib/gmessages.h>
#include <png.h>
#include "png-write.h"
#include <sp-item.h>
#include <sp-root.h>
#include <sp-defs.h>
-#include "prefs-utils.h"
+#include "preferences.h"
+#include "rdf.h"
/* This is an example of how to use libpng to read and write PNG files.
* The file libpng.txt is much more verbose then this. If you have not
int rowstride;
} SPPNGBD;
+/**
+ * A simple wrapper to list png_text.
+ */
+class PngTextList {
+public:
+ PngTextList() : count(0), textItems(0) {}
+ ~PngTextList();
+
+ void add(gchar const* key, gchar const* text);
+ gint getCount() {return count;}
+ png_text* getPtext() {return textItems;}
+
+private:
+ gint count;
+ png_text* textItems;
+};
+
+PngTextList::~PngTextList() {
+ for (gint i = 0; i < count; i++) {
+ if (textItems[i].key) {
+ g_free(textItems[i].key);
+ }
+ if (textItems[i].text) {
+ g_free(textItems[i].text);
+ }
+ }
+}
+
+void PngTextList::add(gchar const* key, gchar const* text)
+{
+ if (count < 0) {
+ count = 0;
+ textItems = 0;
+ }
+ png_text* tmp = (count > 0) ? g_try_renew(png_text, textItems, count + 1): g_try_new(png_text, 1);
+ if (tmp) {
+ textItems = tmp;
+ count++;
+
+ png_text* item = &(textItems[count - 1]);
+ item->compression = PNG_TEXT_COMPRESSION_NONE;
+ item->key = g_strdup(key);
+ item->text = g_strdup(text);
+ item->text_length = 0;
+#ifdef PNG_iTXt_SUPPORTED
+ item->itxt_length = 0;
+ item->lang = 0;
+ item->lang_key = 0;
+#endif // PNG_iTXt_SUPPORTED
+ } else {
+ g_warning("Unable to allocate arrary for %d PNG text data.", count);
+ textItems = 0;
+ count = 0;
+ }
+}
+
static bool
-sp_png_write_rgba_striped(gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi,
+sp_png_write_rgba_striped(SPDocument *doc,
+ gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi,
int (* get_rows)(guchar const **rows, int row, int num_rows, void *data),
void *data)
{
@@ -71,10 +130,10 @@ sp_png_write_rgba_striped(gchar const *filename, unsigned long int width, unsign
png_structp png_ptr;
png_infop info_ptr;
png_color_8 sig_bit;
- png_text text_ptr[3];
png_uint_32 r;
g_return_val_if_fail(filename != NULL, false);
+ g_return_val_if_fail(data != NULL, false);
/* open the file */
@@ -141,11 +200,49 @@ sp_png_write_rgba_striped(gchar const *filename, unsigned long int width, unsign
sig_bit.alpha = 8;
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
- /* Made by Inkscape comment */
- text_ptr[0].key = "Software";
- text_ptr[0].text = "www.inkscape.org";
- text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
- png_set_text(png_ptr, info_ptr, text_ptr, 1);
+ PngTextList textList;
+
+ textList.add("Software", "www.inkscape.org"); // Made by Inkscape comment
+ {
+ const gchar* pngToDc[] = {"Title", "title",
+ "Author", "creator",
+ "Description", "description",
+ //"Copyright", "",
+ "Creation Time", "date",
+ //"Disclaimer", "",
+ //"Warning", "",
+ "Source", "source"
+ //"Comment", ""
+ };
+ for (size_t i = 0; i < G_N_ELEMENTS(pngToDc); i += 2) {
+ struct rdf_work_entity_t * entity = rdf_find_entity ( pngToDc[i + 1] );
+ if (entity) {
+ gchar const* data = rdf_get_work_entity(doc, entity);
+ if (data && *data) {
+ textList.add(pngToDc[i], data);
+ }
+ } else {
+ g_warning("Unable to find entity [%s]", pngToDc[i + 1]);
+ }
+ }
+
+
+ struct rdf_license_t *license = rdf_get_license(doc);
+ if (license) {
+ if (license->name && license->uri) {
+ gchar* tmp = g_strdup_printf("%s %s", license->name, license->uri);
+ textList.add("Copyright", tmp);
+ g_free(tmp);
+ } else if (license->name) {
+ textList.add("Copyright", license->name);
+ } else if (license->uri) {
+ textList.add("Copyright", license->uri);
+ }
+ }
+ }
+ if (textList.getCount() > 0) {
+ png_set_text(png_ptr, info_ptr, textList.getPtext(), textList.getCount());
+ }
/* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
/* note that if sRGB is present the cHRM chunk must be ignored
bbox.y1 = row + num_rows;
/* Update to renderable state */
NRGC gc(NULL);
- gc.transform.set_identity();
+ gc.transform.setIdentity();
nr_arena_item_invoke_update(ebp->root, &bbox, &gc,
NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
/**
* Hide all items that are not listed in list, recursively, skipping groups and defs.
*/
-static void
-hide_other_items_recursively(SPObject *o, GSList *list, unsigned dkey)
+static void hide_other_items_recursively(SPObject *o, GSList *list, unsigned dkey)
{
if ( SP_IS_ITEM(o)
&& !SP_IS_DEFS(o)
&& !SP_IS_GROUP(o)
&& !g_slist_find(list, o) )
{
- sp_item_invoke_hide(SP_ITEM(o), dkey);
+ SP_ITEM(o)->invoke_hide(dkey);
}
// recurse
if (!g_slist_find(list, o)) {
- for (SPObject *child = sp_object_first_child(o) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
+ for ( SPObject *child = o->firstChild() ; child; child = child->getNext() ) {
hide_other_items_recursively(child, list, dkey);
}
}
*
* \return true if succeeded (or if no action was taken), false if an error occurred.
*/
+bool sp_export_png_file (SPDocument *doc, gchar const *filename,
+ double x0, double y0, double x1, double y1,
+ unsigned long int width, unsigned long int height, double xdpi, double ydpi,
+ unsigned long bgcolor,
+ unsigned int (*status) (float, void *),
+ void *data, bool force_overwrite,
+ GSList *items_only)
+{
+ return sp_export_png_file(doc, filename, Geom::Rect(Geom::Point(x0,y0),Geom::Point(x1,y1)),
+ width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only);
+}
bool
sp_export_png_file(SPDocument *doc, gchar const *filename,
- double x0, double y0, double x1, double y1,
+ Geom::Rect const &area,
unsigned long width, unsigned long height, double xdpi, double ydpi,
unsigned long bgcolor,
unsigned (*status)(float, void *),
g_return_val_if_fail(filename != NULL, false);
g_return_val_if_fail(width >= 1, false);
g_return_val_if_fail(height >= 1, false);
+ g_return_val_if_fail(!area.hasZeroArea(), false);
if (!force_overwrite && !sp_ui_overwrite_file(filename)) {
/* Remark: We return true so as not to invoke an error dialog in case export is cancelled
return true;
}
- // export with maximum blur rendering quality
- int saved_quality = prefs_get_int_attribute("options.blurquality", "value", 0);
- prefs_set_int_attribute("options.blurquality", "value", 2);
+ doc->ensureUpToDate();
- sp_document_ensure_up_to_date(doc);
+ /* Calculate translation by transforming to document coordinates (flipping Y)*/
+ Geom::Point translation = Geom::Point(-area[Geom::X][0], area[Geom::Y][1] - doc->getHeight());
- /* Go to document coordinates */
- {
- gdouble const t = y0;
- y0 = sp_document_height(doc) - y1;
- y1 = sp_document_height(doc) - t;
- }
-
- /*
+ /* This calculation is only valid when assumed that (x0,y0)= area.corner(0) and (x1,y1) = area.corner(2)
* 1) a[0] * x0 + a[2] * y1 + a[4] = 0.0
* 2) a[1] * x0 + a[3] * y1 + a[5] = 0.0
* 3) a[0] * x1 + a[2] * y1 + a[4] = width
* (2) a[5] = -a[3] * y1
*/
- NR::Matrix const affine(NR::translate(-x0, -y0)
- * NR::scale(width / (x1 - x0),
- height / (y1 - y0)));
+ Geom::Matrix const affine(Geom::Translate(translation)
+ * Geom::Scale(width / area.width(),
+ height / area.height()));
//SP_PRINT_MATRIX("SVG2PNG", &affine);
/* Create new arena */
NRArena *const arena = NRArena::create();
- unsigned const dkey = sp_item_display_key_new(1);
+ // export with maximum blur rendering quality
+ nr_arena_set_renderoffscreen(arena);
+ unsigned const dkey = SPItem::display_key_new(1);
/* Create ArenaItems and set transform */
- ebp.root = sp_item_invoke_show(SP_ITEM(sp_document_root(doc)), arena, dkey, SP_ITEM_SHOW_DISPLAY);
+ ebp.root = SP_ITEM(doc->getRoot())->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY);
nr_arena_item_set_transform(NR_ARENA_ITEM(ebp.root), affine);
// We show all and then 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_only) {
- hide_other_items_recursively(sp_document_root(doc), items_only, dkey);
+ hide_other_items_recursively(doc->getRoot(), items_only, dkey);
}
ebp.status = status;
if ((width < 256) || ((width * height) < 32768)) {
ebp.px = nr_pixelstore_64K_new(FALSE, 0);
ebp.sheight = 65536 / (4 * width);
- write_status = sp_png_write_rgba_striped(filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp);
+ write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp);
nr_pixelstore_64K_free(ebp.px);
} else {
- ebp.px = g_new(guchar, 4 * 64 * width);
ebp.sheight = 64;
- write_status = sp_png_write_rgba_striped(filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp);
+ ebp.px = g_try_new(guchar, 4 * ebp.sheight * width);
+ write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp);
g_free(ebp.px);
}
- // Hide items
- sp_item_invoke_hide(SP_ITEM(sp_document_root(doc)), dkey);
+ // Hide items, this releases arenaitem
+ SP_ITEM(doc->getRoot())->invoke_hide(dkey);
- /* Free Arena and ArenaItem */
- nr_arena_item_unref(ebp.root);
+ /* Free arena */
nr_object_unref((NRObject *) arena);
- // restore saved blur quality
- prefs_set_int_attribute("options.blurquality", "value", saved_quality);
-
return write_status;
}
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :