Commit dd535e70 authored by RazrFalcon's avatar RazrFalcon

Added partial 'feImage' support.

parent 72f012a8
......@@ -31,7 +31,7 @@ travis-ci = { repository = "RazrFalcon/resvg" }
log = "0.4.5"
rgb = "0.8.9"
#usvg = "0.2"
usvg = { git = "https://github.com/RazrFalcon/usvg", rev = "5bb30d9" }
usvg = { git = "https://github.com/RazrFalcon/usvg", rev = "1bcd5b7" }
#usvg = { path = "../usvg" }
unicode-segmentation = "1.2.1"
......
......@@ -32,9 +32,10 @@ pub fn apply(
filter: &usvg::Filter,
bbox: Rect,
ts: &usvg::Transform,
opt: &Options,
canvas: &mut cairo::ImageSurface,
) {
CairoFilter::apply(filter, bbox, ts, canvas);
CairoFilter::apply(filter, bbox, ts, opt, canvas);
}
......@@ -383,6 +384,40 @@ impl Filter<cairo::ImageSurface> for CairoFilter {
Ok(Image::from_image(buffer, ColorSpace::SRGB))
}
fn apply_image(
fe: &usvg::FeImage,
region: ScreenRect,
subregion: ScreenRect,
opt: &Options,
) -> Result<Image, Error> {
let buffer = create_image(region.width, region.height)?;
match fe.data {
usvg::FeImageKind::None => {}
usvg::FeImageKind::Image(ref data, format) => {
let cr = cairo::Context::new(&buffer);
let dx = (subregion.x - region.x) as f64;
let dy = (subregion.y - region.y) as f64;
cr.translate(dx, dy);
let view_box = usvg::ViewBox {
rect: ScreenRect::new(0, 0, subregion.width, subregion.height).to_rect(),
aspect: fe.aspect,
};
if format == usvg::ImageFormat::SVG {
super::image::draw_svg(data, view_box, opt, &cr);
} else {
super::image::draw_raster(data, view_box, opt, &cr);
}
}
usvg::FeImageKind::Use => {}
}
Ok(Image::from_image(buffer, ColorSpace::SRGB))
}
fn apply_to_canvas(
input: Image,
region: ScreenRect,
......
......@@ -26,20 +26,21 @@ pub fn draw(
}
if image.format == usvg::ImageFormat::SVG {
draw_svg(image, opt, cr);
draw_svg(&image.data, image.view_box, opt, cr);
} else {
draw_raster(image, opt, cr);
draw_raster(&image.data, image.view_box, opt, cr);
}
image.view_box.rect
}
fn draw_raster(
image: &usvg::Image,
pub fn draw_raster(
data: &usvg::ImageData,
mut view_box: usvg::ViewBox,
opt: &Options,
cr: &cairo::Context,
) {
let img = match image.data {
let img = match data {
usvg::ImageData::Path(ref path) => {
let path = image::get_abs_path(path, opt);
try_opt_warn!(gdk_pixbuf::Pixbuf::new_from_file(path.clone()).ok(), (),
......@@ -52,7 +53,6 @@ fn draw_raster(
};
let img_size = ScreenSize::new(img.get_width() as u32, img.get_height() as u32);
let mut view_box = image.view_box;
image::prepare_image_viewbox(img_size, &mut view_box);
let r = view_box.rect;
......@@ -144,15 +144,16 @@ fn load_raster_data(data: &[u8]) -> Option<gdk_pixbuf::Pixbuf> {
loader.get_pixbuf()
}
fn draw_svg(
image: &usvg::Image,
pub fn draw_svg(
data: &usvg::ImageData,
view_box: usvg::ViewBox,
opt: &Options,
cr: &cairo::Context,
) {
let (tree, sub_opt) = try_opt!(image::load_sub_svg(image, opt), ());
let (tree, sub_opt) = try_opt!(image::load_sub_svg(data, opt), ());
let img_size = tree.svg_node().size.to_screen_size();
let (ts, clip) = image::prepare_sub_svg_geom(image, img_size);
let (ts, clip) = image::prepare_sub_svg_geom(view_box, img_size);
if let Some(clip) = clip {
cr.rectangle(clip.x, clip.y, clip.width, clip.height);
......
......@@ -310,7 +310,7 @@ fn render_group_impl(
if let Some(filter_node) = node.tree().defs_by_id(id) {
if let usvg::NodeKind::Filter(ref filter) = *filter_node.borrow() {
let ts = usvg::Transform::from_native(&curr_ts);
filter::apply(filter, bbox, &ts, &mut *sub_surface);
filter::apply(filter, bbox, &ts, opt, &mut *sub_surface);
}
}
}
......
......@@ -28,9 +28,10 @@ pub fn apply(
filter: &usvg::Filter,
bbox: Rect,
ts: &usvg::Transform,
opt: &Options,
canvas: &mut qt::Image,
) {
QtFilter::apply(filter, bbox, ts, canvas);
QtFilter::apply(filter, bbox, ts, opt, canvas);
}
......@@ -318,6 +319,40 @@ impl Filter<qt::Image> for QtFilter {
Ok(Image::from_image(buffer, ColorSpace::SRGB))
}
fn apply_image(
fe: &usvg::FeImage,
region: ScreenRect,
subregion: ScreenRect,
opt: &Options,
) -> Result<Image, Error> {
let mut buffer = create_image(region.width, region.height)?;
match fe.data {
usvg::FeImageKind::None => {}
usvg::FeImageKind::Image(ref data, format) => {
let mut p = qt::Painter::new(&mut buffer);
let dx = (subregion.x - region.x) as f64;
let dy = (subregion.y - region.y) as f64;
p.translate(dx, dy);
let view_box = usvg::ViewBox {
rect: ScreenRect::new(0, 0, subregion.width, subregion.height).to_rect(),
aspect: fe.aspect,
};
if format == usvg::ImageFormat::SVG {
super::image::draw_svg(data, view_box, opt, &mut p);
} else {
super::image::draw_raster(data, view_box, opt, &mut p);
}
}
usvg::FeImageKind::Use => {}
}
Ok(Image::from_image(buffer, ColorSpace::SRGB))
}
fn apply_to_canvas(
input: Image,
region: ScreenRect,
......
......@@ -21,20 +21,21 @@ pub fn draw(
}
if image.format == usvg::ImageFormat::SVG {
draw_svg(image, opt, p);
draw_svg(&image.data, image.view_box, opt, p);
} else {
draw_raster(image, opt, p);
draw_raster(&image.data, image.view_box, opt, p);
}
image.view_box.rect
}
fn draw_raster(
image: &usvg::Image,
pub fn draw_raster(
data: &usvg::ImageData,
mut view_box: usvg::ViewBox,
opt: &Options,
p: &mut qt::Painter,
) {
let img = match image.data {
let img = match data {
usvg::ImageData::Path(ref path) => {
let path = image::get_abs_path(path, opt);
try_opt_warn!(qt::Image::from_file(&path), (),
......@@ -47,7 +48,6 @@ fn draw_raster(
};
let img_size = ScreenSize::new(img.width(), img.height());
let mut view_box = image.view_box;
image::prepare_image_viewbox(img_size, &mut view_box);
let r = view_box.rect;
......@@ -83,15 +83,16 @@ fn draw_raster(
}
}
fn draw_svg(
image: &usvg::Image,
pub fn draw_svg(
data: &usvg::ImageData,
view_box: usvg::ViewBox,
opt: &Options,
p: &mut qt::Painter,
) {
let (tree, sub_opt) = try_opt!(image::load_sub_svg(image, opt), ());
let (tree, sub_opt) = try_opt!(image::load_sub_svg(data, opt), ());
let img_size = tree.svg_node().size.to_screen_size();
let (ts, clip) = image::prepare_sub_svg_geom(image, img_size);
let (ts, clip) = image::prepare_sub_svg_geom(view_box, img_size);
if let Some(clip) = clip {
p.set_clip_rect(clip.x, clip.y, clip.width, clip.height);
......
......@@ -285,7 +285,7 @@ fn render_group_impl(
if let Some(filter_node) = node.tree().defs_by_id(id) {
if let usvg::NodeKind::Filter(ref filter) = *filter_node.borrow() {
let ts = usvg::Transform::from_native(&curr_ts);
filter::apply(filter, bbox, &ts, &mut sub_img);
filter::apply(filter, bbox, &ts, opt, &mut sub_img);
}
}
}
......
......@@ -125,9 +125,10 @@ pub trait Filter<T: ImageExt> {
filter: &usvg::Filter,
bbox: Rect,
ts: &usvg::Transform,
opt: &Options,
canvas: &mut T,
) {
match Self::_apply(filter, bbox, ts, canvas) {
match Self::_apply(filter, bbox, ts, opt, canvas) {
Ok(_) => {}
Err(Error::AllocFailed) =>
warn!("Memory allocation failed while processing the '{}' filter. Skipped.", filter.id),
......@@ -142,6 +143,7 @@ pub trait Filter<T: ImageExt> {
filter: &usvg::Filter,
bbox: Rect,
ts: &usvg::Transform,
opt: &Options,
canvas: &mut T,
) -> Result<(), Error> {
let mut results = Vec::new();
......@@ -152,6 +154,7 @@ pub trait Filter<T: ImageExt> {
for primitive in &filter.children {
let input = &primitive.filter_input;
let cs = primitive.color_interpolation;
let subregion = calc_subregion(filter, primitive, bbox, region, ts, &results);
let mut result = match primitive.kind {
usvg::FilterKind::FeBlend(ref fe) => {
......@@ -182,9 +185,11 @@ pub trait Filter<T: ImageExt> {
let input = Self::get_input(input, region, &results, canvas)?;
Self::apply_tile(input, region)
}
usvg::FilterKind::FeImage(ref fe) => {
Self::apply_image(fe, region, subregion, opt)
}
}?;
let subregion = calc_subregion(filter, primitive, region, ts, &results);
if region != subregion {
// Clip result.
......@@ -274,6 +279,13 @@ pub trait Filter<T: ImageExt> {
region: ScreenRect,
) -> Result<Image<T>, Error>;
fn apply_image(
fe: &usvg::FeImage,
region: ScreenRect,
subregion: ScreenRect,
opt: &Options,
) -> Result<Image<T>, Error>;
fn apply_to_canvas(
input: Image<T>,
region: ScreenRect,
......@@ -557,33 +569,49 @@ fn calc_region(
fn calc_subregion<T: ImageExt>(
filter: &usvg::Filter,
primitive: &usvg::FilterPrimitive,
bbox: Rect,
filter_region: ScreenRect,
ts: &usvg::Transform,
results: &[FilterResult<T>],
) -> ScreenRect {
let region = if let usvg::FilterKind::FeOffset(..) = primitive.kind {
// `feOffset` inherits it's region from the input.
match primitive.filter_input {
Some(usvg::FilterInput::Reference(ref name)) => {
match results.iter().rev().find(|v| v.name == *name) {
Some(ref res) => res.image.region,
None => filter_region,
let region = match primitive.kind {
usvg::FilterKind::FeOffset(..) => {
// `feOffset` inherits it's region from the input.
match primitive.filter_input {
Some(usvg::FilterInput::Reference(ref name)) => {
match results.iter().rev().find(|v| v.name == *name) {
Some(ref res) => res.image.region,
None => filter_region,
}
}
}
None => {
match results.last() {
Some(ref res) => res.image.region,
None => filter_region,
None => {
match results.last() {
Some(ref res) => res.image.region,
None => filter_region,
}
}
_ => {
filter_region
}
}
_ => {
}
usvg::FilterKind::FeImage(..) => {
// `feImage` uses the object bbox.
if filter.primitive_units == usvg::Units::ObjectBoundingBox {
return Rect::new(
bbox.x + bbox.width * primitive.x.unwrap_or(0.0),
bbox.y + bbox.height * primitive.y.unwrap_or(0.0),
bbox.width * primitive.width.unwrap_or(1.0),
bbox.height * primitive.height.unwrap_or(1.0),
).transform(*ts).to_screen_rect();
} else {
filter_region
}
}
} else {
filter_region
_ => filter_region,
};
// TODO: Wrong! Does not account rotate and skew.
let subregion = if filter.primitive_units == usvg::Units::ObjectBoundingBox {
let subregion_bbox = Rect::new(
primitive.x.unwrap_or(0.0),
......@@ -595,10 +623,11 @@ fn calc_subregion<T: ImageExt>(
region.to_rect().transform(ts)
} else {
let (dx, dy) = ts.get_translate();
let (sx, sy) = ts.get_scale();
Rect::new(
primitive.x.map(|n| n * sx).unwrap_or(region.x as f64),
primitive.y.map(|n| n * sy).unwrap_or(region.y as f64),
primitive.x.map(|n| n * sx + dx).unwrap_or(region.x as f64),
primitive.y.map(|n| n * sy + dy).unwrap_or(region.y as f64),
primitive.width.map(|n| n * sx).unwrap_or(region.width as f64),
primitive.height.map(|n| n * sy).unwrap_or(region.height as f64),
)
......
......@@ -17,7 +17,7 @@ use {
};
pub fn load_sub_svg(
image: &usvg::Image,
data: &usvg::ImageData,
opt: &Options,
) -> Option<(usvg::Tree, Options)> {
let mut sub_opt = Options {
......@@ -33,7 +33,7 @@ pub fn load_sub_svg(
background: None,
};
let tree = match image.data {
let tree = match data {
usvg::ImageData::Path(ref path) => {
let path = get_abs_path(path, opt);
sub_opt.usvg.path = Some(path.clone());
......@@ -84,10 +84,9 @@ pub fn prepare_image_viewbox(img_size: ScreenSize, view_box: &mut usvg::ViewBox)
}
pub fn prepare_sub_svg_geom(
image: &usvg::Image,
mut view_box: usvg::ViewBox,
img_size: ScreenSize,
) -> (usvg::Transform, Option<Rect>) {
let mut view_box = image.view_box;
prepare_image_viewbox(img_size, &mut view_box);
let r = view_box.rect;
......
......@@ -165,18 +165,22 @@ impl ScreenRect {
ScreenSize::new(self.width, self.height)
}
/// Returns rect's left edge position.
pub fn left(&self) -> i32 {
self.x
}
/// Returns rect's right edge position.
pub fn right(&self) -> i32 {
self.x + self.width as i32
}
/// Returns rect's top edge position.
pub fn top(&self) -> i32 {
self.y
}
/// Returns rect's bottom edge position.
pub fn bottom(&self) -> i32 {
self.y + self.height as i32
}
......@@ -194,6 +198,7 @@ impl ScreenRect {
true
}
/// Fits the current rect into the specified bounds.
pub fn fit_to_rect(&self, bounds: ScreenRect) -> Self {
let mut r = *self;
......@@ -211,6 +216,7 @@ impl ScreenRect {
r
}
/// Converts into `Rect`.
pub fn to_rect(&self) -> Rect {
Rect::new(self.x as f64, self.y as f64, self.width as f64, self.height as f64)
}
......
......@@ -17,7 +17,7 @@ And as an embeddable library to paint SVG on an application native canvas.
#![doc(html_root_url = "https://docs.rs/resvg/0.3.0")]
//#![forbid(unsafe_code)]
//#![warn(missing_docs)]
#![warn(missing_docs)]
#[macro_use] pub extern crate usvg;
#[macro_use] extern crate log;
......
e-feImage-001.svg
e-feImage-002.svg
e-feImage-003.svg
e-feImage-004.svg
e-feImage-005.svg
e-feImage-006.svg
e-feImage-007.svg
e-feImage-008.svg
e-feImage-009.svg
e-feImage-010.svg
e-feImage-011.svg
e-filter-055.svg
e-feImage-001.svg
e-feImage-002.svg
e-feImage-003.svg
e-feImage-004.svg
e-feImage-005.svg
e-feImage-006.svg
e-feImage-007.svg
e-feImage-008.svg
e-feImage-009.svg
e-feImage-010.svg
e-feImage-011.svg
e-filter-055.svg
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment