Code

remove many unnecessary to_2geom and from_2geom calls
[inkscape.git] / src / sp-image.cpp
index c5ed9117b162e4c684290780d3a9e99299578f3e..5a02517e260267d27800ca44e2de314c7fbde740 100644 (file)
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
-#include <libnr/nr-matrix-fns.h>
 
+#include <cstring>
+#include <string>
+#include <libnr/nr-matrix-fns.h>
+#include <libnr/nr-matrix-ops.h>
+#include <libnr/nr-translate-matrix-ops.h>
+#include <libnr/nr-scale-translate-ops.h>
+#include <libnr/nr-convert2geom.h>
+#include <2geom/rect.h>
 //#define GDK_PIXBUF_ENABLE_BACKEND 1
 //#include <gdk-pixbuf/gdk-pixbuf-io.h>
 #include "display/nr-arena-image.h"
+#include <display/curve.h>
+#include <glib/gstdio.h>
 
 //Added for preserveAspectRatio support -- EAF
 #include "enums.h"
 #include "brokenimage.xpm"
 #include "document.h"
 #include "sp-image.h"
+#include "sp-clippath.h"
 #include <glibmm/i18n.h>
 #include "xml/quote.h"
 #include <xml/repr.h>
 
+#include "libnr/nr-matrix-fns.h"
+
 #include "io/sys.h"
 #include <png.h>
 #if ENABLE_LCMS
@@ -57,7 +69,7 @@ static void sp_image_build (SPObject * object, SPDocument * document, Inkscape::
 static void sp_image_release (SPObject * object);
 static void sp_image_set (SPObject *object, unsigned int key, const gchar *value);
 static void sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags);
-static Inkscape::XML::Node *sp_image_write (SPObject *object, Inkscape::XML::Node *repr, guint flags);
+static Inkscape::XML::Node *sp_image_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
 
 static void sp_image_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags);
 static void sp_image_print (SPItem * item, SPPrintContext *ctx);
@@ -65,8 +77,10 @@ static gchar * sp_image_description (SPItem * item);
 static void sp_image_snappoints(SPItem const *item, SnapPointsIter p);
 static NRArenaItem *sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags);
 static NR::Matrix sp_image_set_transform (SPItem *item, NR::Matrix const &xform);
+static void sp_image_set_curve(SPImage *image);
+
 
-GdkPixbuf * sp_image_repr_read_image (Inkscape::XML::Node * repr);
+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 void sp_image_update_canvas_image (SPImage *image);
 static GdkPixbuf * sp_image_repr_read_dataURI (const gchar * uri_data);
@@ -225,28 +239,43 @@ void user_read_data( png_structp png_ptr, png_bytep data, png_size_t length )
 //    g_message("things out");
 }
 
-void user_write_data( png_structp png_ptr, png_bytep data, png_size_t length )
+void user_write_data( png_structp /*png_ptr*/, png_bytep /*data*/, png_size_t /*length*/ )
 {
     //g_message( "user_write_data(%d)", length );
 }
 
-void user_flush_data( png_structp png_ptr )
+void user_flush_data( png_structp /*png_ptr*/ )
 {
     //g_message( "user_flush_data" );
 }
 
