feat: update krilla

bounding boxes for links are now automatically generated by krilla
This commit is contained in:
Tobias Schmitz 2025-07-17 16:51:10 +02:00
parent 0bd0dc6d92
commit f8f900d40b
No known key found for this signature in database
4 changed files with 25 additions and 70 deletions

4
Cargo.lock generated
View File

@ -1373,7 +1373,7 @@ dependencies = [
[[package]] [[package]]
name = "krilla" name = "krilla"
version = "0.4.0" version = "0.4.0"
source = "git+https://github.com/LaurenzV/krilla?branch=main#c0a456829bb63212470a6fa29d604dd9e051a9bd" source = "git+https://github.com/LaurenzV/krilla?branch=main#d40f81a01ca8f8654510a76effeef12518437800"
dependencies = [ dependencies = [
"base64", "base64",
"bumpalo", "bumpalo",
@ -1402,7 +1402,7 @@ dependencies = [
[[package]] [[package]]
name = "krilla-svg" name = "krilla-svg"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/LaurenzV/krilla?branch=main#c0a456829bb63212470a6fa29d604dd9e051a9bd" source = "git+https://github.com/LaurenzV/krilla?branch=main#d40f81a01ca8f8654510a76effeef12518437800"
dependencies = [ dependencies = [
"flate2", "flate2",
"fontdb", "fontdb",

View File

@ -373,6 +373,12 @@ fn finish(
.collect::<EcoVec<_>>(); .collect::<EcoVec<_>>();
Err(errors) Err(errors)
} }
KrillaError::DuplicateTagId(_, _) => {
unreachable!("duplicate IDs shouldn't be generated")
}
KrillaError::UnknownTagId(_, _) => {
unreachable!("all referenced IDs should be present in the tag tree")
}
KrillaError::Image(_, loc) => { KrillaError::Image(_, loc) => {
let span = to_span(loc); let span = to_span(loc);
bail!(span, "failed to process image"); bail!(span, "failed to process image");
@ -597,16 +603,6 @@ fn convert_error(
"{prefix} missing document date"; "{prefix} missing document date";
hint: "set the date of the document" hint: "set the date of the document"
), ),
ValidationError::DuplicateTagId(_id, loc) => {
// TODO: display the id and better error message
let span = to_span(*loc);
error!(span, "{prefix} duplicate tag id")
}
ValidationError::UnknownTagId(_id, loc) => {
// TODO: display the id and better error message
let span = to_span(*loc);
error!(span, "{prefix} unknown header tag id")
}
} }
} }

View File

@ -4,7 +4,7 @@ use krilla::annotation::Target;
use krilla::configure::Validator; use krilla::configure::Validator;
use krilla::destination::XyzDestination; use krilla::destination::XyzDestination;
use krilla::geom as kg; use krilla::geom as kg;
use typst_library::layout::{Abs, Point, Position, Size}; use typst_library::layout::{Point, Position, Size};
use typst_library::model::Destination; use typst_library::model::Destination;
use crate::convert::{FrameContext, GlobalContext}; use crate::convert::{FrameContext, GlobalContext};
@ -15,8 +15,7 @@ pub(crate) struct LinkAnnotation {
pub(crate) id: tags::LinkId, pub(crate) id: tags::LinkId,
pub(crate) placeholder: Placeholder, pub(crate) placeholder: Placeholder,
pub(crate) alt: Option<String>, pub(crate) alt: Option<String>,
pub(crate) rect: kg::Rect, pub(crate) quad_points: Vec<kg::Quadrilateral>,
pub(crate) quad_points: Vec<kg::Point>,
pub(crate) target: Target, pub(crate) target: Target,
} }
@ -54,27 +53,21 @@ pub(crate) fn handle_link(
}; };
let alt = link.alt.as_ref().map(EcoString::to_string); let alt = link.alt.as_ref().map(EcoString::to_string);
let rect = to_rect(fc, size); let quad = to_quadrilateral(fc, size);
let quadpoints = quadpoints(rect);
// Unfortunately quadpoints still aren't well supported by most PDF readers, // Unfortunately quadpoints still aren't well supported by most PDF readers,
// even by acrobat. Which is understandable since they were only introduced // even by acrobat. Which is understandable since they were only introduced
// in PDF 1.6 (2005) /s // in PDF 1.6 (2005) /s
let should_use_quadpoints = gc.options.standards.config.validator() == Validator::UA1; let should_use_quadpoints = gc.options.standards.config.validator() == Validator::UA1;
match fc.get_link_annotation(link_id) { match fc.get_link_annotation(link_id) {
Some(annotation) if should_use_quadpoints => { Some(annotation) if should_use_quadpoints => annotation.quad_points.push(quad),
// Update the bounding box and add the quadpoints to an existing link annotation.
annotation.rect = bounding_rect(annotation.rect, rect);
annotation.quad_points.extend_from_slice(&quadpoints);
}
_ => { _ => {
let placeholder = gc.tags.placeholders.reserve(); let placeholder = gc.tags.placeholders.reserve();
link_nodes.push(TagNode::Placeholder(placeholder)); link_nodes.push(TagNode::Placeholder(placeholder));
fc.push_link_annotation(LinkAnnotation { fc.push_link_annotation(LinkAnnotation {
id: link_id, id: link_id,
placeholder, placeholder,
rect, quad_points: vec![quad],
quad_points: quadpoints.to_vec(),
alt, alt,
target, target,
}); });
@ -82,53 +75,20 @@ pub(crate) fn handle_link(
} }
} }
// Compute the bounding box of the transformed link. /// Compute the quadrilateral representing the transformed rectangle of this frame.
fn to_rect(fc: &FrameContext, size: Size) -> kg::Rect { fn to_quadrilateral(fc: &FrameContext, size: Size) -> kg::Quadrilateral {
let mut min_x = Abs::inf();
let mut min_y = Abs::inf();
let mut max_x = -Abs::inf();
let mut max_y = -Abs::inf();
let pos = Point::zero(); let pos = Point::zero();
let points = [
for point in [
pos,
pos + Point::with_x(size.x),
pos + Point::with_y(size.y), pos + Point::with_y(size.y),
pos + size.to_point(), pos + size.to_point(),
] { pos + Point::with_x(size.x),
let t = point.transform(fc.state().transform()); pos,
min_x.set_min(t.x); ];
min_y.set_min(t.y);
max_x.set_max(t.x);
max_y.set_max(t.y);
}
let x1 = min_x.to_f32(); kg::Quadrilateral(points.map(|point| {
let x2 = max_x.to_f32(); let p = point.transform(fc.state().transform());
let y1 = min_y.to_f32(); kg::Point::from_xy(p.x.to_f32(), p.y.to_f32())
let y2 = max_y.to_f32(); }))
kg::Rect::from_ltrb(x1, y1, x2, y2).unwrap()
}
fn bounding_rect(a: kg::Rect, b: kg::Rect) -> kg::Rect {
kg::Rect::from_ltrb(
a.left().min(b.left()),
a.top().min(b.top()),
a.right().max(b.right()),
a.bottom().max(b.bottom()),
)
.unwrap()
}
fn quadpoints(rect: kg::Rect) -> [kg::Point; 4] {
[
kg::Point::from_xy(rect.left(), rect.bottom()),
kg::Point::from_xy(rect.right(), rect.bottom()),
kg::Point::from_xy(rect.right(), rect.top()),
kg::Point::from_xy(rect.left(), rect.top()),
]
} }
fn pos_to_target(gc: &mut GlobalContext, pos: Position) -> Option<Target> { fn pos_to_target(gc: &mut GlobalContext, pos: Position) -> Option<Target> {

View File

@ -324,10 +324,9 @@ pub(crate) fn add_annotations(
annotations: Vec<LinkAnnotation>, annotations: Vec<LinkAnnotation>,
) { ) {
for annotation in annotations.into_iter() { for annotation in annotations.into_iter() {
let LinkAnnotation { id: _, placeholder, alt, rect, quad_points, target } = let LinkAnnotation { id: _, placeholder, alt, quad_points, target } = annotation;
annotation;
let annot = krilla::annotation::Annotation::new_link( let annot = krilla::annotation::Annotation::new_link(
krilla::annotation::LinkAnnotation::new(rect, Some(quad_points), target), krilla::annotation::LinkAnnotation::new_with_quad_points(quad_points, target),
alt, alt,
); );
let annot_id = page.add_tagged_annotation(annot); let annot_id = page.add_tagged_annotation(annot);