Skip to content

Commit

Permalink
finish
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenzV committed Aug 20, 2024
1 parent 33740b1 commit 75cfa62
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 18 deletions.
5 changes: 5 additions & 0 deletions src/document.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::object::outline::Outline;
use crate::object::page::PageLabel;
use crate::serialize::{SerializeSettings, SerializerContext};
use crate::surface::PageBuilder;
Expand Down Expand Up @@ -26,6 +27,10 @@ impl Document {
PageBuilder::new_with(&mut self.serializer_context, size, page_label)
}

pub fn set_outline(&mut self, outline: Outline) {
self.serializer_context.set_outline(outline);
}

pub fn finish(self) -> Vec<u8> {
self.serializer_context.finish().finish()
}
Expand Down
1 change: 0 additions & 1 deletion src/object/ext_g_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ impl Object for ExtGState {
ext_st.blend_mode(bm);
}


if let Some(mask_ref) = mask_ref {
ext_st.pair(Name(b"SMask"), mask_ref);
}
Expand Down
171 changes: 164 additions & 7 deletions src/object/outline.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use pdf_writer::{Chunk, Ref};
use tiny_skia_path::Point;
use crate::serialize::{Object, SerializerContext};
use pdf_writer::{Chunk, Finish, Ref, TextStr};
use tiny_skia_path::{Point, Transform};

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Outline {
children: Vec<OutlineNode>,
}
Expand All @@ -17,8 +17,8 @@ impl Outline {
}
}

#[derive(Debug)]
struct OutlineNode {
#[derive(Debug, Clone)]
pub struct OutlineNode {
children: Vec<Box<OutlineNode>>,
text: String,
page_index: u32,
Expand All @@ -39,11 +39,168 @@ impl OutlineNode {
self.children.push(Box::new(node))
}

pub fn serialize_into(
&self,
sc: &mut SerializerContext,
parent: Ref,
root: Ref,
next: Option<Ref>,
prev: Option<Ref>,
) -> Chunk {
let mut chunk = Chunk::new();

let mut sub_chunks = vec![];

let mut outline_entry = chunk.outline_item(root);
outline_entry.parent(parent);

if let Some(next) = next {
outline_entry.next(next);
}

if let Some(prev) = prev {
outline_entry.prev(prev);
}

if !self.children.is_empty() {
let first = sc.new_ref();
let mut last = first;

let mut prev = None;
let mut cur = Some(first);

for i in 0..self.children.len() {
let next = if i < self.children.len() - 1 {
Some(sc.new_ref())
} else {
None
};

last = cur.unwrap();

sub_chunks.push(self.children[i].serialize_into(sc, root, last, next, prev));

prev = cur;
cur = next;
}

outline_entry.first(first);
outline_entry.last(last);
outline_entry.count(-i32::try_from(self.children.len()).unwrap());
}

if !self.text.is_empty() {
outline_entry.title(TextStr(&self.text));
}

let page_ref = sc.page_infos()[self.page_index as usize].ref_;
let page_size = sc.page_infos()[self.page_index as usize].media_box.height();
let mut mapped_point = self.pos;
let invert_transform = Transform::from_row(1.0, 0.0, 0.0, -1.0, 0.0, page_size);
invert_transform.map_point(&mut mapped_point);

outline_entry
.dest()
.page(page_ref)
.xyz(mapped_point.x, mapped_point.y, None);

outline_entry.finish();

for sub_chunk in sub_chunks {
chunk.extend(&sub_chunk);
}

chunk
}
}

impl Object for Outline {
fn serialize_into(self, sc: &mut SerializerContext, root_ref: Ref) -> Chunk {
todo!()
let mut chunk = Chunk::new();

let mut sub_chunks = vec![];

let mut outline = chunk.outline(root_ref);

if !self.children.is_empty() {
let first = sc.new_ref();
let mut last = first;

let mut prev = None;
let mut cur = Some(first);

for i in 0..self.children.len() {
let next = if i < self.children.len() - 1 {
Some(sc.new_ref())
} else {
None
};

last = cur.unwrap();

sub_chunks.push(self.children[i].serialize_into(sc, root_ref, last, next, prev));

prev = cur;
cur = next;
}

outline.first(first);
outline.last(last);
outline.count(i32::try_from(self.children.len()).unwrap());
}

outline.finish();

for sub_chunk in sub_chunks {
chunk.extend(&sub_chunk);
}

chunk
}
}

#[cfg(test)]
mod tests {
use crate::document::Document;
use crate::object::outline::{Outline, OutlineNode};
use crate::rgb::Rgb;
use crate::serialize::SerializeSettings;
use crate::test_utils::check_snapshot;
use crate::Fill;
use tiny_skia_path::{PathBuilder, Point, Rect, Size};

#[test]
fn simple() {
let mut builder = PathBuilder::new();
builder.push_rect(Rect::from_xywh(50.0, 50.0, 100.0, 100.0).unwrap());
let path = builder.finish().unwrap();

let mut db = Document::new(SerializeSettings::default_test());
let mut page = db.start_page(Size::from_wh(200.0, 200.0).unwrap());
let mut surface = page.surface();
surface.fill_path(&path, Fill::<Rgb>::default());
surface.finish();
page.finish();

db.start_page(Size::from_wh(200.0, 500.0).unwrap());
db.start_page(Size::from_wh(250.0, 700.0).unwrap());

let mut outline = Outline::new();

let mut child1 = OutlineNode::new("Level 1".to_string(), 0, Point::from_xy(50.0, 50.0));
child1.push_child(OutlineNode::new(
"Level 2".to_string(),
0,
Point::from_xy(50.0, 150.0),
));

let child2 = OutlineNode::new("Level 1 try 2".to_string(), 1, Point::from_xy(75.0, 150.0));

outline.push_child(child1);
outline.push_child(child2);

db.set_outline(outline);

check_snapshot("outline/simple", &db.finish());
}
}
}
1 change: 0 additions & 1 deletion src/object/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ mod tests {
check_snapshot("page/page_label", sc.finish().as_bytes());
}