-GdkPixbuf*  pixbuf_new_from_file( const char *filename, GError **error )
+static GdkPixbuf* pixbuf_new_from_file( const char *filename, time_t &modTime, gchar*& pixPath, GError **/*error*/ )
 {
     GdkPixbuf* buf = NULL;
     PushPull youme;
     gint dpiX = 0;
     gint dpiY = 0;
+    modTime = 0;
+    if ( pixPath ) {
+        g_free(pixPath);
+        pixPath = 0;
+    }
 
     //buf = gdk_pixbuf_new_from_file( filename, error );
     dump_fopen_call( filename, "pixbuf_new_from_file" );
     FILE* fp = fopen_utf8name( filename, "r" );
     if ( fp )
     {
+        {
+            struct stat st;
+            memset(&st, 0, sizeof(st));
+            int val = g_stat(filename, &st);
+            if ( !val ) {
+                modTime = st.st_mtime;
+                pixPath = g_strdup(filename);
+            }
+        }
+
         GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
         if ( loader )
         {
@@ -355,12 +384,64 @@ GdkPixbuf*  pixbuf_new_from_file( const char *filename, GError **error )
                                 }
 */
 
+#if defined(PNG_sRGB_SUPPORTED)
+                                {
+                                    int intent = 0;
+                                    if ( png_get_sRGB(pngPtr, infoPtr, &intent) ) {
+//                                         g_message("Found an sRGB png chunk");
+                                    }
+                                }
+#endif // defined(PNG_sRGB_SUPPORTED)
+
+#if defined(PNG_cHRM_SUPPORTED)
+                                {
+                                    double white_x = 0;
+                                    double white_y = 0;
+                                    double red_x = 0;
+                                    double red_y = 0;
+                                    double green_x = 0;
+                                    double green_y = 0;
+                                    double blue_x = 0;
+                                    double blue_y = 0;
+
+                                    if ( png_get_cHRM(pngPtr, infoPtr,
+                                                      &white_x, &white_y,
+                                                      &red_x, &red_y,
+                                                      &green_x, &green_y,
+                                                      &blue_x, &blue_y) ) {
+//                                         g_message("Found a cHRM png chunk");
+                                    }
+                                }
+#endif // defined(PNG_cHRM_SUPPORTED)
+
+#if defined(PNG_gAMA_SUPPORTED)
+                                {
+                                    double file_gamma = 0;
+                                    if ( png_get_gAMA(pngPtr, infoPtr, &file_gamma) ) {
+//                                         g_message("Found a gAMA png chunk");
+                                    }
+                                }
+#endif // defined(PNG_gAMA_SUPPORTED)
+
+#if defined(PNG_iCCP_SUPPORTED)
+                                {
+                                    char* name = 0;
+                                    int compression_type = 0;
+                                    char* profile = 0;
+                                    png_uint_32 proflen = 0;
+                                    if ( png_get_iCCP(pngPtr, infoPtr, &name, &compression_type, &profile, &proflen) ) {
+//                                         g_message("Found an iCCP chunk named [%s] with %d bytes and comp %d", name, proflen, compression_type);
+                                    }
+                                }
+#endif // defined(PNG_iCCP_SUPPORTED)
+
+
                                 // now clean it up.
                                 png_destroy_read_struct( &pngPtr, &infoPtr, NULL );//&endPtr );
                             }
                             else
                             {
-                                g_message("Error when creating PNG read struct");
+//                                 g_message("Error when creating PNG read struct");
                             }
                         }
                     }
@@ -388,6 +469,7 @@ GdkPixbuf*  pixbuf_new_from_file( const char *filename, GError **error )
                         gchar *tmp = g_strdup_printf( "%d", dpiX );
                         if ( tmp )
                         {
+//                             g_message("Need to set DpiX: %s", tmp);
                             //gdk_pixbuf_set_option( buf, "Inkscape::DpiX", tmp );
                             g_free( tmp );
                         }
@@ -397,6 +479,7 @@ GdkPixbuf*  pixbuf_new_from_file( const char *filename, GError **error )
                         gchar *tmp = g_strdup_printf( "%d", dpiY );
                         if ( tmp )
                         {
+//                             g_message("Need to set DpiY: %s", tmp);
                             //gdk_pixbuf_set_option( buf, "Inkscape::DpiY", tmp );
                             g_free( tmp );
                         }
@@ -442,66 +525,96 @@ GdkPixbuf*  pixbuf_new_from_file( const char *filename, GError **error )
     return buf;
 }
 
