Commit 0826dba5 authored by Ivan Molodetskikh's avatar Ivan Molodetskikh

Port feColorMatrix

parent ab720bfe
......@@ -178,6 +178,14 @@ name = "matches"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "matrixmultiply"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.0.1"
......@@ -186,6 +194,33 @@ dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.5"
......@@ -316,6 +351,11 @@ dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rawpointer"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex"
version = "1.0.1"
......@@ -357,6 +397,16 @@ dependencies = [
"phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rulinalg 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rulinalg"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matrixmultiply 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -459,7 +509,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum matrixmultiply 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cac1a66eab356036af85ea093101a14223dc6e3f4c02a59b7d572e5b93270bf7"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
"checksum pango 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45374801e224373c3c0393cd48073c81093494c8735721e81d1dbaa4096b2767"
"checksum pango-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94039b3921a4af4058a3e4335e5d15099101f298a92f5afc40bab3a3027594a1"
......@@ -474,8 +528,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum procedural-masquerade 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1574a51c3fd37b26d2c0032b649d08a7d51d4cca9c41bbc5bf7118fa4509d0"
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019"
"checksum regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13c93d55961981ba9226a213b385216f83ab43bd6ac53ab16b2eeb47e337cf4e"
"checksum regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05b06a75f5217880fc5e905952a42750bf44787e56a6c6d6852ed0992f5e1d54"
"checksum rulinalg 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "04ada202c9685e1d72a7420c578e92b358dbf807d3dfabb676a3dab9cc3bb12f"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
"checksum smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "312a7df010092e73d6bbaf141957e868d4f30efd2bfd9bb1028ad91abec58514"
"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b"
......
......@@ -22,7 +22,6 @@ BUILT_SOURCES += $(enum_sources)
librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
librsvg/filters/common.c \
librsvg/filters/common.h \
librsvg/filters/color_matrix.c \
librsvg/filters/convolve_matrix.c \
librsvg/filters/diffuse_lighting.c \
librsvg/filters/displacement_map.c \
......@@ -79,6 +78,7 @@ RUST_SRC = \
rsvg_internals/src/drawing_ctx.rs \
rsvg_internals/src/filters/bounds.rs \
rsvg_internals/src/filters/blend.rs \
rsvg_internals/src/filters/color_matrix.rs \
rsvg_internals/src/filters/component_transfer.rs \
rsvg_internals/src/filters/composite.rs \
rsvg_internals/src/filters/context.rs \
......
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 sts=4 expandtab: */
/*
rsvg-filter.c: Provides filters
Copyright (C) 2004 Caleb Moore
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Author: Caleb Moore <c.moore@student.unsw.edu.au>
*/
#include "config.h"
#include "../rsvg-private.h"
#include "../rsvg-styles.h"
#include "../rsvg-css.h"
#include "common.h"
typedef struct _RsvgFilterPrimitiveColorMatrix RsvgFilterPrimitiveColorMatrix;
struct _RsvgFilterPrimitiveColorMatrix {
RsvgFilterPrimitive super;
gint *KernelMatrix;
};
static void
rsvg_filter_primitive_color_matrix_render (RsvgNode *node, RsvgComputedValues *values,
RsvgFilterPrimitive *primitive,
RsvgFilterContext *ctx,
RsvgDrawingCtx *draw_ctx)
{
RsvgFilterPrimitiveColorMatrix *color_matrix = (RsvgFilterPrimitiveColorMatrix *) primitive;
guchar ch;
gint x, y;
gint i;
gint rowstride, height, width;
RsvgIRect boundarys;
guchar *in_pixels;
guchar *output_pixels;
cairo_surface_t *output, *in;
int sum;
boundarys = rsvg_filter_primitive_get_bounds (primitive, ctx, draw_ctx);
in = rsvg_filter_get_in (primitive->in, ctx, draw_ctx);
if (in == NULL)
return;
cairo_surface_flush (in);
in_pixels = cairo_image_surface_get_data (in);
height = cairo_image_surface_get_height (in);
width = cairo_image_surface_get_width (in);
rowstride = cairo_image_surface_get_stride (in);
output = _rsvg_image_surface_new (width, height);
if (output == NULL) {
cairo_surface_destroy (in);
return;
}
output_pixels = cairo_image_surface_get_data (output);
const int *ctx_channelmap = rsvg_filter_context_get_channelmap(ctx);
for (y = boundarys.y0; y < boundarys.y1; y++)
for (x = boundarys.x0; x < boundarys.x1; x++) {
int umch;
int alpha = in_pixels[4 * x + y * rowstride + ctx_channelmap[3]];
if (!alpha)
for (umch = 0; umch < 4; umch++) {
sum = color_matrix->KernelMatrix[umch * 5 + 4];
if (sum > 255)
sum = 255;
if (sum < 0)
sum = 0;
output_pixels[4 * x + y * rowstride + ctx_channelmap[umch]] = sum;
} else
for (umch = 0; umch < 4; umch++) {
int umi;
ch = ctx_channelmap[umch];
sum = 0;
for (umi = 0; umi < 4; umi++) {
i = ctx_channelmap[umi];
if (umi != 3)
sum += color_matrix->KernelMatrix[umch * 5 + umi] *
in_pixels[4 * x + y * rowstride + i] / alpha;
else
sum += color_matrix->KernelMatrix[umch * 5 + umi] *
in_pixels[4 * x + y * rowstride + i] / 255;
}
sum += color_matrix->KernelMatrix[umch * 5 + 4];
if (sum > 255)
sum = 255;
if (sum < 0)
sum = 0;
output_pixels[4 * x + y * rowstride + ch] = sum;
}
for (umch = 0; umch < 3; umch++) {
ch = ctx_channelmap[umch];
output_pixels[4 * x + y * rowstride + ch] =
output_pixels[4 * x + y * rowstride + ch] *
output_pixels[4 * x + y * rowstride + ctx_channelmap[3]] / 255;
}
}
cairo_surface_mark_dirty (output);
RsvgFilterPrimitiveOutput op;
op.surface = output;
op.bounds = boundarys;
rsvg_filter_store_output(primitive->result, op, ctx);
/* rsvg_filter_store_result (primitive->result, output, ctx); */
cairo_surface_destroy (in);
}
static void
rsvg_filter_primitive_color_matrix_free (gpointer impl)
{
RsvgFilterPrimitiveColorMatrix *matrix = impl;
g_free (matrix->KernelMatrix);
rsvg_filter_primitive_free (impl);
}
static void
rsvg_filter_primitive_color_matrix_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
{
RsvgFilterPrimitiveColorMatrix *filter = impl;
gint type;
gsize listlen = 0;
RsvgPropertyBagIter *iter;
const char *key;
RsvgAttribute attr;
const char *value;
type = 0;
filter_primitive_set_x_y_width_height_atts ((RsvgFilterPrimitive *) filter, atts);
iter = rsvg_property_bag_iter_begin (atts);
while (rsvg_property_bag_iter_next (iter, &key, &attr, &value)) {
switch (attr) {
case RSVG_ATTRIBUTE_IN:
g_string_assign (filter->super.in, value);
break;
case RSVG_ATTRIBUTE_RESULT:
g_string_assign (filter->super.result, value);
break;
case RSVG_ATTRIBUTE_VALUES: {
unsigned int i;
double *temp;
if (!rsvg_css_parse_number_list (value,
NUMBER_LIST_LENGTH_MAXIMUM,
20,
&temp,
&listlen)) {
rsvg_node_set_attribute_parse_error (node, "values", "invalid number list");
goto out;
}
filter->KernelMatrix = g_new0 (int, listlen);
for (i = 0; i < listlen; i++)
filter->KernelMatrix[i] = temp[i] * 255.;
g_free (temp);
break;
}
case RSVG_ATTRIBUTE_TYPE:
if (!strcmp (value, "matrix"))
type = 0;
else if (!strcmp (value, "saturate"))
type = 1;
else if (!strcmp (value, "hueRotate"))
type = 2;
else if (!strcmp (value, "luminanceToAlpha"))
type = 3;
else
type = 0;
break;
default:
break;
}
}
if (type == 0) {
if (listlen != 20) {
if (filter->KernelMatrix != NULL)
g_free (filter->KernelMatrix);
filter->KernelMatrix = g_new0 (int, 20);
}
} else if (type == 1) {
float s;
if (listlen != 0) {
s = filter->KernelMatrix[0];
g_free (filter->KernelMatrix);
} else
s = 255;
filter->KernelMatrix = g_new0 (int, 20);
filter->KernelMatrix[0] = 0.213 * 255. + 0.787 * s;
filter->KernelMatrix[1] = 0.715 * 255. - 0.715 * s;
filter->KernelMatrix[2] = 0.072 * 255. - 0.072 * s;
filter->KernelMatrix[5] = 0.213 * 255. - 0.213 * s;
filter->KernelMatrix[6] = 0.715 * 255. + 0.285 * s;
filter->KernelMatrix[7] = 0.072 * 255. - 0.072 * s;
filter->KernelMatrix[10] = 0.213 * 255. - 0.213 * s;
filter->KernelMatrix[11] = 0.715 * 255. - 0.715 * s;
filter->KernelMatrix[12] = 0.072 * 255. + 0.928 * s;
filter->KernelMatrix[18] = 255;
} else if (type == 2) {
double cosval, sinval, arg;
if (listlen != 0) {
arg = (double) filter->KernelMatrix[0] / 255.;
g_free (filter->KernelMatrix);
} else
arg = 0;
cosval = cos (arg);
sinval = sin (arg);
filter->KernelMatrix = g_new0 (int, 20);
filter->KernelMatrix[0] = (0.213 + cosval * 0.787 + sinval * -0.213) * 255.;
filter->KernelMatrix[1] = (0.715 + cosval * -0.715 + sinval * -0.715) * 255.;
filter->KernelMatrix[2] = (0.072 + cosval * -0.072 + sinval * 0.928) * 255.;
filter->KernelMatrix[5] = (0.213 + cosval * -0.213 + sinval * 0.143) * 255.;
filter->KernelMatrix[6] = (0.715 + cosval * 0.285 + sinval * 0.140) * 255.;
filter->KernelMatrix[7] = (0.072 + cosval * -0.072 + sinval * -0.283) * 255.;
filter->KernelMatrix[10] = (0.213 + cosval * -0.213 + sinval * -0.787) * 255.;
filter->KernelMatrix[11] = (0.715 + cosval * -0.715 + sinval * 0.715) * 255.;
filter->KernelMatrix[12] = (0.072 + cosval * 0.928 + sinval * 0.072) * 255.;
filter->KernelMatrix[18] = 255;
} else if (type == 3) {
if (filter->KernelMatrix != NULL)
g_free (filter->KernelMatrix);
filter->KernelMatrix = g_new0 (int, 20);
filter->KernelMatrix[15] = 0.2125 * 255.;
filter->KernelMatrix[16] = 0.7154 * 255.;
filter->KernelMatrix[17] = 0.0721 * 255.;
} else {
g_assert_not_reached ();
}
out:
rsvg_property_bag_iter_end (iter);
}
RsvgNode *
rsvg_new_filter_primitive_color_matrix (const char *element_name, RsvgNode *parent, const char *id, const char *klass)
{
RsvgFilterPrimitiveColorMatrix *filter;
filter = g_new0 (RsvgFilterPrimitiveColorMatrix, 1);
filter->super.in = g_string_new ("none");
filter->super.result = g_string_new ("none");
filter->KernelMatrix = NULL;
filter->super.render = rsvg_filter_primitive_color_matrix_render;
return rsvg_rust_cnode_new (RSVG_NODE_TYPE_FILTER_PRIMITIVE_COLOR_MATRIX,
parent,
id,
klass,
filter,
rsvg_filter_primitive_color_matrix_set_atts,
rsvg_filter_primitive_color_matrix_free);
}
......@@ -32,6 +32,7 @@ cssparser = "0.23"
lazy_static = "1.0.0"
phf = "0.7.21"
float-cmp = "0.4.0"
rulinalg = "0.4"
[dependencies.cairo-sys-rs]
version = "0.6"
......
use std::cell::RefCell;
use cairo::{self, ImageSurface};
use rulinalg::{
self,
matrix::{BaseMatrix, BaseMatrixMut, Matrix},
};
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
use error::NodeError;
use handle::RsvgHandle;
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{self, ListLength, NumberListError, ParseError};
use property_bag::PropertyBag;
use surface_utils::{
iterators::Pixels,
shared_surface::SharedImageSurface,
ImageSurfaceDataExt,
Pixel,
};
use util::clamp;
use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{make_result, Filter, FilterError, PrimitiveWithInput};
/// Color matrix operation types.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum OperationType {
Matrix,
Saturate,
HueRotate,
LuminanceToAlpha,
}
/// The `feColorMatrix` filter primitive.
pub struct ColorMatrix {
base: PrimitiveWithInput,
matrix: RefCell<Matrix<f64>>,
}
impl ColorMatrix {
/// Constructs a new `ColorMatrix` with empty properties.
#[inline]
pub fn new() -> ColorMatrix {
ColorMatrix {
base: PrimitiveWithInput::new::<Self>(),
matrix: RefCell::new(Matrix::identity(5)),
}
}
}
impl NodeTrait for ColorMatrix {
fn set_atts(
&self,
node: &RsvgNode,
handle: *const RsvgHandle,
pbag: &PropertyBag,
) -> NodeResult {
self.base.set_atts(node, handle, pbag)?;
// First, determine the operation type.
let mut operation_type = OperationType::Matrix;
for (_, attr, value) in pbag.iter().filter(|(_, attr, _)| *attr == Attribute::Type) {
operation_type = OperationType::parse(attr, value)?;
}
// Now read the matrix correspondingly.
// LuminanceToAlpha doesn't accept any matrix.
if operation_type == OperationType::LuminanceToAlpha {
self.matrix.replace(matrix![
0.0, 0.0, 0.0, 0.0, 0.0;
0.0, 0.0, 0.0, 0.0, 0.0;
0.0, 0.0, 0.0, 0.0, 0.0;
0.2125, 0.7154, 0.0721, 0.0, 0.0;
0.0, 0.0, 0.0, 0.0, 1.0
]);
} else {
for (_, attr, value) in pbag
.iter()
.filter(|(_, attr, _)| *attr == Attribute::Values)
{
let new_matrix = match operation_type {
OperationType::LuminanceToAlpha => unreachable!(),
OperationType::Matrix => {
let top = Matrix::new(
4,
5,
parsers::number_list_from_str(value, ListLength::Exact(20)).map_err(
|err| {
NodeError::parse_error(
attr,
match err {
NumberListError::IncorrectNumberOfElements => {
ParseError::new(
"incorrect number of elements: expected 20",
)
}
NumberListError::Parse(err) => err,
},
)
},
)?,
);
let mut matrix = Matrix::identity(5);
matrix.sub_slice_mut([0, 0], 4, 5).set_to(top);
matrix
}
OperationType::Saturate => {
let s = parsers::number(value)
.map_err(|err| NodeError::parse_error(attr, err))?;
if s < 0.0 || s > 1.0 {
return Err(NodeError::value_error(attr, "expected value from 0 to 1"));
}
matrix![
0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s, 0.0, 0.0;
0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s, 0.0, 0.0;
0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s, 0.0, 0.0;
0.0, 0.0, 0.0, 1.0, 0.0;
0.0, 0.0, 0.0, 0.0, 1.0
]
}
OperationType::HueRotate => {
let degrees = parsers::number(value)
.map_err(|err| NodeError::parse_error(attr, err))?;
let (sin, cos) = degrees.to_radians().sin_cos();
let a = matrix![
0.213, 0.715, 0.072;
0.213, 0.715, 0.072;
0.213, 0.715, 0.072
];
let b = matrix![
0.787, -0.715, -0.072;
-0.213, 0.285, -0.072;
-0.213, -0.715, 0.928
];
let c = matrix![
-0.213, -0.715, 0.928;
0.143, 0.140, -0.283;
-0.787, 0.715, 0.072
];
let top_left = a + b * cos + c * sin;
let mut matrix = Matrix::identity(5);
matrix.sub_slice_mut([0, 0], 3, 3).set_to(top_left);
matrix
}
};
self.matrix.replace(new_matrix);
}
}
Ok(())
}
#[inline]
fn get_c_impl(&self) -> *const RsvgCNodeImpl {
self.base.get_c_impl()
}
}
impl Filter for ColorMatrix {
fn render(
&self,
_node: &RsvgNode,
ctx: &FilterContext,
draw_ctx: &mut DrawingCtx,
) -> Result<FilterResult, FilterError> {
let input = make_result(self.base.get_input(ctx, draw_ctx))?;
let bounds = self
.base
.get_bounds(ctx)
.add_input(&input)
.into_irect(draw_ctx);
let matrix = &*self.matrix.borrow();
/// Multiplies a matrix by a vector and puts the result into a slice.
#[inline]
fn mul_into(out: &mut [f64], m: &Matrix<f64>, v: &[f64]) {
assert!(v.len() == m.cols());
assert!(v.len() == out.len());
for (i, row) in m.row_iter().enumerate() {
out[i] = rulinalg::utils::dot(row.raw_slice(), v);
}
}
let mut output_surface = ImageSurface::create(
cairo::Format::ARgb32,
ctx.source_graphic().width(),
ctx.source_graphic().height(),
).map_err(FilterError::OutputSurfaceCreation)?;
let output_stride = output_surface.get_stride() as usize;
{
let mut output_data = output_surface.get_data().unwrap();
for (x, y, pixel) in Pixels::new(input.surface(), bounds) {
let alpha = f64::from(pixel.a) / 255f64;
let pixel_vec = [
f64::from(pixel.r) / 255f64 / alpha,
f64::from(pixel.g) / 255f64 / alpha,
f64::from(pixel.b) / 255f64 / alpha,
alpha,
1.0,
];
let mut new_pixel_vec = [0.0; 5];
mul_into(&mut new_pixel_vec, &matrix, &pixel_vec);
let new_alpha = clamp(new_pixel_vec[3], 0.0, 1.0);
let premultiply = |x: f64| (clamp(x, 0.0, 1.0) * new_alpha * 255f64).round() as u8;
let output_pixel = Pixel {
r: premultiply(new_pixel_vec[0]),
g: premultiply(new_pixel_vec[1]),
b: premultiply(new_pixel_vec[2]),
a: (new_alpha * 255f64).round() as u8,
};
output_data.set_pixel(output_stride, output_pixel, x, y);
}
}
Ok(FilterResult {
name: self.base.result.borrow().clone(),
output: FilterOutput {
surface: SharedImageSurface::new(output_surface).unwrap(),
bounds,
},
})
}
#[inline]
fn is_affected_by_color_interpolation_filters() -> bool {
true
}
}
impl OperationType {
fn parse(attr: Attribute, s: &str) -> Result<Self, NodeError> {
match s {
"matrix" => Ok(OperationType::Matrix),
"saturate" => Ok(OperationType::Saturate),
"hueRotate" => Ok(OperationType::HueRotate),
"luminanceToAlpha" => Ok(OperationType::LuminanceToAlpha),
_ => Err(NodeError::parse_error(
attr,
ParseError::new("invalid value"),
)),
}
}
}
......@@ -136,6 +136,7 @@ pub fn filter_render(
})
.for_each(|(mut c, linear_rgb)| match c.get_type() {
NodeType::FilterPrimitiveBlend
| NodeType::FilterPrimitiveColorMatrix
| NodeType::FilterPrimitiveComponentTransfer
| NodeType::FilterPrimitiveComposite
| NodeType::FilterPrimitiveFlood
......
......@@ -31,6 +31,7 @@ pub mod node;
use self::node::NodeFilter;
pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod flood;
......
......@@ -22,6 +22,9 @@ extern crate lazy_static;
#[macro_use]
extern crate downcast_rs;
#[macro_use]
extern crate rulinalg;
pub use attributes::rsvg_attribute_from_name;
pub use cnode::{rsvg_rust_cnode_get_impl, rsvg_rust_cnode_new};
......
......@@ -6,6 +6,7 @@ use std::ptr;
use attributes::Attribute;
use clip_path::NodeClipPath;