mirror of
https://github.com/typst/typst
synced 2025-06-08 13:16:24 +08:00
Reformat + add some link handling agian
This commit is contained in:
parent
1d135ddd90
commit
761c8cf15e
@ -62,7 +62,14 @@ impl RasterImage {
|
|||||||
// Extract pixel density.
|
// Extract pixel density.
|
||||||
let dpi = determine_dpi(&data, exif.as_ref());
|
let dpi = determine_dpi(&data, exif.as_ref());
|
||||||
|
|
||||||
Ok(Self(Arc::new(Repr { data, format, is_rotated, dynamic: Arc::new(dynamic), icc, dpi })))
|
Ok(Self(Arc::new(Repr {
|
||||||
|
data,
|
||||||
|
format,
|
||||||
|
is_rotated,
|
||||||
|
dynamic: Arc::new(dynamic),
|
||||||
|
icc,
|
||||||
|
dpi,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The raw image data.
|
/// The raw image data.
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
use ecow::eco_format;
|
use ecow::eco_format;
|
||||||
use image::{DynamicImage, GenericImageView, Rgba};
|
use image::{GenericImageView, Rgba};
|
||||||
use pdf_writer::{Chunk, Filter, Finish, Ref};
|
use pdf_writer::{Chunk, Filter, Finish, Ref};
|
||||||
|
use std::collections::HashMap;
|
||||||
use typst_library::diag::{At, SourceResult, StrResult};
|
use typst_library::diag::{At, SourceResult, StrResult};
|
||||||
use typst_library::visualize::{
|
use typst_library::visualize::{ColorSpace, Image, ImageKind, RasterImage, SvgImage};
|
||||||
ColorSpace, Image, ImageKind, RasterFormat, RasterImage, SvgImage,
|
|
||||||
};
|
|
||||||
use typst_utils::Deferred;
|
use typst_utils::Deferred;
|
||||||
|
|
||||||
use crate::{color_old, deflate, PdfChunk, WithGlobalRefs};
|
use crate::{color_old, deflate, PdfChunk, WithGlobalRefs};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::content_old::Builder;
|
||||||
use crate::primitive::{PointExt, SizeExt, TransformExt};
|
use crate::primitive::{PointExt, SizeExt, TransformExt};
|
||||||
use crate::{paint, AbsExt};
|
use crate::{paint, AbsExt};
|
||||||
use bytemuck::TransparentWrapper;
|
use bytemuck::TransparentWrapper;
|
||||||
@ -16,7 +17,9 @@ use std::hash::{Hash, Hasher};
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use svg2pdf::usvg::Rect;
|
use svg2pdf::usvg::Rect;
|
||||||
use typst_library::layout::{Abs, Frame, FrameItem, GroupItem, PagedDocument, Point, Ratio, Size, Transform};
|
use typst_library::layout::{
|
||||||
|
Abs, Frame, FrameItem, GroupItem, PagedDocument, Point, Size, Transform,
|
||||||
|
};
|
||||||
use typst_library::model::Destination;
|
use typst_library::model::Destination;
|
||||||
use typst_library::text::{Font, Glyph, TextItem};
|
use typst_library::text::{Font, Glyph, TextItem};
|
||||||
use typst_library::visualize::{
|
use typst_library::visualize::{
|
||||||
@ -37,7 +40,11 @@ struct State {
|
|||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Creates a new, clean state for a given `size`.
|
/// Creates a new, clean state for a given `size`.
|
||||||
fn new(size: Size, transform_chain: Transform, container_transform_chain: Transform) -> Self {
|
fn new(
|
||||||
|
size: Size,
|
||||||
|
transform_chain: Transform,
|
||||||
|
container_transform_chain: Transform,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
transform_chain,
|
transform_chain,
|
||||||
transform: Transform::identity(),
|
transform: Transform::identity(),
|
||||||
@ -73,15 +80,15 @@ impl State {
|
|||||||
|
|
||||||
pub(crate) struct FrameContext {
|
pub(crate) struct FrameContext {
|
||||||
states: Vec<State>,
|
states: Vec<State>,
|
||||||
|
annotations: Vec<krilla::annotation::Annotation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameContext {
|
impl FrameContext {
|
||||||
pub fn new(size: Size) -> Self {
|
pub fn new(size: Size) -> Self {
|
||||||
Self { states: vec![State::new(size, Transform::identity(), Transform::identity())] }
|
Self {
|
||||||
|
states: vec![State::new(size, Transform::identity(), Transform::identity())],
|
||||||
|
annotations: vec![],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_new(&self, size: Size) -> Self {
|
|
||||||
Self { states: vec![State::new(size, self.state().transform_chain, self.state().container_transform_chain)] }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self) {
|
pub fn push(&mut self) {
|
||||||
@ -148,12 +155,11 @@ impl krilla::font::Glyph for PdfGlyph {
|
|||||||
|
|
||||||
pub struct GlobalContext {
|
pub struct GlobalContext {
|
||||||
fonts: HashMap<Font, krilla::font::Font>,
|
fonts: HashMap<Font, krilla::font::Font>,
|
||||||
annotations: Vec<krilla::annotation::Annotation>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalContext {
|
impl GlobalContext {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { fonts: Default::default(), annotations: vec![] }
|
Self { fonts: Default::default() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,8 +199,7 @@ pub fn pdf(typst_document: &PagedDocument) -> Vec<u8> {
|
|||||||
);
|
);
|
||||||
surface.finish();
|
surface.finish();
|
||||||
|
|
||||||
let annotations = std::mem::take(&mut context.annotations);
|
for annotation in fc.annotations {
|
||||||
for annotation in annotations {
|
|
||||||
page.add_annotation(annotation);
|
page.add_annotation(annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +242,7 @@ pub fn process_frame(
|
|||||||
FrameItem::Image(image, size, span) => {
|
FrameItem::Image(image, size, span) => {
|
||||||
handle_image(fc, image, *size, surface)
|
handle_image(fc, image, *size, surface)
|
||||||
}
|
}
|
||||||
FrameItem::Link(d, s) => {}
|
FrameItem::Link(d, s) => write_link(fc, d, *s),
|
||||||
FrameItem::Tag(_) => {}
|
FrameItem::Tag(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +252,53 @@ pub fn process_frame(
|
|||||||
fc.pop();
|
fc.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save a link for later writing in the annotations dictionary.
|
||||||
|
fn write_link(fc: &mut FrameContext, dest: &Destination, size: Size) {
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Compute the bounding box of the transformed link.
|
||||||
|
for point in [
|
||||||
|
pos,
|
||||||
|
pos + Point::with_x(size.x),
|
||||||
|
pos + Point::with_y(size.y),
|
||||||
|
pos + size.to_point(),
|
||||||
|
] {
|
||||||
|
let t = point.transform(fc.state().transform);
|
||||||
|
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();
|
||||||
|
let x2 = max_x.to_f32();
|
||||||
|
let y1 = min_y.to_f32();
|
||||||
|
let y2 = max_y.to_f32();
|
||||||
|
|
||||||
|
let rect = Rect::from_ltrb(x1, y1, x2, y2).unwrap();
|
||||||
|
|
||||||
|
let target = match dest {
|
||||||
|
Destination::Url(u) => {
|
||||||
|
Target::Action(Action::Link(LinkAction::new(u.to_string())))
|
||||||
|
}
|
||||||
|
Destination::Position(p) => {
|
||||||
|
// TODO: Ignore non-exported destinations
|
||||||
|
Target::Destination(krilla::destination::Destination::Xyz(
|
||||||
|
XyzDestination::new(p.page.get() - 1, p.point.as_krilla()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
// TODO: Implement
|
||||||
|
Destination::Location(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
fc.annotations.push(LinkAnnotation::new(rect, target).into());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_group(
|
pub fn handle_group(
|
||||||
fc: &mut FrameContext,
|
fc: &mut FrameContext,
|
||||||
group: &GroupItem,
|
group: &GroupItem,
|
||||||
@ -390,8 +442,10 @@ pub fn handle_shape(
|
|||||||
// Typst supports them, so we apply a transform if needed
|
// Typst supports them, so we apply a transform if needed
|
||||||
// Because this operation is expensive according to tiny-skia's
|
// Because this operation is expensive according to tiny-skia's
|
||||||
// docs, we prefer to not apply it if not needed
|
// docs, we prefer to not apply it if not needed
|
||||||
let transform = krilla::geom::Transform::from_scale(w.signum(), h.signum());
|
let transform =
|
||||||
Rect::from_xywh(0.0, 0.0, w.abs(), h.abs()).and_then(|rect| rect.transform(transform))
|
krilla::geom::Transform::from_scale(w.signum(), h.signum());
|
||||||
|
Rect::from_xywh(0.0, 0.0, w.abs(), h.abs())
|
||||||
|
.and_then(|rect| rect.transform(transform))
|
||||||
} else {
|
} else {
|
||||||
Rect::from_xywh(0.0, 0.0, w, h)
|
Rect::from_xywh(0.0, 0.0, w, h)
|
||||||
};
|
};
|
||||||
@ -460,50 +514,3 @@ pub fn convert_path(path: &Path, builder: &mut PathBuilder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn handle_link(
|
|
||||||
// pos: typst_library::layout::Point,
|
|
||||||
// dest: &Destination,
|
|
||||||
// size: typst_library::layout::Size,
|
|
||||||
// ctx: &mut GlobalContext,
|
|
||||||
// surface: &mut Surface,
|
|
||||||
// ) {
|
|
||||||
// let mut min_x = Abs::inf();
|
|
||||||
// let mut min_y = Abs::inf();
|
|
||||||
// let mut max_x = -Abs::inf();
|
|
||||||
// let mut max_y = -Abs::inf();
|
|
||||||
//
|
|
||||||
// // Compute the bounding box of the transformed link.
|
|
||||||
// for point in [
|
|
||||||
// pos,
|
|
||||||
// pos + Point::with_x(size.x),
|
|
||||||
// pos + Point::with_y(size.y),
|
|
||||||
// pos + size.to_point(),
|
|
||||||
// ] {
|
|
||||||
// let t = point.transform(ctx.cur_transform);
|
|
||||||
// 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();
|
|
||||||
// let x2 = max_x.to_f32();
|
|
||||||
// let y1 = min_y.to_f32();
|
|
||||||
// let y2 = max_y.to_f32();
|
|
||||||
// let rect = krilla::geom::Rect::from_ltrb(x1, y1, x2, y2).unwrap();
|
|
||||||
//
|
|
||||||
// let target = match dest {
|
|
||||||
// Destination::Url(u) => {
|
|
||||||
// Target::Action(Action::Link(LinkAction::new(u.to_string())))
|
|
||||||
// }
|
|
||||||
// Destination::Position(p) => {
|
|
||||||
// Target::Destination(krilla::destination::Destination::Xyz(
|
|
||||||
// XyzDestination::new(p.page.get() - 1, p.point.as_krilla()),
|
|
||||||
// ))
|
|
||||||
// }
|
|
||||||
// Destination::Location(_) => return,
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// ctx.annotations.push(LinkAnnotation::new(rect, target).into());
|
|
||||||
// }
|
|
||||||
|
@ -158,8 +158,13 @@ pub(crate) fn convert_pattern(
|
|||||||
|
|
||||||
let transform = match pattern.unwrap_relative(on_text) {
|
let transform = match pattern.unwrap_relative(on_text) {
|
||||||
RelativeTo::Self_ => Transform::identity(),
|
RelativeTo::Self_ => Transform::identity(),
|
||||||
RelativeTo::Parent => transforms.transform_chain_.invert().unwrap().pre_concat(transforms.container_transform_chain)
|
RelativeTo::Parent => transforms
|
||||||
}.as_krilla();
|
.transform_chain_
|
||||||
|
.invert()
|
||||||
|
.unwrap()
|
||||||
|
.pre_concat(transforms.container_transform_chain),
|
||||||
|
}
|
||||||
|
.as_krilla();
|
||||||
|
|
||||||
let mut stream_builder = surface.stream_builder();
|
let mut stream_builder = surface.stream_builder();
|
||||||
let mut surface = stream_builder.surface();
|
let mut surface = stream_builder.surface();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user