+GdkPixbuf* pixbuf_new_from_file( const char *filename, GError **error )
+{
+    time_t modTime = 0;
+    gchar* pixPath = 0;
+    GdkPixbuf* result = pixbuf_new_from_file( filename, modTime, pixPath, error );
+    if (pixPath) {
+        g_free(pixPath);
+    }
+    return result;
+}
+
+
 }
 }
 
 GType
 sp_image_get_type (void)
 {
-       static GType image_type = 0;
-       if (!image_type) {
-               GTypeInfo image_info = {
-                       sizeof (SPImageClass),
-                       NULL,   /* base_init */
-                       NULL,   /* base_finalize */
-                       (GClassInitFunc) sp_image_class_init,
-                       NULL,   /* class_finalize */
-                       NULL,   /* class_data */
-                       sizeof (SPImage),
-                       16,     /* n_preallocs */
-                       (GInstanceInitFunc) sp_image_init,
-                       NULL,   /* value_table */
-               };
-               image_type = g_type_register_static (sp_item_get_type (), "SPImage", &image_info, (GTypeFlags)0);
-       }
-       return image_type;
+    static GType image_type = 0;
+    if (!image_type) {
+        GTypeInfo image_info = {
+            sizeof (SPImageClass),
+            NULL,       /* base_init */
+            NULL,       /* base_finalize */
+            (GClassInitFunc) sp_image_class_init,
+            NULL,       /* class_finalize */
+            NULL,       /* class_data */
+            sizeof (SPImage),
+            16, /* n_preallocs */
+            (GInstanceInitFunc) sp_image_init,
+            NULL,       /* value_table */
+        };
+        image_type = g_type_register_static (sp_item_get_type (), "SPImage", &image_info, (GTypeFlags)0);
+    }
+    return image_type;
 }
 
 static void
 sp_image_class_init (SPImageClass * klass)
 {
-       GObjectClass * gobject_class;
-       SPObjectClass * sp_object_class;
-       SPItemClass * item_class;
-
-       gobject_class = (GObjectClass *) klass;
-       sp_object_class = (SPObjectClass *) klass;
-       item_class = (SPItemClass *) klass;
-
-       parent_class = (SPItemClass*)g_type_class_ref (sp_item_get_type ());
-
-       sp_object_class->build = sp_image_build;
-       sp_object_class->release = sp_image_release;
-       sp_object_class->set = sp_image_set;
-       sp_object_class->update = sp_image_update;
-       sp_object_class->write = sp_image_write;
-
-       item_class->bbox = sp_image_bbox;
-       item_class->print = sp_image_print;
-       item_class->description = sp_image_description;
-       item_class->show = sp_image_show;
-       item_class->snappoints = sp_image_snappoints;
-       item_class->set_transform = sp_image_set_transform;
+    GObjectClass * gobject_class;
+    SPObjectClass * sp_object_class;
+    SPItemClass * item_class;
+
+    gobject_class = (GObjectClass *) klass;
+    sp_object_class = (SPObjectClass *) klass;
+    item_class = (SPItemClass *) klass;
+
+    parent_class = (SPItemClass*)g_type_class_ref (sp_item_get_type ());
+
+    sp_object_class->build = sp_image_build;
+    sp_object_class->release = sp_image_release;
+    sp_object_class->set = sp_image_set;
+    sp_object_class->update = sp_image_update;
+    sp_object_class->write = sp_image_write;
+
+    item_class->bbox = sp_image_bbox;
+    item_class->print = sp_image_print;
+    item_class->description = sp_image_description;
+    item_class->show = sp_image_show;
+    item_class->snappoints = sp_image_snappoints;
+    item_class->set_transform = sp_image_set_transform;
 }
 
-static void
-sp_image_init (SPImage *image)
+static void sp_image_init( SPImage *image )
 {
-       image->x.unset();
-       image->y.unset();
-       image->width.unset();
-       image->height.unset();
-       image->aspect_align = SP_ASPECT_NONE;
+    image->x.unset();
+    image->y.unset();
+    image->width.unset();
+    image->height.unset();
+    image->aspect_align = SP_ASPECT_NONE;
+
+    image->trimx = 0;
+    image->trimy = 0;
+    image->trimwidth = 0;
+    image->trimheight = 0;
+    image->viewx = 0;
+    image->viewy = 0;
+    image->viewwidth = 0;
+    image->viewheight = 0;
+
+    image->curve = NULL;
+
+    image->href = 0;
+#if ENABLE_LCMS
+    image->color_profile = 0;
+#endif // ENABLE_LCMS
+    image->pixbuf = 0;
+    image->pixPath = 0;
+    image->lastMod = 0;
 }
 
 static void
