@@ -9,6 +9,7 @@ use std::{
99 fs:: { create_dir_all, File } ,
1010 io:: { BufWriter , Write } ,
1111 path:: { Path , PathBuf } ,
12+ str:: FromStr ,
1213} ;
1314
1415use anyhow:: Context ;
@@ -20,7 +21,7 @@ use image::{
2021 png:: { CompressionType , FilterType as PngFilterType , PngEncoder } ,
2122 } ,
2223 imageops:: FilterType ,
23- open, ColorType , DynamicImage , ImageEncoder ,
24+ open, ColorType , DynamicImage , ImageBuffer , ImageEncoder , Rgba ,
2425} ;
2526use serde:: Deserialize ;
2627
@@ -48,11 +49,25 @@ pub struct Options {
4849 /// Default: 'icons' directory next to the tauri.conf.json file.
4950 #[ clap( short, long) ]
5051 output : Option < PathBuf > ,
52+ /// The background color of the iOS icon - string as defined in the W3C's CSS Color Module Level 4 <https://www.w3.org/TR/css-color-4/>.
53+ #[ clap( long, default_value = "#fff" ) ]
54+ ios_color : String ,
5155}
5256
5357pub fn command ( options : Options ) -> Result < ( ) > {
5458 let input = options. input ;
5559 let out_dir = options. output . unwrap_or_else ( || tauri_dir ( ) . join ( "icons" ) ) ;
60+ let ios_color = css_color:: Srgb :: from_str ( & options. ios_color )
61+ . map ( |color| {
62+ Rgba ( [
63+ ( color. red * 255. ) as u8 ,
64+ ( color. green * 255. ) as u8 ,
65+ ( color. blue * 255. ) as u8 ,
66+ ( color. alpha * 255. ) as u8 ,
67+ ] )
68+ } )
69+ . map_err ( |_| anyhow:: anyhow!( "failed to parse iOS color" ) ) ?;
70+
5671 create_dir_all ( & out_dir) . context ( "Can't create output directory" ) ?;
5772
5873 // Try to read the image as a DynamicImage, convert it to rgba8 and turn it into a DynamicImage again.
@@ -73,7 +88,7 @@ pub fn command(options: Options) -> Result<()> {
7388
7489 ico ( & source, & out_dir) . context ( "Failed to generate .ico file" ) ?;
7590
76- png ( & source, & out_dir) . context ( "Failed to generate png icons" ) ?;
91+ png ( & source, & out_dir, ios_color ) . context ( "Failed to generate png icons" ) ?;
7792
7893 Ok ( ( ) )
7994}
@@ -161,7 +176,7 @@ fn ico(source: &DynamicImage, out_dir: &Path) -> Result<()> {
161176
162177// Generate .png files in 32x32, 128x128, 256x256, 512x512 (icon.png)
163178// Main target: Linux & Android
164- fn png ( source : & DynamicImage , out_dir : & Path ) -> Result < ( ) > {
179+ fn png ( source : & DynamicImage , out_dir : & Path , ios_color : Rgba < u8 > ) -> Result < ( ) > {
165180 fn desktop_entries ( out_dir : & Path ) -> Vec < PngEntry > {
166181 let mut entries = Vec :: new ( ) ;
167182
@@ -350,24 +365,32 @@ fn png(source: &DynamicImage, out_dir: &Path) -> Result<()> {
350365 create_dir_all ( & out) . context ( "Can't create iOS output directory" ) ?;
351366 out
352367 } ;
353- entries. extend ( ios_entries ( & out) ?) ;
354368
355369 for entry in entries {
356370 log:: info!( action = "PNG" ; "Creating {}" , entry. name) ;
357371 resize_and_save_png ( source, entry. size , & entry. out_path ) ?;
358372 }
359373
374+ let source_rgba8 = source. as_rgba8 ( ) . expect ( "unexpected image type" ) ;
375+ let mut img = ImageBuffer :: from_fn ( source_rgba8. width ( ) , source_rgba8. height ( ) , |_, _| {
376+ ios_color
377+ } ) ;
378+ image:: imageops:: overlay ( & mut img, source_rgba8, 0 , 0 ) ;
379+ let image = DynamicImage :: ImageRgba8 ( img) ;
380+
381+ for entry in ios_entries ( & out) ? {
382+ log:: info!( action = "iOS" ; "Creating {}" , entry. name) ;
383+ resize_and_save_png ( & image, entry. size , & entry. out_path ) ?;
384+ }
385+
360386 Ok ( ( ) )
361387}
362388
363389// Resize image and save it to disk.
364390fn resize_and_save_png ( source : & DynamicImage , size : u32 , file_path : & Path ) -> Result < ( ) > {
365391 let image = source. resize_exact ( size, size, FilterType :: Lanczos3 ) ;
366-
367392 let mut out_file = BufWriter :: new ( File :: create ( file_path) ?) ;
368-
369393 write_png ( image. as_bytes ( ) , & mut out_file, size) ?;
370-
371394 Ok ( out_file. flush ( ) ?)
372395}
373396
0 commit comments