// TODO: Fix issues with not being able to create empty pages with just start_page_with.
// TODO: Fix issue with two duplicate pages not showing up.

#[test]
Expand Down
19 changes: 18 additions & 1 deletion src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::object::cid_font::CIDFont;
use crate::object::color_space::luma::SGray;
use crate::object::color_space::rgb::Srgb;
use crate::object::color_space::{DEVICE_GRAY, DEVICE_RGB};
use crate::object::outline::Outline;
use crate::object::page::{PageLabel, PageLabelContainer};
use crate::object::type3_font::Type3Font;
use crate::resource::{ColorSpaceEnum, FontResource};
Expand All @@ -17,7 +18,6 @@ use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use tiny_skia_path::Rect;
use crate::object::outline::Outline;

#[derive(Copy, Clone, Debug)]
pub struct SvgSettings {
Expand Down Expand Up @@ -83,6 +83,7 @@ pub struct SerializerContext {
catalog_ref: Ref,
page_tree_ref: Ref,
page_labels_ref: Option<Ref>,
outline_ref: Option<Ref>,
page_infos: Vec<PageInfo>,
outline: Option<Outline>,
cached_mappings: HashMap<u128, Ref>,
Expand Down Expand Up @@ -126,6 +127,7 @@ impl SerializerContext {
page_tree_ref,
catalog_ref,
outline: None,
outline_ref: None,
page_labels_ref: None,
page_infos: vec![],
chunks_len: 0,
Expand All @@ -134,6 +136,10 @@ impl SerializerContext {
}
}

pub fn page_infos(&self) -> &[PageInfo] {
&self.page_infos
}

pub fn set_outline(&mut self, outline: Outline) {
self.outline = Some(outline);
}
Expand Down Expand Up @@ -299,6 +305,13 @@ impl SerializerContext {
self.page_labels_ref = Some(self.add(container));
}

if let Some(outline) = self.outline.clone() {
let outline_ref = self.new_ref();
self.outline_ref = Some(outline_ref);
let chunk = outline.serialize_into(&mut self, outline_ref);
self.push_chunk(chunk);
}

// Write fonts
// TODO: Make more efficient
let fonts = std::mem::take(&mut self.font_map);
Expand Down Expand Up @@ -341,6 +354,10 @@ impl SerializerContext {
catalog.pair(Name(b"PageLabels"), plr);
}

if let Some(olr) = self.outline_ref {
catalog.outlines(olr);
}

catalog.finish();

pdf.extend(&page_tree_chunk);
Expand Down
13 changes: 5 additions & 8 deletions src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ impl<'a> PageBuilder<'a> {
}
}

pub(crate) fn root_transform(&self) -> Transform {
Transform::from_row(1.0, 0.0, 0.0, -1.0, 0.0, self.size.height())
}

pub(crate) fn new_with(
sc: &'a mut SerializerContext,
size: Size,
Expand All @@ -234,14 +238,7 @@ impl<'a> PageBuilder<'a> {
pub fn surface(&mut self) -> Surface {
let mut root_builder = ContentBuilder::new();
// Invert the y-axis.
root_builder.concat_transform(&Transform::from_row(
1.0,
0.0,
0.0,
-1.0,
0.0,
self.size.height(),
));
root_builder.concat_transform(&self.root_transform());

let finish_fn = Box::new(|stream| self.page_stream = stream);

Expand Down

0 comments on commit 75cfa62

Please sign in to comment.