Release pipeline after PhotoCraft's: AppImage/deb/rpm/Flatpak/tar.gz for Linux x86_64 and aarch64, FreeBSD, a macOS dmg and CLI zip, Windows x64/x86/arm64 MSI and portable zip (plus the plain x64 exe), web zip, SHA256SUMS.txt; version 0.1.2

Adapted from storytold/photocraft's release.yml and packaging/ (Apache-2.0; ATTRIBUTION.md and
NOTICE say so). Packages install the licence files, THIRD-PARTY-LICENSES.txt included. The app
icon is drawn by `solvecraft-cli icon` (a blue block with a bore, rendered on a transparent
background; .ico too), so no image is committed. Notes: a short header plus GitHub's generated
What's Changed. A dry run (Run workflow, publish off) keeps the files as the release-assets
artifact. packaging-lint.yml checks the workflows, scripts and metadata.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-09 19:18:29 +00:00
1 parent 90fde44c32
commit 7e0618d64b
29 files changed
+1593 -267

No files matched your search

+1 -1
View File
@@ -8,4 +8,4 @@ mod camera;
mod raster;
pub use camera::{Camera, CameraAnim, Mat4, Quat, StandardView, ease_in_out};
pub use raster::{Canvas, Rgb, Scene, SceneLine, SceneMesh, render, render_png};
pub use raster::{Canvas, Rgb, Scene, SceneLine, SceneMesh, png, render, render_png, render_transparent};
+27 -1
View File
@@ -200,12 +200,38 @@ pub fn render(scene: &Scene, cam: &Camera, w: usize, h: usize) -> Canvas {
/// Render to PNG bytes.
pub fn render_png(scene: &Scene, cam: &Camera, w: usize, h: usize) -> Option<Vec<u8>> {
let c = render(scene, cam, w, h);
let img = image::RgbaImage::from_raw(c.w as u32, c.h as u32, c.rgba)?;
png(c.w, c.h, c.rgba)
}
/// RGBA pixels (`w × h`) to PNG bytes.
pub fn png(w: usize, h: usize, rgba: Vec<u8>) -> Option<Vec<u8>> {
let img = image::RgbaImage::from_raw(u32::try_from(w).ok()?, u32::try_from(h).ok()?, rgba)?;
let mut buf = std::io::Cursor::new(Vec::new());
img.write_to(&mut buf, image::ImageFormat::Png).ok()?;
Some(buf.into_inner())
}
/// Render on a transparent background: the scene drawn over black and over white, and the
/// alpha recovered from the difference (exact for the anti-aliased edges).
pub fn render_transparent(scene: &mut Scene, cam: &Camera, w: usize, h: usize) -> Canvas {
let keep = scene.background;
scene.background = Some((Rgb(0, 0, 0), Rgb(0, 0, 0)));
let black = render(scene, cam, w, h);
scene.background = Some((Rgb(255, 255, 255), Rgb(255, 255, 255)));
let mut out = render(scene, cam, w, h);
scene.background = keep;
for (o, b) in out.rgba.as_chunks_mut::<4>().0.iter_mut().zip(black.rgba.as_chunks::<4>().0) {
// white - black = 255 (1 - alpha) in every channel; average them.
let d: u32 = (0..3).map(|k| u32::from(o[k].saturating_sub(b[k]))).sum();
let a = 255.0 - d as f64 / 3.0;
for k in 0..3 {
o[k] = if a > 0.5 { (f64::from(b[k]) * 255.0 / a).round().clamp(0.0, 255.0) as u8 } else { 0 };
}
o[3] = a.round().clamp(0.0, 255.0) as u8;
}
out
}
#[cfg(test)]
mod tests {
use super::*;