Skip to content

Commit

Permalink
Add docs and CI
Browse files Browse the repository at this point in the history
  • Loading branch information
reknih committed Dec 6, 2021
1 parent a127d6f commit a156cda
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 3 deletions.
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "cargo" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"
35 changes: 35 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Continuous integration

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
ci:
runs-on: ubuntu-latest
strategy:
matrix:
rust: [stable]

steps:
- name: Checkout source code
uses: actions/checkout@v2

- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true

- name: Build
uses: actions-rs/cargo@v1
with:
command: build

- name: Test
uses: actions-rs/cargo@v1
with:
command: test
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
[package]
name = "svg2pdf"
version = "0.1.0"
authors = ["Martin Haug <[email protected]>"]
edition = "2018"
description = "Convert SVG files to PDFs."
repository = "https://github.com/typst/svg2pdf"
readme = "README.md"
license = "MIT OR Apache-2.0"
categories = ["encoding", "graphics", "multimedia"]
keywords = ["svg", "pdf", "vector-graphics", "conversion"]

[features]
default = ["png", "jpeg", "text", "system-fonts"]
Expand All @@ -14,5 +20,5 @@ system-fonts = ["usvg/system-fonts", "usvg/memmap-fonts"]
[dependencies]
image = { version = "0.23", default-features = false, optional = true }
miniz_oxide = "0.4"
pdf-writer = { git = "https://github.com/typst/pdf-writer", rev = "e1ec200" }
pdf-writer = "0.4.1"
usvg = { version = "0.19", default-features = false }
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# svg2pdf

[![Build status](https://github.com/typst/svg2pdf/workflows/Continuous%20integration/badge.svg)](https://github.com/typst/svg2pdf/actions)
[![Current crates.io release](https://img.shields.io/crates/v/svg2pdf)](https://crates.io/crates/svg2pdf)
[![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/)

Convert SVG files to PDFs.

This crate allows to convert static (i.e. non-interactive) SVG files to
either standalone PDF files or Form XObjects that can be embedded in another
PDF file and used just like images.

The conversion will translate the SVG content to PDF without rasterizing it,
so no quality is lost.

## Example
This example reads an SVG file and writes the corresponding PDF back to the disk.

```rust
let svg = std::fs::read_to_string("tests/example.svg").unwrap();

// This can only fail if the SVG is malformed. This one is not.
let pdf = svg2pdf::convert_str(&svg, svg2pdf::Options::default()).unwrap();

// ... and now you have a Vec<u8> which you could write to a file or
// transmit over the network!
std::fs::write("target/example.pdf", pdf).unwrap();
```

## Supported features
- Path drawing with fills and strokes
- Gradients
- Patterns
- Clip paths
- Masks
- Transformation matrices
- Respecting the `keepAspectRatio` attribute
- Raster images and nested SVGs

Filters are not currently supported and embedded raster images are not color
managed. Instead, they use PDF's `DeviceRGB` color space.

## Contributing
We are looking forward to receiving your bugs and feature requests in the Issues
tab. We would also be very happy to accept PRs for bug fixes, features, or
refactorings!

If you want to contribute but are uncertain where to start, yo could look into
filters like `feBlend` and `feColorMatrix` that can be implemented with
transparency groups and color spaces, respectively. We'd be happy to assist you
with your PR's, so feel free to post Work in Progress PRs if marked as such.
Please be kind to the maintainers and other contributors. If you feel that there
are any problems, please feel free to reach out to us privately.

Thanks to each and every prospective contributor for the effort you (plan to)
invest in this project and for adopting it!

## License
svg2pdf is licensed under a MIT / Apache 2.0 dual license.

Users and consumers of the library may choose which of those licenses they want
to apply whereas contributors have to accept that their code is in compliance
and distributed under the terms of both of these licenses.
109 changes: 107 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,39 @@
//! Convert SVG files to PDFs.
/*! Convert SVG files to PDFs.
This crate allows to convert static (i.e. non-interactive) SVG files to
either standalone PDF files or Form XObjects that can be embedded in another
PDF file and used just like images.
The conversion will translate the SVG content to PDF without rasterizing it,
so no quality is lost.
## Example
This example reads an SVG file and writes the corresponding PDF back to the disk.
```rust
let svg = std::fs::read_to_string("tests/example.svg").unwrap();
// This can only fail if the SVG is malformed. This one is not.
let pdf = svg2pdf::convert_str(&svg, svg2pdf::Options::default()).unwrap();
// ... and now you have a Vec<u8> which you could write to a file or
// transmit over the network!
std::fs::write("target/example.pdf", pdf).unwrap();
```
## Supported features
- Path drawing with fills and strokes
- Gradients
- Patterns
- Clip paths
- Masks
- Transformation matrices
- Respecting the `keepAspectRatio` attribute
- Raster images and nested SVGs
Filters are not currently supported and embedded raster images are not color
managed. Instead, they use PDF's `DeviceRGB` color space.
*/

use std::collections::HashMap;

Expand Down Expand Up @@ -258,12 +293,82 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
///
/// 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`](pdf_writer::Content::x_object)
/// dictionary and then invoking the [`Do`](pdf_writer::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.
///
/// ## Example
/// Write a PDF file with some text and an SVG graphic.
///
/// ```rust
/// use svg2pdf;
/// use pdf_writer::{Content, Finish, Name, PdfWriter, Rect, Ref, Str};
///
/// // Allocate the indirect reference IDs and names.
/// let catalog_id = Ref::new(1);
/// let page_tree_id = Ref::new(2);
/// let page_id = Ref::new(3);
/// let font_id = Ref::new(4);
/// let content_id = Ref::new(5);
/// let svg_id = Ref::new(6);
/// let font_name = Name(b"F1");
/// 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);
///
/// // Set up a simple A4 page.
/// let mut page = writer.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);
///
/// // Add the font and, more importantly, the SVG to the resource dictionary
/// // so that it can be referenced in the content stream.
/// let mut resources = page.resources();
/// resources.x_objects().pair(svg_name, svg_id);
/// resources.fonts().pair(font_name, font_id);
/// resources.finish();
/// 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"));
///
/// // Let's add an SVG graphic to this file.
/// // We need to load its source first and manually parse it into a usvg Tree.
/// let svg = std::fs::read_to_string("tests/example.svg").unwrap();
/// let tree = usvg::Tree::from_str(&svg, &usvg::Options::default().to_ref()).unwrap();
///
/// // Then, we will write it to the page as the 6th indirect object.
/// //
/// // 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);
///
/// // Write a content stream with some text and our SVG.
/// let mut content = Content::new();
/// content
/// .begin_text()
/// .set_font(font_name, 16.0)
/// .next_line(108.0, 734.0)
/// .show(Str(b"Look at my wonderful vector graphic!"))
/// .end_text();
///
/// // Add our graphic.
/// content
/// .transform([300.0, 0.0, 0.0, 300.0, 147.5, 385.0])
/// .x_object(svg_name);
///
/// // Write the file to the disk.
/// writer.stream(content_id, &content.finish());
/// std::fs::write("target/embedded.pdf", writer.finish()).unwrap();
/// ```
pub fn convert_tree_into(
tree: &Tree,
options: Options,
Expand Down
14 changes: 14 additions & 0 deletions tests/example.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit a156cda

Please sign in to comment.