diff --git a/src/sp-image.cpp b/src/sp-image.cpp
index 86998156720ec511c979cf1196e719436ee78c0b..9f67670504a80eb268d1a5e22ea94d9db9bae50d 100644 (file)
--- a/src/sp-image.cpp
+++ b/src/sp-image.cpp
//#define GDK_PIXBUF_ENABLE_BACKEND 1
//#include <gdk-pixbuf/gdk-pixbuf-io.h>
#include "display/nr-arena-image.h"
+#include <display/curve.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 "io/sys.h"
#include <png.h>
-
+#if ENABLE_LCMS
+#include "color-profile-fns.h"
+#include "color-profile.h"
+//#define DEBUG_LCMS
+#ifdef DEBUG_LCMS
+#include "prefs-utils.h"
+#include <gtk/gtkmessagedialog.h>
+#endif // DEBUG_LCMS
+#endif // ENABLE_LCMS
/*
* SPImage
*/
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);
+GdkPixbuf *sp_image_repr_read_image (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);
}
+
+#ifdef DEBUG_LCMS
+extern guint update_in_progress;
+#define DEBUG_MESSAGE(key, ...) \
+{\
+ gint dump = prefs_get_int_attribute_limited("options.scislac", #key, 0, 0, 1);\
+ gint dumpD = prefs_get_int_attribute_limited("options.scislac", #key"D", 0, 0, 1);\
+ gint dumpD2 = prefs_get_int_attribute_limited("options.scislac", #key"D2", 0, 0, 1);\
+ dumpD &= ( (update_in_progress == 0) || dumpD2 );\
+ if ( dump )\
+ {\
+ g_message( __VA_ARGS__ );\
+\
+ }\
+ if ( dumpD )\
+ {\
+ GtkWidget *dialog = gtk_message_dialog_new(NULL,\
+ GTK_DIALOG_DESTROY_WITH_PARENT, \
+ GTK_MESSAGE_INFO, \
+ GTK_BUTTONS_OK, \
+ __VA_ARGS__ \
+ );\
+ g_signal_connect_swapped(dialog, "response",\
+ G_CALLBACK(gtk_widget_destroy), \
+ dialog); \
+ gtk_widget_show_all( dialog );\
+ }\
+}
+#endif // DEBUG_LCMS
+
namespace Inkscape {
namespace IO {
//g_message( " __read %d bytes", (int)got );
if ( !gdk_pixbuf_loader_write( loader, scratch + used, got, &err ) )
{
- //g_message("_error writing pixbuf data");
+ //g_message("_error writing pixbuf data");
}
}
"unknown", // PNG_SCALE_UNKNOWN
"meter", // PNG_SCALE_METER
"radian", // PNG_SCALE_RADIAN
- "last", //
+ "last", //
NULL
};
}
else
{
- g_warning ("unable to open file: %s", filename);
+ g_warning ("Unable to open linked file: %s", filename);
}
/*
image->width.unset();
image->height.unset();
image->aspect_align = SP_ASPECT_NONE;
+ image->curve = NULL;
}
static void
@@ -478,6 +521,7 @@ sp_image_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
sp_object_read_attr (object, "width");
sp_object_read_attr (object, "height");
sp_object_read_attr (object, "preserveAspectRatio");
+ sp_object_read_attr (object, "color-profile");
/* Register */
sp_document_add_resource (document, "image", object);
image->pixbuf = NULL;
}
+#if ENABLE_LCMS
+ if (image->color_profile) {
+ g_free (image->color_profile);
+ image->color_profile = NULL;
+ }
+#endif // ENABLE_LCMS
+
+ if (image->curve) {
+ image->curve = sp_curve_unref (image->curve);
+ }
+
if (((SPObjectClass *) parent_class)->release)
((SPObjectClass *) parent_class)->release (object);
}
image->aspect_clip = clip;
}
break;
+#if ENABLE_LCMS
+ case SP_PROP_COLOR_PROFILE:
+ if ( image->color_profile ) {
+ g_free (image->color_profile);
+ }
+ image->color_profile = (value) ? g_strdup (value) : NULL;
+#ifdef DEBUG_LCMS
+ if ( value ) {
+ DEBUG_MESSAGE( lcmsFour, "<image> color-profile set to '%s'", value );
+ } else {
+ DEBUG_MESSAGE( lcmsFour, "<image> color-profile cleared" );
+ }
+#endif // DEBUG_LCMS
+ // TODO check on this HREF_MODIFIED flag
+ object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG);
+ break;
+#endif // ENABLE_LCMS
default:
if (((SPObjectClass *) (parent_class))->set)
((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;
+ SPImage *image;
- image = (SPImage *) object;
+ image = (SPImage *) object;
+ SPDocument *doc = SP_OBJECT_DOCUMENT(object);
if (((SPObjectClass *) (parent_class))->update)
((SPObjectClass *) (parent_class))->update (object, ctx, flags);
}
if (image->href) {
GdkPixbuf *pixbuf;
- pixbuf = sp_image_repr_read_image (object->repr);
+ pixbuf = sp_image_repr_read_image (
+ 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 )
+ {
+ 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 );
+
+ if ( px ) {
+#ifdef DEBUG_LCMS
+ DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" );
+#endif // DEBUG_LCMS
+ guint profIntent = Inkscape::RENDERING_INTENT_UNKNOWN;
+ cmsHPROFILE prof = Inkscape::colorprofile_get_handle( SP_OBJECT_DOCUMENT( object ),
+ &profIntent,
+ image->color_profile );
+ if ( prof ) {
+ icProfileClassSignature profileClass = cmsGetDeviceClass( prof );
+ if ( profileClass != icSigNamedColorClass ) {
+ int intent = INTENT_PERCEPTUAL;
+ switch ( profIntent ) {
+ case Inkscape::RENDERING_INTENT_RELATIVE_COLORIMETRIC:
+ intent = INTENT_RELATIVE_COLORIMETRIC;
+ break;
+ case Inkscape::RENDERING_INTENT_SATURATION:
+ intent = INTENT_SATURATION;
+ break;
+ case Inkscape::RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
+ intent = INTENT_ABSOLUTE_COLORIMETRIC;
+ break;
+ case Inkscape::RENDERING_INTENT_PERCEPTUAL:
+ case Inkscape::RENDERING_INTENT_UNKNOWN:
+ case Inkscape::RENDERING_INTENT_AUTO:
+ default:
+ intent = INTENT_PERCEPTUAL;
+ }
+ cmsHPROFILE destProf = cmsCreate_sRGBProfile();
+ cmsHTRANSFORM transf = cmsCreateTransform( prof,
+ TYPE_RGBA_8,
+ destProf,
+ TYPE_RGBA_8,
+ intent, 0 );
+ if ( transf ) {
+ guchar* currLine = px;
+ for ( int y = 0; y < imageheight; y++ ) {
+ // Since the types are the same size, we can do the transformation in-place
+ cmsDoTransform( transf, currLine, currLine, imagewidth );
+ currLine += rowstride;
+ }
+
+ cmsDeleteTransform( transf );
+ }
+#ifdef DEBUG_LCMS
+ else
+ {
+ DEBUG_MESSAGE( lcmsSix, "in <image>'s sp_image_update. Unable to create LCMS transform." );
+ }
+#endif // DEBUG_LCMS
+ cmsCloseProfile( destProf );
+ }
+#ifdef DEBUG_LCMS
+ else
+ {
+ DEBUG_MESSAGE( lcmsSeven, "in <image>'s sp_image_update. Profile type is named color. Can't transform." );
+ }
+#endif // DEBUG_LCMS
+ }
+#ifdef DEBUG_LCMS
+ else
+ {
+ DEBUG_MESSAGE( lcmsEight, "in <image>'s sp_image_update. No profile found." );
+ }
+#endif // DEBUG_LCMS
+ }
+ }
+#endif // ENABLE_LCMS
image->pixbuf = pixbuf;
}
}
}
}
}
-
sp_image_update_canvas_image ((SPImage *) object);
}
image = SP_IMAGE (object);
if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
- repr = sp_repr_new ("svg:image");
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
+ repr = xml_doc->createElement("svg:image");
}
repr->setAttribute("xlink:href", image->href);
if (image->width._set) sp_repr_set_svg_double(repr, "width", image->width.computed);
if (image->height._set) sp_repr_set_svg_double(repr, "height", image->height.computed);
repr->setAttribute("preserveAspectRatio", object->repr->attribute("preserveAspectRatio"));
+#if ENABLE_LCMS
+ if (image->color_profile) repr->setAttribute("color-profile", image->color_profile);
+#endif // ENABLE_LCMS
if (((SPObjectClass *) (parent_class))->write)
((SPObjectClass *) (parent_class))->write (object, repr, flags);
if (!image->pixbuf) return;
if ((image->width.computed <= 0.0) || (image->height.computed <= 0.0)) return;
-
+
px = gdk_pixbuf_get_pixels (image->pixbuf);
w = gdk_pixbuf_get_width (image->pixbuf);
h = gdk_pixbuf_get_height (image->pixbuf);
rs = gdk_pixbuf_get_rowstride (image->pixbuf);
pixskip = gdk_pixbuf_get_n_channels (image->pixbuf) * gdk_pixbuf_get_bits_per_sample (image->pixbuf) / 8;
-
+
if (image->aspect_align == SP_ASPECT_NONE) {
/* fixme: (Lauris) */
nr_matrix_set_translate (&tp, image->x.computed, image->y.computed);
SPImage *image = SP_IMAGE(item);
char *href_desc;
if (image->href) {
- href_desc = (strncmp(image->href, "data:", 5) == 0)
+ href_desc = (strncmp(image->href, "data:", 5) == 0)
? g_strdup(_("embedded"))
: xml_quote_strdup(image->href);
} else {
g_warning("Attempting to call strncmp() with a null pointer.");
- href_desc = g_strdup(_("(null_pointer)")); // we call g_free() on href_desc
- }
+ href_desc = g_strdup("(null_pointer)"); // we call g_free() on href_desc
+ }
char *ret = ( image->pixbuf == NULL
? g_strdup_printf(_("<b>Image with bad reference</b>: %s"), href_desc)
@@ -853,6 +1011,7 @@ sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flag
if (image->pixbuf) {
pixskip = gdk_pixbuf_get_n_channels (image->pixbuf) * gdk_pixbuf_get_bits_per_sample (image->pixbuf) / 8;
rs = gdk_pixbuf_get_rowstride (image->pixbuf);
+ nr_arena_image_set_style(NR_ARENA_IMAGE(ai), SP_OBJECT_STYLE(SP_OBJECT(item)));
if (image->aspect_align == SP_ASPECT_NONE)
nr_arena_image_set_pixels (NR_ARENA_IMAGE (ai),
gdk_pixbuf_get_pixels (image->pixbuf),
@@ -885,55 +1044,72 @@ sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flag
*/
GdkPixbuf *
-sp_image_repr_read_image (Inkscape::XML::Node * repr)
+sp_image_repr_read_image (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 = sp_repr_document_root (sp_repr_document (repr))->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;
+
+ 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, 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 {
- /* It should be included xpm, so if it still does not does load, */
- /* our libraries are broken */
- g_assert (pixbuf != NULL);
+ 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, NULL );
+ g_free (fullname);
+ if (pixbuf != NULL) return pixbuf;
+ }
+ }
- 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, 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, 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 *
for (v = item->display; v != NULL; v = v->next) {
pixskip = gdk_pixbuf_get_n_channels (image->pixbuf) * gdk_pixbuf_get_bits_per_sample (image->pixbuf) / 8;
rs = gdk_pixbuf_get_rowstride (image->pixbuf);
+ nr_arena_image_set_style (NR_ARENA_IMAGE(v->arenaitem), SP_OBJECT_STYLE(SP_OBJECT(image)));
if (image->aspect_align == SP_ASPECT_NONE) {
nr_arena_image_set_pixels (NR_ARENA_IMAGE (v->arenaitem),
gdk_pixbuf_get_pixels (image->pixbuf),
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
+ } 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;
+ }
}
/*
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 = sp_curve_unref(image->curve);
+ }
+ return;
+ }
+
+ SPCurve *c = sp_curve_new();
+
+ double const x = image->x.computed;
+ double const y = image->y.computed;
+ double const w = image->width.computed;
+ double const h = image->height.computed;
+
+ sp_curve_moveto(c, x, y);
+ sp_curve_lineto(c, x + w, y);
+ sp_curve_lineto(c, x + w, y + h);
+ sp_curve_lineto(c, x, y + h);
+ sp_curve_lineto(c, x, y);
+
+ sp_curve_closepath_current(c);
+
+ if (image->curve) {
+ image->curve = sp_curve_unref(image->curve);
+ }
+
+ if (c) {
+ image->curve = sp_curve_ref(c);
+ }
+
+ sp_curve_unref(c);
+
+}
+
+/**
+ * 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 sp_curve_copy(image->curve);
+ }
+ return NULL;
+}
+
/*
Local Variables:
mode:c++