@@ -15,7 +15,7 @@ This example reads an SVG file and writes the corresponding PDF back to the disk
1515```
1616# fn main() -> Result<(), Box<dyn std::error::Error>> {
1717use svg2pdf::usvg::fontdb;
18- use svg2pdf::Options ;
18+ use svg2pdf::{ConversionOptions, PageOptions} ;
1919
2020let input = "tests/svg/custom/integration/matplotlib/stairs.svg";
2121let output = "target/stairs.pdf";
@@ -26,7 +26,7 @@ let mut db = fontdb::Database::new();
2626db.load_system_fonts();
2727let tree = svg2pdf::usvg::Tree::from_str(&svg, &options, &db)?;
2828
29- let pdf = svg2pdf::to_pdf(&tree, Options ::default(), &db);
29+ let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions ::default(), &db);
3030std::fs::write(output, pdf)?;
3131# Ok(()) }
3232```
@@ -59,14 +59,14 @@ mod util;
5959pub use usvg;
6060
6161use once_cell:: sync:: Lazy ;
62- use pdf_writer:: { Chunk , Content , Filter , Finish , Pdf , Rect , Ref , TextStr } ;
62+ use pdf_writer:: { Chunk , Content , Filter , Finish , Pdf , Ref , TextStr } ;
6363#[ cfg( feature = "text" ) ]
6464use usvg:: fontdb;
65- use usvg:: Tree ;
65+ use usvg:: { Size , Transform , Tree } ;
6666
6767use crate :: render:: { tree_to_stream, tree_to_xobject} ;
6868use crate :: util:: context:: Context ;
69- use crate :: util:: helper:: deflate;
69+ use crate :: util:: helper:: { deflate, RectExt , TransformExt } ;
7070use crate :: util:: resources:: ResourceContainer ;
7171
7272// The ICC profiles.
@@ -75,9 +75,24 @@ static SRGB_ICC_DEFLATED: Lazy<Vec<u8>> =
7575static GRAY_ICC_DEFLATED : Lazy < Vec < u8 > > =
7676 Lazy :: new ( || deflate ( include_bytes ! ( "icc/sGrey-v4.icc" ) ) ) ;
7777
78- /// Preferences for the PDF conversion .
78+ /// Options for the resulting PDF file .
7979#[ derive( Copy , Clone ) ]
80- pub struct Options {
80+ pub struct PageOptions {
81+ /// The DPI that should be assumed for the conversion to PDF.
82+ ///
83+ /// _Default:_ 72.0
84+ pub dpi : f32 ,
85+ }
86+
87+ impl Default for PageOptions {
88+ fn default ( ) -> Self {
89+ Self { dpi : 72.0 }
90+ }
91+ }
92+
93+ /// Options for the PDF conversion.
94+ #[ derive( Copy , Clone ) ]
95+ pub struct ConversionOptions {
8196 /// Whether the content streams should be compressed.
8297 ///
8398 /// The smaller PDFs generated by this are generally more practical, but it
@@ -102,7 +117,7 @@ pub struct Options {
102117 pub embed_text : bool ,
103118}
104119
105- impl Default for Options {
120+ impl Default for ConversionOptions {
106121 fn default ( ) -> Self {
107122 Self {
108123 compress : false ,
@@ -124,7 +139,7 @@ impl Default for Options {
124139/// ```
125140/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
126141/// use svg2pdf::usvg::fontdb;
127- /// use svg2pdf::Options ;
142+ /// use svg2pdf::{ConversionOptions, PageOptions} ;
128143///
129144/// let input = "tests/svg/custom/integration/matplotlib/stairs.svg";
130145/// let output = "target/stairs.pdf";
@@ -136,24 +151,31 @@ impl Default for Options {
136151/// let mut tree = svg2pdf::usvg::Tree::from_str(&svg, &options, &db)?;
137152///
138153///
139- /// let pdf = svg2pdf::to_pdf(&tree, Options ::default(), &db);
154+ /// let pdf = svg2pdf::to_pdf(&tree, ConversionOptions::default(), PageOptions ::default(), &db);
140155/// std::fs::write(output, pdf)?;
141156/// # Ok(()) }
142157/// ```
143158pub fn to_pdf (
144159 tree : & Tree ,
145- options : Options ,
160+ conversion_options : ConversionOptions ,
161+ page_options : PageOptions ,
146162 #[ cfg( feature = "text" ) ] fontdb : & fontdb:: Database ,
147163) -> Vec < u8 > {
148164 let mut ctx = Context :: new (
149165 #[ cfg( feature = "text" ) ]
150166 tree,
151- options ,
167+ conversion_options ,
152168 #[ cfg( feature = "text" ) ]
153169 fontdb,
154170 ) ;
155171 let mut pdf = Pdf :: new ( ) ;
156172
173+ let dpi_ratio = 72.0 / page_options. dpi ;
174+ let dpi_transform = Transform :: from_scale ( dpi_ratio, dpi_ratio) ;
175+ let page_size =
176+ Size :: from_wh ( tree. size ( ) . width ( ) * dpi_ratio, tree. size ( ) . height ( ) * dpi_ratio)
177+ . unwrap ( ) ;
178+
157179 let catalog_ref = ctx. alloc_ref ( ) ;
158180 let page_tree_ref = ctx. alloc_ref ( ) ;
159181 let page_ref = ctx. alloc_ref ( ) ;
@@ -165,7 +187,10 @@ pub fn to_pdf(
165187 // Generate main content
166188 let mut rc = ResourceContainer :: new ( ) ;
167189 let mut content = Content :: new ( ) ;
190+ content. save_state ( ) ;
191+ content. transform ( dpi_transform. to_pdf_transform ( ) ) ;
168192 tree_to_stream ( tree, & mut pdf, & mut content, & mut ctx, & mut rc) ;
193+ content. restore_state ( ) ;
169194 let content_stream = ctx. finish_content ( content) ;
170195 let mut stream = pdf. stream ( content_ref, & content_stream) ;
171196
@@ -179,7 +204,7 @@ pub fn to_pdf(
179204 rc. finish ( & mut page_resources) ;
180205 page_resources. finish ( ) ;
181206
182- page. media_box ( Rect :: new ( 0.0 , 0.0 , tree . size ( ) . width ( ) , tree . size ( ) . height ( ) ) ) ;
207+ page. media_box ( page_size . to_non_zero_rect ( 0.0 , 0.0 ) . to_pdf_rect ( ) ) ;
183208 page. parent ( page_tree_ref) ;
184209 page. group ( )
185210 . transparency ( )
@@ -240,7 +265,7 @@ pub fn to_pdf(
240265/// let mut db = fontdb::Database::new();
241266/// db.load_system_fonts();
242267/// let tree = svg2pdf::usvg::Tree::from_str(&svg, &svg2pdf::usvg::Options::default(), &db)?;
243- /// let (mut svg_chunk, svg_id) = svg2pdf::to_chunk(&tree, svg2pdf::Options ::default(), &db);
268+ /// let (mut svg_chunk, svg_id) = svg2pdf::to_chunk(&tree, svg2pdf::ConversionOptions ::default(), &db);
244269///
245270/// // Renumber the chunk so that we can embed it into our existing workflow, and also make sure
246271/// // to update `svg_id`.
@@ -297,15 +322,15 @@ pub fn to_pdf(
297322/// ```
298323pub fn to_chunk (
299324 tree : & Tree ,
300- options : Options ,
325+ conversion_options : ConversionOptions ,
301326 #[ cfg( feature = "text" ) ] fontdb : & fontdb:: Database ,
302327) -> ( Chunk , Ref ) {
303328 let mut chunk = Chunk :: new ( ) ;
304329
305330 let mut ctx = Context :: new (
306331 #[ cfg( feature = "text" ) ]
307332 tree,
308- options ,
333+ conversion_options ,
309334 #[ cfg( feature = "text" ) ]
310335 fontdb,
311336 ) ;
0 commit comments