Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow writing into chunks #40

Merged
merged 2 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ required-features = ["cli"]

[dependencies]
miniz_oxide = "0.7"
pdf-writer = "0.8"
pdf-writer = "0.9"
usvg = { version = "0.35", default-features = false }
image = { version = "0.24", default-features = false, features = ["jpeg", "png", "gif"], optional = true }
termcolor = { version = "1", optional = true }
Expand Down
56 changes: 28 additions & 28 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Among the unsupported features are currently:
mod render;
mod util;

use pdf_writer::{Content, Filter, Finish, PdfWriter, Rect, Ref, TextStr};
use pdf_writer::{Chunk, Content, Filter, Finish, Pdf, Rect, Ref, TextStr};
use usvg::utils::view_box_to_transform;
use usvg::{Align, AspectRatio, NonZeroRect, Size, Transform, Tree, TreeParsing};

Expand Down Expand Up @@ -161,35 +161,35 @@ pub fn convert_str(src: &str, options: Options) -> Result<Vec<u8>, usvg::Error>
pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
let pdf_size = pdf_size(tree, options);
let mut ctx = Context::new(tree, options, None);
let mut writer = PdfWriter::new();
let mut pdf = Pdf::new();

let catalog_ref = ctx.alloc_ref();
let page_tree_ref = ctx.alloc_ref();
let page_ref = ctx.alloc_ref();
let content_ref = ctx.alloc_ref();

writer.catalog(catalog_ref).pages(page_tree_ref);
writer.pages(page_tree_ref).count(1).kids([page_ref]);
pdf.catalog(catalog_ref).pages(page_tree_ref);
pdf.pages(page_tree_ref).count(1).kids([page_ref]);

// Generate main content
ctx.deferrer.push();
let mut content = Content::new();
tree_to_stream(
tree,
&mut writer,
&mut pdf,
&mut content,
&mut ctx,
initial_transform(options.aspect, tree, pdf_size),
);
let content_stream = ctx.finish_content(content);
let mut stream = writer.stream(content_ref, &content_stream);
let mut stream = pdf.stream(content_ref, &content_stream);

if ctx.options.compress {
stream.filter(Filter::FlateDecode);
}
stream.finish();

let mut page = writer.page(page_ref);
let mut page = pdf.page(page_ref);
let mut page_resources = page.resources();
ctx.deferrer.pop(&mut page_resources);
page_resources.finish();
Expand All @@ -206,27 +206,27 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
page.finish();

let document_info_id = ctx.alloc_ref();
writer.document_info(document_info_id).producer(TextStr("svg2pdf"));
pdf.document_info(document_info_id).producer(TextStr("svg2pdf"));

writer.finish()
pdf.finish()
}