@@ -525,34 +638,42 @@ sp_image_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
 static void
 sp_image_release (SPObject *object)
 {
-       SPImage *image;
-
-       image = SP_IMAGE (object);
+    SPImage *image = SP_IMAGE(object);
 
-       if (SP_OBJECT_DOCUMENT (object)) {
-               /* Unregister ourselves */
-               sp_document_remove_resource (SP_OBJECT_DOCUMENT (object), "image", SP_OBJECT (object));
-       }
+    if (SP_OBJECT_DOCUMENT (object)) {
+        /* Unregister ourselves */
+        sp_document_remove_resource (SP_OBJECT_DOCUMENT (object), "image", SP_OBJECT (object));
+    }
 
-       if (image->href) {
-               g_free (image->href);
-               image->href = NULL;
-       }
+    if (image->href) {
+        g_free (image->href);
+        image->href = NULL;
+    }
 
-       if (image->pixbuf) {
-               gdk_pixbuf_unref (image->pixbuf);
-               image->pixbuf = NULL;
-       }
+    if (image->pixbuf) {
+        gdk_pixbuf_unref (image->pixbuf);
+        image->pixbuf = NULL;
+    }
 
 #if ENABLE_LCMS
-       if (image->color_profile) {
-               g_free (image->color_profile);
-               image->color_profile = NULL;
-       }
+    if (image->color_profile) {
+        g_free (image->color_profile);
+        image->color_profile = NULL;
+    }
 #endif // ENABLE_LCMS
 
-       if (((SPObjectClass *) parent_class)->release)
-               ((SPObjectClass *) parent_class)->release (object);
+    if (image->pixPath) {
+        g_free(image->pixPath);
+        image->pixPath = 0;
+    }
+
+    if (image->curve) {
+        image->curve = image->curve->unref();
+    }
+
+    if (((SPObjectClass *) parent_class)->release) {
+        ((SPObjectClass *) parent_class)->release (object);
+    }
 }
 
 static void
@@ -676,28 +797,39 @@ sp_image_set (SPObject *object, unsigned int key, const gchar *value)
                        ((SPObjectClass *) (parent_class))->set (object, key, value);
                break;
        }
+       
+       sp_image_set_curve(image); //creates a curve at the image's boundary for snapping
 }
 
 static void
 sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags)
 {
-       SPImage *image;
-
-       image = (SPImage *) object;
+    SPImage *image = SP_IMAGE(object);
+    SPDocument *doc = SP_OBJECT_DOCUMENT(object);
 
-       if (((SPObjectClass *) (parent_class))->update)
-               ((SPObjectClass *) (parent_class))->update (object, ctx, flags);
+    if (((SPObjectClass *) (parent_class))->update)
+        ((SPObjectClass *) (parent_class))->update (object, ctx, flags);
 
-       if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) {
-               if (image->pixbuf) {
-                       gdk_pixbuf_unref (image->pixbuf);
-                       image->pixbuf = NULL;
-               }
-               if (image->href) {
-                       GdkPixbuf *pixbuf;
-                       pixbuf = sp_image_repr_read_image (object->repr);
-                       if (pixbuf) {
-                               pixbuf = sp_image_pixbuf_force_rgba (pixbuf);
+    if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) {
+        if (image->pixbuf) {
+            gdk_pixbuf_unref (image->pixbuf);
+            image->pixbuf = NULL;
+        }
+        if ( image->pixPath ) {
+            g_free(image->pixPath);
+            image->pixPath = 0;
+        }
+        image->lastMod = 0;
+        if (image->href) {
+            GdkPixbuf *pixbuf;
+            pixbuf = sp_image_repr_read_image (
+                image->lastMod,
+                image->pixPath,
+                object->repr->attribute("xlink:href"),
+                object->repr->attribute("sodipodi:absref"),
+                doc->base);
+            if (pixbuf) {
+                pixbuf = sp_image_pixbuf_force_rgba (pixbuf);
 // BLIP
 #if ENABLE_LCMS
                                 if ( image->color_profile )
@@ -736,7 +868,7 @@ sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags)
                                                         intent = INTENT_PERCEPTUAL;
                                                 }
                                                 cmsHPROFILE destProf = cmsCreate_sRGBProfile();
-                                                cmsHTRANSFORM transf = cmsCreateTransform( prof, 
+                                                cmsHTRANSFORM transf = cmsCreateTransform( prof,
                                                                                            TYPE_RGBA_8,
                                                                                            destProf,
                                                                                            TYPE_RGBA_8,
@@ -869,19 +1001,17 @@ sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags)
                                }
                        }
        }
-
        sp_image_update_canvas_image ((SPImage *) object);
 }
 
 static Inkscape::XML::Node *
