diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-07-29 00:56:18 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-07-29 00:56:18 +0000 |
| commit | f014bfbb52135cfa486a22269e1a7770d0713a22 (patch) | |
| tree | 1cc575f01e48b353abab4c82a74413a4eb0e0750 /src | |
| parent | Add OpenMP IF clauses to filter templates, instead of modifying num_threads (diff) | |
| download | inkscape-f014bfbb52135cfa486a22269e1a7770d0713a22.tar.gz inkscape-f014bfbb52135cfa486a22269e1a7770d0713a22.zip | |
First half of image filter (display from external image)
(bzr r9508.1.38)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/nr-filter-image.cpp | 122 | ||||
| -rw-r--r-- | src/display/nr-filter-image.h | 10 | ||||
| -rw-r--r-- | src/display/nr-filter-slot.h | 1 |
3 files changed, 118 insertions, 15 deletions
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 5dec64dc7..eda19afcd 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -11,6 +11,7 @@ */ #include "document.h" #include "sp-item.h" +#include "display/cairo-utils.h" #include "display/nr-arena.h" #include "display/nr-arena-item.h" #include "display/nr-filter.h" @@ -23,11 +24,12 @@ namespace Inkscape { namespace Filters { -FilterImage::FilterImage() : - SVGElem(0), - document(0), - feImageHref(0), - image_pixbuf(0) +FilterImage::FilterImage() + : SVGElem(0) + , document(0) + , feImageHref(0) + , image_surface(0) + , broken_ref(false) { } FilterPrimitive * FilterImage::create() { @@ -40,17 +42,18 @@ FilterImage::~FilterImage() g_free(feImageHref); } -/* void FilterImage::render_cairo(FilterSlot &slot) { if (!feImageHref) return; - cairo_surface_t *input = slot.getcairo(_input); + //cairo_surface_t *input = slot.getcairo(_input); if (from_element) { if (!SVGElem) return; + return; //not ready yet +/* // prep the document // TODO: do not recreate the rendering tree every time sp_document_ensure_up_to_date(document); @@ -69,7 +72,7 @@ void FilterImage::render_cairo(FilterSlot &slot) Geom::Rect area = *optarea; Geom::Matrix itrans = slot.get_units().get_matrix_display2pb(); - NRRectL const &slot_area = slot.get_units().get_slot_area(); + NRRectL const &slot_area = slot.get_slot_area(); NRRectL rect; rect.x0 = floor(area->left()); rect.x1 = ceil(area->right()); @@ -95,10 +98,103 @@ void FilterImage::render_cairo(FilterSlot &slot) slot.set(_output, out); cairo_surface_destroy(out); - return; + return;*/ + } + + 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 && document->base, + * 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->base, 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 ); + } + 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 %i", e.code() ); + return; + } + catch (const Gdk::PixbufError & e) + { + g_warning("Gdk::PixbufError in FilterImage::render: %i", e.code() ); + 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); + } + + // Native size of image + //width = image->get_width(); + //height = image->get_height(); + //rowstride = image->get_rowstride(); + + convert_pixbuf_normal_to_argb32(image->gobj()); + + image_surface = cairo_image_surface_create_for_data(image->get_pixels(), + CAIRO_FORMAT_ARGB32, image->get_width(), image->get_height(), image->get_rowstride()); } -}*/ + NRRectL const &sa = slot.get_slot_area(); + cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + sa.x1 - sa.x0, sa.y1 - sa.y0); + + cairo_t *ct = cairo_create(out); + cairo_translate(ct, -sa.x0, -sa.y0); + // now ct is in pb coordinates + ink_cairo_transform(ct, slot.get_units().get_matrix_primitiveunits2pb()); + // now ct is in the coordinates of feImageX etc. + + // Get the object bounding box in user coordinates. Image is placed with respect to box. + // Array values: 0: width; 3: height; 4: -x; 5: -y. + Geom::Matrix object_bbox = slot.get_units().get_matrix_user2filterunits(); + + // feImage is suppose to use the same parameters as a normal SVG image. + // If a width or height is set to zero, the image is not suppose to be displayed. + // This does not seem to be what Firefox or Opera does, nor does the W3C displacement + // filter test expect this behavior. If the width and/or height are zero, we use + // the width and height of the object bounding box. + if( feImageWidth == 0 ) feImageWidth = object_bbox[0]; + if( feImageHeight == 0 ) feImageHeight = object_bbox[3]; + + double scaleX = feImageWidth / image->get_width(); + double scaleY = feImageHeight / image->get_height(); + + cairo_translate(ct, feImageX, feImageY); + cairo_scale(ct, scaleX, scaleY); + cairo_set_source_surface(ct, image_surface, 0, 0); + cairo_paint(ct); + cairo_destroy(ct); + + slot.set(_output, out); +} + +bool FilterImage::can_handle_affine(Geom::Matrix const &) +{ + return true; +} + +#if 0 int FilterImage::render(FilterSlot &slot, FilterUnits const &units) { if (!feImageHref) return 0; @@ -279,10 +375,16 @@ int FilterImage::render(FilterSlot &slot, FilterUnits const &units) { slot.set(_output, out); return 0; } +#endif void FilterImage::set_href(const gchar *href){ if (feImageHref) g_free (feImageHref); feImageHref = (href) ? g_strdup (href) : NULL; + + if (image_surface) { + cairo_surface_destroy(image_surface); + } + image.reset(); } void FilterImage::set_document(SPDocument *doc){ diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index f3565ef9f..1f7064196 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -27,8 +27,8 @@ public: static FilterPrimitive *create(); virtual ~FilterImage(); - virtual int render(FilterSlot &slot, FilterUnits const &units); - virtual FilterTraits get_input_traits(); + virtual void render_cairo(FilterSlot &slot); + virtual bool can_handle_affine(Geom::Matrix const &); void set_document( SPDocument *document ); void set_href(const gchar *href); void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height); @@ -38,11 +38,11 @@ public: private: SPDocument *document; gchar *feImageHref; - guint8* image_pixbuf; Glib::RefPtr<Gdk::Pixbuf> image; - int width, height, rowstride; + cairo_surface_t *image_surface; + //int width, height, rowstride; float feImageX,feImageY,feImageWidth,feImageHeight; - bool has_alpha; + bool broken_ref; }; } /* namespace Filters */ diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index a9fac61d9..57f3f1054 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -79,6 +79,7 @@ public: FilterUnits const &get_units() const { return _units; } NRRectL const &get_slot_area() const { return _slot_area; } + NRRectL const &get_sg_area() const { return *_source_graphic_area; } private: typedef std::map<int, cairo_surface_t *> SlotMap; |
