mirror of
https://github.com/typst/typst
synced 2025-06-08 13:16:24 +08:00
First attempt at conic gradients
This commit is contained in:
parent
79173b1c55
commit
16bcad9d5a
@ -162,7 +162,7 @@ pub fn pdf(typst_document: &PagedDocument) -> Vec<u8> {
|
|||||||
let mut page = document.start_page_with(settings);
|
let mut page = document.start_page_with(settings);
|
||||||
let mut surface = page.surface();
|
let mut surface = page.surface();
|
||||||
let mut fc = FrameContext::new(typst_page.frame.size());
|
let mut fc = FrameContext::new(typst_page.frame.size());
|
||||||
// println!("{:?}", &typst_page.frame);
|
println!("{:?}", &typst_page.frame);
|
||||||
process_frame(
|
process_frame(
|
||||||
&mut fc,
|
&mut fc,
|
||||||
&typst_page.frame,
|
&typst_page.frame,
|
||||||
@ -381,7 +381,7 @@ pub fn handle_shape(
|
|||||||
shape.fill_rule,
|
shape.fill_rule,
|
||||||
false,
|
false,
|
||||||
surface,
|
surface,
|
||||||
fc.state().transforms(Size::zero()),
|
fc.state().transforms(shape.geometry.bbox_size()),
|
||||||
);
|
);
|
||||||
surface.fill_path(&path, fill);
|
surface.fill_path(&path, fill);
|
||||||
}
|
}
|
||||||
@ -400,7 +400,7 @@ pub fn handle_shape(
|
|||||||
stroke,
|
stroke,
|
||||||
false,
|
false,
|
||||||
surface,
|
surface,
|
||||||
fc.state().transforms(Size::zero()),
|
fc.state().transforms(shape.geometry.bbox_size()),
|
||||||
);
|
);
|
||||||
surface.stroke_path(&path, stroke);
|
surface.stroke_path(&path, stroke);
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,11 @@ use krilla::geom::NormalizedF32;
|
|||||||
use krilla::page::{NumberingStyle, PageLabel};
|
use krilla::page::{NumberingStyle, PageLabel};
|
||||||
use krilla::surface::Surface;
|
use krilla::surface::Surface;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use typst_library::layout::{Abs, Angle, Ratio, Transform};
|
use typst_library::layout::{Abs, Angle, AngleUnit, Ratio, Transform};
|
||||||
use typst_library::model::Numbering;
|
use typst_library::model::Numbering;
|
||||||
use typst_library::visualize::{ColorSpace, DashPattern, FillRule, FixedStroke, Gradient, Paint, Pattern, RelativeTo};
|
use typst_library::visualize::{Color, ColorSpace, DashPattern, FillRule, FixedStroke, Gradient, Paint, Pattern, RelativeTo, WeightedColor};
|
||||||
use typst_utils::Numeric;
|
use typst_utils::Numeric;
|
||||||
|
use crate::color_old::ColorSpaceExt;
|
||||||
use crate::gradient_old::PdfGradient;
|
use crate::gradient_old::PdfGradient;
|
||||||
|
|
||||||
pub(crate) fn fill(
|
pub(crate) fn fill(
|
||||||
@ -57,6 +58,19 @@ fn dash(dash: &DashPattern<Abs, Abs>) -> krilla::path::StrokeDash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn convert_color(color: &Color) -> (krilla::color::rgb::Color, u8) {
|
||||||
|
let components = color.to_space(ColorSpace::Srgb).to_vec4_u8();
|
||||||
|
(
|
||||||
|
krilla::color::rgb::Color::new(
|
||||||
|
components[0],
|
||||||
|
components[1],
|
||||||
|
components[2],
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
components[3],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
gc: &mut GlobalContext,
|
gc: &mut GlobalContext,
|
||||||
paint: &Paint,
|
paint: &Paint,
|
||||||
@ -66,18 +80,10 @@ fn paint(
|
|||||||
) -> (krilla::paint::Paint, u8) {
|
) -> (krilla::paint::Paint, u8) {
|
||||||
match paint {
|
match paint {
|
||||||
Paint::Solid(c) => {
|
Paint::Solid(c) => {
|
||||||
let components = c.to_space(ColorSpace::Srgb).to_vec4_u8();
|
let (c, alpha) = convert_color(c);
|
||||||
(
|
(c.into(), alpha)
|
||||||
krilla::color::rgb::Color::new(
|
},
|
||||||
components[0],
|
Paint::Gradient(g) => convert_gradient(g, on_text, transforms),
|
||||||
components[1],
|
|
||||||
components[2],
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
components[3],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Paint::Gradient(_) => (krilla::color::rgb::Color::black().into(), 255),
|
|
||||||
Paint::Pattern(p) => convert_pattern(gc, p, on_text, surface, transforms),
|
Paint::Pattern(p) => convert_pattern(gc, p, on_text, surface, transforms),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,15 +202,6 @@ fn convert_gradient(
|
|||||||
RelativeTo::Self_ => transforms.size,
|
RelativeTo::Self_ => transforms.size,
|
||||||
RelativeTo::Parent => transforms.container_size,
|
RelativeTo::Parent => transforms.container_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (offset_x, offset_y) = match gradient {
|
|
||||||
Gradient::Conic(conic) => (
|
|
||||||
-size.x * (1.0 - conic.center.x.get() / 2.0) / 2.0,
|
|
||||||
-size.y * (1.0 - conic.center.y.get() / 2.0) / 2.0,
|
|
||||||
),
|
|
||||||
_ => (Abs::zero(), Abs::zero()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let rotation = gradient.angle().unwrap_or_else(Angle::zero);
|
let rotation = gradient.angle().unwrap_or_else(Angle::zero);
|
||||||
|
|
||||||
let transform = match gradient.unwrap_relative(on_text) {
|
let transform = match gradient.unwrap_relative(on_text) {
|
||||||
@ -212,26 +209,17 @@ fn convert_gradient(
|
|||||||
RelativeTo::Parent => transforms.container_transform,
|
RelativeTo::Parent => transforms.container_transform,
|
||||||
};
|
};
|
||||||
|
|
||||||
let scale_offset = match gradient {
|
|
||||||
Gradient::Conic(_) => 4.0_f64,
|
|
||||||
_ => 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let pdf_gradient = PdfGradient {
|
let pdf_gradient = PdfGradient {
|
||||||
aspect_ratio: size.aspect_ratio(),
|
aspect_ratio: size.aspect_ratio(),
|
||||||
transform: transform
|
transform,
|
||||||
.pre_concat(Transform::translate(
|
|
||||||
offset_x * scale_offset,
|
|
||||||
offset_y * scale_offset,
|
|
||||||
))
|
|
||||||
.pre_concat(Transform::scale(
|
|
||||||
Ratio::new(size.x.to_pt() * scale_offset),
|
|
||||||
Ratio::new(size.y.to_pt() * scale_offset),
|
|
||||||
)),
|
|
||||||
gradient: gradient.clone(),
|
gradient: gradient.clone(),
|
||||||
angle: Gradient::correct_aspect_ratio(rotation, size.aspect_ratio()),
|
angle: Gradient::correct_aspect_ratio(rotation, size.aspect_ratio()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let actual_transform = transforms.transform.invert().unwrap().pre_concat(transform)
|
||||||
|
.pre_concat(Transform::scale(-Ratio::one(), Ratio::one()))
|
||||||
|
.pre_concat(Transform::rotate(-pdf_gradient.angle));
|
||||||
|
|
||||||
match &gradient {
|
match &gradient {
|
||||||
Gradient::Linear(_) => {
|
Gradient::Linear(_) => {
|
||||||
(krilla::color::rgb::Color::black().into(), 255)
|
(krilla::color::rgb::Color::black().into(), 255)
|
||||||
@ -242,6 +230,29 @@ fn convert_gradient(
|
|||||||
Gradient::Conic(conic) => {
|
Gradient::Conic(conic) => {
|
||||||
// Correct the gradient's angle
|
// Correct the gradient's angle
|
||||||
let angle = Gradient::correct_aspect_ratio(conic.angle, pdf_gradient.aspect_ratio);
|
let angle = Gradient::correct_aspect_ratio(conic.angle, pdf_gradient.aspect_ratio);
|
||||||
|
let mut stops: Vec<krilla::paint::Stop<krilla::color::rgb::Color>> = vec![];
|
||||||
|
|
||||||
|
let mut add_single = |color: &Color, offset: Ratio| {
|
||||||
|
let (color, opacity) = convert_color(color);
|
||||||
|
let opacity = NormalizedF32::new((opacity as f32) / 255.0).unwrap();
|
||||||
|
let offset = NormalizedF32::new(offset.get() as f32).unwrap();
|
||||||
|
let stop = krilla::paint::Stop {
|
||||||
|
offset,
|
||||||
|
color,
|
||||||
|
opacity,
|
||||||
|
};
|
||||||
|
stops.push(stop);
|
||||||
|
};
|
||||||
|
|
||||||
|
let encode_space = conic
|
||||||
|
.space
|
||||||
|
.hue_index()
|
||||||
|
.map(|_| ColorSpace::Oklab)
|
||||||
|
.unwrap_or(conic.space);
|
||||||
|
|
||||||
|
if let Some((c, t)) = conic.stops.first() {
|
||||||
|
add_single(c, *t);
|
||||||
|
}
|
||||||
|
|
||||||
for window in conic.stops.windows(2) {
|
for window in conic.stops.windows(2) {
|
||||||
let ((c0, t0), (c1, t1)) = (window[0], window[1]);
|
let ((c0, t0), (c1, t1)) = (window[0], window[1]);
|
||||||
@ -257,24 +268,13 @@ fn convert_gradient(
|
|||||||
} else {
|
} else {
|
||||||
0.05
|
0.05
|
||||||
};
|
};
|
||||||
let encode_space = conic
|
|
||||||
.space
|
|
||||||
.hue_index()
|
|
||||||
.map(|_| ColorSpace::Oklab)
|
|
||||||
.unwrap_or(conic.space);
|
|
||||||
let mut t_x = t0.get();
|
let mut t_x = t0.get();
|
||||||
let dt = (t1.get() - t0.get()).min(max_dt);
|
let dt = (t1.get() - t0.get()).min(max_dt);
|
||||||
|
|
||||||
// Special casing for sharp gradients.
|
// Special casing for sharp gradients.
|
||||||
if t0 == t1 {
|
if t0 == t1 {
|
||||||
write_patch(
|
add_single(&c1, t1);
|
||||||
&mut vertices,
|
|
||||||
t0.get() as f32,
|
|
||||||
t1.get() as f32,
|
|
||||||
&encode_space.convert(c0),
|
|
||||||
&encode_space.convert(c1),
|
|
||||||
angle,
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,33 +283,38 @@ fn convert_gradient(
|
|||||||
|
|
||||||
// The current progress in the current window.
|
// The current progress in the current window.
|
||||||
let t = |t| (t - t0.get()) / (t1.get() - t0.get());
|
let t = |t| (t - t0.get()) / (t1.get() - t0.get());
|
||||||
let c = Color::mix_iter(
|
|
||||||
[WeightedColor::new(c0, 1.0 - t(t_x)), WeightedColor::new(c1, t(t_x))],
|
|
||||||
conic.space,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let c_next = Color::mix_iter(
|
let c_next = Color::mix_iter(
|
||||||
[
|
[
|
||||||
WeightedColor::new(c0, 1.0 - t(t_next)),
|
WeightedColor::new(c0, 1.0 - t(t_next)),
|
||||||
WeightedColor::new(c1, t(t_next)),
|
WeightedColor::new(c1, t(t_next)),
|
||||||
],
|
],
|
||||||
conic.space,
|
encode_space,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
write_patch(
|
add_single(&c_next, Ratio::new(t_next));
|
||||||
&mut vertices,
|
|
||||||
t_x as f32,
|
|
||||||
t_next as f32,
|
|
||||||
&encode_space.convert(c),
|
|
||||||
&encode_space.convert(c_next),
|
|
||||||
angle,
|
|
||||||
);
|
|
||||||
|
|
||||||
t_x = t_next;
|
t_x = t_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add_single(&c1, t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("{:?}, {:?}", size.x.to_f32(), size.y.to_f32());
|
||||||
|
println!("{:?}, {:?}", conic.center.x.get(), conic.center.y.get());
|
||||||
|
|
||||||
|
let sweep = krilla::paint::SweepGradient {
|
||||||
|
cx: size.x.to_f32() * conic.center.x.get() as f32,
|
||||||
|
cy: size.y.to_f32() * conic.center.y.get() as f32,
|
||||||
|
start_angle: 0.0,
|
||||||
|
end_angle: 360.0,
|
||||||
|
transform: actual_transform.as_krilla(),
|
||||||
|
spread_method: Default::default(),
|
||||||
|
stops: stops.into(),
|
||||||
|
anti_alias: gradient.anti_alias(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(sweep.into(), 255)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user