X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsp-image.cpp;h=95e104b7652774de37739cd4266a38ea20e179d1;hb=4f79c421fc7c86689cdb502c0651c2e0fc840750;hp=c5ed9117b162e4c684290780d3a9e99299578f3e;hpb=89949341e299d2857fc2435d5a8758845947dc0a;p=inkscape.git diff --git a/src/sp-image.cpp b/src/sp-image.cpp index c5ed9117b..95e104b76 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -16,11 +16,17 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include +#include +#include +#include +#include +#include +#include //#define GDK_PIXBUF_ENABLE_BACKEND 1 //#include #include "display/nr-arena-image.h" +#include //Added for preserveAspectRatio support -- EAF #include "enums.h" @@ -30,10 +36,13 @@ #include "brokenimage.xpm" #include "document.h" #include "sp-image.h" +#include "sp-clippath.h" #include #include "xml/quote.h" #include +#include "libnr/nr-matrix-fns.h" + #include "io/sys.h" #include #if ENABLE_LCMS @@ -65,8 +74,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); +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); @@ -225,17 +236,17 @@ 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 ) +GdkPixbuf* pixbuf_new_from_file( const char *filename, GError **/*error*/ ) { GdkPixbuf* buf = NULL; PushPull youme; @@ -355,12 +366,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 +451,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 +461,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 ); } @@ -502,6 +567,7 @@ sp_image_init (SPImage *image) image->width.unset(); image->height.unset(); image->aspect_align = SP_ASPECT_NONE; + image->curve = NULL; } static void @@ -551,6 +617,10 @@ sp_image_release (SPObject *object) } #endif // ENABLE_LCMS + if (image->curve) { + image->curve = sp_curve_unref (image->curve); + } + if (((SPObjectClass *) parent_class)->release) ((SPObjectClass *) parent_class)->release (object); } @@ -676,14 +746,17 @@ 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; + 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); @@ -695,7 +768,10 @@ sp_image_update (SPObject *object, SPCtx *ctx, unsigned int 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 @@ -736,7 +812,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,7 +945,6 @@ sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags) } } } - sp_image_update_canvas_image ((SPImage *) object); } @@ -903,7 +978,7 @@ sp_image_write (SPObject *object, Inkscape::XML::Node *repr, guint flags) } 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 +999,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 +1013,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 +1060,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; @@ -1030,55 +1106,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 = 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; + + 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 (" 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 * @@ -1143,9 +1236,30 @@ 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 + } 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 +1448,45 @@ 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 = sp_curve_unref(image->curve); + } + return; + } + + NRRect rect; + sp_image_bbox(image, &rect, NR::identity(), 0); + NR::Maybe rect2 = rect.upgrade(); + SPCurve *c = sp_curve_new_from_rect(rect2); + + 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++