Skip to content

Commit a156cda

Browse files
committed
Add docs and CI
1 parent a127d6f commit a156cda

6 files changed

Lines changed: 232 additions & 3 deletions

File tree

.github/dependabot.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "cargo" # See documentation for possible values
4+
directory: "/" # Location of package manifests
5+
schedule:
6+
interval: "daily"

.github/workflows/rust.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Continuous integration
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
ci:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
rust: [stable]
15+
16+
steps:
17+
- name: Checkout source code
18+
uses: actions/checkout@v2
19+
20+
- name: Install Rust
21+
uses: actions-rs/toolchain@v1
22+
with:
23+
profile: minimal
24+
toolchain: ${{ matrix.rust }}
25+
override: true
26+
27+
- name: Build
28+
uses: actions-rs/cargo@v1
29+
with:
30+
command: build
31+
32+
- name: Test
33+
uses: actions-rs/cargo@v1
34+
with:
35+
command: test

Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
[package]
22
name = "svg2pdf"
33
version = "0.1.0"
4+
authors = ["Martin Haug <[email protected]>"]
45
edition = "2018"
6+
description = "Convert SVG files to PDFs."
7+
repository = "https://github.com/typst/svg2pdf"
8+
readme = "README.md"
59
license = "MIT OR Apache-2.0"
10+
categories = ["encoding", "graphics", "multimedia"]
11+
keywords = ["svg", "pdf", "vector-graphics", "conversion"]
612

713
[features]
814
default = ["png", "jpeg", "text", "system-fonts"]
@@ -14,5 +20,5 @@ system-fonts = ["usvg/system-fonts", "usvg/memmap-fonts"]
1420
[dependencies]
1521
image = { version = "0.23", default-features = false, optional = true }
1622
miniz_oxide = "0.4"
17-
pdf-writer = { git = "https://github.com/typst/pdf-writer", rev = "e1ec200" }
23+
pdf-writer = "0.4.1"
1824
usvg = { version = "0.19", default-features = false }