-sp_image_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
+sp_image_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
        SPImage *image;
 
        image = SP_IMAGE (object);
 
        if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-                Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
                repr = xml_doc->createElement("svg:image");
        }
 
@@ -897,13 +1027,13 @@ sp_image_write (SPObject *object, Inkscape::XML::Node *repr, guint flags)
 #endif // ENABLE_LCMS
 
        if (((SPObjectClass *) (parent_class))->write)
-               ((SPObjectClass *) (parent_class))->write (object, repr, flags);
+               ((SPObjectClass *) (parent_class))->write (object, xml_doc, repr, flags);
 
        return repr;
 }
 
 static void
-sp_image_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags)
+sp_image_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const /*flags*/)
 {
        SPImage const &image = *SP_IMAGE(item);
 
@@ -924,7 +1054,6 @@ static void
 sp_image_print (SPItem *item, SPPrintContext *ctx)
 {
        SPImage *image;
-       NRMatrix tp, ti, s, t;
        guchar *px;
        int w, h, rs, pixskip;
 
@@ -939,20 +1068,22 @@ sp_image_print (SPItem *item, SPPrintContext *ctx)
        rs = gdk_pixbuf_get_rowstride (image->pixbuf);
        pixskip = gdk_pixbuf_get_n_channels (image->pixbuf) * gdk_pixbuf_get_bits_per_sample (image->pixbuf) / 8;
 
+    NR::Matrix t;
        if (image->aspect_align == SP_ASPECT_NONE) {
                /* fixme: (Lauris) */
-               nr_matrix_set_translate (&tp, image->x.computed, image->y.computed);
-               nr_matrix_set_scale (&s, image->width.computed, -image->height.computed);
-               nr_matrix_set_translate (&ti, 0.0, -1.0);
+        NR::translate tp = NR::translate(image->x.computed, image->y.computed);
+        NR::scale s = NR::scale(image->width.computed, -image->height.computed);
+        NR::translate ti = NR::translate(0.0, -1.0);
+           t = s * tp;
+           t = ti * t;
        } else { // preserveAspectRatio
-               nr_matrix_set_translate (&tp, image->viewx, image->viewy);
-               nr_matrix_set_scale (&s, image->viewwidth, -image->viewheight);
-               nr_matrix_set_translate (&ti, 0.0, -1.0);
+        NR::translate tp = NR::translate(image->viewx, image->viewy);
+        NR::scale s = NR::scale(image->viewwidth, -image->viewheight);
+        NR::translate ti = NR::translate(0.0, -1.0);
+           t = s * tp;
+           t = ti * t;
        }
 
-       nr_matrix_multiply (&t, &s, &tp);
-       nr_matrix_multiply (&t, &ti, &t);
-
        if (image->aspect_align == SP_ASPECT_NONE)
                sp_print_image_R8G8B8A8_N (ctx, px, w, h, rs, &t, SP_OBJECT_STYLE (item));
        else // preserveAspectRatio
@@ -984,7 +1115,7 @@ sp_image_description(SPItem *item)
 }
 
 static NRArenaItem *
-sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags)
+sp_image_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/)
 {
        int pixskip, rs;
        SPImage * image;
@@ -1029,56 +1160,77 @@ sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flag
  *
  */
 
-GdkPixbuf *
-sp_image_repr_read_image (Inkscape::XML::Node * repr)
+GdkPixbuf *sp_image_repr_read_image( time_t& modTime, char*& pixPath, const gchar *href, const gchar *absref, const gchar *base )
 {
-       const gchar * filename, * docbase;
-       gchar * fullname;
-       GdkPixbuf * pixbuf;
-
-       filename = repr->attribute("xlink:href");
-       if (filename == NULL) filename = repr->attribute("href"); /* FIXME */
-       if (filename != NULL) {
-               if (strncmp (filename,"file:",5) == 0) {
-                       fullname = g_filename_from_uri(filename, NULL, NULL);
-                       if (fullname) {
-                               // TODO check this. Was doing a UTF-8 to filename conversion here.
-                               pixbuf = Inkscape::IO::pixbuf_new_from_file (fullname, NULL);
-                               if (pixbuf != NULL) return pixbuf;
-                       }
-               } 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;
-               } else if (!g_path_is_absolute (filename)) {
-                       /* try to load from relative pos */
-                       docbase = repr->document()->root()->attribute("sodipodi:docbase");
-                       if (!docbase) docbase = ".";
-                       fullname = g_build_filename(docbase, filename, NULL);
-                       pixbuf = Inkscape::IO::pixbuf_new_from_file( fullname, NULL );
-                       g_free (fullname);
-                       if (pixbuf != NULL) return pixbuf;
-               } else {
-                       /* try absolute filename */
-                       pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, NULL );
-                       if (pixbuf != NULL) return pixbuf;
-               }
-       }
-       /* at last try to load from sp absolute path name */
-       filename = repr->attribute("sodipodi:absref");
-       if (filename != NULL) {
-               pixbuf = Inkscape::IO::pixbuf_new_from_file( filename, NULL );
-               if (pixbuf != NULL) return pixbuf;
-       }
-       /* Nope: We do not find any valid pixmap file :-( */
-       pixbuf = gdk_pixbuf_new_from_xpm_data ((const gchar **) brokenimage_xpm);
+    const gchar *filename, *docbase;
+    gchar *fullname;
+    GdkPixbuf *pixbuf;
+    modTime = 0;
+    if ( pixPath ) {
+        g_free(pixPath);
+        pixPath = 0;
+    }
 
