summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2013-09-19 00:57:10 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2013-09-19 00:57:10 +0000
commit083367b313247a4cf0c082fff25e993892dc38d1 (patch)
tree35e5da339ef5d30a333270d644ac1d61e6ed6620
parentMerge in patch for Jabiertxo Arraiza Cenoz in bug lp:1127103 (diff)
downloadinkscape-083367b313247a4cf0c082fff25e993892dc38d1.tar.gz
inkscape-083367b313247a4cf0c082fff25e993892dc38d1.zip
Encapsulate the shared memory hack for Cairo and GdkPixbuf in a class
called Inkscape::Pixbuf. Replace usage in the code as appropriate. (bzr r12531)
-rw-r--r--src/display/cairo-utils.cpp539
-rw-r--r--src/display/cairo-utils.h70
-rw-r--r--src/display/drawing-image.cpp64
-rw-r--r--src/display/drawing-image.h6
-rw-r--r--src/display/nr-filter-image.cpp69
-rw-r--r--src/display/nr-filter-image.h6
-rw-r--r--src/extension/internal/cairo-render-context.cpp8
-rw-r--r--src/extension/internal/cairo-render-context.h6
-rw-r--r--src/extension/internal/cairo-renderer.cpp26
-rw-r--r--src/extension/internal/emf-print.cpp9
-rw-r--r--src/extension/internal/gdkpixbuf-input.cpp20
-rw-r--r--src/extension/internal/metafile-print.cpp2
-rw-r--r--src/extension/internal/metafile-print.h4
-rw-r--r--src/extension/internal/wmf-print.cpp13
-rw-r--r--src/filters/image.cpp2
-rw-r--r--src/helper/pixbuf-ops.cpp19
-rw-r--r--src/helper/pixbuf-ops.h3
-rw-r--r--src/selection-chemistry.cpp4
-rw-r--r--src/sp-image.cpp343
-rw-r--r--src/sp-image.h30
-rw-r--r--src/trace/trace.cpp25
21 files changed, 689 insertions, 579 deletions
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index 755553033..2c7b543c1 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -15,6 +15,8 @@
#include "display/cairo-utils.h"
#include <stdexcept>
+#include <glib/gstdio.h>
+#include <glibmm/fileutils.h>
#include <2geom/pathvector.h>
#include <2geom/bezier-curve.h>
#include <2geom/hvlinesegment.h>
@@ -28,6 +30,8 @@
#include "helper/geom-curves.h"
#include "display/cairo-templates.h"
+static void ink_cairo_pixbuf_cleanup(guchar *, void *);
+
/**
* Key for cairo_surface_t to keep track of current color interpolation value
* Only the address of the structure is used, it is never initialized. See:
@@ -116,6 +120,380 @@ Cairo::RefPtr<CairoContext> CairoContext::create(Cairo::RefPtr<Cairo::Surface> c
return ret;
}
+
+/* The class below implement the following hack:
+ *
+ * The pixels formats of Cairo and GdkPixbuf are different.
+ * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied,
+ * and successive bytes of a single pixel contain R, G, B and A components.
+ * Cairo accesses pixels as 32-bit ints, alpha is premultiplied,
+ * and each int contains as 0xAARRGGBB, accessed with bitwise operations.
+ *
+ * In other words, on a little endian system, a GdkPixbuf will contain:
+ * char *data = "rgbargbargba...."
+ * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... }
+ * while a Cairo image surface will contain:
+ * char *data = "bgrabgrabgra...."
+ * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... }
+ *
+ * It is possible to convert between these two formats (almost) losslessly.
+ * Some color information from partially transparent regions of the image
+ * is lost, but the result when displaying this image will remain the same.
+ *
+ * The class allows interoperation between GdkPixbuf
+ * and Cairo surfaces without creating a copy of the image.
+ * This is implemented by creating a GdkPixbuf and a Cairo image surface
+ * which share their data. Depending on what is needed at a given time,
+ * the pixels are converted in place to the Cairo or the GdkPixbuf format.
+ */
+
+/** Create a pixbuf from a Cairo surface.
+ * The constructor takes ownership of the passed surface,
+ * so it should not be destroyed. */
+Pixbuf::Pixbuf(cairo_surface_t *s)
+ : _pixbuf(gdk_pixbuf_new_from_data(
+ cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8,
+ cairo_image_surface_get_width(s), cairo_image_surface_get_height(s),
+ cairo_image_surface_get_stride(s), NULL, NULL))
+ , _surface(s)
+ , _mod_time(0)
+ , _pixel_format(PF_CAIRO)
+ , _cairo_store(true)
+{}
+
+/** Create a pixbuf from a GdkPixbuf.
+ * The constructor takes ownership of the passed GdkPixbuf reference,
+ * so it should not be unrefed. */
+Pixbuf::Pixbuf(GdkPixbuf *pb)
+ : _pixbuf(pb)
+ , _surface(0)
+ , _mod_time(0)
+ , _pixel_format(PF_GDK)
+ , _cairo_store(false)
+{
+ _forceAlpha();
+ _surface = cairo_image_surface_create_for_data(
+ gdk_pixbuf_get_pixels(_pixbuf), CAIRO_FORMAT_ARGB32,
+ gdk_pixbuf_get_width(_pixbuf), gdk_pixbuf_get_height(_pixbuf), gdk_pixbuf_get_rowstride(_pixbuf));
+}
+
+Pixbuf::Pixbuf(Inkscape::Pixbuf const &other)
+ : _pixbuf(gdk_pixbuf_copy(other._pixbuf))
+ , _surface(cairo_image_surface_create_for_data(
+ gdk_pixbuf_get_pixels(_pixbuf), CAIRO_FORMAT_ARGB32,
+ gdk_pixbuf_get_width(_pixbuf), gdk_pixbuf_get_height(_pixbuf), gdk_pixbuf_get_rowstride(_pixbuf)))
+ , _mod_time(other._mod_time)
+ , _path(other._path)
+ , _pixel_format(other._pixel_format)
+ , _cairo_store(false)
+{}
+
+Pixbuf::~Pixbuf()
+{
+ if (_cairo_store) {
+ g_object_unref(_pixbuf);
+ cairo_surface_destroy(_surface);
+ } else {
+ cairo_surface_destroy(_surface);
+ g_object_unref(_pixbuf);
+ }
+}
+
+Pixbuf *Pixbuf::create_from_data_uri(gchar const *uri_data)
+{
+ Pixbuf *pixbuf = NULL;
+
+ bool data_is_image = false;
+ bool data_is_base64 = false;
+
+ gchar const *data = uri_data;
+
+ while (*data) {
+ if (strncmp(data,"base64",6) == 0) {
+ /* base64-encoding */
+ data_is_base64 = true;
+ data_is_image = true; // Illustrator produces embedded images without MIME type, so we assume it's image no matter what
+ data += 6;
+ }
+ else if (strncmp(data,"image/png",9) == 0) {
+ /* PNG image */
+ data_is_image = true;
+ data += 9;
+ }
+ else if (strncmp(data,"image/jpg",9) == 0) {
+ /* JPEG image */
+ data_is_image = true;
+ data += 9;
+ }
+ else if (strncmp(data,"image/jpeg",10) == 0) {
+ /* JPEG image */
+ data_is_image = true;
+ data += 10;
+ }
+ else if (strncmp(data,"image/jp2",9) == 0) {
+ /* JPEG2000 image */
+ data_is_image = true;
+ data += 9;
+ }
+ else { /* unrecognized option; skip it */
+ while (*data) {
+ if (((*data) == ';') || ((*data) == ',')) {
+ break;
+ }
+ data++;
+ }
+ }
+ if ((*data) == ';') {
+ data++;
+ continue;
+ }
+ if ((*data) == ',') {
+ data++;
+ break;
+ }
+ }
+
+ if ((*data) && data_is_image && data_is_base64) {
+ GdkPixbuf *buf = NULL;
+ GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
+
+ if (!loader) return NULL;
+
+ gsize decoded_len = 0;
+ guchar *decoded = g_base64_decode(data, &decoded_len);
+
+ if (gdk_pixbuf_loader_write(loader, decoded, decoded_len, NULL)) {
+ gdk_pixbuf_loader_close(loader, NULL);
+ buf = gdk_pixbuf_loader_get_pixbuf(loader);
+ if (buf) {
+ g_object_ref(buf);
+ pixbuf = new Pixbuf(buf);
+
+ GdkPixbufFormat *fmt = gdk_pixbuf_loader_get_format(loader);
+ gchar *fmt_name = gdk_pixbuf_format_get_name(fmt);
+ pixbuf->_setMimeData(decoded, decoded_len, fmt_name);
+ g_free(fmt_name);
+ } else {
+ g_free(decoded);
+ }
+ } else {
+ g_free(decoded);
+ }
+ g_object_unref(loader);
+ }
+
+ return pixbuf;
+}
+
+Pixbuf *Pixbuf::create_from_file(std::string const &fn)
+{
+ Pixbuf *pb = NULL;
+ // test correctness of filename
+ if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) {
+ return NULL;
+ }
+ struct stat stdir;
+ int val = g_stat(fn.c_str(), &stdir);
+ if (val == 0 && stdir.st_mode & S_IFDIR){
+ return NULL;
+ }
+
+ // 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;
+
+ if (g_file_get_contents(fn.c_str(), &data, &len, &error)) {
+
+ GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
+ gdk_pixbuf_loader_write(loader, (guchar *) data, len, NULL);
+ gdk_pixbuf_loader_close(loader, NULL);
+
+ GdkPixbuf *buf = gdk_pixbuf_loader_get_pixbuf(loader);
+ if (buf) {
+ g_object_ref(buf);
+ pb = new Pixbuf(buf);
+ pb->_mod_time = stdir.st_mtime;
+ pb->_path = fn;
+
+ GdkPixbufFormat *fmt = gdk_pixbuf_loader_get_format(loader);
+ gchar *fmt_name = gdk_pixbuf_format_get_name(fmt);
+ pb->_setMimeData((guchar *) data, len, fmt_name);
+ g_free(fmt_name);
+ } else {
+ g_free(data);
+ }
+ g_object_unref(loader);
+
+ // TODO: we could also read DPI, ICC profile, gamma correction, and other information
+ // from the file. This can be done by using format-specific libraries e.g. libpng.
+ } else {
+ return NULL;
+ }
+
+ return pb;
+}
+
+/**
+ * Converts the pixbuf to GdkPixbuf pixel format.
+ * The returned pixbuf can be used e.g. in calls to gdk_pixbuf_save().
+ */
+GdkPixbuf *Pixbuf::getPixbufRaw(bool convert_format)
+{
+ if (convert_format) {
+ ensurePixelFormat(PF_GDK);
+ }
+ return _pixbuf;
+}
+
+/**
+ * Converts the pixbuf to Cairo pixel format and returns an image surface
+ * which can be used as a source.
+ *
+ * The returned surface is owned by the GdkPixbuf and should not be freed.
+ * Calling this function causes the pixbuf to be unsuitable for use
+ * with GTK drawing functions until ensurePixelFormat(Pixbuf::PIXEL_FORMAT_PIXBUF) is called.
+ */
+cairo_surface_t *Pixbuf::getSurfaceRaw(bool convert_format)
+{
+ if (convert_format) {
+ ensurePixelFormat(PF_CAIRO);
+ }
+ return _surface;
+}
+
+/* Declaring this function in the header requires including <gdkmm/pixbuf.h>,
+ * which stupidly includes <glibmm.h> which in turn pulls in <glibmm/threads.h>.
+ * However, since glib 2.32, <glibmm/threads.h> has to be included before <glib.h>
+ * when compiling with G_DISABLE_DEPRECATED, as we do in non-release builds.
+ * This necessitates spamming a lot of files with #include <glibmm/threads.h>
+ * at the top.
+ *
+ * Since we don't really use gdkmm, do not define this function for now. */
+
+/*
+Glib::RefPtr<Gdk::Pixbuf> Pixbuf::getPixbuf(bool convert_format = true)
+{
+ g_object_ref(_pixbuf);
+ Glib::RefPtr<Gdk::Pixbuf> p(getPixbuf(convert_format));
+ return p;
+}
+*/
+
+Cairo::RefPtr<Cairo::Surface> Pixbuf::getSurface(bool convert_format)
+{
+ Cairo::RefPtr<Cairo::Surface> p(new Cairo::Surface(getSurfaceRaw(convert_format), false));
+ return p;
+}
+
+/** Retrieves the original compressed data for the surface, if any.
+ * The returned data belongs to the object and should not be freed. */
+guchar const *Pixbuf::getMimeData(gsize &len, std::string &mimetype) const
+{
+ static gchar const *mimetypes[] = {
+ CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL };
+ static guint mimetypes_len = g_strv_length(const_cast<gchar**>(mimetypes));
+
+ guchar const *data = NULL;
+
+ for (guint i = 0; i < mimetypes_len; ++i) {
+ unsigned long len_long = 0;
+ cairo_surface_get_mime_data(const_cast<cairo_surface_t*>(_surface), mimetypes[i], &data, &len);
+ len = len_long; // this assumes that the added range of long is not needed. the code below assumes gsize range of values is sufficient.
+ if (data != NULL) {
+ mimetype = mimetypes[i];
+ break;
+ }
+ }
+
+ return data;
+}
+
+int Pixbuf::width() const {
+ return gdk_pixbuf_get_width(const_cast<GdkPixbuf*>(_pixbuf));
+}
+int Pixbuf::height() const {
+ return gdk_pixbuf_get_height(const_cast<GdkPixbuf*>(_pixbuf));
+}
+int Pixbuf::rowstride() const {
+ return gdk_pixbuf_get_rowstride(const_cast<GdkPixbuf*>(_pixbuf));
+}
+guchar const *Pixbuf::pixels() const {
+ return gdk_pixbuf_get_pixels(const_cast<GdkPixbuf*>(_pixbuf));
+}
+guchar *Pixbuf::pixels() {
+ return gdk_pixbuf_get_pixels(_pixbuf);
+}
+void Pixbuf::markDirty() {
+ cairo_surface_mark_dirty(_surface);
+}
+
+void Pixbuf::_forceAlpha()
+{
+ if (gdk_pixbuf_get_has_alpha(_pixbuf)) return;
+
+ GdkPixbuf *old = _pixbuf;
+ _pixbuf = gdk_pixbuf_add_alpha(old, FALSE, 0, 0, 0);
+ g_object_unref(old);
+}
+
+void Pixbuf::_setMimeData(guchar *data, gsize len, Glib::ustring const &format)
+{
+ gchar const *mimetype = NULL;
+
+ if (format == "jpeg") {
+ mimetype = CAIRO_MIME_TYPE_JPEG;
+ } else if (format == "jpeg2000") {
+ mimetype = CAIRO_MIME_TYPE_JP2;
+ } else if (format == "png") {
+ mimetype = CAIRO_MIME_TYPE_PNG;
+ }
+
+ if (mimetype != NULL) {
+ cairo_surface_set_mime_data(_surface, mimetype, data, len, g_free, data);
+ //g_message("Setting Cairo MIME data: %s", mimetype);
+ } else {
+ g_free(data);
+ //g_message("Not setting Cairo MIME data: unknown format %s", name.c_str());
+ }
+}
+
+void Pixbuf::ensurePixelFormat(PixelFormat fmt)
+{
+ if (_pixel_format == PF_GDK) {
+ if (fmt == PF_GDK) {
+ return;
+ }
+ if (fmt == PF_CAIRO) {
+ convert_pixels_pixbuf_to_argb32(
+ gdk_pixbuf_get_pixels(_pixbuf),
+ gdk_pixbuf_get_width(_pixbuf),
+ gdk_pixbuf_get_height(_pixbuf),
+ gdk_pixbuf_get_rowstride(_pixbuf));
+ _pixel_format = fmt;
+ return;
+ }
+ g_assert_not_reached();
+ }
+ if (_pixel_format == PF_CAIRO) {
+ if (fmt == PF_GDK) {
+ convert_pixels_argb32_to_pixbuf(
+ gdk_pixbuf_get_pixels(_pixbuf),
+ gdk_pixbuf_get_width(_pixbuf),
+ gdk_pixbuf_get_height(_pixbuf),
+ gdk_pixbuf_get_rowstride(_pixbuf));
+ _pixel_format = fmt;
+ return;
+ }
+ if (fmt == PF_CAIRO) {
+ return;
+ }
+ g_assert_not_reached();
+ }
+ g_assert_not_reached();
+}
+
} // namespace Inkscape
/*
@@ -371,129 +749,6 @@ ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m)
cairo_pattern_set_matrix(cp, &cm);
}
-void
-ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y)
-{
- cairo_surface_t *pbs = ink_cairo_surface_get_for_pixbuf(pb);
- cairo_set_source_surface(ct, pbs, x, y);
-}
-
-/* The functions below implement the following hack:
- *
- * The pixels formats of Cairo and GdkPixbuf are different.
- * GdkPixbuf accesses pixels as bytes, alpha is not premultiplied,
- * and successive bytes of a single pixel contain R, G, B and A components.
- * Cairo accesses pixels as 32-bit ints, alpha is premultiplied,
- * and each int contains as 0xAARRGGBB, accessed with bitwise operations.
- *
- * In other words, on a little endian system, a GdkPixbuf will contain:
- * char *data = "rgbargbargba...."
- * int *data = { 0xAABBGGRR, 0xAABBGGRR, 0xAABBGGRR, ... }
- * while a Cairo image surface will contain:
- * char *data = "bgrabgrabgra...."
- * int *data = { 0xAARRGGBB, 0xAARRGGBB, 0xAARRGGBB, ... }
- *
- * It is possible to convert between these two formats (almost) losslessly.
- * Some color information from partially transparent regions of the image
- * is lost, but the result when displaying this image will remain the same.
- *
- * The functions below allow interoperation between GdkPixbuf
- * and Cairo surfaces, allowing pixbufs to be used as Cairo sources,
- * and saving Cairo surfaces using GdkPixbuf APIs.
- * This is implemented by creating a GdkPixbuf and a Cairo image surface
- * which share their data. Depending on what is needed at a given time,
- * the pixels are converted in place to the Cairo or the GdkPixbuf format.
- * In this way, only one copy of the image data is needed.
- *
- * Given either a GdkPixbuf or a Cairo surface, these functions create
- * the other object and convert to its format. The returned object should be
- * freed using cairo_surface_destroy or g_object_unref when it's no longer
- * needed.
- *
- * Memory ownership semantics:
- * Regardless of whether the pixels are stored in memory originally belonging
- * to Cairo surface or to GdkPixbuf, the GdkPixbuf is the master object.
- * To free the memory, unref the GdkPixbuf ONLY.
- */
-
-/**
- * Converts the pixbuf to Cairo pixel format and returns an image surface
- * which can be used as a source.
- *
- * The returned surface is owned by the GdkPixbuf and should not be freed.
- * Calling this function causes the pixbuf to be unsuitable for use
- * with GTK drawing functions until ink_pixbuf_ensure_normal() is called.
- *
- * @bug You have to call g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL)
- * when unrefing the last reference to the pixbuf. Otherwise there will be
- * crashes, because cairo_surface_destroy is called after the pixbuf data
- * is already freed.
- */
-cairo_surface_t *
-ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb)
-{
- cairo_surface_t *pbs =
- reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface"));
-
- ink_pixbuf_ensure_argb32(pb);
-
- if (pbs == NULL) {
- guchar *data = gdk_pixbuf_get_pixels(pb);
- int w = gdk_pixbuf_get_width(pb);
- int h = gdk_pixbuf_get_height(pb);
- int stride = gdk_pixbuf_get_rowstride(pb);
-
- // create a surface that stores the data
- pbs = cairo_image_surface_create_for_data(
- data, CAIRO_FORMAT_ARGB32, w, h, stride);
-
- g_object_set_data_full(G_OBJECT(pb), "cairo_surface", pbs, (GDestroyNotify) cairo_surface_destroy);
- cairo_surface_set_user_data(pbs, &ink_pixbuf_key, pb, NULL);
- }
-
- return pbs;
-}
-
-/**
- * Converts the Cairo surface to GdkPixbuf pixel format.
- * GdkPixbuf takes ownership of the passed surface reference,
- * so it should NOT be freed after calling this function.
- */
-GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s)
-{
- GdkPixbuf *pb = reinterpret_cast<GdkPixbuf*>(cairo_surface_get_user_data(s, &ink_pixbuf_key));
- if (pb == NULL) {
- pb = gdk_pixbuf_new_from_data(
- cairo_image_surface_get_data(s), GDK_COLORSPACE_RGB, TRUE, 8,
- cairo_image_surface_get_width(s), cairo_image_surface_get_height(s),
- cairo_image_surface_get_stride(s), NULL, NULL);
-
- g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free);
- g_object_set_data_full(G_OBJECT(pb), "cairo_surface", s, (GDestroyNotify) cairo_surface_destroy);
-
- cairo_surface_set_user_data(s, &ink_pixbuf_key, pb, NULL);
- } else {
- g_warning("Received surface which is already owned by GdkPixbuf");
- g_object_ref(pb);
- }
-
- ink_pixbuf_ensure_normal(pb);
-
- return pb;
-}
-
-/**
- * Cleanup function for GdkPixbuf.
- * This function should be passed as the GdkPixbufDestroyNotify parameter
- * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by
- * a Cairo surface.
- */
-void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data)
-{
- cairo_surface_t *surface = reinterpret_cast<cairo_surface_t*>(data);
- cairo_surface_destroy(surface);
-}
-
/**
* Create an exact copy of a surface.
* Creates a surface that has the same type, content type, dimensions and contents
@@ -833,6 +1088,44 @@ ink_cairo_pattern_create_checkerboard()
return p;
}
+/**
+ * Converts the Cairo surface to a GdkPixbuf pixel format,
+ * without allocating extra memory.
+ *
+ * This function is intended mainly for creating previews displayed by GTK.
+ * For loading images for display on the canvas, use the Inkscape::Pixbuf object.
+ *
+ * The returned GdkPixbuf takes ownership of the passed surface reference,
+ * so it should NOT be freed after calling this function.
+ */
+GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s)
+{
+ guchar *pixels = cairo_image_surface_get_data(s);
+ int w = cairo_image_surface_get_width(s);
+ int h = cairo_image_surface_get_height(s);
+ int rs = cairo_image_surface_get_stride(s);
+
+ convert_pixels_argb32_to_pixbuf(pixels, w, h, rs);
+
+ GdkPixbuf *pb = gdk_pixbuf_new_from_data(
+ pixels, GDK_COLORSPACE_RGB, TRUE, 8,
+ w, h, rs, ink_cairo_pixbuf_cleanup, s);
+
+ return pb;
+}
+
+/**
+ * Cleanup function for GdkPixbuf.
+ * This function should be passed as the GdkPixbufDestroyNotify parameter
+ * to gdk_pixbuf_new_from_data when creating a GdkPixbuf backed by
+ * a Cairo surface.
+ */
+static void ink_cairo_pixbuf_cleanup(guchar * /*pixels*/, void *data)
+{
+ cairo_surface_t *surface = static_cast<cairo_surface_t*>(data);
+ cairo_surface_destroy(surface);
+}
+
/* The following two functions use "from" instead of "to", because when you write:
val1 = argb32_from_pixbuf(val1);
the name of the format is closer to the value in that format. */
diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h
index 289d4e01f..505e2ca77 100644
--- a/src/display/cairo-utils.h
+++ b/src/display/cairo-utils.h
@@ -12,14 +12,15 @@
#ifndef SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H
#define SEEN_INKSCAPE_DISPLAY_CAIRO_UTILS_H
+#include <boost/noncopyable.hpp>
+//#include <glibmm/threads.h> // workaround
#include <glib.h>
#include <cairomm/cairomm.h>
+//#include <gdkmm/pixbuf.h>
#include <2geom/forward.h>
#include "style.h"
struct SPColor;
-struct _GdkPixbuf;
-typedef struct _GdkPixbuf GdkPixbuf;
namespace Inkscape {
@@ -80,15 +81,61 @@ public:
static Cairo::RefPtr<CairoContext> create(Cairo::RefPtr<Cairo::Surface> const &target);
};
-} // namespace Inkscape
+/** Class to hold image data for raster images.
+ * Allows easy interoperation with GdkPixbuf and Cairo. */
+class Pixbuf {
+public:
+ enum PixelFormat {
+ PF_CAIRO = 1,
+ PF_GDK = 2,
+ PF_LAST
+ };
+
+ explicit Pixbuf(cairo_surface_t *s);
+ explicit Pixbuf(GdkPixbuf *pb);
+ Pixbuf(Inkscape::Pixbuf const &other);
+ ~Pixbuf();
+
+ GdkPixbuf *getPixbufRaw(bool convert_format = true);
+ //Glib::RefPtr<Gdk::Pixbuf> getPixbuf(bool convert_format = true);
+
+ cairo_surface_t *getSurfaceRaw(bool convert_format = true);
+ Cairo::RefPtr<Cairo::Surface> getSurface(bool convert_format = true);
+
+ int width() const;
+ int height() const;
+ int rowstride() const;
+ guchar const *pixels() const;
+ guchar *pixels();
+ void markDirty();
+
+ bool hasMimeData() const;
+ guchar const *getMimeData(gsize &len, std::string &mimetype) const;
+ std::string const &originalPath() const { return _path; }
+ time_t modificationTime() const { return _mod_time; }
-enum InkPixelFormat {
- INK_PIXEL_FORMAT_NONE,
- INK_PIXEL_FORMAT_CAIRO,
- INK_PIXEL_FORMAT_PIXBUF,
- INK_PIXEL_FORMAT_LAST
+ PixelFormat pixelFormat() const { return _pixel_format; }
+ void ensurePixelFormat(PixelFormat fmt);
+
+ static Pixbuf *create_from_data_uri(gchar const *uri);
+ static Pixbuf *create_from_file(std::string const &fn);
+
+private:
+ void _ensurePixelsARGB32();
+ void _ensurePixelsPixbuf();
+ void _forceAlpha();
+ void _setMimeData(guchar *data, gsize len, Glib::ustring const &format);
+
+ GdkPixbuf *_pixbuf;
+ cairo_surface_t *_surface;
+ time_t _mod_time;
+ std::string _path;
+ PixelFormat _pixel_format;
+ bool _cairo_store;
};
+} // namespace Inkscape
+
// TODO: these declarations may not be needed in the header
extern cairo_user_data_key_t ink_color_interpolation_key;
extern cairo_user_data_key_t ink_pixbuf_key;
@@ -102,7 +149,6 @@ void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacit
void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba);
void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m);
void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m);
-void ink_cairo_set_source_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y);
void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &);
void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &);
@@ -125,13 +171,9 @@ int ink_cairo_surface_linear_to_srgb(cairo_surface_t *surface);
cairo_pattern_t *ink_cairo_pattern_create_checkerboard();
+GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s);
void convert_pixels_pixbuf_to_argb32(guchar *data, int w, int h, int rs);
void convert_pixels_argb32_to_pixbuf(guchar *data, int w, int h, int rs);
-void ink_pixbuf_ensure_argb32(GdkPixbuf *);
-void ink_pixbuf_ensure_normal(GdkPixbuf *);
-cairo_surface_t *ink_cairo_surface_get_for_pixbuf(GdkPixbuf *pb);
-GdkPixbuf *ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s);
-void ink_cairo_pixbuf_cleanup(guchar *pixels, void *surface);
G_GNUC_CONST guint32 argb32_from_pixbuf(guint32 in);
G_GNUC_CONST guint32 pixbuf_from_argb32(guint32 in);
diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp
index 46f066b8e..0b661a450 100644
--- a/src/display/drawing-image.cpp
+++ b/src/display/drawing-image.cpp
@@ -22,34 +22,23 @@ namespace Inkscape {
DrawingImage::DrawingImage(Drawing &drawing)
: DrawingItem(drawing)
, _pixbuf(NULL)
- , _surface(NULL) // this is owned by _pixbuf!
, _style(NULL)
, _new_surface(NULL)
{}
DrawingImage::~DrawingImage()
{
- if (_style)
+ if (_style) {
sp_style_unref(_style);
- if (_pixbuf) {
- if (_new_surface) cairo_surface_destroy(_new_surface);
- g_object_unref(_pixbuf);
}
+
+ // _pixbuf is owned by SPImage - do not delete it
}
void
-DrawingImage::setARGB32Pixbuf(GdkPixbuf *pb)
+DrawingImage::setPixbuf(Inkscape::Pixbuf *pb)
{
- // when done in this order, it won't break if pb == image->pixbuf and the refcount is 1
- if (pb != NULL) {
- g_object_ref (pb);
- }
- if (_pixbuf != NULL) {
- g_object_unref(_pixbuf);
- // unrefing the pixbuf also destroys surface
- }
_pixbuf = pb;
- _surface = pb ? ink_cairo_surface_get_for_pixbuf(pb) : NULL;
_markForUpdate(STATE_ALL, false);
}
@@ -86,8 +75,8 @@ DrawingImage::bounds() const
{
if (!_pixbuf) return _clipbox;
- double pw = gdk_pixbuf_get_width(_pixbuf);
- double ph = gdk_pixbuf_get_height(_pixbuf);
+ double pw = _pixbuf->width();
+ double ph = _pixbuf->height();
double vw = pw * _scale[Geom::X];
double vh = ph * _scale[Geom::Y];
Geom::Point wh(vw, vh);
@@ -143,14 +132,16 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar
// See https://bugs.launchpad.net/inkscape/+bug/804162
Geom::Scale expansion(_ctm.expansion());
- int orgwidth = cairo_image_surface_get_width(_surface);
- int orgheight = cairo_image_surface_get_height(_surface);
+ int orgwidth = _pixbuf->width();
+ int orgheight = _pixbuf->height();
if (_scale[Geom::X]*expansion[Geom::X]*orgwidth*255.0<1.0 || _scale[Geom::Y]*expansion[Geom::Y]*orgheight*255.0<1.0) {
// Resized image too small to actually see anything
return RENDER_OK;
}
-
+
+ _pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_CAIRO);
+
// Split scale*expansion in a part that is <= 1.0 and a part that is >= 1.0. We only take care of the part <= 1.0.
Geom::Scale scaleExpansionSmall(std::min<Geom::Coord>(fabs(_scale[Geom::X]*expansion[Geom::X]),1),std::min<Geom::Coord>(fabs(_scale[Geom::Y]*expansion[Geom::Y]),1));
Geom::Scale scaleExpansionLarge(_scale[Geom::X]*expansion[Geom::X]/scaleExpansionSmall[Geom::X],_scale[Geom::Y]*expansion[Geom::Y]/scaleExpansionSmall[Geom::Y]);
@@ -161,7 +152,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar
ct.scale(expansion.inverse()); // This should not include scale (see derivation above)
ct.translate(_origin*expansion);
ct.scale(scaleExpansionLarge);
- ct.setSource(_surface, 0, 0);
+ ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0);
} else if (!_new_surface || (newSize-_rescaledSize).length()>0.1) {
// Rescaled image is sufficiently different from cached image to recompute
if (_new_surface) cairo_surface_destroy(_new_surface);
@@ -200,13 +191,13 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar
}
}
+ cairo_surface_t *surface = _pixbuf->getSurfaceRaw();
_new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, newwidth,newheight);
- unsigned char * orgdata = cairo_image_surface_get_data(_surface);
+ unsigned char * orgdata = cairo_image_surface_get_data(surface);
unsigned char * newdata = cairo_image_surface_get_data(_new_surface);
- int orgstride = cairo_image_surface_get_stride(_surface);
+ int orgstride = cairo_image_surface_get_stride(surface);
int newstride = cairo_image_surface_get_stride(_new_surface);
-
- //cairo_surface_flush(_surface);
+
cairo_surface_flush(_new_surface);
for(int y=0; y<newheight; y++) {
@@ -245,7 +236,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar
// TODO: If Cairo's problems are gone, uncomment the following:
//ct.translate(_origin);
//ct.scale(_scale);
- //ct.setSource(_surface, 0, 0);
+ //ct.setSource(_pixbuf->getSurfaceRaw(), 0, 0);
//ct.paint(_opacity);
ct.paint();
@@ -315,10 +306,10 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/)
return NULL;
} else {
- unsigned char *const pixels = gdk_pixbuf_get_pixels(_pixbuf);
- int width = gdk_pixbuf_get_width(_pixbuf);
- int height = gdk_pixbuf_get_height(_pixbuf);
- int rowstride = gdk_pixbuf_get_rowstride(_pixbuf);
+ unsigned char *const pixels = _pixbuf->pixels();
+ int width = _pixbuf->width();
+ int height = _pixbuf->height();
+ int rowstride = _pixbuf->rowstride();
Geom::Point tp = p * _ctm.inverse();
Geom::Rect r = bounds();
@@ -336,8 +327,17 @@ DrawingImage::_pickItem(Geom::Point const &p, double delta, unsigned /*sticky*/)
unsigned char *pix_ptr = pixels + iy * rowstride + ix * 4;
// pick if the image is less than 99% transparent
- float alpha = (pix_ptr[3] / 255.0f) * _opacity;
- return alpha > 0.01 ? this : NULL;
+ guint32 alpha = 0;
+ if (_pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) {
+ guint32 px = *reinterpret_cast<guint32 const *>(pix_ptr);
+ alpha = (px & 0xff000000) >> 24;
+ } else if (_pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_GDK) {
+ alpha = pix_ptr[3];
+ } else {
+ throw std::runtime_error("Unrecognized pixel format");
+ }
+ float alpha_f = (alpha / 255.0f) * _opacity;
+ return alpha_f > 0.01 ? this : NULL;
}
}
diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h
index 593185c97..58e6de72e 100644
--- a/src/display/drawing-image.h
+++ b/src/display/drawing-image.h
@@ -19,6 +19,7 @@
#include "display/drawing-item.h"
namespace Inkscape {
+class Pixbuf;
class DrawingImage
: public DrawingItem
@@ -27,7 +28,7 @@ public:
DrawingImage(Drawing &drawing);
~DrawingImage();
- void setARGB32Pixbuf(GdkPixbuf *pb);
+ void setPixbuf(Inkscape::Pixbuf *pb);
void setStyle(SPStyle *style);
void setScale(double sx, double sy);
void setOrigin(Geom::Point const &o);
@@ -41,8 +42,7 @@ protected:
DrawingItem *stop_at);
virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags);
- GdkPixbuf *_pixbuf;
- cairo_surface_t *_surface;
+ Inkscape::Pixbuf *_pixbuf;
SPStyle *_style;
cairo_surface_t *_new_surface; // Part of hack around Cairo bug
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp
index b9d73f0ad..4ca4cd07c 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -30,6 +30,7 @@ FilterImage::FilterImage()
: SVGElem(0)
, document(0)
, feImageHref(0)
+ , image(0)
, broken_ref(false)
{ }
@@ -41,7 +42,7 @@ FilterImage::~FilterImage()
{
if (feImageHref)
g_free(feImageHref);
- g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL);
+ delete image;
}
void FilterImage::render_cairo(FilterSlot &slot)
@@ -131,50 +132,38 @@ void FilterImage::render_cairo(FilterSlot &slot)
// External image, like <image>
if (!image && !broken_ref) {
broken_ref = true;
- try {
- /* TODO: If feImageHref is absolute, then use that (preferably handling the
- * case that it's not a file URI). Otherwise, go up the tree looking
- * for an xml:base attribute, and use that as the base URI for resolving
- * the relative feImageHref URI. Otherwise, if document->base is valid,
- * then use that as the base URI. Otherwise, use feImageHref directly
- * (i.e. interpreting it as relative to our current working directory).
- * (See http://www.w3.org/TR/xmlbase/#resolution .) */
- gchar *fullname = feImageHref;
- if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) {
- // Try to load from relative postion combined with document base
- if( document ) {
- fullname = g_build_filename( document->getBase(), feImageHref, NULL );
- }
- }
- if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) {
- // Should display Broken Image png.
- g_warning("FilterImage::render: Can not find: %s", feImageHref );
- return;
+
+ /* TODO: If feImageHref is absolute, then use that (preferably handling the
+ * case that it's not a file URI). Otherwise, go up the tree looking
+ * for an xml:base attribute, and use that as the base URI for resolving
+ * the relative feImageHref URI. Otherwise, if document->base is valid,
+ * then use that as the base URI. Otherwise, use feImageHref directly
+ * (i.e. interpreting it as relative to our current working directory).
+ * (See http://www.w3.org/TR/xmlbase/#resolution .) */
+ gchar *fullname = feImageHref;
+ if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) {
+ // Try to load from relative postion combined with document base
+ if( document ) {
+ fullname = g_build_filename( document->getBase(), feImageHref, NULL );
}
- image = Gdk::Pixbuf::create_from_file(fullname);
- if( fullname != feImageHref ) g_free( fullname );
}
- catch (const Glib::FileError & e)
- {
- g_warning("caught Glib::FileError in FilterImage::render: %s", e.what().data() );
+ if ( !g_file_test( fullname, G_FILE_TEST_EXISTS ) ) {
+ // Should display Broken Image png.
+ g_warning("FilterImage::render: Can not find: %s", feImageHref );
return;
}
- catch (const Gdk::PixbufError & e)
- {
- g_warning("Gdk::PixbufError in FilterImage::render: %s", e.what().data() );
+ image = Inkscape::Pixbuf::create_from_file(fullname);
+ if( fullname != feImageHref ) g_free( fullname );
+
+ if ( !image ) {
+ g_warning("FilterImage::render: failed to load image: %s", feImageHref);
return;
}
- if ( !image ) return;
broken_ref = false;
-
- bool has_alpha = image->get_has_alpha();
- if (!has_alpha) {
- image = image->add_alpha(false, 0, 0, 0);
- }
}
- cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(image->gobj());
+ cairo_surface_t *image_surface = image->getSurfaceRaw();
Geom::Rect sa = slot.get_slot_area();
cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
@@ -199,7 +188,7 @@ void FilterImage::render_cairo(FilterSlot &slot)
// Check aspect ratio of image vs. viewport
double feAspect = feImageHeight/feImageWidth;
- double aspect = (double)image->get_height()/(double)image->get_width();
+ double aspect = (double)image->height()/(double)image->width();
bool ratio = (feAspect < aspect);
double ax, ay; // Align side
@@ -274,8 +263,8 @@ void FilterImage::render_cairo(FilterSlot &slot)
}
}
- double scaleX = feImageWidth / image->get_width();
- double scaleY = feImageHeight / image->get_height();
+ double scaleX = feImageWidth / image->width();
+ double scaleY = feImageHeight / image->height();
cairo_translate(ct, feImageX, feImageY);
cairo_scale(ct, scaleX, scaleY);
@@ -302,8 +291,8 @@ void FilterImage::set_href(const gchar *href){
if (feImageHref) g_free (feImageHref);
feImageHref = (href) ? g_strdup (href) : NULL;
- g_object_set_data(G_OBJECT(image->gobj()), "cairo_surface", NULL);
- image.reset();
+ delete image;
+ image = NULL;
broken_ref = false;
}
diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h
index f45f42265..69691ac99 100644
--- a/src/display/nr-filter-image.h
+++ b/src/display/nr-filter-image.h
@@ -12,14 +12,14 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <gdkmm/pixbuf.h>
#include "display/nr-filter-primitive.h"
-#include <glibmm/refptr.h>
class SPDocument;
class SPItem;
namespace Inkscape {
+class Pixbuf;
+
namespace Filters {
class FilterSlot;
@@ -43,7 +43,7 @@ public:
private:
SPDocument *document;
gchar *feImageHref;
- Glib::RefPtr<Gdk::Pixbuf> image;
+ Inkscape::Pixbuf *image;
float feImageX, feImageY, feImageWidth, feImageHeight;
unsigned int aspect_align, aspect_clip;
bool broken_ref;
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp
index a950fa177..4f9273cbb 100644
--- a/src/extension/internal/cairo-render-context.cpp
+++ b/src/extension/internal/cairo-render-context.cpp
@@ -1436,7 +1436,7 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con
return true;
}
-bool CairoRenderContext::renderImage(GdkPixbuf *pb,
+bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb,
Geom::Affine const &image_transform, SPStyle const * /*style*/)
{
g_assert( _is_valid );
@@ -1447,13 +1447,13 @@ bool CairoRenderContext::renderImage(GdkPixbuf *pb,
_prepareRenderGraphic();
- int w = gdk_pixbuf_get_width (pb);
- int h = gdk_pixbuf_get_height (pb);
+ int w = pb->width();
+ int h = pb->height();
// TODO: reenable merge_opacity if useful
float opacity = _state->opacity;
- cairo_surface_t *image_surface = ink_cairo_surface_get_for_pixbuf(pb);
+ cairo_surface_t *image_surface = pb->getSurfaceRaw();
if (cairo_surface_status(image_surface)) {
TRACE(("Image surface creation failed:\n%s\n", cairo_status_to_string(cairo_surface_status(image_surface))));
return false;
diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h
index f8426aebe..6fccc71b7 100644
--- a/src/extension/internal/cairo-render-context.h
+++ b/src/extension/internal/cairo-render-context.h
@@ -6,7 +6,7 @@
*/
/*
* Authors:
- * Miklos Erdelyi <erdelyim@gmail.com>
+ * Miklos Erdelyi <erdelyim@gmail.com>
*
* Copyright (C) 2006 Miklos Erdelyi
*
@@ -32,6 +32,8 @@ class SPClipPath;
struct SPMask;
namespace Inkscape {
+class Pixbuf;
+
namespace Extension {
namespace Internal {
@@ -144,7 +146,7 @@ public:
/* Rendering methods */
bool renderPathVector(Geom::PathVector const &pathv, SPStyle const *style, Geom::OptRect const &pbox);
- bool renderImage(GdkPixbuf *pb,
+ bool renderImage(Inkscape::Pixbuf *pb,
Geom::Affine const &image_transform, SPStyle const *style);
bool renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix,
std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style);
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index 3463925b6..eb16a38e1 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -27,6 +27,7 @@
#include <signal.h>
#include <errno.h>
+#include <boost/scoped_ptr.hpp>
#include "libnrtype/Layout-TNG.h"
#include <2geom/transforms.h>
@@ -347,8 +348,8 @@ static void sp_image_render(SPItem *item, CairoRenderContext *ctx)
if (!image->pixbuf) return;
if ((image->width.computed <= 0.0) || (image->height.computed <= 0.0)) return;
- w = gdk_pixbuf_get_width (image->pixbuf);
- h = gdk_pixbuf_get_height (image->pixbuf);
+ w = image->pixbuf->width();
+ h = image->pixbuf->height();
double x = image->x.computed;
double y = image->y.computed;
@@ -497,22 +498,15 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx)
GSList *items = NULL;
items = g_slist_append(items, item);
- GdkPixbuf *pb = sp_generate_internal_bitmap(document, NULL,
- bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y],
- width, height, res, res, (guint32) 0xffffff00, items );
+ boost::scoped_ptr<Inkscape::Pixbuf> pb(
+ sp_generate_internal_bitmap(document, NULL,
+ bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y],
+ width, height, res, res, (guint32) 0xffffff00, items ));
if (pb) {
- TEST(gdk_pixbuf_save( pb, "bitmap.png", "png", NULL, NULL ));
-
- /* TODO: find a way to avoid a duplicate conversion between
- * Cairo and GdkPixbuf pixel formats here.
- * Internally, generate_internal_bitmap creates a Cairo surface,
- * but then converts it to pixbuf format. In turn, renderImage()
- * below converts back to Cairo format.
- */
- ctx->renderImage(pb, t, item->style);
- g_object_unref(pb);
- pb = 0;
+ //TEST(gdk_pixbuf_save( pb, "bitmap.png", "png", NULL, NULL ));
+
+ ctx->renderImage(pb.get(), t, item->style);
}
g_slist_free (items);
}
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
index 826a52ade..770257978 100644
--- a/src/extension/internal/emf-print.cpp
+++ b/src/extension/internal/emf-print.cpp
@@ -53,6 +53,7 @@
#include "sp-gradient.h"
#include "sp-radial-gradient.h"
#include "sp-linear-gradient.h"
+#include "display/cairo-utils.h"
#include "splivarot.h" // pieces for union on shapes
#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path
@@ -333,7 +334,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
U_LOGBRUSH lb;
uint32_t brush, fmode;
MFDrawMode fill_mode;
- GdkPixbuf *pixbuf;
+ Inkscape::Pixbuf *pixbuf;
uint32_t brushStyle;
int hatchType;
U_COLORREF hatchColor;
@@ -462,7 +463,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
int numCt;
U_BITMAPINFOHEADER Bmih;
PU_BITMAPINFO Bmi;
- rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!!
+ rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!!
colortype = U_BCBM_COLOR32;
(void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1);
// Not sure why the next swap is needed because the preceding does it, and the code is identical
@@ -528,7 +529,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
int linejoin = 0;
uint32_t pen;
uint32_t brushStyle;
- GdkPixbuf *pixbuf;
+ Inkscape::Pixbuf *pixbuf;
int hatchType;
U_COLORREF hatchColor;
U_COLORREF bkColor;
@@ -565,7 +566,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor);
if (pixbuf) {
brushStyle = U_BS_DIBPATTERN;
- rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!!
+ rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!!
colortype = U_BCBM_COLOR32;
(void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1);
// Not sure why the next swap is needed because the preceding does it, and the code is identical
diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp
index 117c2fe39..87cf8a9cc 100644
--- a/src/extension/internal/gdkpixbuf-input.cpp
+++ b/src/extension/internal/gdkpixbuf-input.cpp
@@ -1,6 +1,7 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <boost/scoped_ptr.hpp>
#include <glib/gprintf.h>
#include <glibmm/i18n.h>
#include "document-private.h"
@@ -14,15 +15,11 @@
#include "document-undo.h"
#include "util/units.h"
#include "image-resolution.h"
+#include "display/cairo-utils.h"
#include <set>
namespace Inkscape {
-namespace IO {
-// this is defined in sp-image.cpp
-GdkPixbuf* pixbuf_new_from_file(char const *filename, time_t &modTime, gchar*& pixPath);
-}
-
namespace Extension {
namespace Internal {
@@ -47,9 +44,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
}
SPDocument *doc = NULL;
- gchar *pixpath = NULL;
- time_t dummy;
- GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file(uri, dummy, pixpath);
+ boost::scoped_ptr<Inkscape::Pixbuf> pb(Inkscape::Pixbuf::create_from_file(uri));
// TODO: the pixbuf is created again from the base64-encoded attribute in SPImage.
// Find a way to create the pixbuf only once.
@@ -59,8 +54,8 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
bool saved = DocumentUndo::getUndoSensitive(doc);
DocumentUndo::setUndoSensitive(doc, false); // no need to undo in this temporary document
- double width = gdk_pixbuf_get_width(pb);
- double height = gdk_pixbuf_get_height(pb);
+ double width = pb->width();
+ double height = pb->height();
double defaultxdpi = prefs->getDouble("/dialogs/import/defaultxdpi/value", Inkscape::Util::Quantity::convert(1, "in", "px"));
bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi");
ImageResolution *ir = 0;
@@ -91,7 +86,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
sp_repr_set_svg_double(image_node, "height", height);
if (embed) {
- sp_embed_image(image_node, pb);
+ sp_embed_image(image_node, pb.get());
} else {
// convert filename to uri
gchar* _uri = g_filename_to_uri(uri, NULL, NULL);
@@ -103,9 +98,6 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
}
}
- g_object_set_data(G_OBJECT(pb), "cairo_surface", NULL);
- g_object_unref(pb);
-
// Add it to the current layer
doc->getRoot()->appendChildRepr(image_node);
Inkscape::GC::release(image_node);
diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp
index 9d080bd96..1e7735410 100644
--- a/src/extension/internal/metafile-print.cpp
+++ b/src/extension/internal/metafile-print.cpp
@@ -266,7 +266,7 @@ void PrintMetafile::hatch_classify(char *name, int *hatchType, U_COLORREF *hatch
// otherwise hatchType is set to -1 and hatchColor is not defined.
//
-void PrintMetafile::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor)
+void PrintMetafile::brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor)
{
if (depth == 0) {
*epixbuf = NULL;
diff --git a/src/extension/internal/metafile-print.h b/src/extension/internal/metafile-print.h
index e64ba92f3..cba4d564d 100644
--- a/src/extension/internal/metafile-print.h
+++ b/src/extension/internal/metafile-print.h
@@ -30,6 +30,8 @@ struct SPGradient;
struct SPObject;
namespace Inkscape {
+class Pixbuf;
+
namespace Extension {
namespace Internal {
@@ -93,7 +95,7 @@ protected:
U_COLORREF weight_colors(U_COLORREF c1, U_COLORREF c2, double t);
void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
- void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
+ void brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
static void swapRBinRGBA(char *px, int pixels);
int hold_gradient(void *gr, int mode);
diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp
index e5816073e..99262b109 100644
--- a/src/extension/internal/wmf-print.cpp
+++ b/src/extension/internal/wmf-print.cpp
@@ -56,6 +56,7 @@
#include "sp-gradient.h"
#include "sp-radial-gradient.h"
#include "sp-linear-gradient.h"
+#include "display/cairo-utils.h"
#include "splivarot.h" // pieces for union on shapes
#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path
@@ -336,7 +337,7 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
U_WLOGBRUSH lb;
uint32_t brush, fmode;
MFDrawMode fill_mode;
- GdkPixbuf *pixbuf;
+ Inkscape::Pixbuf *pixbuf;
uint32_t brushStyle;
int hatchType;
U_COLORREF hatchColor;
@@ -464,7 +465,7 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
int numCt;
U_BITMAPINFOHEADER Bmih;
PU_BITMAPINFO Bmi;
- rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!!
+ rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!!
colortype = U_BCBM_COLOR32;
(void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1);
// Not sure why the next swap is needed because the preceding does it, and the code is identical
@@ -1112,10 +1113,10 @@ unsigned int PrintWmf::image(
g_error("Fatal programming error in PrintWmf::image at EMRHEADER");
}
- x1 = atof(style->object->getAttribute("x"));
- y1 = atof(style->object->getAttribute("y"));
- dw = atof(style->object->getAttribute("width"));
- dh = atof(style->object->getAttribute("height"));
+ x1 = g_ascii_strtod(style->object->getAttribute("x"), NULL);
+ y1 = g_ascii_strtod(style->object->getAttribute("y"), NULL);
+ dw = g_ascii_strtod(style->object->getAttribute("width"), NULL);
+ dh = g_ascii_strtod(style->object->getAttribute("height"), NULL);
Geom::Point pLL(x1, y1);
Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates
diff --git a/src/filters/image.cpp b/src/filters/image.cpp
index 0f15e9d0f..365ad9eb6 100644
--- a/src/filters/image.cpp
+++ b/src/filters/image.cpp
@@ -17,6 +17,8 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+
+#include <sigc++/bind.h>
#include "display/nr-filter-image.h"
#include "uri.h"
#include "uri-references.h"
diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp
index a51a62f42..8e611d197 100644
--- a/src/helper/pixbuf-ops.cpp
+++ b/src/helper/pixbuf-ops.cpp
@@ -16,6 +16,7 @@
#endif
#include <png.h>
+#include <boost/scoped_ptr.hpp>
#include <2geom/transforms.h>
#include "interface.h"
@@ -67,16 +68,14 @@ bool sp_export_jpg_file(SPDocument *doc, gchar const *filename,
unsigned width, unsigned height, double xdpi, double ydpi,
unsigned long bgcolor, double quality,GSList *items)
{
- GdkPixbuf* pixbuf = 0;
- pixbuf = sp_generate_internal_bitmap(doc, filename, x0, y0, x1, y1,
- width, height, xdpi, ydpi,
- bgcolor, items );
+ boost::scoped_ptr<Inkscape::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);
+ gboolean saved = gdk_pixbuf_save(pixbuf->getPixbufRaw(), filename, "jpeg", NULL, "quality", c, NULL);
g_free(c);
- g_object_unref (pixbuf);
return saved;
}
@@ -94,7 +93,7 @@ bool sp_export_jpg_file(SPDocument *doc, gchar const *filename,
@param ydpi
@return the created GdkPixbuf structure or NULL if no memory is allocable
*/
-GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/,
+Inkscape::Pixbuf *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*/,
@@ -103,7 +102,7 @@ GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*
{
if (width == 0 || height == 0) return NULL;
- GdkPixbuf* pixbuf = NULL;
+ Inkscape::Pixbuf *inkpb = NULL;
/* Create new drawing for offscreen rendering*/
Inkscape::Drawing drawing;
drawing.setExact(true);
@@ -146,7 +145,7 @@ GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*
// render items
drawing.render(ct, final_bbox, Inkscape::DrawingItem::RENDER_BYPASS_CACHE);
- pixbuf = ink_pixbuf_create_from_cairo_surface(surface);
+ inkpb = new Inkscape::Pixbuf(surface);
}
else
{
@@ -158,7 +157,7 @@ GdkPixbuf *sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*
// gdk_pixbuf_save (pixbuf, "C:\\temp\\internal.jpg", "jpeg", NULL, "quality","100", NULL);
- return pixbuf;
+ return inkpb;
}
/*
diff --git a/src/helper/pixbuf-ops.h b/src/helper/pixbuf-ops.h
index 44851d388..61a879f9b 100644
--- a/src/helper/pixbuf-ops.h
+++ b/src/helper/pixbuf-ops.h
@@ -15,11 +15,12 @@
#include <glib.h>
class SPDocument;
+namespace Inkscape { class Pixbuf; }
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,
+Inkscape::Pixbuf *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);
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index 868f5a35c..5ee21a738 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -96,6 +96,7 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS;
#include "uri-references.h"
#include "display/curve.h"
#include "display/canvas-bpath.h"
+#include "display/cairo-utils.h"
#include "inkscape-private.h"
#include "path-chemistry.h"
#include "ui/tool/control-point-selection.h"
@@ -3480,9 +3481,10 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop)
}
// Import the image back
- GdkPixbuf *pb = gdk_pixbuf_new_from_file(filepath, NULL);
+ Inkscape::Pixbuf *pb = Inkscape::Pixbuf::create_from_file(filepath);
if (pb) {
// Create the repr for the image
+ // TODO: avoid unnecessary roundtrip between data URI and decoded pixbuf
Inkscape::XML::Node * repr = xml_doc->createElement("svg:image");
sp_embed_image(repr, pb);
if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 90 dpi, snap it to pixel grid
diff --git a/src/sp-image.cpp b/src/sp-image.cpp
index 0e692eb40..57bcd69b9 100644
--- a/src/sp-image.cpp
+++ b/src/sp-image.cpp
@@ -17,9 +17,6 @@
# include "config.h"
#endif
-// This has to be included prior to anything that includes setjmp.h, it croaks otherwise
-#include <png.h>
-
#include <cstring>
#include <algorithm>
#include <string>
@@ -90,8 +87,7 @@ static Inkscape::DrawingItem *sp_image_show (SPItem *item, Inkscape::Drawing &dr
static Geom::Affine sp_image_set_transform (SPItem *item, Geom::Affine const &xform);
static void sp_image_set_curve(SPImage *image);
-static GdkPixbuf *sp_image_repr_read_image( time_t& modTime, gchar*& pixPath, const gchar *href, const gchar *absref, const gchar *base );
-static GdkPixbuf *sp_image_pixbuf_force_rgba (GdkPixbuf * pixbuf);
+static Inkscape::Pixbuf *sp_image_repr_read_image(gchar const *href, gchar const *absref, gchar const *base );
static void sp_image_update_arenaitem (SPImage *img, Inkscape::DrawingImage *ai);
static void sp_image_update_canvas_image (SPImage *image);
static GdkPixbuf * sp_image_repr_read_dataURI (const gchar * uri_data);
@@ -130,65 +126,6 @@ extern guint update_in_progress;
#define DEBUG_MESSAGE_SCISLAC(key, ...)
#endif // DEBUG_LCMS
-namespace Inkscape {
-namespace IO {
-
-GdkPixbuf* pixbuf_new_from_file(const char *filename, time_t &modTime, gchar*& pixPath)
-{
- GdkPixbuf* buf = NULL;
- modTime = 0;
- if ( pixPath ) {
- g_free(pixPath);
- pixPath = NULL;
- }
-
- //test correctness of filename
- if (!g_file_test (filename, G_FILE_TEST_EXISTS)){
- return NULL;
- }
- struct stat stdir;
- int val = g_stat(filename, &stdir);
- if (stdir.st_mode & S_IFDIR){
- g_warning("Linked image file %s is a directory", filename);
- return NULL;
- }
-
- // we need to load the entire pixbuf into memory
- gchar *data = NULL;
- gsize len = 0;
-
- if (g_file_get_contents(filename, &data, &len, NULL)) {
- if (!val) {
- modTime = stdir.st_mtime;
- pixPath = g_strdup(filename);
- }
-
- GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
- gdk_pixbuf_loader_write(loader, (guchar *) data, len, NULL);
- gdk_pixbuf_loader_close(loader, NULL);
-
- buf = gdk_pixbuf_loader_get_pixbuf(loader);
- if (buf) {
- g_object_ref(buf);
- buf = sp_image_pixbuf_force_rgba(buf);
- pixbuf_set_mime_data(buf, (guchar *) data, len, gdk_pixbuf_loader_get_format(loader));
- } else {
- g_free(data);
- g_warning("Error loading pixbuf");
- }
-
- // TODO: we could also read DPI, ICC profile, gamma correction, and other information
- // from the file. This can be done by using format-specific libraries e.g. libpng.
- } else {
- g_warning("Unable to open linked file: %s", filename);
- }
-
- return buf;
-}
-
-}
-}
-
G_DEFINE_TYPE(SPImage, sp_image, SP_TYPE_ITEM);
static void sp_image_class_init( SPImageClass * klass )
@@ -229,8 +166,6 @@ static void sp_image_init( SPImage *image )
image->color_profile = 0;
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
image->pixbuf = 0;
- image->pixPath = 0;
- image->lastMod = 0;
}
static void sp_image_build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr )
@@ -266,8 +201,7 @@ static void sp_image_release( SPObject *object )
}
if (image->pixbuf) {
- g_object_set_data(G_OBJECT(image->pixbuf), "cairo_surface", NULL);
- g_object_unref (image->pixbuf);
+ delete image->pixbuf;
image->pixbuf = NULL;
}
@@ -278,11 +212,6 @@ static void sp_image_release( SPObject *object )
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
- if (image->pixPath) {
- g_free(image->pixPath);
- image->pixPath = 0;
- }
-
if (image->curve) {
image->curve = image->curve->unref();
}
@@ -427,24 +356,13 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags )
if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) {
if (image->pixbuf) {
- g_object_unref (image->pixbuf);
+ delete image->pixbuf;
image->pixbuf = NULL;
}
- if ( image->pixPath ) {
- g_free(image->pixPath);
- image->pixPath = 0;
- }
- image->lastMod = 0;
if (image->href) {
- GdkPixbuf *pixbuf;
+ Inkscape::Pixbuf *pixbuf = NULL;
pixbuf = sp_image_repr_read_image (
- image->lastMod,
- image->pixPath,
-
- //XML Tree being used directly while it shouldn't be.
object->getRepr()->attribute("xlink:href"),
-
- //XML Tree being used directly while it shouldn't be.
object->getRepr()->attribute("sodipodi:absref"),
doc->getBase());
if (pixbuf) {
@@ -452,10 +370,13 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags )
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
if ( image->color_profile )
{
- int imagewidth = gdk_pixbuf_get_width( pixbuf );
- int imageheight = gdk_pixbuf_get_height( pixbuf );
- int rowstride = gdk_pixbuf_get_rowstride( pixbuf );
- guchar* px = gdk_pixbuf_get_pixels( pixbuf );
+ // TODO: this will prevent using MIME data when exporting.
+ // Integrate color correction into loading.
+ pixbuf->ensurePixelFormat(Inkscape::Pixbuf::PF_GDK);
+ int imagewidth = pixbuf->width();
+ int imageheight = pixbuf->height();
+ int rowstride = pixbuf->rowstride();;
+ guchar* px = pixbuf->pixels();
if ( px ) {
DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" );
@@ -522,10 +443,10 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags )
if (image->pixbuf) {
/* fixme: We are slightly violating spec here (Lauris) */
if (!image->width._set) {
- image->width.computed = gdk_pixbuf_get_width(image->pixbuf);
+ image->width.computed = image->pixbuf->width();
}
if (!image->height._set) {
- image->height.computed = gdk_pixbuf_get_height(image->pixbuf);
+ image->height.computed = image->pixbuf->height();
}
}
@@ -536,8 +457,8 @@ static void sp_image_update( SPObject *object, SPCtx *ctx, unsigned int flags )
image->ox = image->x.computed;
image->oy = image->y.computed;
- int pixwidth = gdk_pixbuf_get_width (image->pixbuf);
- int pixheight = gdk_pixbuf_get_height (image->pixbuf);
+ int pixwidth = image->pixbuf->width();
+ int pixheight = image->pixbuf->height();
image->sx = image->width.computed / pixwidth;
image->sy = image->height.computed / pixheight;
@@ -678,16 +599,15 @@ static void sp_image_print( SPItem *item, SPPrintContext *ctx )
SPImage *image = SP_IMAGE(item);
if (image->pixbuf && (image->width.computed > 0.0) && (image->height.computed > 0.0) ) {
- GdkPixbuf *pb = gdk_pixbuf_copy(image->pixbuf);
- // GObject data is not copied, so we have to set the pixel format explicitly
- g_object_set_data_full(G_OBJECT(pb), "pixel_format", g_strdup("argb32"), g_free);
- ink_pixbuf_ensure_normal(pb);
+ Inkscape::Pixbuf *pb = new Inkscape::Pixbuf(*image->pixbuf);
+ pb->ensurePixelFormat(Inkscape::Pixbuf::PF_GDK);
- guchar *px = gdk_pixbuf_get_pixels(pb);
- int w = gdk_pixbuf_get_width(pb);
- int h = gdk_pixbuf_get_height(pb);
- int rs = gdk_pixbuf_get_rowstride(pb);
- int pixskip = gdk_pixbuf_get_n_channels(pb) * gdk_pixbuf_get_bits_per_sample(pb) / 8;
+ guchar *px = pb->pixels();
+ int w = pb->width();
+ int h = pb->height();
+ int rs = pb->rowstride();
+ //int pixskip = gdk_pixbuf_get_n_channels(pb) * gdk_pixbuf_get_bits_per_sample(pb) / 8;
+ int pixskip = 4;
if (image->aspect_align == SP_ASPECT_NONE) {
Geom::Affine t;
@@ -739,8 +659,8 @@ static gchar *sp_image_description( SPItem *item )
char *ret = ( image->pixbuf == NULL
? g_strdup_printf(_("<b>Image with bad reference</b>: %s"), href_desc)
: g_strdup_printf(_("<b>Image</b> %d &#215; %d: %s"),
- gdk_pixbuf_get_width(image->pixbuf),
- gdk_pixbuf_get_height(image->pixbuf),
+ image->pixbuf->width(),
+ image->pixbuf->height(),
href_desc) );
g_free(href_desc);
return ret;
@@ -756,22 +676,9 @@ static Inkscape::DrawingItem *sp_image_show( SPItem *item, Inkscape::Drawing &dr
return ai;
}
-/*
- * utility function to try loading image from href
- *
- * docbase/relative_src
- * absolute_src
- *
- */
-
-GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gchar *href, const gchar *absref, const gchar *base )
+Inkscape::Pixbuf *sp_image_repr_read_image(gchar const *href, gchar const *absref, gchar const *base)
{
- GdkPixbuf *pixbuf = 0;
- modTime = 0;
- if ( pixPath ) {
- g_free(pixPath);
- pixPath = 0;
- }
+ Inkscape::Pixbuf *inkpb = 0;
gchar const *filename = href;
@@ -779,18 +686,18 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha
if (strncmp (filename,"file:",5) == 0) {
gchar *fullname = g_filename_from_uri(filename, NULL, NULL);
if (fullname) {
- pixbuf = Inkscape::IO::pixbuf_new_from_file(fullname, modTime, pixPath);
+ inkpb = Inkscape::Pixbuf::create_from_file(fullname);
g_free(fullname);
- if (pixbuf != NULL) {
- return pixbuf;
+ if (inkpb != NULL) {
+ return inkpb;
}
}
} else if (strncmp (filename,"data:",5) == 0) {
/* data URI - embedded image */
filename += 5;
- pixbuf = sp_image_repr_read_dataURI (filename);
- if (pixbuf != NULL) {
- return pixbuf;
+ inkpb = Inkscape::Pixbuf::create_from_data_uri(filename);
+ if (inkpb != NULL) {
+ return inkpb;
}
} else {
@@ -806,19 +713,19 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha
// different dir) or unset (when doc is not saved yet), so we check for base+href existence first,
// and if it fails, we also try to use bare href regardless of its g_path_is_absolute
if (g_file_test (fullname, G_FILE_TEST_EXISTS) && !g_file_test (fullname, G_FILE_TEST_IS_DIR)) {
- pixbuf = Inkscape::IO::pixbuf_new_from_file(fullname, modTime, pixPath);
+ inkpb = Inkscape::Pixbuf::create_from_file(fullname);
g_free (fullname);
- if (pixbuf != NULL) {
- return pixbuf;
+ if (inkpb != NULL) {
+ return inkpb;
}
}
}
/* try filename as absolute */
if (g_file_test (filename, G_FILE_TEST_EXISTS) && !g_file_test (filename, G_FILE_TEST_IS_DIR)) {
- pixbuf = Inkscape::IO::pixbuf_new_from_file(filename, modTime, pixPath);
- if (pixbuf != NULL) {
- return pixbuf;
+ inkpb = Inkscape::Pixbuf::create_from_file(filename);
+ if (inkpb != NULL) {
+ return inkpb;
}
}
}
@@ -834,31 +741,20 @@ GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gcha
g_warning ("xlink:href did not resolve to a valid image file, now trying sodipodi:absref=\"%s\"", absref);
}
- pixbuf = Inkscape::IO::pixbuf_new_from_file(filename, modTime, pixPath);
- if (pixbuf != NULL) {
- return pixbuf;
+ inkpb = Inkscape::Pixbuf::create_from_file(filename);
+ if (inkpb != NULL) {
+ return inkpb;
}
}
/* Nope: We do not find any valid pixmap file :-( */
- pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **) brokenimage_xpm);
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **) brokenimage_xpm);
+ inkpb = new Inkscape::Pixbuf(pixbuf);
/* It should be included xpm, so if it still does not does load, */
/* our libraries are broken */
- g_assert (pixbuf != NULL);
-
- return pixbuf;
-}
+ g_assert (inkpb != NULL);
-static GdkPixbuf *sp_image_pixbuf_force_rgba( GdkPixbuf * pixbuf )
-{
- GdkPixbuf* result;
- if (gdk_pixbuf_get_has_alpha(pixbuf)) {
- result = pixbuf;
- } else {
- result = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
- g_object_unref(pixbuf);
- }
- return result;
+ return inkpb;
}
/* We assert that realpixbuf is either NULL or identical size to pixbuf */
@@ -866,7 +762,7 @@ static void
sp_image_update_arenaitem (SPImage *image, Inkscape::DrawingImage *ai)
{
ai->setStyle(SP_OBJECT(image)->style);
- ai->setARGB32Pixbuf(image->pixbuf);
+ ai->setPixbuf(image->pixbuf);
ai->setOrigin(Geom::Point(image->ox, image->oy));
ai->setScale(image->sx, image->sy);
ai->setClipbox(image->clipbox);
@@ -957,113 +853,6 @@ static Geom::Affine sp_image_set_transform( SPItem *item, Geom::Affine const &xf
return ret;
}
-static GdkPixbuf *sp_image_repr_read_dataURI( const gchar * uri_data )
-{
- GdkPixbuf * pixbuf = NULL;
-
- gint data_is_image = 0;
- gint data_is_base64 = 0;
-
- const gchar * data = uri_data;
-
- while (*data) {
- if (strncmp(data,"base64",6) == 0) {
- /* base64-encoding */
- data_is_base64 = 1;
- data_is_image = 1; // Illustrator produces embedded images without MIME type, so we assume it's image no matter what
- data += 6;
- }
- else if (strncmp(data,"image/png",9) == 0) {
- /* PNG image */
- data_is_image = 1;
- data += 9;
- }
- else if (strncmp(data,"image/jpg",9) == 0) {
- /* JPEG image */
- data_is_image = 1;
- data += 9;
- }
- else if (strncmp(data,"image/jpeg",10) == 0) {
- /* JPEG image */
- data_is_image = 1;
- data += 10;
- }
- else { /* unrecognized option; skip it */
- while (*data) {
- if (((*data) == ';') || ((*data) == ',')) {
- break;
- }
- data++;
- }
- }
- if ((*data) == ';') {
- data++;
- continue;
- }
- if ((*data) == ',') {
- data++;
- break;
- }
- }
-
- if ((*data) && data_is_image && data_is_base64) {
- pixbuf = sp_image_repr_read_b64(data);
- }
-
- return pixbuf;
-}
-
-static GdkPixbuf *sp_image_repr_read_b64(gchar const *uri_data)
-{
- GdkPixbuf *pixbuf = NULL;
- GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
-
- if (!loader) return NULL;
-
- gsize decoded_len = 0;
- guchar *decoded = g_base64_decode(uri_data, &decoded_len);
-
- if (gdk_pixbuf_loader_write(loader, decoded, decoded_len, NULL)) {
- gdk_pixbuf_loader_close(loader, NULL);
- pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
- g_object_ref(pixbuf);
- pixbuf = sp_image_pixbuf_force_rgba(pixbuf);
- pixbuf_set_mime_data(pixbuf, decoded, decoded_len, gdk_pixbuf_loader_get_format(loader));
- } else {
- g_free(decoded);
- }
- g_object_unref(loader);
-
- return pixbuf;
-}
-
-// takes ownership of passed data
-static void pixbuf_set_mime_data(GdkPixbuf *pb, guchar *data, gsize len, GdkPixbufFormat *fmt)
-{
- cairo_surface_t *s = ink_cairo_surface_get_for_pixbuf(pb);
-
- gchar const *mimetype = NULL;
- gchar *fmt_name = gdk_pixbuf_format_get_name(fmt);
- Glib::ustring name = fmt_name;
- g_free(fmt_name);
-
- if (name == "jpeg") {
- mimetype = CAIRO_MIME_TYPE_JPEG;
- } else if (name == "jpeg2000") {
- mimetype = CAIRO_MIME_TYPE_JP2;
- } else if (name == "png") {
- mimetype = CAIRO_MIME_TYPE_PNG;
- }
-
- if (mimetype != NULL) {
- cairo_surface_set_mime_data(s, mimetype, data, len, g_free, data);
- //g_message("Setting Cairo MIME data: %s", mimetype);
- } else {
- g_free(data);
- //g_message("Not setting Cairo MIME data: unknown format %s", name.c_str());
- }
-}
-
static void sp_image_set_curve( SPImage *image )
{
//create a curve at the image's boundary for snapping
@@ -1099,31 +888,16 @@ SPCurve *sp_image_get_curve( SPImage *image )
return result;
}
-void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb)
+void sp_embed_image(Inkscape::XML::Node *image_node, Inkscape::Pixbuf *pb)
{
- static gchar const *mimetypes[] = {
- CAIRO_MIME_TYPE_JPEG, CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL };
- static guint mimetypes_len = g_strv_length(const_cast<gchar**>(mimetypes));
-
bool free_data = false;
// check whether the pixbuf has MIME data
guchar *data = NULL;
gsize len = 0;
- gchar const *data_mimetype = NULL;
-
- cairo_surface_t *s = reinterpret_cast<cairo_surface_t*>(g_object_get_data(G_OBJECT(pb), "cairo_surface"));
- if (s) {
- for (guint i = 0; i < mimetypes_len; ++i) {
- unsigned long len_long = 0;
- cairo_surface_get_mime_data(s, mimetypes[i], const_cast<unsigned char const **>(&data), &len_long);
- len = len_long; // this assumes that the added range of long is not needed. the code below assumes gsize range of values is sufficient.
- if (data != NULL) {
- data_mimetype = mimetypes[i];
- break;
- }
- }
- }
+ std::string data_mimetype;
+
+ data = const_cast<guchar *>(pb->getMimeData(len, data_mimetype));
if (data == NULL) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1131,8 +905,7 @@ void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb)
// if there is no supported MIME data, embed as PNG
data_mimetype = "image/png";
- ink_pixbuf_ensure_normal(pb);
- gdk_pixbuf_save_to_buffer(pb, reinterpret_cast<gchar**>(&data), &len, "png", NULL,
+ gdk_pixbuf_save_to_buffer(pb->getPixbufRaw(), reinterpret_cast<gchar**>(&data), &len, "png", NULL,
"quality", quality.c_str(), NULL);
free_data = true;
}
@@ -1140,11 +913,11 @@ void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb)
// 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 + strlen(data_mimetype); // 5 bytes for data: + 8 for ;base64,
+ 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);
+ buf_work += g_sprintf(buffer, "data:%s;base64,", data_mimetype.c_str());
gint state = 0;
gint save = 0;
@@ -1164,18 +937,18 @@ void sp_embed_image(Inkscape::XML::Node *image_node, GdkPixbuf *pb)
void sp_image_refresh_if_outdated( SPImage* image )
{
- if ( image->href && image->lastMod ) {
+ if ( image->href && image->pixbuf && image->pixbuf->modificationTime()) {
// It *might* change
struct stat st;
memset(&st, 0, sizeof(st));
int val = 0;
- if (g_file_test (image->pixPath, G_FILE_TEST_EXISTS)){
- val = g_stat(image->pixPath, &st);
+ if (g_file_test (image->pixbuf->originalPath().c_str(), G_FILE_TEST_EXISTS)){
+ val = g_stat(image->pixbuf->originalPath().c_str(), &st);
}
if ( !val ) {
// stat call worked. Check time now
- if ( st.st_mtime != image->lastMod ) {
+ if ( st.st_mtime != image->pixbuf->modificationTime() ) {
SPCtx *ctx = 0;
unsigned int flags = SP_IMAGE_HREF_MODIFIED_FLAG;
sp_image_update(image, ctx, flags);
diff --git a/src/sp-image.h b/src/sp-image.h
index c197f6473..d137c7bf4 100644
--- a/src/sp-image.h
+++ b/src/sp-image.h
@@ -1,9 +1,6 @@
-#ifndef __SP_IMAGE_H__
-#define __SP_IMAGE_H__
-
-/*
+/** @file
* SVG <image> implementation
- *
+ *//*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Edward Flick (EAF)
@@ -14,21 +11,24 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#define SP_TYPE_IMAGE (sp_image_get_type ())
-#define SP_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_IMAGE, SPImage))
-#define SP_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_IMAGE, SPImageClass))
-#define SP_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_IMAGE))
-#define SP_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_IMAGE))
-
-/* SPImage */
+#ifndef SEEN_INKSCAPE_SP_IMAGE_H
+#define SEEN_INKSCAPE_SP_IMAGE_H
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glibmm/ustring.h>
#include "svg/svg-length.h"
#include "sp-item.h"
+#define SP_TYPE_IMAGE (sp_image_get_type ())
+#define SP_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_IMAGE, SPImage))
+#define SP_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_IMAGE, SPImageClass))
+#define SP_IS_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_IMAGE))
+#define SP_IS_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_IMAGE))
+
#define SP_IMAGE_HREF_MODIFIED_FLAG SP_OBJECT_USER_MODIFIED_FLAG_A
+namespace Inkscape { class Pixbuf; }
+
struct SPImage : public SPItem {
SVGLength x;
SVGLength y;
@@ -53,9 +53,7 @@ struct SPImage : public SPItem {
gchar *color_profile;
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
- GdkPixbuf *pixbuf;
- gchar *pixPath;
- time_t lastMod;
+ Inkscape::Pixbuf *pixbuf;
};
struct SPImageClass {
@@ -66,7 +64,7 @@ GType sp_image_get_type (void);
/* Return duplicate of curve or NULL */
SPCurve *sp_image_get_curve (SPImage *image);
-void sp_embed_image(Inkscape::XML::Node *imgnode, GdkPixbuf *pb);
+void sp_embed_image(Inkscape::XML::Node *imgnode, Inkscape::Pixbuf *pb);
void sp_image_refresh_if_outdated( SPImage* image );
#endif
diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp
index cad8ea9be..e2cda6247 100644
--- a/src/trace/trace.cpp
+++ b/src/trace/trace.cpp
@@ -31,6 +31,7 @@
#include <2geom/transforms.h>
#include "verbs.h"
+#include "display/cairo-utils.h"
#include "display/drawing.h"
#include "display/drawing-shape.h"
@@ -336,8 +337,17 @@ Glib::RefPtr<Gdk::Pixbuf> Tracer::getSelectedImage()
if (!img->pixbuf)
return Glib::RefPtr<Gdk::Pixbuf>(NULL);
- Glib::RefPtr<Gdk::Pixbuf> pixbuf =
- Glib::wrap(img->pixbuf, true);
+ GdkPixbuf *raw_pb = img->pixbuf->getPixbufRaw(false);
+ GdkPixbuf *trace_pb = gdk_pixbuf_copy(raw_pb);
+ if (img->pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) {
+ convert_pixels_argb32_to_pixbuf(
+ gdk_pixbuf_get_pixels(trace_pb),
+ gdk_pixbuf_get_width(trace_pb),
+ gdk_pixbuf_get_height(trace_pb),
+ gdk_pixbuf_get_rowstride(trace_pb));
+ }
+
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(trace_pb, false);
if (sioxEnabled)
{
@@ -410,7 +420,16 @@ void Tracer::traceThread()
return;
}
- Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(img->pixbuf, true);
+ GdkPixbuf *trace_pb = gdk_pixbuf_copy(img->pixbuf->getPixbufRaw(false));
+ if (img->pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) {
+ convert_pixels_argb32_to_pixbuf(
+ gdk_pixbuf_get_pixels(trace_pb),
+ gdk_pixbuf_get_width(trace_pb),
+ gdk_pixbuf_get_height(trace_pb),
+ gdk_pixbuf_get_rowstride(trace_pb));
+ }
+
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(trace_pb, false);
pixbuf = sioxProcessImage(img, pixbuf);