@@ -15,7 +15,7 @@ use usvg::{
1515#[ cfg( any( feature = "png" , feature = "jpeg" ) ) ]
1616use {
1717 image:: io:: Reader as ImageReader ,
18- image:: { DynamicImage , GenericImageView , ImageFormat , Rgb , Rgba , Luma } ,
18+ image:: { DynamicImage , ImageFormat , Luma , Rgb , Rgba } ,
1919 pdf_writer:: writers:: ImageXObject ,
2020} ;
2121
@@ -553,7 +553,7 @@ impl Render for usvg::Image {
553553
554554 let image_ref = ctx. alloc_ref ( ) ;
555555
556- #[ cfg( any( feature = "png" , feature = "jpeg" ) ) ]
556+ #[ cfg( any( feature = "png" , feature = "jpeg" , feature = "gif" ) ) ]
557557 let set_image_props = |
558558 image : & mut ImageXObject ,
559559 raster_size : & mut Option < ( u32 , u32 ) > ,
@@ -576,14 +576,75 @@ impl Render for usvg::Image {
576576 }
577577 } ;
578578
579- #[ cfg( any( feature = "png" , feature = "jpeg" ) ) ]
579+ #[ cfg( any( feature = "png" , feature = "jpeg" , feature = "gif" ) ) ]
580580 let mut raster_size: Option < ( u32 , u32 ) > = None ;
581581 let rect = self . view_box. rect;
582582
583+ #[ cfg( any( feature = "png" , feature = "gif" ) ) ]
584+ let mut apply_transparent = |decoded: DynamicImage | {
585+ let color = decoded. color( ) ;
586+
587+ let bits = color. bits_per_pixel( ) ;
588+ let channels = color. channel_count( ) as u16;
589+ let image_bytes: Vec < u8 > = match ( channels, bits / channels > 8 ) {
590+ ( 1 , false ) => {
591+ decoded. to_luma8( ) . pixels( ) . flat_map( |& Luma ( c) | c) . collect( )
592+ }
593+ ( 1 , true ) => decoded
594+ . to_luma16( )
595+ . pixels( )
596+ . flat_map( |& Luma ( x) | x)
597+ . flat_map( |x| x. to_be_bytes( ) )
598+ . collect( ) ,
599+ ( 3 | 4 , false ) => {
600+ decoded. to_rgb8( ) . pixels( ) . flat_map( |& Rgb ( c) | c) . collect( )
601+ }
602+ ( 3 | 4 , true ) => decoded
603+ . to_rgb16( )
604+ . pixels( )
605+ . flat_map( |& Rgb ( c) | c)
606+ . flat_map( |x| x. to_be_bytes( ) )
607+ . collect( ) ,
608+ _ => panic ! ( "unknown number of channels={channels}" ) ,
609+ } ;
610+ let compressed = compress_to_vec_zlib( & image_bytes, 8 ) ;
611+
612+ let mut image = writer. image_xobject( image_ref, & compressed) ;
613+ set_image_props( & mut image, & mut raster_size, & decoded, false ) ;
614+ image. filter( Filter :: FlateDecode ) ;
615+
616+ // The alpha channel has to be written separately, as a Soft
617+ // Mask.
618+ if color. has_alpha( ) {
619+ let mask_id = ctx. alloc_ref( ) ;
620+ image. pair( Name ( b"SMask" ) , mask_id) ;
621+ image. finish( ) ;
622+
623+ let bits = color. bits_per_pixel( ) ;
624+ let channels = color. channel_count( ) as u16;
625+ let alpha_bytes: Vec < u8 > = if bits / channels > 8 {
626+ decoded
627+ . to_rgba16( )
628+ . pixels( )
629+ . flat_map( |& Rgba ( [ .., a] ) | a. to_be_bytes( ) )
630+ . collect( )
631+ } else {
632+ decoded. to_rgba8( ) . pixels( ) . map( |& Rgba ( [ .., a] ) | a) . collect( )
633+ } ;
634+
635+ let compressed = compress_to_vec_zlib( & alpha_bytes, 8 ) ;
636+ let mut mask = writer. image_xobject( mask_id, & compressed) ;
637+ let mut void = None ;
638+
639+ set_image_props( & mut mask, & mut void, & decoded, true ) ;
640+ mask. filter( Filter :: FlateDecode ) ;
641+ }
642+ } ;
643+
583644 match & self . kind {
584645 #[ cfg( feature = "jpeg" ) ]
585646 ImageKind :: JPEG ( buf) => {
586- let cursor = std:: io:: Cursor :: new( buf) ;
647+ let cursor = std:: io:: Cursor :: new( buf. as_ref ( ) ) ;
587648 let decoded = if let Ok ( decoded) =
588649 ImageReader :: with_format( cursor, ImageFormat :: Jpeg ) . decode ( )
589650 {
@@ -598,72 +659,29 @@ impl Render for usvg::Image {
598659 }
599660 #[ cfg( feature = "png" ) ]
600661 ImageKind :: PNG ( buf) => {
601- let cursor = std:: io:: Cursor :: new( buf) ;
602- let decoded = if let Ok ( decoded) =
603- ImageReader :: with_format( cursor, ImageFormat :: Png ) . decode ( )
604- {
605- decoded
606- } else {
607- return ;
608- } ;
609-
610- let color = decoded. color( ) ;
611-
612- let bits = color. bits_per_pixel( ) ;
613- let channels = color. channel_count( ) as u16;
614- let image_bytes: Vec < u8 > = match ( channels, bits / channels > 8 ) {
615- ( 1 , false ) => {
616- decoded. to_luma8( ) . pixels( ) . flat_map( |& Luma ( c) | c) . collect( )
617- }
618- ( 1 , true ) => decoded
619- . to_luma16( )
620- . pixels( )
621- . flat_map( |& Luma ( x) | x)
622- . flat_map( |x| x. to_be_bytes( ) )
623- . collect( ) ,
624- ( 3 | 4 , false ) => {
625- decoded. to_rgb8( ) . pixels( ) . flat_map( |& Rgb ( c) | c) . collect( )
626- }
627- ( 3 | 4 , true ) => decoded
628- . to_rgb16( )
629- . pixels( )
630- . flat_map( |& Rgb ( c) | c)
631- . flat_map( |x| x. to_be_bytes( ) )
632- . collect( ) ,
633- _ => panic ! ( "unknown number of channels={channels}" ) ,
634- } ;
635- let compressed = compress_to_vec_zlib( & image_bytes, 8 ) ;
636-
637- let mut image = writer. image_xobject( image_ref, & compressed) ;
638- set_image_props( & mut image, & mut raster_size, & decoded, false ) ;
639- image. filter( Filter :: FlateDecode ) ;
640-
641- // The alpha channel has to be written separately, as a Soft
642- // Mask.
643- if color. has_alpha( ) {
644- let mask_id = ctx. alloc_ref( ) ;
645- image. pair( Name ( b"SMask" ) , mask_id) ;
646- image. finish( ) ;
647-
648- let bits = color. bits_per_pixel( ) ;
649- let channels = color. channel_count( ) as u16;
650- let alpha_bytes: Vec < u8 > = if bits / channels > 8 {
662+ let cursor = std:: io:: Cursor :: new( buf. as_ref( ) ) ;
663+ apply_transparent(
664+ if let Ok ( decoded) =
665+ ImageReader :: with_format( cursor, ImageFormat :: Png ) . decode ( )
666+ {
651667 decoded
652- . to_rgba16( )
653- . pixels( )
654- . flat_map( |& Rgba ( [ .., a] ) | a. to_be_bytes( ) )
655- . collect( )
656668 } else {
657- decoded. to_rgba8( ) . pixels( ) . map( |& Rgba ( [ .., a] ) | a) . collect( )
658- } ;
659-
660- let compressed = compress_to_vec_zlib( & alpha_bytes, 8 ) ;
661- let mut mask = writer. image_xobject( mask_id, & compressed) ;
662- let mut void = None ;
663-
664- set_image_props( & mut mask, & mut void, & decoded, true ) ;
665- mask. filter( Filter :: FlateDecode ) ;
666- }
669+ return ;
670+ } ,
671+ ) ;
672+ }
673+ #[ cfg( feature = "gif" ) ]
674+ ImageKind :: GIF ( buf) => {
675+ let cursor = std:: io:: Cursor :: new( buf. as_ref( ) ) ;
676+ apply_transparent(
677+ if let Ok ( decoded) =
678+ ImageReader :: with_format( cursor, ImageFormat :: Gif ) . decode ( )
679+ {
680+ decoded
681+ } else {
682+ return ;
683+ } ,
684+ ) ;
667685 }
668686 ImageKind :: SVG ( tree) => {
669687 // An SVG image means that the file gets embedded in a
@@ -677,13 +695,16 @@ impl Render for usvg::Image {
677695
678696 ctx. next_id = convert_tree_into( tree, opt, writer, image_ref) . get( ) ;
679697 }
680-
681- #[ cfg( any( not( feature = "jpeg" ) , not( feature = "png" ) ) ) ]
698+ #[ cfg( any(
699+ not( feature = "jpeg" ) ,
700+ not( feature = "png" ) ,
701+ not( feature = "gif" )
702+ ) ) ]
682703 _ => { }
683704 }
684705
685706 // Common operations for raster image formats.
686- #[ cfg( any( feature = "png" , feature = "jpeg" ) ) ]
707+ #[ cfg( any( feature = "png" , feature = "jpeg" , feature = "gif" ) ) ]
687708 let image_ref = if let Some ( ( width, height) ) = raster_size {
688709 let mut content = Content :: new( ) ;
689710 let xobj_name = Name ( b"EmbRaster" ) ;
0 commit comments