@@ -9,6 +9,7 @@ use crate::{
99} ;
1010
1111use std:: {
12+ borrow:: Cow ,
1213 collections:: HashMap ,
1314 fs:: { create_dir_all, File } ,
1415 io:: { BufWriter , Write } ,
@@ -124,7 +125,7 @@ impl Source {
124125 }
125126 }
126127
127- fn resize_exact ( & self , size : u32 ) -> Result < DynamicImage > {
128+ fn resize_exact ( & self , size : u32 ) -> DynamicImage {
128129 match self {
129130 Self :: Svg ( svg) => {
130131 let mut pixmap = tiny_skia:: Pixmap :: new ( size, size) . unwrap ( ) ;
@@ -134,39 +135,49 @@ impl Source {
134135 tiny_skia:: Transform :: from_scale ( scale, scale) ,
135136 & mut pixmap. as_mut ( ) ,
136137 ) ;
137- let img_buffer = ImageBuffer :: from_raw ( size, size, pixmap. take ( ) ) . unwrap ( ) ;
138- Ok ( DynamicImage :: ImageRgba8 ( img_buffer) )
138+ // Switch to use `Pixmap::take_demultiplied` in the future when it's published
139+ // https://github.com/linebender/tiny-skia/blob/624257c0feb394bf6c4d0d688f8ea8030aae320f/src/pixmap.rs#L266
140+ let img_buffer = ImageBuffer :: from_par_fn ( size, size, |x, y| {
141+ let pixel = pixmap. pixel ( x, y) . unwrap ( ) . demultiply ( ) ;
142+ Rgba ( [ pixel. red ( ) , pixel. green ( ) , pixel. blue ( ) , pixel. alpha ( ) ] )
143+ } ) ;
144+ DynamicImage :: ImageRgba8 ( img_buffer)
139145 }
140146 Self :: DynamicImage ( image) => {
141- // `image` does not use premultiplied alpha in resize, so we do it manually here,
142- // see https://github.com/image-rs/image/issues/1655
143- //
144147 // image.resize_exact(size, size, FilterType::Lanczos3)
145-
146- // Premultiply alpha
147- let premultiplied_image =
148- ImageBuffer :: from_par_fn ( image. width ( ) , image. height ( ) , |x, y| {
149- let mut pixel = image. get_pixel ( x, y) ;
150- let alpha = pixel. 0 [ 3 ] as f32 / u8:: MAX as f32 ;
151- pixel. apply_without_alpha ( |channel_value| ( channel_value as f32 * alpha) as u8 ) ;
152- pixel
153- } ) ;
154-
155- let mut resized =
156- image:: imageops:: resize ( & premultiplied_image, size, size, FilterType :: Lanczos3 ) ;
157-
158- // Unmultiply alpha
159- resized. par_pixels_mut ( ) . for_each ( |pixel| {
160- let alpha = pixel. 0 [ 3 ] as f32 / u8:: MAX as f32 ;
161- pixel. apply_without_alpha ( |channel_value| ( channel_value as f32 / alpha) as u8 ) ;
162- } ) ;
163-
164- Ok ( DynamicImage :: ImageRgba8 ( resized) )
148+ resize_image ( image, size, size)
165149 }
166150 }
167151 }
168152}
169153
154+ // `image` does not use premultiplied alpha in resize, so we do it manually here,
155+ // see https://github.com/image-rs/image/issues/1655
156+ fn resize_image ( image : & DynamicImage , new_width : u32 , new_height : u32 ) -> DynamicImage {
157+ // Premultiply alpha
158+ let premultiplied_image = ImageBuffer :: from_par_fn ( image. width ( ) , image. height ( ) , |x, y| {
159+ let mut pixel = image. get_pixel ( x, y) ;
160+ let alpha = pixel. 0 [ 3 ] as f32 / u8:: MAX as f32 ;
161+ pixel. apply_without_alpha ( |channel_value| ( channel_value as f32 * alpha) as u8 ) ;
162+ pixel
163+ } ) ;
164+
165+ let mut resized = image:: imageops:: resize (
166+ & premultiplied_image,
167+ new_width,
168+ new_height,
169+ FilterType :: Lanczos3 ,
170+ ) ;
171+
172+ // Demultiply alpha
173+ resized. par_pixels_mut ( ) . for_each ( |pixel| {
174+ let alpha = pixel. 0 [ 3 ] as f32 / u8:: MAX as f32 ;
175+ pixel. apply_without_alpha ( |channel_value| ( channel_value as f32 / alpha) as u8 ) ;
176+ } ) ;
177+
178+ DynamicImage :: ImageRgba8 ( resized)
179+ }
180+
170181fn read_source ( path : PathBuf ) -> Result < Source > {
171182 if let Some ( extension) = path. extension ( ) {
172183 if extension == "svg" {
@@ -183,7 +194,7 @@ fn read_source(path: PathBuf) -> Result<Source> {
183194 ..Default :: default ( )
184195 } ;
185196
186- let svg_data = std:: fs:: read ( & path) . unwrap ( ) ;
197+ let svg_data = std:: fs:: read ( & path) . fs_context ( "Failed to read source icon" , & path ) ? ;
187198 usvg:: Tree :: from_data ( & svg_data, & opt) . unwrap ( )
188199 } ;
189200
@@ -329,7 +340,7 @@ fn icns(source: &Source, out_dir: &Path) -> Result<()> {
329340 let size = entry. size ;
330341 let mut buf = Vec :: new ( ) ;
331342
332- let image = source. resize_exact ( size) ? ;
343+ let image = source. resize_exact ( size) ;
333344
334345 write_png ( image. as_bytes ( ) , & mut buf, size) . context ( "failed to write output file" ) ?;
335346
@@ -364,7 +375,7 @@ fn ico(source: &Source, out_dir: &Path) -> Result<()> {
364375 let mut frames = Vec :: new ( ) ;
365376
366377 for size in [ 32 , 16 , 24 , 48 , 64 , 256 ] {
367- let image = source. resize_exact ( size) ? ;
378+ let image = source. resize_exact ( size) ;
368379
369380 // Only the 256px layer can be compressed according to the ico specs.
370381 if size == 256 {
@@ -795,7 +806,7 @@ fn resize_png(
795806 bg : Option < Background > ,
796807 scale_percent : Option < f32 > ,
797808) -> Result < DynamicImage > {
798- let mut image = source. resize_exact ( size) ? ;
809+ let mut image = source. resize_exact ( size) ;
799810
800811 match bg {
801812 Some ( Background :: Color ( bg_color) ) => {
@@ -809,7 +820,7 @@ fn resize_png(
809820 image = bg_img. into ( ) ;
810821 }
811822 Some ( Background :: Image ( bg_source) ) => {
812- let mut bg = bg_source. resize_exact ( size) ? ;
823+ let mut bg = bg_source. resize_exact ( size) ;
813824
814825 let fg = scale_percent
815826 . map ( |scale| resize_asset ( & image, size, scale) )
@@ -889,9 +900,10 @@ fn content_bounds(img: &DynamicImage) -> Option<(u32, u32, u32, u32)> {
889900
890901fn resize_asset ( img : & DynamicImage , target_size : u32 , scale_percent : f32 ) -> DynamicImage {
891902 let cropped = if let Some ( ( x, y, cw, ch) ) = content_bounds ( img) {
892- img. crop_imm ( x, y, cw, ch)
903+ // TODO: Use `&` here instead when we raise MSRV to above 1.79
904+ Cow :: Owned ( img. crop_imm ( x, y, cw, ch) )
893905 } else {
894- img . clone ( )
906+ Cow :: Borrowed ( img )
895907 } ;
896908
897909 let ( cw, ch) = cropped. dimensions ( ) ;
@@ -901,7 +913,7 @@ fn resize_asset(img: &DynamicImage, target_size: u32, scale_percent: f32) -> Dyn
901913 let new_w = ( cw as f32 * scale) . round ( ) as u32 ;
902914 let new_h = ( ch as f32 * scale) . round ( ) as u32 ;
903915
904- let resized = image :: imageops :: resize ( & cropped, new_w, new_h, image :: imageops :: Lanczos3 ) ;
916+ let resized = resize_image ( & cropped, new_w, new_h) ;
905917
906918 // Place on transparent square canvas
907919 let mut canvas = ImageBuffer :: from_pixel ( target_size, target_size, Rgba ( [ 0 , 0 , 0 , 0 ] ) ) ;
0 commit comments