@@ -39,7 +39,7 @@ use std::collections::HashMap;
3939
4040use pdf_writer:: types:: ProcSet ;
4141use pdf_writer:: writers:: { ColorSpace , ExponentialFunction , FormXObject , Resources } ;
42- use pdf_writer:: { Content , Finish , Name , PdfWriter , Rect , Ref , TextStr , Writer } ;
42+ use pdf_writer:: { Content , Filter , Finish , Name , PdfWriter , Rect , Ref , TextStr , Writer } ;
4343use usvg:: { NodeExt , NodeKind , Opacity , Stop , Tree } ;
4444
4545mod defer;
@@ -91,11 +91,23 @@ pub struct Options {
9191 ///
9292 /// _Default:_ `72.0`.
9393 pub dpi : f64 ,
94+ /// Whether the content streams should be compressed.
95+ ///
96+ /// The smaller PDFs generated by this are generally more practical but it
97+ /// increases runtime a bit.
98+ ///
99+ /// _Default:_ `true`.
100+ pub compress : bool ,
94101}
95102
96103impl Default for Options {
97104 fn default ( ) -> Self {
98- Options { viewport : None , aspect : None , dpi : 72.0 }
105+ Options {
106+ viewport : None ,
107+ aspect : None ,
108+ dpi : 72.0 ,
109+ compress : true ,
110+ }
99111 }
100112}
101113
@@ -137,11 +149,13 @@ struct Context<'a> {
137149 /// The mask that needs to be applied at the start of a path drawing
138150 /// operation.
139151 initial_mask : Option < String > ,
152+ /// Whether the content streas should be compressed.
153+ compress : bool ,
140154}
141155
142156impl < ' a > Context < ' a > {
143157 /// Create a new context.
144- fn new ( tree : & ' a Tree , bbox : & ' a Rect , c : CoordToPdf ) -> Self {
158+ fn new ( tree : & ' a Tree , compress : bool , bbox : & ' a Rect , c : CoordToPdf ) -> Self {
145159 Self {
146160 tree,
147161 bbox,
@@ -159,6 +173,7 @@ impl<'a> Context<'a> {
159173 pending_groups : HashMap :: new ( ) ,
160174 checkpoints : vec ! [ ] ,
161175 initial_mask : None ,
176+ compress,
162177 }
163178 }
164179
@@ -253,7 +268,7 @@ pub fn convert_str(src: &str, options: Options) -> Result<Vec<u8>, usvg::Error>
253268/// Convert a [`usvg` tree](Tree) to a standalone PDF buffer.
254269pub fn convert_tree ( tree : & Tree , options : Options ) -> Vec < u8 > {
255270 let ( c, bbox) = get_sizings ( tree, & options) ;
256- let mut ctx = Context :: new ( & tree, & bbox, c) ;
271+ let mut ctx = Context :: new ( & tree, options . compress , & bbox, c) ;
257272
258273 let mut writer = PdfWriter :: new ( ) ;
259274 let catalog_id = ctx. alloc_ref ( ) ;
@@ -282,7 +297,13 @@ pub fn convert_tree(tree: &Tree, options: Options) -> Vec<u8> {
282297 resources. finish ( ) ;
283298 page. finish ( ) ;
284299
285- writer. stream ( content_id, & content) ;
300+ let mut stream = writer. stream ( content_id, & content) ;
301+ if ctx. compress {
302+ stream. filter ( Filter :: FlateDecode ) ;
303+ }
304+
305+ stream. finish ( ) ;
306+
286307 writer. document_info ( ctx. alloc_ref ( ) ) . producer ( TextStr ( "svg2pdf" ) ) ;
287308
288309 writer. finish ( )
@@ -381,7 +402,7 @@ pub fn convert_tree_into(
381402 id : Ref ,
382403) -> Ref {
383404 let ( c, bbox) = get_sizings ( tree, & options) ;
384- let mut ctx = Context :: new ( & tree, & bbox, c) ;
405+ let mut ctx = Context :: new ( & tree, options . compress , & bbox, c) ;
385406
386407 ctx. next_id = id. get ( ) + 1 ;
387408
@@ -403,6 +424,10 @@ pub fn convert_tree_into(
403424 0.0 ,
404425 ] ) ;
405426
427+ if ctx. compress {
428+ xobject. filter ( Filter :: FlateDecode ) ;
429+ }
430+
406431 let mut resources = xobject. resources ( ) ;
407432 ctx. pop ( & mut resources) ;
408433
@@ -483,7 +508,9 @@ fn content_stream<'a>(
483508 }
484509 }
485510
486- content. finish ( )
511+ let res = content. finish ( ) ;
512+
513+ if ctx. compress { deflate ( & res) } else { res }
487514}
488515
489516/// Draw a clipping path into a content stream.
@@ -695,11 +722,16 @@ fn form_xobject<'a>(
695722 reference : Ref ,
696723 content : & ' a [ u8 ] ,
697724 bbox : Rect ,
725+ compress : bool ,
698726 has_color : bool ,
699727) -> FormXObject < ' a > {
700728 let mut form = writer. form_xobject ( reference, content) ;
701729 form. bbox ( bbox) ;
702730
731+ if compress {
732+ form. filter ( Filter :: FlateDecode ) ;
733+ }
734+
703735 let mut group = form. group ( ) ;
704736 group. transparency ( ) ;
705737 group. isolated ( true ) ;
@@ -716,6 +748,12 @@ fn form_xobject<'a>(
716748 form
717749}
718750
751+ /// Compress data with the DEFLATE algorithm.
752+ fn deflate ( data : & [ u8 ] ) -> Vec < u8 > {
753+ const COMPRESSION_LEVEL : u8 = 6 ;
754+ miniz_oxide:: deflate:: compress_to_vec_zlib ( data, COMPRESSION_LEVEL )
755+ }
756+
719757#[ cfg( test) ]
720758mod tests {
721759 use super :: * ;
0 commit comments