Embed PhotoCraft CLI Windows icon and version metadata (#889)

* Embed PhotoCraft CLI Windows icon and version metadata

The CLI crate now sets build to build.rs and takes winresource 0.1 as a
build dependency. On a Windows target the script embeds photocraft.ico
and sets ProductName to PhotoCraft, FileDescription to PhotoCraft
command-line interface, CompanyName to Learning Machines LLC, the shared
copyright line, OriginalFilename to photocraft-cli.exe, and InternalName
to photocraft-cli. Version strings keep the Cargo package version,
including a pre-release tag, and the numeric file and product versions
are major.minor.patch.0. A missing resource compiler prints a cargo
warning and the link continues, while PHOTOCRAFT_REQUIRE_WINRES makes
the script return an error that names rc.exe or windres. package.ps1
runs check-cli-resources.ps1 after the PE subsystem checks and before
signing, including SkipBuild artifacts, and that script checks those
VERSIONINFO fields against the package version and compares the icon
Windows extracts from the CLI with photocraft.ico drawn at 32x32,
without launching the binary. docs/releasing.md records the same CLI
resource contract beside the existing GUI one.

Refs #613

* Drop the untested check-cli-resources.ps1 release gate

It has never run on Windows, and a misfiring 200-line gate in package.ps1 would block
releases. The CLI build.rs icon/VERSIONINFO stays; PHOTOCRAFT_REQUIRE_WINRES=1 in
package.ps1 already makes a missing resource compiler a build error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Matt Van Horn
2026-10-08 14:05:38 -07:00
committed by GitHub
parent b44133c8b3
commit b885173da1
4 changed files with 57 additions and 3 deletions
Generated
+1
View File
@@ -3576,6 +3576,7 @@ dependencies = [
"photocraft-io",
"serde_json",
"tokio",
"winresource",
]
[[package]]
+5
View File
@@ -4,6 +4,7 @@ description = "Headless Photocraft: convert, inspect, run commands, batch, MCP s
version.workspace = true
edition.workspace = true
license.workspace = true
build = "build.rs"
[features]
# Open HEIC/HEIF photos (the optional photocraft-heif crate). Not default so distributors choose
@@ -30,3 +31,7 @@ photocraft-codecs = { workspace = true }
serde_json = { workspace = true }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
[build-dependencies]
# Icon + VERSIONINFO for photocraft-cli.exe; build.rs only uses it when targeting Windows.
winresource = "0.1"
+36
View File
@@ -0,0 +1,36 @@
//! Windows only: embed the app icon and version info (VERSIONINFO) into `photocraft-cli.exe`.
//!
//! On every other target this does nothing, even when `PHOTOCRAFT_REQUIRE_WINRES` is set. A
//! missing resource compiler is a warning, so a cross-compile from macOS or Linux still links,
//! unless `PHOTOCRAFT_REQUIRE_WINRES=1` (set by the release packaging script) turns it into a
//! build error.
fn main() -> std::io::Result<()> {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=../../assets/app-icon/photocraft.ico");
println!("cargo:rerun-if-env-changed=PHOTOCRAFT_REQUIRE_WINRES");
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") {
return Ok(());
}
let mut res = winresource::WindowsResource::new();
// FileVersion / ProductVersion strings and the numeric FILEVERSION / PRODUCTVERSION are left
// to `WindowsResource::new`, which reads the Cargo package version. A pre-release such as
// `1.2.3-rc.1` stays in the strings; the numeric fields are `1.2.3.0`.
res.set_icon("../../assets/app-icon/photocraft.ico")
.set("ProductName", "PhotoCraft")
.set("FileDescription", "PhotoCraft command-line interface")
.set("CompanyName", "Learning Machines LLC")
.set("LegalCopyright", "Copyright (c) the PhotoCraft authors. MIT OR Apache-2.0.")
.set("OriginalFilename", "photocraft-cli.exe")
.set("InternalName", "photocraft-cli");
if let Err(err) = res.compile() {
if std::env::var_os("PHOTOCRAFT_REQUIRE_WINRES").is_some() {
return Err(std::io::Error::other(format!(
"embedding Windows resources into photocraft-cli.exe failed: {err}. \
Install the Windows SDK resource compiler (rc.exe) or mingw-w64 windres and rebuild."
)));
}
println!("cargo:warning=photocraft-cli.exe built without icon/version resources: {err}");
}
Ok(())
}
+15 -3
View File
@@ -116,10 +116,22 @@ The static C runtime means neither the MSI nor the portable zip needs the Visual
redistributable, which matters for a standalone installer and costs only about 100 KB. The flag
goes in `CARGO_TARGET_<TRIPLE>_RUSTFLAGS`, so host build scripts aren't affected.
- `apps/photocraft/build.rs` embeds the icon (`assets/app-icon/photocraft.ico`) and
VERSIONINFO with the `winresource` crate. It only does this when targeting Windows. Elsewhere
it's a no-op, and the web build doesn't touch that crate.
- `apps/photocraft/build.rs` and `apps/photocraft-cli/build.rs` embed the icon
(`assets/app-icon/photocraft.ico`) and VERSIONINFO with the `winresource` crate
(build dependency `0.1`). They only do this when targeting Windows. Elsewhere each
script is a no-op, even if `PHOTOCRAFT_REQUIRE_WINRES` is set, and the web build
doesn't touch that crate. Both set ProductName to PhotoCraft, CompanyName to
Learning Machines LLC and the same copyright line. The GUI description is
"PhotoCraft image editor" (`photocraft.exe`). The CLI description is
"PhotoCraft command-line interface", with OriginalFilename `photocraft-cli.exe`
and InternalName `photocraft-cli`. Version strings are the Cargo package version,
so a pre-release tag is kept; the numeric file and product versions are
winresource's `major.minor.patch.0`. A missing resource compiler warns, so an
optional cross-compile still links. `package.ps1` sets `PHOTOCRAFT_REQUIRE_WINRES=1`.
The CLI build script then returns an error naming `rc.exe` or `windres` and does
not panic.
- Release builds use the GUI subsystem, so Start Menu launches don't open a console window.
The CLI stays console subsystem 3 so its output reaches the terminal.
- `photocraft.wxs` (WiX v5) is a per-machine install into Program Files with an advertised
Start Menu shortcut. PhotoCraft becomes the default app for `.pcraft` and is listed under
"Open with" for PSD/PSB and image files. It also registers App Paths (Win+R `photocraft`).