@@ -197,7 +197,7 @@ impl<'a> Context<'a> {
197197 }
198198}
199199
200- /// Convert an SVG source string to a PDF buffer.
200+ /// Convert an SVG source string to a standalone PDF buffer.
201201///
202202/// Returns an error if the SVG string is malformed.
203203pub fn convert_str ( src : & str , options : Options ) -> Result < Vec < u8 > , usvg:: Error > {
@@ -210,24 +210,9 @@ pub fn convert_str(src: &str, options: Options) -> Result<Vec<u8>, usvg::Error>
210210 Ok ( convert_tree ( & tree, options) )
211211}
212212
213- /// Convert a [`usvg` tree](Tree) to a PDF buffer.
213+ /// Convert a [`usvg` tree](Tree) to a standalone PDF buffer.
214214pub fn convert_tree ( tree : & Tree , options : Options ) -> Vec < u8 > {
215- let native_size = tree. svg_node ( ) . size ;
216- let viewport = if let Some ( ( width, height) ) = options. viewport {
217- ( width, height)
218- } else {
219- ( native_size. width ( ) , native_size. height ( ) )
220- } ;
221-
222- let c = CoordToPdf :: new (
223- viewport,
224- options. dpi ,
225- tree. svg_node ( ) . view_box ,
226- options. aspect ,
227- ) ;
228-
229- let bbox = Rect :: new ( 0.0 , 0.0 , c. px_to_pt ( viewport. 0 ) , c. px_to_pt ( viewport. 1 ) ) ;
230-
215+ let ( c, bbox) = get_sizings ( tree, & options) ;
231216 let mut ctx = Context :: new ( & tree, & bbox, c) ;
232217
233218 let mut writer = PdfWriter :: new ( ) ;
@@ -239,45 +224,12 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
239224 writer. catalog ( catalog_id) . pages ( page_tree_id) ;
240225 writer. pages ( page_tree_id) . count ( 1 ) . kids ( [ page_id] ) ;
241226
242- for element in tree. defs ( ) . children ( ) {
243- match * element. borrow ( ) {
244- NodeKind :: LinearGradient ( ref lg) => {
245- register_functions ( & mut writer, & mut ctx, & lg. id , & lg. base . stops ) ;
246- }
247- NodeKind :: RadialGradient ( ref rg) => {
248- register_functions ( & mut writer, & mut ctx, & rg. id , & rg. base . stops ) ;
249- }
250- _ => { }
251- }
252- }
227+ preregister ( tree, & mut writer, & mut ctx) ;
253228
254229 ctx. push ( ) ;
255230 let content = content_stream ( & tree. root ( ) , & mut writer, & mut ctx) ;
256231
257- for ( id, gp) in ctx. pending_groups . clone ( ) {
258- let mask_node = tree. defs_by_id ( & id) . unwrap ( ) ;
259- let borrowed = mask_node. borrow ( ) ;
260-
261- if let NodeKind :: Mask ( _) = * borrowed {
262- ctx. push ( ) ;
263- ctx. initial_mask = gp. initial_mask ;
264-
265- let content = content_stream ( & mask_node, & mut writer, & mut ctx) ;
266-
267- let mut group =
268- form_xobject ( & mut writer, gp. reference , & content, gp. bbox , true ) ;
269-
270- if let Some ( matrix) = gp. matrix {
271- group. matrix ( matrix) ;
272- }
273-
274- let mut resources = group. resources ( ) ;
275- ctx. pop ( & mut resources) ;
276- resources. finish ( ) ;
277- }
278- }
279-
280- ctx. initial_mask = None ;
232+ write_masks ( tree, & mut writer, & mut ctx) ;
281233
282234 let mut page = writer. page ( page_id) ;
283235 page. media_box ( bbox) ;
@@ -296,6 +248,81 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
296248 writer. finish ( )
297249}
298250
251+ /// Convert a [`usvg` tree](Tree) into a Form XObject that can be used as part
252+ /// of a larger document.
253+ ///
254+ /// This method is intended for use in an existing [`PdfWriter`] workflow.
255+ ///
256+ /// The resulting object can be used by registering a name and the `id` with a
257+ /// page's [`/XObject`](pdf_writer::writers::Resources::x_objects) resources
258+ /// dictionary and then invoking the [`/Do`](pdf_writer::Content::x_object)
259+ /// operator with the name in the page's content stream.
260+ ///
261+ /// As the conversion process may need to create multiple indirect objects in
262+ /// the PDF, this function allocates consecutive IDs starting at `id` for its
263+ /// objects and returns the next available ID for your future writing.
264+ pub fn convert_tree_into (
265+ tree : & Tree ,
266+ options : Options ,
267+ writer : & mut PdfWriter ,
268+ id : Ref ,
269+ ) -> Ref {
270+ let ( c, bbox) = get_sizings ( tree, & options) ;
271+ let mut ctx = Context :: new ( & tree, & bbox, c) ;
272+
273+ ctx. next_id = id. get ( ) + 1 ;
274+
275+ preregister ( tree, writer, & mut ctx) ;
276+
277+ ctx. push ( ) ;
278+ let content = content_stream ( & tree. root ( ) , writer, & mut ctx) ;
279+
280+ write_masks ( tree, writer, & mut ctx) ;
281+
282+ let mut xobject = writer. form_xobject ( id, & content) ;
283+ xobject. bbox ( bbox) ;
284+ let mut resources = xobject. resources ( ) ;
285+ ctx. pop ( & mut resources) ;
286+
287+ ctx. alloc_ref ( )
288+ }
289+
290+ /// Calculates the bounding box and size conversions for an usvg tree.
291+ fn get_sizings ( tree : & Tree , options : & Options ) -> ( CoordToPdf , Rect ) {
292+ let native_size = tree. svg_node ( ) . size ;
293+ let viewport = if let Some ( ( width, height) ) = options. viewport {
294+ ( width, height)
295+ } else {
296+ ( native_size. width ( ) , native_size. height ( ) )
297+ } ;
298+
299+ let c = CoordToPdf :: new (
300+ viewport,
301+ options. dpi ,
302+ tree. svg_node ( ) . view_box ,
303+ options. aspect ,
304+ ) ;
305+
306+ (
307+ c,
308+ Rect :: new ( 0.0 , 0.0 , c. px_to_pt ( viewport. 0 ) , c. px_to_pt ( viewport. 1 ) ) ,
309+ )
310+ }
311+
312+ fn preregister ( tree : & Tree , writer : & mut PdfWriter , ctx : & mut Context ) {
313+ for element in tree. defs ( ) . children ( ) {
314+ match * element. borrow ( ) {
315+ NodeKind :: LinearGradient ( ref lg) => {
316+ register_functions ( writer, ctx, & lg. id , & lg. base . stops ) ;
317+ }
318+ NodeKind :: RadialGradient ( ref rg) => {
319+ register_functions ( writer, ctx, & rg. id , & rg. base . stops ) ;
320+ }
321+ _ => { }
322+ }
323+ }
324+ }
325+
299326/// Write a content stream for a node.
300327fn content_stream < ' a > (
301328 node : & usvg:: Node ,
0 commit comments