mirror of
https://github.com/typst/typst
synced 2025-06-08 13:16:24 +08:00
add radial gradients
This commit is contained in:
parent
67bc4bbf71
commit
9b8c30a5f0
@ -362,6 +362,7 @@ pub fn handle_shape(
|
|||||||
path_builder.line_to(l.x.to_f32(), l.y.to_f32());
|
path_builder.line_to(l.x.to_f32(), l.y.to_f32());
|
||||||
}
|
}
|
||||||
Geometry::Rect(r) => {
|
Geometry::Rect(r) => {
|
||||||
|
println!("{:?}", r);
|
||||||
if let Some(r) = Rect::from_xywh(0.0, 0.0, r.x.to_f32(), r.y.to_f32()) {
|
if let Some(r) = Rect::from_xywh(0.0, 0.0, r.x.to_f32(), r.y.to_f32()) {
|
||||||
path_builder.push_rect(r);
|
path_builder.push_rect(r);
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,15 @@ use crate::primitive::{FillRuleExt, LineCapExt, LineJoinExt, TransformExt};
|
|||||||
use crate::AbsExt;
|
use crate::AbsExt;
|
||||||
use krilla::geom::NormalizedF32;
|
use krilla::geom::NormalizedF32;
|
||||||
use krilla::page::{NumberingStyle, PageLabel};
|
use krilla::page::{NumberingStyle, PageLabel};
|
||||||
|
use krilla::paint::SpreadMethod;
|
||||||
use krilla::surface::Surface;
|
use krilla::surface::Surface;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use krilla::paint::SpreadMethod;
|
|
||||||
use typst_library::layout::{Abs, Angle, AngleUnit, Quadrant, Ratio, Size, Transform};
|
use typst_library::layout::{Abs, Angle, AngleUnit, Quadrant, Ratio, Size, Transform};
|
||||||
use typst_library::model::Numbering;
|
use typst_library::model::Numbering;
|
||||||
use typst_library::visualize::{Color, ColorSpace, DashPattern, FillRule, FixedStroke, Gradient, Paint, Pattern, RatioOrAngle, RelativeTo, WeightedColor};
|
use typst_library::visualize::{
|
||||||
|
Color, ColorSpace, DashPattern, FillRule, FixedStroke, Gradient, Paint, Pattern,
|
||||||
|
RatioOrAngle, RelativeTo, WeightedColor,
|
||||||
|
};
|
||||||
use typst_utils::Numeric;
|
use typst_utils::Numeric;
|
||||||
|
|
||||||
pub(crate) fn fill(
|
pub(crate) fn fill(
|
||||||
@ -60,11 +63,7 @@ fn dash(dash: &DashPattern<Abs, Abs>) -> krilla::path::StrokeDash {
|
|||||||
fn convert_color(color: &Color) -> (krilla::color::rgb::Color, u8) {
|
fn convert_color(color: &Color) -> (krilla::color::rgb::Color, u8) {
|
||||||
let components = color.to_space(ColorSpace::Srgb).to_vec4_u8();
|
let components = color.to_space(ColorSpace::Srgb).to_vec4_u8();
|
||||||
(
|
(
|
||||||
krilla::color::rgb::Color::new(
|
krilla::color::rgb::Color::new(components[0], components[1], components[2])
|
||||||
components[0],
|
|
||||||
components[1],
|
|
||||||
components[2],
|
|
||||||
)
|
|
||||||
.into(),
|
.into(),
|
||||||
components[3],
|
components[3],
|
||||||
)
|
)
|
||||||
@ -81,7 +80,7 @@ fn paint(
|
|||||||
Paint::Solid(c) => {
|
Paint::Solid(c) => {
|
||||||
let (c, alpha) = convert_color(c);
|
let (c, alpha) = convert_color(c);
|
||||||
(c.into(), alpha)
|
(c.into(), alpha)
|
||||||
},
|
}
|
||||||
Paint::Gradient(g) => convert_gradient(g, on_text, transforms),
|
Paint::Gradient(g) => convert_gradient(g, on_text, transforms),
|
||||||
Paint::Pattern(p) => convert_pattern(gc, p, on_text, surface, transforms),
|
Paint::Pattern(p) => convert_pattern(gc, p, on_text, surface, transforms),
|
||||||
}
|
}
|
||||||
@ -208,7 +207,8 @@ fn convert_gradient(
|
|||||||
RelativeTo::Parent => transforms.container_transform,
|
RelativeTo::Parent => transforms.container_transform,
|
||||||
};
|
};
|
||||||
|
|
||||||
let angle = Gradient::correct_aspect_ratio(rotation, size.aspect_ratio());
|
let angle = rotation;
|
||||||
|
println!("angle: {:?}", angle);
|
||||||
|
|
||||||
let mut stops: Vec<krilla::paint::Stop<krilla::color::rgb::Color>> = vec![];
|
let mut stops: Vec<krilla::paint::Stop<krilla::color::rgb::Color>> = vec![];
|
||||||
|
|
||||||
@ -216,18 +216,14 @@ fn convert_gradient(
|
|||||||
let (color, opacity) = convert_color(color);
|
let (color, opacity) = convert_color(color);
|
||||||
let opacity = NormalizedF32::new((opacity as f32) / 255.0).unwrap();
|
let opacity = NormalizedF32::new((opacity as f32) / 255.0).unwrap();
|
||||||
let offset = NormalizedF32::new(offset.get() as f32).unwrap();
|
let offset = NormalizedF32::new(offset.get() as f32).unwrap();
|
||||||
let stop = krilla::paint::Stop {
|
let stop = krilla::paint::Stop { offset, color, opacity };
|
||||||
offset,
|
|
||||||
color,
|
|
||||||
opacity,
|
|
||||||
};
|
|
||||||
stops.push(stop);
|
stops.push(stop);
|
||||||
};
|
};
|
||||||
|
|
||||||
match &gradient {
|
match &gradient {
|
||||||
Gradient::Linear(linear) => {
|
Gradient::Linear(linear) => {
|
||||||
let actual_transform = transforms.transform.invert().unwrap()
|
let actual_transform =
|
||||||
.pre_concat(transform);
|
transforms.transform.invert().unwrap().pre_concat(transform);
|
||||||
|
|
||||||
if let Some((c, t)) = linear.stops.first() {
|
if let Some((c, t)) = linear.stops.first() {
|
||||||
add_single(c, *t);
|
add_single(c, *t);
|
||||||
@ -244,7 +240,8 @@ fn convert_gradient(
|
|||||||
if gradient.space().hue_index().is_some() {
|
if gradient.space().hue_index().is_some() {
|
||||||
for i in 0..=32 {
|
for i in 0..=32 {
|
||||||
let t = i as f64 / 32.0;
|
let t = i as f64 / 32.0;
|
||||||
let real_t = Ratio::new(first.1.get() * (1.0 - t) + second.1.get() * t);
|
let real_t =
|
||||||
|
Ratio::new(first.1.get() * (1.0 - t) + second.1.get() * t);
|
||||||
|
|
||||||
let c = gradient.sample(RatioOrAngle::Ratio(real_t));
|
let c = gradient.sample(RatioOrAngle::Ratio(real_t));
|
||||||
add_single(&c, real_t);
|
add_single(&c, real_t);
|
||||||
@ -274,7 +271,9 @@ fn convert_gradient(
|
|||||||
y1,
|
y1,
|
||||||
x2,
|
x2,
|
||||||
y2,
|
y2,
|
||||||
transform: actual_transform.as_krilla().pre_concat(krilla::geom::Transform::from_scale(size.x.to_f32(), size.y.to_f32())),
|
transform: actual_transform.as_krilla().pre_concat(
|
||||||
|
krilla::geom::Transform::from_scale(size.x.to_f32(), size.y.to_f32()),
|
||||||
|
),
|
||||||
spread_method: SpreadMethod::Pad,
|
spread_method: SpreadMethod::Pad,
|
||||||
stops: stops.into(),
|
stops: stops.into(),
|
||||||
anti_alias: gradient.anti_alias(),
|
anti_alias: gradient.anti_alias(),
|
||||||
@ -282,16 +281,74 @@ fn convert_gradient(
|
|||||||
|
|
||||||
(linear.into(), 255)
|
(linear.into(), 255)
|
||||||
}
|
}
|
||||||
Gradient::Radial(_) => {
|
Gradient::Radial(radial) => {
|
||||||
(krilla::color::rgb::Color::black().into(), 255)
|
let actual_transform =
|
||||||
|
transforms.transform.invert().unwrap().pre_concat(transform);
|
||||||
|
|
||||||
|
if let Some((c, t)) = radial.stops.first() {
|
||||||
|
add_single(c, *t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the individual gradient functions for each pair of stops.
|
||||||
|
for window in radial.stops.windows(2) {
|
||||||
|
let (first, second) = (window[0], window[1]);
|
||||||
|
|
||||||
|
// If we have a hue index or are using Oklab, we will create several
|
||||||
|
// stops in-between to make the gradient smoother without interpolation
|
||||||
|
// issues with native color spaces.
|
||||||
|
let mut last_c = first.0;
|
||||||
|
if gradient.space().hue_index().is_some() {
|
||||||
|
for i in 0..=32 {
|
||||||
|
let t = i as f64 / 32.0;
|
||||||
|
let real_t =
|
||||||
|
Ratio::new(first.1.get() * (1.0 - t) + second.1.get() * t);
|
||||||
|
|
||||||
|
let c = gradient.sample(RatioOrAngle::Ratio(real_t));
|
||||||
|
add_single(&c, real_t);
|
||||||
|
last_c = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_single(&second.0, second.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let radial = krilla::paint::RadialGradient {
|
||||||
|
fx: radial.focal_center.x.get() as f32,
|
||||||
|
fy: radial.focal_center.y.get() as f32,
|
||||||
|
fr: radial.focal_radius.get() as f32,
|
||||||
|
cx: radial.center.x.get() as f32,
|
||||||
|
cy: radial.center.y.get() as f32,
|
||||||
|
cr: radial.radius.get() as f32,
|
||||||
|
transform: actual_transform.as_krilla().pre_concat(
|
||||||
|
krilla::geom::Transform::from_scale(size.x.to_f32(), size.y.to_f32()),
|
||||||
|
),
|
||||||
|
spread_method: SpreadMethod::Pad,
|
||||||
|
stops: stops.into(),
|
||||||
|
anti_alias: gradient.anti_alias(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(radial.into(), 255)
|
||||||
}
|
}
|
||||||
Gradient::Conic(conic) => {
|
Gradient::Conic(conic) => {
|
||||||
// Correct the gradient's angle
|
// Correct the gradient's angle
|
||||||
let cx = size.x.to_f32() * conic.center.x.get() as f32;
|
let cx = size.x.to_f32() * conic.center.x.get() as f32;
|
||||||
let cy = size.y.to_f32() * conic.center.y.get() as f32;
|
let cy = size.y.to_f32() * conic.center.y.get() as f32;
|
||||||
let actual_transform = transforms.transform.invert().unwrap().pre_concat(transform)
|
let actual_transform = transforms
|
||||||
.pre_concat(Transform::scale_at(-Ratio::one(), Ratio::one(), Abs::pt(cx as f64), Abs::pt(cy as f64)))
|
.transform
|
||||||
.pre_concat(Transform::rotate_at(-angle, Abs::pt(cx as f64), Abs::pt(cy as f64)));
|
.invert()
|
||||||
|
.unwrap()
|
||||||
|
.pre_concat(transform)
|
||||||
|
.pre_concat(Transform::rotate_at(
|
||||||
|
angle,
|
||||||
|
Abs::pt(cx as f64),
|
||||||
|
Abs::pt(cy as f64),
|
||||||
|
))
|
||||||
|
.pre_concat(Transform::scale_at(
|
||||||
|
-Ratio::one(),
|
||||||
|
Ratio::one(),
|
||||||
|
Abs::pt(cx as f64),
|
||||||
|
Abs::pt(cy as f64),
|
||||||
|
));
|
||||||
|
|
||||||
if let Some((c, t)) = conic.stops.first() {
|
if let Some((c, t)) = conic.stops.first() {
|
||||||
add_single(c, *t);
|
add_single(c, *t);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user