-       /* It should be included xpm, so if it still does not does load, */
-       /* our libraries are broken */
-       g_assert (pixbuf != NULL);
+    filename = href;
+    if (filename != NULL) {
+        if (strncmp (filename,"file:",5) == 0) {
+            fullname = g_filename_from_uri(filename, NULL, NULL);
+            if (fullname) {
+                // TODO check this. Was doing a UTF-8 to filename conversion here.
+                pixbuf = Inkscape::IO::pixbuf_new_from_file (fullname, modTime, pixPath, NULL);
+                if (pixbuf != NULL) return pixbuf;
+            }
+        } 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;
+        } else {
 
-       return pixbuf;
+            if (!g_path_is_absolute (filename)) {
+                /* try to load from relative pos combined with document base*/
+                docbase = base;
+                if (!docbase) docbase = ".";
+                fullname = g_build_filename(docbase, filename, NULL);
+
+                // document base can be wrong (on the temporary doc when importing bitmap from a
+                // 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, NULL );
+                    g_free (fullname);
+                    if (pixbuf != NULL) return pixbuf;
+                }
+            }
+
+            /* 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, NULL );
+                if (pixbuf != NULL) return pixbuf;
+            }
+        }
+    }
+
+    /* at last try to load from sp absolute path name */
+    filename = absref;
+    if (filename != NULL) {
+        // using absref is outside of SVG rules, so we must at least warn the user
+        if ( base != NULL && href != NULL )
+               g_warning ("<image xlink:href=\"%s\"> did not resolve to a valid image file (base dir is %s), now trying sodipodi:absref=\"%s\"", href, base, absref);
+               else
+                   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, NULL );
+        if (pixbuf != NULL) return pixbuf;
+    }
+    /* Nope: We do not find any valid pixmap file :-( */
+    pixbuf = gdk_pixbuf_new_from_xpm_data ((const gchar **) brokenimage_xpm);
+
+    /* It should be included xpm, so if it still does not does load, */
+    /* our libraries are broken */
+    g_assert (pixbuf != NULL);
+
+    return pixbuf;
 }
 
 static GdkPixbuf *
