From 5c45c5153b0415f7573f69f4ee3e946b5872a8d1 Mon Sep 17 00:00:00 2001 From: theadib Date: Mon, 14 Jan 2008 00:27:19 +0000 Subject: [PATCH] early version export to PS using blur to bitmap --- src/Makefile_insert | 5 +- src/extension/internal/cairo-ps-out.cpp | 85 +++++++--- src/extension/internal/cairo-renderer.cpp | 174 ++++++++++++++++++++ src/helper/pixbuf-ops.cpp | 188 ++++++++++++++++++++++ src/helper/pixbuf-ops.h | 27 ++++ 5 files changed, 456 insertions(+), 23 deletions(-) create mode 100644 src/helper/pixbuf-ops.cpp create mode 100644 src/helper/pixbuf-ops.h diff --git a/src/Makefile_insert b/src/Makefile_insert index 02943a4ef..196d5e562 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -285,6 +285,7 @@ libinkpre_a_SOURCES = \ version.cpp version.h \ zoom-context.cpp zoom-context.h + # Force libinkpost.a to be rebuilt if we add files to libinkpost_a_SOURCES. libinkpost_a_DEPENDENCIES = Makefile_insert @@ -324,7 +325,9 @@ libinkpost_a_SOURCES = \ composite-undo-stack-observer.cpp \ undo-stack-observer.h \ unit-constants.h \ - uri.cpp uri.h + uri.cpp uri.h \ + helper/pixbuf-ops.cpp \ + helper/pixbuf-ops.h inkscape_private_libs = \ libinkpre.a \ diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index f51d3317d..032592bf5 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -47,8 +47,10 @@ namespace Internal { bool CairoPsOutput::check (Inkscape::Extension::Extension * module) { - return TRUE; -} + if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_PRINT_CAIRO_PS)) + return FALSE; + + return TRUE;} static bool ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, bool texttopath, bool filtertobitmap) @@ -75,11 +77,11 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l bool ret = ctx->setPsTarget(filename); if(ret) { /* Render document */ - ret = renderer->setupDocument(ctx, doc); - if (ret) { - renderer->renderItem(ctx, base); - ret = ctx->finish(); - } + ret = renderer->setupDocument(ctx, doc); + if (ret) { + renderer->renderItem(ctx, base); + ret = ctx->finish(); + } } renderer->destroyContext(ctx); @@ -91,6 +93,7 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l delete renderer; return ret; + } @@ -110,28 +113,66 @@ CairoPsOutput::save (Inkscape::Extension::Output *mod, SPDocument *doc, const gc if (ext == NULL) return; - const gchar *old_level = ext->get_param_enum("PSlevel"); - const gchar *new_level = mod->get_param_enum("PSlevel"); + const gchar *old_level = NULL; + const gchar *new_level = NULL; int level = 1; + try { + old_level = ext->get_param_enum("PSlevel"); + new_level = mod->get_param_enum("PSlevel"); + if((new_level != NULL) && (g_ascii_strcasecmp("PS2", new_level) == 0)) + level = 0; +// ext->set_param_enum("PSlevel", new_level); + } + catch(...) { + g_warning("Parameter might not exists"); + } - bool old_textToPath = ext->get_param_bool("textToPath"); - bool new_textToPath = mod->get_param_bool("textToPath"); - ext->set_param_bool("textToPath", new_textToPath); - - bool old_blurToBitmap = ext->get_param_bool("blurToBitmap"); - bool new_blurToBitmap = mod->get_param_bool("blurToBitmap"); - ext->set_param_bool("blurToBitmap", new_blurToBitmap); + bool old_textToPath = FALSE; + bool new_textToPath = FALSE; + try { + old_textToPath = ext->get_param_bool("textToPath"); + new_textToPath = mod->get_param_bool("textToPath"); + ext->set_param_bool("textToPath", new_textToPath); + } + catch(...) { + g_warning("Parameter might not exists"); + } + bool old_blurToBitmap = FALSE; + bool new_blurToBitmap = FALSE; + try { + old_blurToBitmap = ext->get_param_bool("blurToBitmap"); + new_blurToBitmap = mod->get_param_bool("blurToBitmap"); + ext->set_param_bool("blurToBitmap", new_blurToBitmap); + } + catch(...) { + g_warning("Parameter might not exists"); + } - if(g_ascii_strcasecmp("PS2", new_level) == 0) - level = 0; gchar * final_name; final_name = g_strdup_printf("> %s", uri); ret = ps_print_document_to_file(doc, final_name, level, new_textToPath, new_blurToBitmap); g_free(final_name); - ext->set_param_bool("blurToBitmap", old_blurToBitmap); - ext->set_param_bool("textToPath", old_textToPath); + try { + ext->set_param_bool("blurToBitmap", old_blurToBitmap); + } + catch(...) { + g_warning("Parameter might not exists"); + } + try { + ext->set_param_bool("textToPath", old_textToPath); + } + catch(...) { + g_warning("Parameter might not exists"); + } + try { +// ext->set_param_enum("PSlevel", old_level); + } + catch(...) { + g_warning("Parameter might not exists"); + } + if (!ret) throw Inkscape::Extension::Output::save_failed(); @@ -161,14 +202,14 @@ CairoPsOutput::init (void) Inkscape::Extension::build_from_mem( "\n" "Cairo PS Output\n" - "org.inkscape.print.ps.cairo\n" + "" SP_MODULE_KEY_PRINT_CAIRO_PS "\n" "\n" "" N_("PostScript 3") "\n" #if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2)) "" N_("PostScript level 2") "\n" #endif "\n" - "true\n" + "false\n" "false\n" "\n" ".ps\n" diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index dbb898183..002098bd2 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -34,6 +34,14 @@ #include #include +#include "libnr/nr-matrix-rotate-ops.h" +#include "libnr/nr-matrix-translate-ops.h" +#include "libnr/nr-rotate-fns.h" +#include "libnr/nr-scale-ops.h" +#include "libnr/nr-scale-translate-ops.h" +#include "libnr/nr-translate-matrix-ops.h" +#include "libnr/nr-translate-scale-ops.h" + #include #include @@ -60,6 +68,8 @@ #include "sp-clippath.h" #include +#include "helper/png-write.h" +#include "helper/pixbuf-ops.h" #include "cairo-renderer.h" #include "cairo-render-context.h" @@ -151,6 +161,7 @@ static void sp_text_render(SPItem *item, CairoRenderContext *ctx); static void sp_flowtext_render(SPItem *item, CairoRenderContext *ctx); static void sp_image_render(SPItem *item, CairoRenderContext *ctx); static void sp_symbol_render(SPItem *item, CairoRenderContext *ctx); +static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx); static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) { @@ -165,6 +176,10 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) NR::Matrix const i2d = sp_item_i2d_affine(item); SPStyle* style = SP_OBJECT_STYLE (item); + if(style->filter.set != 0) { + sp_asbitmap_render(item, ctx); + return; + } CairoRenderer *renderer = ctx->getRenderer(); NRBPath bp; @@ -340,6 +355,165 @@ static void sp_root_render(SPItem *item, CairoRenderContext *ctx) ctx->popState(); } +/** + this function convert the item to a raster image and include the raster into the cairo renderer +*/ +static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx) +{ + g_warning("render as bitmap"); + + //the code now was copied from sp_selection_create_bitmap_copy + + SPDocument *document = SP_OBJECT(item)->document; + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + + // Get the bounding box of the selection + //NR::Maybe _bbox = item->getBounds(sp_item_i2d_affine(item)); + // NRRect bbox = item->getBounds(sp_item_i2d_affine(item)); + NRRect bbox(item->getBounds(sp_item_i2d_affine(item))); + + + // List of the items to show; all others will be hidden + GSList *items = NULL; //g_slist_copy ((GSList *) selection->itemList()); + items = g_slist_append(items, item); + + // Generate a random value from the current time (you may create bitmap from the same object(s) + // multiple times, and this is done so that they don't clash) + GTimeVal cu; + g_get_current_time (&cu); + guint current = (int) (cu.tv_sec * 1000000 + cu.tv_usec) % 1024; + + // Create the filename + gchar *filename = g_strdup_printf ("%s-%s-%u.png", document->name, SP_OBJECT_REPR(items->data)->attribute("id"), current); + // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters, + // digits, and a few other chars, with "_" + filename = g_strcanon (filename, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.=+~$#@^&!?", '_'); + // Build the complete path by adding document->base if set + gchar *filepath = g_build_filename (document->base?document->base:"", filename, NULL); + + //g_print ("%s\n", filepath); + + // Remember parent and z-order of the topmost one + gint pos = SP_OBJECT_REPR(g_slist_last(items)->data)->position(); + SPObject *parent_object = SP_OBJECT_PARENT(g_slist_last(items)->data); + Inkscape::XML::Node *parent = SP_OBJECT_REPR(parent_object); + + // Calculate resolution + double res; + /** @TODO reimplement the resolution stuff + */ + res = PX_PER_IN; + + // The width and height of the bitmap in pixels + unsigned width = (unsigned) floor ((bbox.x1 - bbox.x0) * res / PX_PER_IN); + unsigned height =(unsigned) floor ((bbox.y1 - bbox.y0) * res / PX_PER_IN); + + // Find out if we have to run a filter + gchar const *run = NULL; + gchar const *filter = NULL; + /** @TODO reimplement the filter stuff + //gchar const *filter = prefs_get_string_attribute ("options.createbitmap", "filter"); + if (filter) { + // filter command is given; + // see if we have a parameter to pass to it + gchar const *param1 = prefs_get_string_attribute ("options.createbitmap", "filter_param1"); + if (param1) { + if (param1[strlen(param1) - 1] == '%') { + // if the param string ends with %, interpret it as a percentage of the image's max dimension + gchar p1[256]; + g_ascii_dtostr (p1, 256, ceil (g_ascii_strtod (param1, NULL) * MAX(width, height) / 100)); + // the first param is always the image filename, the second is param1 + run = g_strdup_printf ("%s \"%s\" %s", filter, filepath, p1); + } else { + // otherwise pass the param1 unchanged + run = g_strdup_printf ("%s \"%s\" %s", filter, filepath, param1); + } + } else { + // run without extra parameter + run = g_strdup_printf ("%s \"%s\"", filter, filepath); + } + } + */ + // Calculate the matrix that will be applied to the image so that it exactly overlaps the source objects + NR::Matrix eek = sp_item_i2d_affine (SP_ITEM(parent_object)); + NR::Matrix t; + + double shift_x = bbox.x0; + double shift_y = bbox.y1; + if (res == PX_PER_IN) { // for default 90 dpi, snap it to pixel grid + shift_x = round (shift_x); + shift_y = -round (-shift_y); // this gets correct rounding despite coordinate inversion, remove the negations when the inversion is gone + } + t = (NR::Matrix)(NR::scale(1, -1) * (NR::Matrix)(NR::translate (shift_x, shift_y) * eek.inverse())); + + // Do the export + GdkPixbuf *pb = sp_generate_internal_bitmap(document, filepath, + bbox.x0, bbox.y0, bbox.x1, bbox.y1, width, height, res, res, (guint32) 0xffffff00, items ); + + /*sp_export_png_file(document, filepath, + bbox.x0, bbox.y0, bbox.x1, bbox.y1, + width, height, res, res, + (guint32) 0xffffff00, + NULL, NULL, + true, //bool force_overwrite, + items); + */ + // Run filter, if any + /* + if (run) { + g_print ("Running external filter: %s\n", run); + system (run); + } + */ + // Import the image back + //GdkPixbuf *pb = gdk_pixbuf_new_from_file (filepath, NULL); + if (pb) { + unsigned char *px = gdk_pixbuf_get_pixels (pb); + unsigned int w = gdk_pixbuf_get_width(pb); + unsigned int h = gdk_pixbuf_get_height(pb); + unsigned int rs = gdk_pixbuf_get_rowstride(pb); + NRMatrix matrix = t; + //nr_matrix_set_identity(&matrix); + + ctx->renderImage (px, w, h, rs, &matrix, SP_OBJECT_STYLE (item)); + /* + // Create the repr for the image + Inkscape::XML::Node * repr = xml_doc->createElement("svg:image"); + repr->setAttribute("xlink:href", filename); + repr->setAttribute("sodipodi:absref", filepath); + if (res == PX_PER_IN) { // for default 90 dpi, snap it to pixel grid + sp_repr_set_svg_double(repr, "width", width); + sp_repr_set_svg_double(repr, "height", height); + } else { + sp_repr_set_svg_double(repr, "width", (bbox.x1 - bbox.x0)); + sp_repr_set_svg_double(repr, "height", (bbox.y1 - bbox.y0)); + } + + // Write transform + gchar *c=sp_svg_transform_write(t); + repr->setAttribute("transform", c); + g_free(c); + + // add the new repr to the parent + parent->appendChild(repr); + + // move to the saved position + repr->setPosition(pos > 0 ? pos + 1 : 1); + + // Clean up + Inkscape::GC::release(repr); + */ + gdk_pixbuf_unref (pb); + + // Complete undoable transaction + // sp_document_done (document, SP_VERB_SELECTION_CREATE_BITMAP, _("Create bitmap")); + } + g_slist_free (items); + + g_free (filename); + g_free (filepath); +} + static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx) { /* diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp new file mode 100644 index 000000000..acfb6ed30 --- /dev/null +++ b/src/helper/pixbuf-ops.cpp @@ -0,0 +1,188 @@ +#define __SP_PIXBUF_OPS_C__ + +/* + * Helpers for SPItem -> gdk_pixbuf related stuff + * + * Authors: + * John Cliff + * + * Copyright (C) 2008 John Cliff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include "png-write.h" +#include +#include +#include +#include +#include +#include + +#include "libnr/nr-matrix-translate-ops.h" +#include "libnr/nr-scale-ops.h" +#include "libnr/nr-scale-translate-ops.h" +#include "libnr/nr-translate-matrix-ops.h" +#include "libnr/nr-translate-scale-ops.h" + +#include "pixbuf-ops.h" + +/** + * 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) +{ + if ( SP_IS_ITEM(o) + && !SP_IS_DEFS(o) + && !SP_IS_ROOT(o) + && !SP_IS_GROUP(o) + && !g_slist_find(list, o) ) + { + sp_item_invoke_hide(SP_ITEM(o), dkey); + } + + // recurse + if (!g_slist_find(list, o)) { + for (SPObject *child = sp_object_first_child(o) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + hide_other_items_recursively(child, list, dkey); + } + } +} + + +// The following is a mutation of the flood fill code, the marker preview, and random other samplings. +// The dpi settings dont do anything yet, but I want them to, and was wanting to keep reasonably close +// to the call for the interface to the png writing. + +bool +sp_export_jpg_file(SPDocument *doc, gchar const *filename, + double x0, double y0, double x1, double y1, + unsigned width, unsigned height, double xdpi, double ydpi, + unsigned long bgcolor, double quality,GSList *items) + +{ + + + GdkPixbuf* pixbuf; + pixbuf = sp_generate_internal_bitmap(doc, filename, x0, y0, x1, y1, + width, height, xdpi, ydpi, + bgcolor, items ); + + + gchar c[32]; + g_snprintf(c, 32, "%f", quality); + gboolean saved = gdk_pixbuf_save (pixbuf, filename, "jpeg", NULL, "quality", c, NULL); + g_free(c); + if (saved) return true; + else return false; +} + +GdkPixbuf* +sp_generate_internal_bitmap(SPDocument *doc, gchar const *filename, + double x0, double y0, double x1, double y1, + unsigned width, unsigned height, double xdpi, double ydpi, + unsigned long bgcolor, + GSList *items_only) + +{ + + + /* Create new arena */ + NRArena *arena = NRArena::create(); + unsigned dkey = sp_item_display_key_new(1); + + sp_document_ensure_up_to_date (doc); + + NR::Rect screen=NR::Rect(NR::Point(x0,y0), NR::Point(x1, y1)); + + double zoom_scale = 1.0; + double padding = 1.0; + + width = (int)ceil(screen.extent(NR::X) * zoom_scale * padding); + height = (int)ceil(screen.extent(NR::Y) * zoom_scale * padding); + + NR::Point origin(screen.min()[NR::X], + sp_document_height(doc) - screen.extent(NR::Y) - screen.min()[NR::Y]); + + origin[NR::X] = origin[NR::X] + (screen.extent(NR::X) * ((1 - padding) / 2)); + origin[NR::Y] = origin[NR::Y] + (screen.extent(NR::Y) * ((1 - padding) / 2)); + + NR::scale scale(zoom_scale, zoom_scale); + NR::Matrix affine = scale * NR::translate(-origin * scale); + + /* Create ArenaItems and set transform */ + NRArenaItem *root = sp_item_invoke_show(SP_ITEM(sp_document_root(doc)), arena, dkey, SP_ITEM_SHOW_DISPLAY); + nr_arena_item_set_transform(NR_ARENA_ITEM(root), affine); + + NRGC gc(NULL); + nr_matrix_set_identity(&gc.transform); + + // 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); + } + + NRRectL final_bbox; + final_bbox.x0 = 0; + final_bbox.y0 = 0;//row; + final_bbox.x1 = width; + final_bbox.y1 = height;//row + num_rows; + + nr_arena_item_invoke_update(root, &final_bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); + + guchar *px = g_new(guchar, 4 * width * height); + + NRPixBlock B; + nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, + final_bbox.x0, final_bbox.y0, final_bbox.x1, final_bbox.y1, + px, 4 * width, FALSE, FALSE ); + + unsigned char dtc[4]; + dtc[0] = NR_RGBA32_R(bgcolor); + dtc[1] = NR_RGBA32_G(bgcolor); + dtc[2] = NR_RGBA32_B(bgcolor); + dtc[3] = NR_RGBA32_A(bgcolor); + + for (unsigned int fy = 0; fy < height; fy++) { + guchar *p = NR_PIXBLOCK_PX(&B) + fy * B.rs; + for (unsigned int fx = 0; fx < width; fx++) { + for (int i = 0; i < 4; i++) { + *p++ = dtc[i]; + } + } + } + + nr_arena_item_invoke_render(NULL, root, &final_bbox, &B, NR_ARENA_ITEM_RENDER_NO_CACHE ); + + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(px, GDK_COLORSPACE_RGB, + TRUE, + 8, width, height, width * 4, + (GdkPixbufDestroyNotify)g_free, + NULL); + +// gdk_pixbuf_save (pixbuf, "C:\\temp\\internal.jpg", "jpeg", NULL, "quality","100", NULL); + + return pixbuf; +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/helper/pixbuf-ops.h b/src/helper/pixbuf-ops.h new file mode 100644 index 000000000..d87f4fa25 --- /dev/null +++ b/src/helper/pixbuf-ops.h @@ -0,0 +1,27 @@ +#ifndef __SP_PIXBUF_OPS_H__ +#define __SP_PIXBUF_OPS_H__ + +/* + * Helpers for SPItem -> gdk_pixbuf related stuff + * + * Authors: + * John Cliff + * + * Copyright (C) 2008 John Cliff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +struct SPDocument; + +bool sp_export_jpg_file (SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, + unsigned int width, unsigned int height, double xdpi, double ydpi, unsigned long bgcolor, double quality, GSList *items_only = NULL); + +GdkPixbuf* sp_generate_internal_bitmap(SPDocument *doc, gchar const *filename, + double x0, double y0, double x1, double y1, + unsigned width, unsigned height, double xdpi, double ydpi, + unsigned long bgcolor, GSList *items_only = NULL); + +#endif -- 2.30.2