@@ -39,20 +39,20 @@ In general, a large part of the SVG specification is supported, including featur
3939Among the unsupported features are currently:
4040- The `spreadMethod` attribute of gradients
4141- Filters
42- - Blend modes
4342- Raster images are not color managed but use PDF's DeviceRGB color space
4443- A number of features that were added in SVG2
45- */
44+ */
4645
4746mod render;
4847mod util;
4948
5049use pdf_writer:: { Content , Filter , Finish , PdfWriter , Rect , Ref , TextStr } ;
5150use usvg:: utils:: view_box_to_transform;
52- use usvg:: { Align , AspectRatio , Size , Transform , Tree , TreeParsing } ;
51+ use usvg:: { Align , AspectRatio , NonZeroRect , Size , Transform , Tree , TreeParsing } ;
5352
53+ use crate :: render:: tree_to_stream;
5454use crate :: util:: context:: Context ;
55- use crate :: util:: helper:: { dpi_ratio, NameExt , RectExt } ;
55+ use crate :: util:: helper:: dpi_ratio;
5656
5757/// Set size and scaling preferences for the conversion.
5858#[ derive( Copy , Clone ) ]
@@ -118,7 +118,7 @@ impl Default for Options {
118118///
119119/// Does not load any fonts and consequently cannot convert `text` elements. To
120120/// convert text, you should convert your source string to a
121- /// [`usvg` tree](usvg:: Tree) manually,
121+ /// [`usvg` tree](Tree) manually,
122122/// [convert text with usvg](usvg::TreeTextToPath::convert_text) and then use
123123/// [`convert_tree`].
124124///
@@ -132,7 +132,7 @@ pub fn convert_str(src: &str, options: Options) -> Result<Vec<u8>, usvg::Error>
132132 Ok ( convert_tree ( & tree, options) )
133133}
134134
135- /// Convert a [`usvg` tree](usvg:: Tree) into a standalone PDF buffer.
135+ /// Convert a [`usvg` tree](Tree) into a standalone PDF buffer.
136136///
137137/// ## Example
138138/// The example below reads an SVG file, processes text within it, then converts
@@ -159,9 +159,8 @@ pub fn convert_str(src: &str, options: Options) -> Result<Vec<u8>, usvg::Error>
159159/// # Ok(()) }
160160/// ```
161161pub fn convert_tree ( tree : & Tree , options : Options ) -> Vec < u8 > {
162- let page_size = options. viewport . unwrap_or ( tree. size ) ;
163- let mut ctx =
164- Context :: new ( tree, options, initial_transform ( & options, tree, page_size) , None ) ;
162+ let pdf_size = pdf_size ( tree, options) ;
163+ let mut ctx = Context :: new ( tree, options, None ) ;
165164 let mut writer = PdfWriter :: new ( ) ;
166165
167166 let catalog_ref = ctx. alloc_ref ( ) ;
@@ -174,31 +173,35 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
174173
175174 // Generate main content
176175 ctx. deferrer . push ( ) ;
177- let tree_x_object = render:: tree_to_x_object ( tree, & mut writer, & mut ctx) ;
178176 let mut content = Content :: new ( ) ;
179- content. x_object ( tree_x_object. as_name ( ) ) ;
180-
177+ tree_to_stream (
178+ tree,
179+ & mut writer,
180+ & mut content,
181+ & mut ctx,
182+ initial_transform ( options. aspect , tree, pdf_size) ,
183+ ) ;
181184 let content_stream = ctx. finish_content ( content) ;
182185 let mut stream = writer. stream ( content_ref, & content_stream) ;
183186
184187 if ctx. options . compress {
185188 stream. filter ( Filter :: FlateDecode ) ;
186189 }
187-
188190 stream. finish ( ) ;
189191
190192 let mut page = writer. page ( page_ref) ;
191193 let mut page_resources = page. resources ( ) ;
192194 ctx. deferrer . pop ( & mut page_resources) ;
193195 page_resources. finish ( ) ;
194196
195- page. media_box ( Rect :: new (
196- 0.0 ,
197- 0.0 ,
198- dpi_ratio ( options. dpi ) * page_size. width ( ) as f32 ,
199- dpi_ratio ( options. dpi ) * page_size. height ( ) as f32 ,
200- ) ) ;
197+ page. media_box ( Rect :: new ( 0.0 , 0.0 , pdf_size. width ( ) , pdf_size. height ( ) ) ) ;
201198 page. parent ( page_tree_ref) ;
199+ page. group ( )
200+ . transparency ( )
201+ . isolated ( true )
202+ . knockout ( false )
203+ . color_space ( )
204+ . srgb ( ) ;
202205 page. contents ( content_ref) ;
203206 page. finish ( ) ;
204207
@@ -208,7 +211,7 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
208211 writer. finish ( )
209212}
210213
211- /// Convert a [`usvg` tree](usvg:: Tree) into a Form XObject that can be used as
214+ /// Convert a [`usvg` tree](Tree) into a Form XObject that can be used as
212215/// part of a larger document.
213216///
214217/// This method is intended for use in an existing [`PdfWriter`] workflow. It
@@ -304,30 +307,29 @@ pub fn convert_tree_into(
304307 writer : & mut PdfWriter ,
305308 start_ref : Ref ,
306309) -> Ref {
307- let mut ctx = Context :: new (
308- tree,
309- options,
310- initial_transform ( & options, tree, tree. size ) ,
311- Some ( start_ref. get ( ) ) ,
312- ) ;
310+ let pdf_size = pdf_size ( tree, options) ;
311+ let mut ctx = Context :: new ( tree, options, Some ( start_ref. get ( ) ) ) ;
313312
314313 let x_ref = ctx. alloc_ref ( ) ;
315314 ctx. deferrer . push ( ) ;
316315
317- let tree_x_object = render:: tree_to_x_object ( tree, writer, & mut ctx) ;
318316 let mut content = Content :: new ( ) ;
319- content. x_object ( tree_x_object. as_name ( ) ) ;
320-
317+ tree_to_stream (
318+ tree,
319+ writer,
320+ & mut content,
321+ & mut ctx,
322+ initial_transform ( options. aspect , tree, pdf_size) ,
323+ ) ;
321324 let content_stream = ctx. finish_content ( content) ;
322325
323326 let mut x_object = writer. form_xobject ( x_ref, & content_stream) ;
324- x_object. bbox ( ctx. get_rect ( ) . as_pdf_rect ( ) ) ;
325- // Revert the PDF transformation so that the resulting XObject is 1x1 in size.
327+ x_object. bbox ( Rect :: new ( 0.0 , 0.0 , pdf_size. width ( ) , pdf_size. height ( ) ) ) ;
326328 x_object. matrix ( [
327- 1.0 / ctx . get_rect ( ) . width ( ) as f32 ,
329+ 1.0 / pdf_size . width ( ) ,
328330 0.0 ,
329331 0.0 ,
330- 1.0 / ctx . get_rect ( ) . height ( ) as f32 ,
332+ 1.0 / pdf_size . height ( ) ,
331333 0.0 ,
332334 0.0 ,
333335 ] ) ;
@@ -342,33 +344,35 @@ pub fn convert_tree_into(
342344 ctx. alloc_ref ( )
343345}
344346
345- /// Return the initial transform that is necessary for the conversion between SVG coordinates
346- /// and the final PDF page (including DPI and a custom viewport).
347- fn initial_transform ( options : & Options , tree : & Tree , actual_size : Size ) -> Transform {
348- // Account for DPI.
349- let dpi_transform = Transform :: new_scale (
350- dpi_ratio ( options. dpi ) as f64 ,
351- dpi_ratio ( options. dpi ) as f64 ,
352- ) ;
347+ /// Return the dimensions of the PDF page
348+ fn pdf_size ( tree : & Tree , options : Options ) -> Size {
349+ // If no custom viewport is defined, we use the size of the tree.
350+ let viewport_size = options. viewport . unwrap_or ( tree. size ) ;
351+ Size :: from_wh (
352+ viewport_size. width ( ) * dpi_ratio ( options. dpi ) ,
353+ viewport_size. height ( ) * dpi_ratio ( options. dpi ) ,
354+ )
355+ . unwrap ( )
356+ }
353357
358+ /// Return the initial transform that is necessary for the conversion between SVG coordinates
359+ /// and the final PDF page.
360+ fn initial_transform (
361+ aspect : Option < AspectRatio > ,
362+ tree : & Tree ,
363+ pdf_size : Size ,
364+ ) -> Transform {
354365 // Account for the custom viewport that has been passed in the Options struct. If nothing has
355- // been passed, actual_size will be same as tree.size, so the transform will just be the
366+ // been passed, pdf_size should be the same as tree.size, so the transform will just be the
356367 // default transform.
357368 let custom_viewport_transform = view_box_to_transform (
358- usvg:: Rect :: new ( 0.0 , 0.0 , tree. size . width ( ) , tree. size . height ( ) ) . unwrap ( ) ,
359- options. aspect . unwrap_or ( AspectRatio {
360- defer : false ,
361- align : Align :: None ,
362- slice : false ,
363- } ) ,
364- actual_size,
369+ NonZeroRect :: from_xywh ( 0.0 , 0.0 , tree. size . width ( ) , tree. size . height ( ) ) . unwrap ( ) ,
370+ aspect. unwrap_or ( AspectRatio { defer : false , align : Align :: None , slice : false } ) ,
371+ pdf_size,
365372 ) ;
366373
367374 // Account for the direction of the y axis and the shift of the origin in the coordinate system.
368- let pdf_transform = Transform :: new ( 1.0 , 0.0 , 0.0 , -1.0 , 0.0 , actual_size . height ( ) ) ;
375+ let pdf_transform = Transform :: from_row ( 1.0 , 0.0 , 0.0 , -1.0 , 0.0 , pdf_size . height ( ) ) ;
369376
370- let mut base_transform = dpi_transform;
371- base_transform. append ( & pdf_transform) ;
372- base_transform. append ( & custom_viewport_transform) ;
373- base_transform
377+ pdf_transform. pre_concat ( custom_viewport_transform)
374378}
0 commit comments