Skip to content

Commit 6775542

Browse files
authored
feat(cli): add --ios-color option to set iOS icon background color (#6247)
1 parent 96b5e92 commit 6775542

22 files changed

+44
-7
lines changed

.changes/ios-icon-color.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"cli.rs": patch
3+
"cli.js": patch
4+
---
5+
6+
Added `--ios-color` option to the `tauri icon` command.

tooling/cli/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tooling/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ kuchiki = "0.8"
8585
tokio = { version = "1", features = [ "macros", "sync" ] }
8686
common-path = "1"
8787
local-ip-address = "0.4"
88+
css-color = "0.2"
8889

8990
[target."cfg(windows)".dependencies]
9091
winapi = { version = "0.3", features = [ "handleapi", "processenv", "winbase", "wincon", "winnt" ] }

tooling/cli/src/icon.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

1415
use 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
};
2526
use 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

5357
pub 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.
364390
fn 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

-131 Bytes
Loading
-391 Bytes
Loading
-391 Bytes
Loading
-1002 Bytes
Loading
-222 Bytes
Loading
-928 Bytes
Loading

0 commit comments

Comments
 (0)