fix(bundler): find icon for AppImage, define .DirIcon, closes #749 (#1594)

This commit is contained in:
Lucas Fernandes Nogueira 2021-04-23 00:25:50 -03:00 committed by GitHub
parent 1b159748e7
commit fbf73f3ab5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 24 deletions

View File

@ -0,0 +1,5 @@
---
"tauri-bundler": patch
---
Find best available icon for AppImage, follow `.DirIcon` spec.

View File

@ -47,7 +47,8 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
let package_dir = settings.project_out_directory().join("bundle/appimage_deb");
// generate deb_folder structure
deb_bundle::generate_data(settings, &package_dir)?;
let (_, icons) = deb_bundle::generate_data(settings, &package_dir)?;
let icons: Vec<deb_bundle::DebIcon> = icons.into_iter().collect();
let output_path = settings.project_out_directory().join("bundle/appimage");
if output_path.exists() {
@ -71,6 +72,18 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
sh_map.insert("app_name", settings.main_binary_name());
sh_map.insert("app_name_uppercase", &upcase_app_name);
sh_map.insert("appimage_filename", &appimage_filename);
let larger_icon = icons
.iter()
.filter(|i| i.width == i.height)
.max_by_key(|i| i.width)
.expect("couldn't find a square icon to use as AppImage icon");
let larger_icon_path = larger_icon
.path
.strip_prefix(package_dir.join("data"))
.unwrap()
.to_string_lossy()
.to_string();
sh_map.insert("icon_path", &larger_icon_path);
// initialize shell script template.
let temp = HANDLEBARS.render("appimage", &sh_map)?;

View File

@ -39,6 +39,14 @@ use std::{
path::{Path, PathBuf},
};
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct DebIcon {
pub width: u32,
pub height: u32,
pub is_high_density: bool,
pub path: PathBuf,
}
/// Bundles the project.
/// Returns a vector of PathBuf that shows where the DEB was created.
pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
@ -63,7 +71,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
}
let package_path = base_dir.join(package_name);
let data_dir = generate_data(settings, &package_dir)
let (data_dir, _) = generate_data(settings, &package_dir)
.with_context(|| "Failed to build data folders and files")?;
// Generate control files.
let control_dir = package_dir.join("control");
@ -91,7 +99,10 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
}
/// Generate the debian data folders and files.
pub fn generate_data(settings: &Settings, package_dir: &Path) -> crate::Result<PathBuf> {
pub fn generate_data(
settings: &Settings,
package_dir: &Path,
) -> crate::Result<(PathBuf, BTreeSet<DebIcon>)> {
// Generate data files.
let data_dir = package_dir.join("data");
let bin_dir = data_dir.join("usr/bin");
@ -108,7 +119,8 @@ pub fn generate_data(settings: &Settings, package_dir: &Path) -> crate::Result<P
.copy_binaries(&bin_dir)
.with_context(|| "Failed to copy external binaries")?;
generate_icon_files(settings, &data_dir).with_context(|| "Failed to create icon files")?;
let icons =
generate_icon_files(settings, &data_dir).with_context(|| "Failed to create icon files")?;
generate_desktop_file(settings, &data_dir).with_context(|| "Failed to create desktop file")?;
let use_bootstrapper = settings.deb().use_bootstrapper.unwrap_or_default();
@ -117,7 +129,7 @@ pub fn generate_data(settings: &Settings, package_dir: &Path) -> crate::Result<P
.with_context(|| "Failed to generate bootstrap file")?;
}
Ok(data_dir)
Ok((data_dir, icons))
}
/// Generates the bootstrap script file.
@ -307,7 +319,7 @@ fn transfer_resource_files(settings: &Settings, data_dir: &Path) -> crate::Resul
}
/// Generate the icon files and store them under the `data_dir`.
fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<()> {
fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<BTreeSet<DebIcon>> {
let base_dir = data_dir.join("usr/share/icons/hicolor");
let get_dest_path = |width: u32, height: u32, is_high_density: bool| {
base_dir.join(format!(
@ -318,7 +330,7 @@ fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<()
settings.main_binary_name()
))
};
let mut sizes = BTreeSet::new();
let mut icons = BTreeSet::new();
// Prefer PNG files.
for icon_path in settings.icon_files() {
let icon_path = icon_path?;
@ -329,10 +341,16 @@ fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<()
let width = decoder.dimensions().0;
let height = decoder.dimensions().1;
let is_high_density = common::is_retina(&icon_path);
if !sizes.contains(&(width, height, is_high_density)) {
sizes.insert((width, height, is_high_density));
let dest_path = get_dest_path(width, height, is_high_density);
common::copy_file(&icon_path, &dest_path)?;
let dest_path = get_dest_path(width, height, is_high_density);
let deb_icon = DebIcon {
width,
height,
is_high_density,
path: dest_path,
};
if !icons.contains(&deb_icon) {
common::copy_file(&icon_path, &deb_icon.path)?;
icons.insert(deb_icon);
}
}
// Fall back to non-PNG files for any missing sizes.
@ -346,28 +364,40 @@ fn generate_icon_files(settings: &Settings, data_dir: &Path) -> crate::Result<()
let width = icon_type.screen_width();
let height = icon_type.screen_height();
let is_high_density = icon_type.pixel_density() > 1;
if !sizes.contains(&(width, height, is_high_density)) {
sizes.insert((width, height, is_high_density));
let dest_path = get_dest_path(width, height, is_high_density);
let dest_path = get_dest_path(width, height, is_high_density);
let deb_icon = DebIcon {
width,
height,
is_high_density,
path: dest_path,
};
if !icons.contains(&deb_icon) {
let icon = icon_family.get_icon_with_type(icon_type)?;
icon.write_png(common::create_file(&dest_path)?)?;
icon.write_png(common::create_file(&deb_icon.path)?)?;
icons.insert(deb_icon);
}
}
} else {
let icon = image::open(&icon_path)?;
let (width, height) = icon.dimensions();
let is_high_density = common::is_retina(&icon_path);
if !sizes.contains(&(width, height, is_high_density)) {
sizes.insert((width, height, is_high_density));
let dest_path = get_dest_path(width, height, is_high_density);
let dest_path = get_dest_path(width, height, is_high_density);
let deb_icon = DebIcon {
width,
height,
is_high_density,
path: dest_path,
};
if !icons.contains(&deb_icon) {
icon.write_to(
&mut common::create_file(&dest_path)?,
&mut common::create_file(&deb_icon.path)?,
image::ImageOutputFormat::Png,
)?;
icons.insert(deb_icon);
}
}
}
Ok(())
Ok(icons)
}
/// Create an empty file at the given path, creating any parent directories as

View File

@ -15,13 +15,13 @@ cd "{{app_name}}.AppDir"
wget -q -4 -O AppRun https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-x86_64 || wget -q -4 -O AppRun https://github.com/AppImage/AppImageKit/releases/download/12/AppRun-aarch64
chmod +x AppRun
cp "usr/share/icons/hicolor/256x256/apps/{{app_name}}.png" "{{app_name}}.png"
cp "{{icon_path}}" .DirIcon
ln -s "{{icon_path}}" "{{app_name}}.png"
ln -s "usr/share/applications/{{app_name}}.desktop" "{{app_name}}.desktop"
cd ..
cp "../appimage_deb/data/usr/share/applications/{{app_name}}.desktop" "{{app_name}}.AppDir/usr/share/applications/{{app_name}}.desktop"
cp "../appimage_deb/data/usr/share/applications/{{app_name}}.desktop" "{{app_name}}.AppDir/{{app_name}}.desktop"
mksquashfs "{{app_name}}.AppDir" "{{app_name}}.squashfs" -root-owned -noappend
wget -q -4 -O appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage || wget -q -4 -O appimagetool https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage