diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-03-04 23:34:30 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-03-04 23:34:30 +0000 |
| commit | 6d833eac6f8775095c3c0a0979a6dcab1e4f5c3c (patch) | |
| tree | b2765fbd0d101c27da577a95ec2ce75d78c92d7e /src/extension/internal/gdkpixbuf-input.cpp | |
| parent | Clean up the unordered containers fix. (diff) | |
| download | inkscape-6d833eac6f8775095c3c0a0979a6dcab1e4f5c3c.tar.gz inkscape-6d833eac6f8775095c3c0a0979a6dcab1e4f5c3c.zip | |
Improve behavior when pasting, DnDing and importing bitmap images
(bzr r9143)
Diffstat (limited to 'src/extension/internal/gdkpixbuf-input.cpp')
| -rw-r--r-- | src/extension/internal/gdkpixbuf-input.cpp | 113 |
1 files changed, 78 insertions, 35 deletions
diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp index 64a099c8a..47cde4a5a 100644 --- a/src/extension/internal/gdkpixbuf-input.cpp +++ b/src/extension/internal/gdkpixbuf-input.cpp @@ -1,8 +1,10 @@ #ifdef HAVE_CONFIG_H # include <config.h> #endif +#include <glib/gprintf.h> #include "document-private.h" #include <dir-util.h> +#include "extension/input.h" #include "extension/system.h" #include "gdkpixbuf-input.h" #include "selection-chemistry.h" @@ -16,69 +18,107 @@ GdkPixbuf* pixbuf_new_from_file( char const *utf8name, GError **error ); namespace Extension { namespace Internal { +static std::set<Glib::ustring> create_lossy_set() +{ + std::set<Glib::ustring> lossy; + lossy.insert(".jpg"); + lossy.insert(".jpeg"); + return lossy; +} + SPDocument * -GdkpixbufInput::open(Inkscape::Extension::Input */*mod*/, char const *uri) +GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) { + bool embed = !mod->get_param_bool("link"); SPDocument *doc = NULL; GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file( uri, NULL ); + static std::set<Glib::ustring> lossy = create_lossy_set(); if (pb) { /* We are readable */ + bool is_lossy; + Glib::ustring mime_type, ext; + Glib::ustring u = uri; + std::size_t dotpos = u.rfind('.'); + if (dotpos != Glib::ustring::npos) { + ext = u.substr(dotpos, Glib::ustring::npos); + } + + // HACK: replace with something better based on GIO + if (!ext.empty() && lossy.find(ext) != lossy.end()) { + is_lossy = true; + mime_type = "image/jpeg"; + } else { + is_lossy = false; + mime_type = "image/png"; + } + doc = sp_document_new(NULL, TRUE, TRUE); bool saved = sp_document_get_undo_sensitive(doc); sp_document_set_undo_sensitive(doc, false); // no need to undo in this temporary document - Inkscape::XML::Node *repr = NULL; - double width = gdk_pixbuf_get_width(pb); double height = gdk_pixbuf_get_height(pb); gchar const *str = gdk_pixbuf_get_option( pb, "Inkscape::DpiX" ); - if ( str ) - { + if ( str ) { gint dpi = atoi(str); - if ( dpi > 0 && dpi != 72 ) - { + if ( dpi > 0 && dpi != 72 ) { double scale = 72.0 / (double)dpi; width *= scale; } } str = gdk_pixbuf_get_option( pb, "Inkscape::DpiY" ); - if ( str ) - { + if ( str ) { gint dpi = atoi(str); - if ( dpi > 0 && dpi != 72 ) - { + if ( dpi > 0 && dpi != 72 ) { double scale = 72.0 / (double)dpi; height *= scale; } } + // Create image node Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); - // import as <image> - repr = xml_doc->createElement("svg:image"); - - // convert filename to uri - gchar* _uri = g_filename_to_uri(uri, NULL, NULL); - if(_uri) { - repr->setAttribute("xlink:href", _uri); - g_free(_uri); + Inkscape::XML::Node *image_node = xml_doc->createElement("svg:image"); + sp_repr_set_svg_double(image_node, "width", width); + sp_repr_set_svg_double(image_node, "height", height); + + if (embed) { + // Save pixbuf as JPEG or PNG for embedding + gchar *data; + gsize length; + gdk_pixbuf_save_to_buffer(pb, &data, &length, is_lossy ? "jpeg" : "png", NULL, NULL); + + // Save base64 encoded data in image node + // this formula taken from Glib docs + guint needed_size = length * 4 / 3 + length * 4 / (3 * 72) + 7; + needed_size += 5 + 8 + mime_type.size(); // 5 bytes for data:, 8 for ;base64, + + gchar *buffer = (gchar *) g_malloc(needed_size), *buf_work = buffer; + buf_work += g_sprintf(buffer, "data:%s;base64,", mime_type.data()); + + gint state = 0, save = 0; + gsize written = 0; + written += g_base64_encode_step((guchar*) data, length, TRUE, buf_work, &state, &save); + written += g_base64_encode_close(TRUE, buf_work + written, &state, &save); + buf_work[written] = 0; // null terminate + + image_node->setAttribute("xlink:href", buffer); + g_free(buffer); } else { - repr->setAttribute("xlink:href", uri); + // convert filename to uri + gchar* _uri = g_filename_to_uri(uri, NULL, NULL); + if(_uri) { + image_node->setAttribute("xlink:href", _uri); + g_free(_uri); + } else { + image_node->setAttribute("xlink:href", uri); + } } - /* impl: doc->base is currently NULL, so we can use uri for href whether it's absolute - * or relative. The href will get rewritten by rebase_hrefs if by chance uri is relative - * and doc gets saved to a different directory. - * - * We don't bother setting sodipodi:absref, as we assume it's never useful to have - * sodipodi:absref with the same value as xlink:href, and rebase_hrefs will provide - * sodipodi:absref values where necessary. */ - - sp_repr_set_svg_double(repr, "width", width); - sp_repr_set_svg_double(repr, "height", height); - - SP_DOCUMENT_ROOT(doc)->appendChildRepr(repr); - Inkscape::GC::release(repr); - gdk_pixbuf_unref(pb); - //alter the canvas size to fit the image size + + g_object_unref(pb); + + // Add it to the current layer + SP_DOCUMENT_ROOT(doc)->appendChildRepr(image_node); + Inkscape::GC::release(image_node); fit_canvas_to_drawing(doc); // restore undo, as now this document may be shown to the user if a bitmap was opened sp_document_set_undo_sensitive(doc, saved); @@ -126,6 +166,9 @@ GdkpixbufInput::init(void) "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" "<name>" N_("%s GDK pixbuf Input") "</name>\n" "<id>org.inkscape.input.gdkpixbuf.%s</id>\n" + "<param name=\"link\" gui-text=\"" + N_("Link image (leave unchecked if in doubt)") + "\" type=\"boolean\">false</param>" "<input>\n" "<extension>.%s</extension>\n" "<mimetype>%s</mimetype>\n" |
