diff options
| author | Jabier Arraiza <jabier.arraiza@marker.es> | 2018-05-13 14:35:04 +0000 |
|---|---|---|
| committer | Jabier Arraiza <jabier.arraiza@marker.es> | 2018-05-13 14:35:04 +0000 |
| commit | e6616e3a2aa1ffa83fe173e2180849d1ca14a49d (patch) | |
| tree | e7b2d1392abea351244452fba0356d72509b900f /src | |
| parent | Add preview for numeric OpenType features. (diff) | |
| download | inkscape-e6616e3a2aa1ffa83fe173e2180849d1ca14a49d.tar.gz inkscape-e6616e3a2aa1ffa83fe173e2180849d1ca14a49d.zip | |
Fix bug embeding SVG as PNG
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/cairo-utils.cpp | 48 | ||||
| -rw-r--r-- | src/extension/internal/svg.cpp | 25 | ||||
| -rw-r--r-- | src/object/sp-image.cpp | 95 | ||||
| -rw-r--r-- | src/object/sp-image.h | 2 | ||||
| -rw-r--r-- | src/ui/dialog/inkscape-preferences.cpp | 7 | ||||
| -rw-r--r-- | src/ui/dialog/inkscape-preferences.h | 1 |
6 files changed, 140 insertions, 38 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 29e542b01..eae6b0d19 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -212,6 +212,7 @@ Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) Pixbuf *pixbuf = NULL; bool data_is_image = false; + bool data_is_svg = false; bool data_is_base64 = false; gchar const *data = uri_data; @@ -243,6 +244,12 @@ Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) data_is_image = true; data += 9; } + else if (strncmp(data,"image/svg+xml",13) == 0) { + /* JPEG2000 image */ + data_is_svg = true; + data_is_image = true; + data += 13; + } else { /* unrecognized option; skip it */ while (*data) { if (((*data) == ';') || ((*data) == ',')) { @@ -261,7 +268,7 @@ Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) } } - if ((*data) && data_is_image && data_is_base64) { + if ((*data) && data_is_image && !data_is_svg && data_is_base64) { GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); if (!loader) return NULL; @@ -288,6 +295,45 @@ Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data) } g_object_unref(loader); } + + if ((*data) && data_is_image && data_is_svg && data_is_base64) { + gsize decoded_len = 0; + guchar *decoded = g_base64_decode(data, &decoded_len); + SPDocument *svgDoc = SPDocument::createNewDocFromMem (reinterpret_cast<gchar const *>(decoded), decoded_len, false); + // Check the document loaded properly + if (svgDoc == NULL) { + return NULL; + } + if (svgDoc->getRoot() == NULL) + { + svgDoc->doUnref(); + return NULL; + } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + const double dpi = prefs->getDouble("/dialogs/import/defaultxdpi/value", 96.0); + // Get the size of the document + Inkscape::Util::Quantity svgWidth = svgDoc->getWidth(); + Inkscape::Util::Quantity svgHeight = svgDoc->getHeight(); + const double svgWidth_px = svgWidth.value("px"); + const double svgHeight_px = svgHeight.value("px"); + + // Now get the resized values + const int scaledSvgWidth = round(svgWidth_px/(96.0/dpi)); + const int scaledSvgHeight = round(svgHeight_px/(96.0/dpi)); + + GdkPixbuf *buf = sp_generate_internal_bitmap(svgDoc, NULL, 0, 0, svgWidth_px, svgHeight_px, scaledSvgWidth, scaledSvgHeight, dpi, dpi, (guint32) 0xffffff00, NULL)->getPixbufRaw(); + // Tidy up + svgDoc->doUnref(); + if (buf == NULL) { + std::cerr << "Pixbuf::create_from_data: failed to load contents: " << std::endl; + g_free(decoded); + return NULL; + } else { + g_object_ref(buf); + pixbuf = new Pixbuf(buf); + pixbuf->_setMimeData(decoded, decoded_len, "svg+xml"); + } + } return pixbuf; } diff --git a/src/extension/internal/svg.cpp b/src/extension/internal/svg.cpp index bf4924b2a..41fca734f 100644 --- a/src/extension/internal/svg.cpp +++ b/src/extension/internal/svg.cpp @@ -137,12 +137,11 @@ Svg::init(void) "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" "<name>" N_("SVG Input") "</name>\n" "<id>" SP_MODULE_KEY_INPUT_SVG "</id>\n" - "<param name='method' type='optiongroup' appearance='full' _gui-text='" N_("Method to import SVG:") "' _gui-description='" N_("Select the way the SVG is imported.") "' >\n" - "<_option value='include' >" N_("Include SVG image as editable object(s) in the current file") "</_option>\n" - "<_option value='link' >" N_("Link the SVG file in a image tag (not editable in this document") "</_option>\n" - "<_option value='embed' >" N_("Embed the SVG file in a image tag (not editable in this document") "</_option>\n" + "<param name='link_svg' type='optiongroup' appearance='full' _gui-text='" N_("SVG Image Import Type:") "' _gui-description='" N_("Include SVG image as editable object(s) in the current file, Embed the SVG file in a image tag (not editable in this document) or Link the SVG file in a image tag (not editable in this document).") "' >\n" + "<_option value='include' >" N_("Include") "</_option>\n" + "<_option value='embed' >" N_("Embed") "</_option>\n" + "<_option value='link' >" N_("Link") "</_option>\n" "</param>\n" - "<param name='scale' appearance='minimal' type='optiongroup' _gui-text='" N_("Image Rendering Mode:") "' _gui-description='" N_("When an image is upscaled, apply smoothing or keep blocky (pixelated). (Will not work in all browsers.)") "' >\n" "<_option value='auto' >" N_("None (auto)") "</_option>\n" "<_option value='optimizeQuality' >" N_("Smooth (optimizeQuality)") "</_option>\n" @@ -206,19 +205,19 @@ Svg::open (Inkscape::Extension::Input *mod, const gchar *uri) const auto path = file->get_path(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool ask = prefs->getBool("/dialogs/import/ask"); - Glib::ustring method = prefs->getString("/dialogs/import/method"); + Glib::ustring link_svg = prefs->getString("/dialogs/import/link_svg"); Glib::ustring scale = prefs->getString("/dialogs/import/scale"); bool is_import = false; if (strcmp(prefs->getString("/options/openmethod/value").c_str(), "import") == 0) { is_import = true; } if(INKSCAPE.use_gui() && is_import && ask) { - Glib::ustring mod_method = mod->get_param_optiongroup("method"); + Glib::ustring mod_link_svg = mod->get_param_optiongroup("link_svg"); Glib::ustring mod_scale = mod->get_param_optiongroup("scale"); - if( method.compare( mod_method) != 0 ) { - method = mod_method; + if( link_svg.compare( mod_link_svg) != 0 ) { + link_svg = mod_link_svg; } - prefs->setString("/dialogs/import/method", method ); + prefs->setString("/dialogs/import/link_svg", link_svg ); if( scale.compare( mod_scale ) != 0 ) { scale = mod_scale; } @@ -227,8 +226,8 @@ Svg::open (Inkscape::Extension::Input *mod, const gchar *uri) } SPDocument * doc = SPDocument::createNewDoc (NULL, TRUE, TRUE); - if (method.compare("include") != 0 && is_import) { - bool embed = ( method.compare( "embed" ) == 0 ); + if (link_svg.compare("include") != 0 && is_import) { + bool embed = ( link_svg.compare( "embed" ) == 0 ); SPDocument * ret = SPDocument::createNewDoc(uri, TRUE); SPNamedView *nv = sp_document_namedview(doc, NULL); Glib::ustring display_unit = nv->display_units->abbr; @@ -257,7 +256,7 @@ Svg::open (Inkscape::Extension::Input *mod, const gchar *uri) if (embed) { std::unique_ptr<Inkscape::Pixbuf> pb(Inkscape::Pixbuf::create_from_file(uri)); if(pb) { - sp_embed_image(image_node, pb.get()); + sp_embed_svg(image_node, uri); } } else { gchar* _uri = g_filename_to_uri(uri, NULL, NULL); diff --git a/src/object/sp-image.cpp b/src/object/sp-image.cpp index 3a76b9633..cc319a924 100644 --- a/src/object/sp-image.cpp +++ b/src/object/sp-image.cpp @@ -125,7 +125,6 @@ SPImage::SPImage() : SPItem(), SPViewBox() { this->color_profile = 0; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) this->pixbuf = 0; - this->on_construct = true; } SPImage::~SPImage() { @@ -327,12 +326,9 @@ void SPImage::update(SPCtx *ctx, unsigned int flags) { SPDocument *doc = this->document; SPItem::update(ctx, flags); - - if ((flags & SP_IMAGE_HREF_MODIFIED_FLAG) || this->on_construct) { - this->on_construct = false; + if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) { delete this->pixbuf; this->pixbuf = NULL; - if (this->href) { Inkscape::Pixbuf *pixbuf = NULL; pixbuf = sp_image_repr_read_image ( @@ -512,24 +508,23 @@ gchar* SPImage::description() const { this->pixbuf->height(), href_desc) ); -// if (this->pixbuf == NULL && -// this->document) -// { -// Inkscape::Pixbuf * pb = NULL; -// pb = sp_image_repr_read_image ( -// this->getRepr()->attribute("xlink:href"), -// this->getRepr()->attribute("sodipodi:absref"), -// this->document->getBase()); - -// if (pb) { -// ret = ( pb == NULL ? g_strdup_printf(_("[bad reference]: %s"), href_desc) -// : g_strdup_printf(_("%d × %d: %s"), -// pb->width(), -// pb->height(), -// href_desc)); -// delete pb; -// } -// } + if (this->pixbuf == NULL && + this->document) + { + Inkscape::Pixbuf * pb = NULL; + pb = sp_image_repr_read_image ( + this->getRepr()->attribute("xlink:href"), + this->getRepr()->attribute("sodipodi:absref"), + this->document->getBase()); + + if (pb) { + ret = g_strdup_printf(_("%d × %d: %s"), + pb->width(), + pb->height(), + href_desc); + delete pb; + } + } g_free(href_desc); return ret; @@ -793,6 +788,60 @@ void sp_embed_image(Inkscape::XML::Node *image_node, Inkscape::Pixbuf *pb) if (free_data) g_free(data); } +void sp_embed_svg(Inkscape::XML::Node *image_node, std::string const &fn) +{ + if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) { + return; + } + GStatBuf stdir; + int val = g_stat(fn.c_str(), &stdir); + if (val == 0 && stdir.st_mode & S_IFDIR){ + return; + } + + // we need to load the entire file into memory, + // since we'll store it as MIME data + gchar *data = NULL; + gsize len = 0; + GError *error = NULL; + + if (g_file_get_contents(fn.c_str(), &data, &len, &error)) { + + if (error != NULL) { + std::cerr << "Pixbuf::create_from_file: " << error->message << std::endl; + std::cerr << " (" << fn << ")" << std::endl; + return; + } + + std::string data_mimetype = "image/svg+xml"; + + + // Save base64 encoded data in image node + // this formula taken from Glib docs + gsize needed_size = len * 4 / 3 + len * 4 / (3 * 72) + 7; + needed_size += 5 + 8 + data_mimetype.size(); // 5 bytes for data: + 8 for ;base64, + + gchar *buffer = (gchar *) g_malloc(needed_size); + gchar *buf_work = buffer; + buf_work += g_sprintf(buffer, "data:%s;base64,", data_mimetype.c_str()); + + gint state = 0; + gint save = 0; + gsize written = 0; + written += g_base64_encode_step(reinterpret_cast<guchar *>(data), len, TRUE, buf_work, &state, &save); + written += g_base64_encode_close(TRUE, buf_work + written, &state, &save); + buf_work[written] = 0; // null terminate + + // TODO: this is very wasteful memory-wise. + // It would be better to only keep the binary data around, + // and base64 encode on the fly when saving the XML. + image_node->setAttribute("xlink:href", buffer); + + g_free(buffer); + g_free(data); + } +} + void sp_image_refresh_if_outdated( SPImage* image ) { if ( image->href && image->pixbuf && image->pixbuf->modificationTime()) { diff --git a/src/object/sp-image.h b/src/object/sp-image.h index a5dd84fe2..9a45f819c 100644 --- a/src/object/sp-image.h +++ b/src/object/sp-image.h @@ -63,12 +63,12 @@ public: #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) void apply_profile(Inkscape::Pixbuf *pixbuf); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - bool on_construct; }; /* Return duplicate of curve or NULL */ SPCurve *sp_image_get_curve (SPImage *image); void sp_embed_image(Inkscape::XML::Node *imgnode, Inkscape::Pixbuf *pb); +void sp_embed_svg(Inkscape::XML::Node *image_node, std::string const &fn); void sp_image_refresh_if_outdated( SPImage* image ); #endif diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index f0ac55736..6b55da0da 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -1563,6 +1563,13 @@ void InkscapePreferences::initPageBitmaps() } { + Glib::ustring labels[] = {_("Include"), _("Embed"), _("Link")}; + Glib::ustring values[] = {"include", "embed", "link"}; + _svg_link.init("/dialogs/import/link_svg", labels, values, G_N_ELEMENTS(values), "include"); + _page_bitmaps.add_line( false, _("SVG link:"), _svg_link, "", "", false); + } + + { Glib::ustring labels[] = {_("None (auto)"), _("Smooth (optimizeQuality)"), _("Blocky (optimizeSpeed)") }; Glib::ustring values[] = {"auto", "optimizeQuality", "optimizeSpeed"}; _bitmap_scale.init("/dialogs/import/scale", labels, values, G_N_ELEMENTS(values), "scale"); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 80df5ed65..828859bb8 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -380,6 +380,7 @@ protected: UI::Widget::PrefSpinButton _bitmap_copy_res; UI::Widget::PrefCheckButton _bitmap_ask; UI::Widget::PrefCombo _bitmap_link; + UI::Widget::PrefCombo _svg_link; UI::Widget::PrefCombo _bitmap_scale; UI::Widget::PrefSpinButton _bitmap_import_quality; |