/// Convert a [`usvg` tree](Tree) into a Form XObject that can be used as
/// part of a larger document.
///
/// This method is intended for use in an existing [`PdfWriter`] workflow. It
/// will always return an XObject with the width and height of one printer's
/// This method is intended for use in an existing [`pdf-writer`] workflow. It
/// will always produce an XObject with the width and height of one printer's
/// point, just like an [`ImageXObject`](pdf_writer::writers::ImageXObject)
/// would.
///
/// The resulting object can be used by registering a name and the `id` with a
/// page's [`/XObject`](pdf_writer::writers::Resources::x_objects) resources
/// dictionary and then invoking the [`Do`](Content::x_object) operator with the
/// name in the page's content stream.
/// The resulting object can be used by registering a name and the `start_ref`
/// with a page's [`/XObject`](pdf_writer::writers::Resources::x_objects)
/// resources dictionary and then invoking the [`Do`](Content::x_object)
/// operator with the name in the page's content stream.
///
/// As the conversion process may need to create multiple indirect objects in
/// the PDF, this function allocates consecutive IDs starting at `id` for its
/// objects and returns the next available ID for your future writing.
/// the PDF, this function allocates consecutive IDs starting at `start_ref` for
/// its objects and returns the next available ID for your future writing.
///
/// ## Example
/// Write a PDF file with some text and an SVG graphic.
Expand All @@ -248,12 +248,12 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
/// let svg_name = Name(b"S1");
///
/// // Start writing a PDF.
/// let mut writer = PdfWriter::new();
/// writer.catalog(catalog_id).pages(page_tree_id);
/// writer.pages(page_tree_id).kids([page_id]).count(1);
/// let mut pdf = Pdf::new();
/// pdf.catalog(catalog_id).pages(page_tree_id);
/// pdf.pages(page_tree_id).kids([page_id]).count(1);
///
/// // Set up a simple A4 page.
/// let mut page = writer.page(page_id);
/// let mut page = pdf.page(page_id);
/// page.media_box(Rect::new(0.0, 0.0, 595.0, 842.0));
/// page.parent(page_tree_id);
/// page.contents(content_id);
Expand All @@ -267,7 +267,7 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
/// page.finish();
///
/// // Set a predefined font, so we do not have to load anything extra.
/// writer.type1_font(font_id).base_font(Name(b"Helvetica"));
/// pdf.type1_font(font_id).base_font(Name(b"Helvetica"));
///
/// // Let's add an SVG graphic to this file.
/// // We need to load its source first and manually parse it into a usvg Tree.
Expand All @@ -280,7 +280,7 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
/// // This call allocates some indirect object reference IDs for itself. If we
/// // wanted to write some more indirect objects afterwards, we could use the
/// // return value as the next unused reference ID.
/// svg2pdf::convert_tree_into(&tree, svg2pdf::Options::default(), &mut writer, svg_id);
/// svg2pdf::convert_tree_into(&tree, svg2pdf::Options::default(), &mut pdf, svg_id);
///
/// // Write a content stream with some text and our SVG.
/// let mut content = Content::new();
Expand All @@ -297,14 +297,14 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
/// .x_object(svg_name);
///
/// // Write the file to the disk.
/// writer.stream(content_id, &content.finish());
/// std::fs::write("target/embedded.pdf", writer.finish())?;
/// pdf.stream(content_id, &content.finish());
/// std::fs::write("target/embedded.pdf", pdf.finish())?;
/// # Ok(()) }
/// ```
pub fn convert_tree_into(
tree: &Tree,
options: Options,
writer: &mut PdfWriter,
chunk: &mut Chunk,
start_ref: Ref,
) -> Ref {
let pdf_size = pdf_size(tree, options);
Expand All @@ -316,14 +316,14 @@ pub fn convert_tree_into(
let mut content = Content::new();
tree_to_stream(
tree,
writer,
chunk,
&mut content,
&mut ctx,
initial_transform(options.aspect, tree, pdf_size),
);
let content_stream = ctx.finish_content(content);

let mut x_object = writer.form_xobject(x_ref, &content_stream);
let mut x_object = chunk.form_xobject(x_ref, &content_stream);
x_object.bbox(Rect::new(0.0, 0.0, pdf_size.width(), pdf_size.height()));
x_object.matrix([
1.0 / pdf_size.width(),
Expand Down
16 changes: 8 additions & 8 deletions src/render/clip_path.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::rc::Rc;

use pdf_writer::types::MaskType;
use pdf_writer::{Content, Filter, Finish, PdfWriter};
use pdf_writer::{Chunk, Content, Filter, Finish};
use usvg::tiny_skia_path::PathSegment;
use usvg::{ClipPath, FillRule, Node, NodeKind, Transform, Units, Visibility};

Expand All @@ -14,7 +14,7 @@ use crate::util::helper::{plain_bbox, NameExt, RectExt, TransformExt};
pub fn render(
node: &Node,
clip_path: Rc<ClipPath>,
writer: &mut PdfWriter,
chunk: &mut Chunk,
content: &mut Content,
ctx: &mut Context,
) {
Expand All @@ -41,7 +41,7 @@ pub fn render(
create_simple_clip_path(node, clip_path, content);
} else {
content.set_parameters(
create_complex_clip_path(node, clip_path, writer, ctx).to_pdf_name(),
create_complex_clip_path(node, clip_path, chunk, ctx).to_pdf_name(),
);
}
}
Expand Down Expand Up @@ -139,7 +139,7 @@ fn extend_segments_from_node(
fn create_complex_clip_path(
parent: &Node,
clip_path: Rc<ClipPath>,
writer: &mut PdfWriter,
chunk: &mut Chunk,
ctx: &mut Context,
) -> Rc<String> {
ctx.deferrer.push();
Expand All @@ -149,7 +149,7 @@ fn create_complex_clip_path(
content.save_state();

if let Some(recursive_clip_path) = &clip_path.clip_path {
render(parent, recursive_clip_path.clone(), writer, &mut content, ctx);
render(parent, recursive_clip_path.clone(), chunk, &mut content, ctx);
}

content.transform(clip_path.transform.to_pdf_transform());
Expand All @@ -166,7 +166,7 @@ fn create_complex_clip_path(
group::render(
&clip_path.root,
group,
writer,
chunk,
&mut content,
ctx,
Transform::default(),
Expand All @@ -178,7 +178,7 @@ fn create_complex_clip_path(
content.restore_state();
let content_stream = ctx.finish_content(content);

let mut x_object = writer.form_xobject(x_object_reference, &content_stream);
let mut x_object = chunk.form_xobject(x_object_reference, &content_stream);

if ctx.options.compress {
x_object.filter(Filter::FlateDecode);
Expand All @@ -198,7 +198,7 @@ fn create_complex_clip_path(
x_object.finish();

let gs_ref = ctx.alloc_ref();
let mut gs = writer.ext_graphics(gs_ref);
let mut gs = chunk.ext_graphics(gs_ref);
gs.soft_mask().subtype(MaskType::Alpha).group(x_object_reference);

ctx.deferrer.add_graphics_state(gs_ref)
Expand Down
Loading