README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# svg2pdf
2+
3+
[![Build status](https://github.com/typst/svg2pdf/workflows/Continuous%20integration/badge.svg)](https://github.com/typst/svg2pdf/actions)
4+
[![Current crates.io release](https://img.shields.io/crates/v/svg2pdf)](https://crates.io/crates/svg2pdf)
5+
[![Documentation](https://img.shields.io/badge/docs.rs-svg2pdf-66c2a5?labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K)](https://docs.rs/svg2pdf/)
6+
7+
Convert SVG files to PDFs.
8+
9+
This crate allows to convert static (i.e. non-interactive) SVG files to
10+
either standalone PDF files or Form XObjects that can be embedded in another
11+
PDF file and used just like images.
12+
13+
The conversion will translate the SVG content to PDF without rasterizing it,
14+
so no quality is lost.
15+
16+
## Example
17+
This example reads an SVG file and writes the corresponding PDF back to the disk.
18+
19+
```rust
20+
let svg = std::fs::read_to_string("tests/example.svg").unwrap();
21+
22+
// This can only fail if the SVG is malformed. This one is not.
23+
let pdf = svg2pdf::convert_str(&svg, svg2pdf::Options::default()).unwrap();
24+
25+
// ... and now you have a Vec<u8> which you could write to a file or
26+
// transmit over the network!
27+
std::fs::write("target/example.pdf", pdf).unwrap();
28+
```
29+
30+
## Supported features
31+
- Path drawing with fills and strokes
32+
- Gradients
33+
- Patterns
34+
- Clip paths
35+
- Masks
36+
- Transformation matrices
37+
- Respecting the `keepAspectRatio` attribute
38+
- Raster images and nested SVGs
39+
40+
Filters are not currently supported and embedded raster images are not color
41+
managed. Instead, they use PDF's `DeviceRGB` color space.
42+
43+
## Contributing
44+
We are looking forward to receiving your bugs and feature requests in the Issues
45+
tab. We would also be very happy to accept PRs for bug fixes, features, or
46+
refactorings!
47+
48+
If you want to contribute but are uncertain where to start, yo could look into
49+
filters like `feBlend` and `feColorMatrix` that can be implemented with
50+
transparency groups and color spaces, respectively. We'd be happy to assist you
51+
with your PR's, so feel free to post Work in Progress PRs if marked as such.
52+
Please be kind to the maintainers and other contributors. If you feel that there
53+
are any problems, please feel free to reach out to us privately.
54+
55+
Thanks to each and every prospective contributor for the effort you (plan to)
56+
invest in this project and for adopting it!
57+
58+
## License
59+
svg2pdf is licensed under a MIT / Apache 2.0 dual license.
60+
61+
Users and consumers of the library may choose which of those licenses they want
62+
to apply whereas contributors have to accept that their code is in compliance
63+
and distributed under the terms of both of these licenses.

src/lib.rs

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,39 @@
1-
//! Convert SVG files to PDFs.
1+
/*! Convert SVG files to PDFs.
2+
3+
This crate allows to convert static (i.e. non-interactive) SVG files to
4+
either standalone PDF files or Form XObjects that can be embedded in another
5+
PDF file and used just like images.
6+
7+
The conversion will translate the SVG content to PDF without rasterizing it,
8+
so no quality is lost.
9+
10+
## Example
11+
This example reads an SVG file and writes the corresponding PDF back to the disk.
12+
13+
```rust
14+
let svg = std::fs::read_to_string("tests/example.svg").unwrap();
15+
16+
// This can only fail if the SVG is malformed. This one is not.
17+
let pdf = svg2pdf::convert_str(&svg, svg2pdf::Options::default()).unwrap();
18+
19+
// ... and now you have a Vec<u8> which you could write to a file or
20+
// transmit over the network!
21+
std::fs::write("target/example.pdf", pdf).unwrap();
22+
```
23+
24+
## Supported features
25+
- Path drawing with fills and strokes
26+
- Gradients
27+
- Patterns
28+
- Clip paths
29+
- Masks
30+
- Transformation matrices
31+
- Respecting the `keepAspectRatio` attribute
32+
- Raster images and nested SVGs
33+
34+
Filters are not currently supported and embedded raster images are not color
35+
managed. Instead, they use PDF's `DeviceRGB` color space.
36+
*/
237

338
use std::collections::HashMap;
439

@@ -258,12 +293,82 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
258293
///
259294
/// The resulting object can be used by registering a name and the `id` with a
260295
/// page's [`/XObject`](pdf_writer::writers::Resources::x_objects) resources
261-
/// dictionary and then invoking the [`/Do`](pdf_writer::Content::x_object)
296+
/// dictionary and then invoking the [`Do`](pdf_writer::Content::x_object)
262297
/// operator with the name in the page's content stream.
263298
///
264299
/// As the conversion process may need to create multiple indirect objects in
265300
/// the PDF, this function allocates consecutive IDs starting at `id` for its
266301
/// objects and returns the next available ID for your future writing.
302+
///
303+
/// ## Example
304+
/// Write a PDF file with some text and an SVG graphic.
305+
///
306+
/// ```rust
307+
/// use svg2pdf;
308+
/// use pdf_writer::{Content, Finish, Name, PdfWriter, Rect, Ref, Str};
309+
///
310+
/// // Allocate the indirect reference IDs and names.
311+
/// let catalog_id = Ref::new(1);
312+
/// let page_tree_id = Ref::new(2);
313+
/// let page_id = Ref::new(3);
314+
/// let font_id = Ref::new(4);
315+
/// let content_id = Ref::new(5);
316+
/// let svg_id = Ref::new(6);
317+
/// let font_name = Name(b"F1");
318+
/// let svg_name = Name(b"S1");
319+
///
320+
/// // Start writing a PDF.
321+
/// let mut writer = PdfWriter::new();
322+
/// writer.catalog(catalog_id).pages(page_tree_id);
323+
/// writer.pages(page_tree_id).kids([page_id]).count(1);
324+
///
325+
/// // Set up a simple A4 page.
326+
/// let mut page = writer.page(page_id);
327+
/// page.media_box(Rect::new(0.0, 0.0, 595.0, 842.0));
328+
/// page.parent(page_tree_id);
329+
/// page.contents(content_id);
330+
///
331+
/// // Add the font and, more importantly, the SVG to the resource dictionary
332+
/// // so that it can be referenced in the content stream.
333+
/// let mut resources = page.resources();
334+
/// resources.x_objects().pair(svg_name, svg_id);
335+
/// resources.fonts().pair(font_name, font_id);
336+
/// resources.finish();
337+
/// page.finish();
338+
///
339+
/// // Set a predefined font, so we do not have to load anything extra.
340+
/// writer.type1_font(font_id).base_font(Name(b"Helvetica"));
341+
///
342+
/// // Let's add an SVG graphic to this file.
343+
/// // We need to load its source first and manually parse it into a usvg Tree.
344+
/// let svg = std::fs::read_to_string("tests/example.svg").unwrap();
345+
/// let tree = usvg::Tree::from_str(&svg, &usvg::Options::default().to_ref()).unwrap();
346+
///
347+
/// // Then, we will write it to the page as the 6th indirect object.
348+
/// //
349+
/// // This call allocates some indirect object reference IDs for itself. If we
350+
/// // wanted to write some more indirect objects afterwards, we could use the
351+
/// // return value as the next unused reference ID.
352+
/// svg2pdf::convert_tree_into(&tree, svg2pdf::Options::default(), &mut writer, svg_id);
353+
///
354+
/// // Write a content stream with some text and our SVG.
355+
/// let mut content = Content::new();
356+
/// content
357+
/// .begin_text()
358+
/// .set_font(font_name, 16.0)
359+
/// .next_line(108.0, 734.0)
360+
/// .show(Str(b"Look at my wonderful vector graphic!"))
361+
/// .end_text();
362+
///
363+
/// // Add our graphic.
364+
/// content
365+
/// .transform([300.0, 0.0, 0.0, 300.0, 147.5, 385.0])
366+
/// .x_object(svg_name);
367+
///
368+
/// // Write the file to the disk.
369+
/// writer.stream(content_id, &content.finish());
370+
/// std::fs::write("target/embedded.pdf", writer.finish()).unwrap();
371+
/// ```
267372
pub fn convert_tree_into(
268373
tree: &Tree,
269374
options: Options,

tests/example.svg

Lines changed: 14 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)