@@ -1143,9 +1295,31 @@ sp_image_update_canvas_image (SPImage *image)
 
 static void sp_image_snappoints(SPItem const *item, SnapPointsIter p)
 {
-     if (((SPItemClass *) parent_class)->snappoints) {
-         ((SPItemClass *) parent_class)->snappoints (item, p);
-     }
+    /* An image doesn't have any nodes to snap, but still we want to be able snap one image 
+    to another. Therefore we will create some snappoints at the corner, similar to a rect. If
+    the image is rotated, then the snappoints will rotate with it. Again, just like a rect.
+    */
+     
+    g_assert(item != NULL);
+    g_assert(SP_IS_IMAGE(item));
+
+    if (item->clip_ref->getObject()) {
+        //We are looking at a clipped image: do not return any snappoints, as these might be
+        //far far away from the visible part from the clipped image
+       //TODO Do return snappoints, but only when within visual bounding box
+    } else {
+        // The image has not been clipped: return its corners, which might be rotated for example
+        SPImage &image = *SP_IMAGE(item);
+        double const x0 = image.x.computed;
+               double const y0 = image.y.computed;
+               double const x1 = x0 + image.width.computed;
+               double const y1 = y0 + image.height.computed;
+               NR::Matrix const i2d (sp_item_i2d_affine (item));
+               *p = NR::Point(x0, y0) * i2d;
+        *p = NR::Point(x0, y1) * i2d;
+        *p = NR::Point(x1, y1) * i2d;
+        *p = NR::Point(x1, y0) * i2d;
+    }
 }
 
 /*
@@ -1334,6 +1508,64 @@ sp_image_repr_read_b64 (const gchar * uri_data)
        return pixbuf;
 }
 
+static void
+sp_image_set_curve(SPImage *image) 
+{
+    //create a curve at the image's boundary for snapping
+    if ((image->height.computed < 1e-18) || (image->width.computed < 1e-18) || (image->clip_ref->getObject())) {
+        if (image->curve) {
+            image->curve = image->curve->unref();
+        }
+        return;
+    }
+    
+    NRRect rect;
+       sp_image_bbox(image, &rect, NR::identity(), 0);
+    Geom::Rect rect2 = to_2geom(*rect.upgrade());
+    SPCurve *c = SPCurve::new_from_rect(rect2);
+        
+    if (image->curve) {
+        image->curve = image->curve->unref();
+    }
+    
+    if (c) {
+        image->curve = c->ref();
+    }
+    
+    c->unref();    
+}
+
+/**
+ * Return duplicate of curve (if any exists) or NULL if there is no curve
+ */
+SPCurve *
+sp_image_get_curve (SPImage *image)
+{
+       if (image->curve) {
+               return image->curve->copy();
+       }
+       return NULL;
+}
+
+void sp_image_refresh_if_outdated( SPImage* image )
+{
+    if ( image->href && image->lastMod ) {
+        // It *might* change
+
+        struct stat st;
+        memset(&st, 0, sizeof(st));
+        int val = g_stat(image->pixPath, &st);
+        if ( !val ) {
+            // stat call worked. Check time now
+            if ( st.st_mtime != image->lastMod ) {
+                SPCtx *ctx = 0;
+                unsigned int flags = SP_IMAGE_HREF_MODIFIED_FLAG;
+                sp_image_update(image, ctx, flags);
+            }
+        }
+    }
+}
+
 /*
   Local Variables:
   mode:c++