mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-19 02:10:49 -05:00
UI.9: keep browser bundle under size budget on current main
This commit is contained in:
commit
d0a18cfd83
11 files changed
+827
-311
No files matched your search
@@ -372,9 +372,79 @@ jobs:
|
||||
path: dist/release/*
|
||||
if-no-files-found: error
|
||||
|
||||
linux-riscv64:
|
||||
name: Linux riscv64
|
||||
needs: version
|
||||
# Cross-compiled on x86_64 (no hosted RISC-V runners) against the runner's own Ubuntu release
|
||||
# from ports.ubuntu.com, so the binaries need that release's glibc (24.04: 2.39). 22.04's
|
||||
# riscv64 ports lag its amd64 updates, which breaks the multiarch install. tar.gz only; the
|
||||
# CLI is smoke-tested under QEMU. Same recipe as GridCraft's linux-riscv64 job.
|
||||
runs-on: ubuntu-24.04
|
||||
# No `environment: release`: this job reads no secrets, so a branch dry run can run it.
|
||||
env:
|
||||
PHOTOCRAFT_VERSION: ${{ needs.version.outputs.version }}
|
||||
PHOTOCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check out craft-fonts (embedded fonts)
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
repository: storytold/craft-fonts
|
||||
ref: ${{ env.CRAFT_FONTS_REF }}
|
||||
path: craft-fonts
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: riscv64gc-unknown-linux-gnu
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: release-linux-riscv64
|
||||
- name: Apply version override
|
||||
if: inputs.version != ''
|
||||
run: cargo xtask version set "$PHOTOCRAFT_VERSION"
|
||||
- name: Install cross-compilation dependencies
|
||||
run: |
|
||||
. /etc/os-release
|
||||
sudo dpkg --add-architecture riscv64
|
||||
# Pin the existing (archive.ubuntu.com) sources to amd64; riscv64 comes from ports.
|
||||
if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then
|
||||
sudo sed -i '/^Types: deb/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources
|
||||
fi
|
||||
if [ -f /etc/apt/sources.list ]; then
|
||||
sudo sed -i 's/^deb /deb [arch=amd64] /g' /etc/apt/sources.list
|
||||
sudo sed -i 's/^deb-src /deb-src [arch=amd64] /g' /etc/apt/sources.list
|
||||
fi
|
||||
for suite in "$VERSION_CODENAME" "$VERSION_CODENAME-updates" "$VERSION_CODENAME-security"; do
|
||||
echo "deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports $suite main universe restricted multiverse"
|
||||
done | sudo tee /etc/apt/sources.list.d/riscv64.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu libc6-dev-riscv64-cross libc6-dev:riscv64 qemu-user \
|
||||
libxkbcommon-dev:riscv64 libwayland-dev:riscv64 libx11-dev:riscv64 libxrandr-dev:riscv64 \
|
||||
libxi-dev:riscv64 libgl1-mesa-dev:riscv64 \
|
||||
desktop-file-utils appstream
|
||||
- name: Build and package (tar.gz)
|
||||
env:
|
||||
CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
|
||||
CRAFT_FONTS_REQUIRED: "1"
|
||||
CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER: riscv64-linux-gnu-gcc
|
||||
PKG_CONFIG_SYSROOT_DIR: /
|
||||
PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig:/usr/share/pkgconfig
|
||||
PKG_CONFIG_ALLOW_CROSS: "1"
|
||||
CROSS_ARCH: riscv64
|
||||
CROSS_TARGET: riscv64gc-unknown-linux-gnu
|
||||
CROSS_COMPILE: riscv64-linux-gnu-
|
||||
EMULATOR: qemu-riscv64
|
||||
QEMU_LD_PREFIX: /usr/riscv64-linux-gnu
|
||||
run: packaging/linux/package.sh --formats tar
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-linux-riscv64
|
||||
path: dist/release/*.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
release:
|
||||
name: Draft GitHub Release
|
||||
needs: [version, macos, windows, linux, flatpak, freebsd, web]
|
||||
needs: [version, macos, windows, linux, linux-riscv64, flatpak, freebsd, web]
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
permissions:
|
||||
|
||||
Generated
+29
-29
@@ -4182,7 +4182,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"async-io",
|
||||
@@ -4223,7 +4223,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-affinity"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
@@ -4233,7 +4233,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-algo"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-color",
|
||||
"photocraft-geom",
|
||||
@@ -4246,7 +4246,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-automation"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cap-std",
|
||||
@@ -4268,7 +4268,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-cli"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-automation",
|
||||
"photocraft-codecs",
|
||||
@@ -4282,7 +4282,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-cms"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"moxcms",
|
||||
"rayon",
|
||||
@@ -4290,7 +4290,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-codecs"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"exr",
|
||||
"flate2",
|
||||
@@ -4311,7 +4311,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-color"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-cms",
|
||||
"serde",
|
||||
@@ -4319,7 +4319,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-compose"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"photocraft-color",
|
||||
@@ -4334,7 +4334,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-doc"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-color",
|
||||
"photocraft-geom",
|
||||
@@ -4345,7 +4345,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-engine"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"exr",
|
||||
@@ -4378,7 +4378,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-format"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"flate2",
|
||||
@@ -4397,14 +4397,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-geom"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-gpu"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"half",
|
||||
"log",
|
||||
@@ -4421,14 +4421,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-heif"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"heic-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-io"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"crc32fast",
|
||||
@@ -4457,14 +4457,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-ops"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-doc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-paint"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-color",
|
||||
"photocraft-geom",
|
||||
@@ -4475,7 +4475,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-plugins"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-color",
|
||||
"photocraft-geom",
|
||||
@@ -4490,7 +4490,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-psd"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"photocraft-psd",
|
||||
@@ -4501,7 +4501,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-raster"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-color",
|
||||
"photocraft-geom",
|
||||
@@ -4511,7 +4511,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-raw"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"image",
|
||||
@@ -4526,7 +4526,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-tablet"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"block2 0.6.2",
|
||||
"objc2 0.6.4",
|
||||
@@ -4538,7 +4538,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-testkit"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"memory-stats",
|
||||
"photocraft-color",
|
||||
@@ -4549,7 +4549,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-text"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"parley",
|
||||
@@ -4563,7 +4563,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-ui-egui"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"craft-ui",
|
||||
@@ -4601,7 +4601,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-vector"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"photocraft-color",
|
||||
"photocraft-doc",
|
||||
@@ -4612,7 +4612,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "photocraft-web"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"eframe",
|
||||
"egui",
|
||||
@@ -7445,7 +7445,7 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
+9
-5
@@ -4,7 +4,7 @@ members = ["crates/*", "apps/*", "xtask"]
|
||||
default-members = ["crates/*", "apps/photocraft", "apps/photocraft-cli", "xtask"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
rust-version = "1.95"
|
||||
@@ -81,11 +81,10 @@ codegen-units = 1
|
||||
|
||||
# The browser build (apps/photocraft-web, `data-cargo-profile` in its index.html). Hosts cap the
|
||||
# size of a single file (Cloudflare Pages/Workers: 25 MiB), and the wasm is downloaded on every
|
||||
# visit, so this profile optimizes for size: fat LTO, and opt-level "s" for everything except the
|
||||
# pixel-processing crates, which keep opt-level 3 so filters and compositing stay fast. panic
|
||||
# visit, so this profile optimizes for size: fat LTO, opt-level "z" for the UI shell, and "s" for
|
||||
# other crates except pixel processing, which keeps opt-level 3 for filters and compositing. panic
|
||||
# stays the target default (wasm32-unknown-unknown aborts; AGENTS.md's `panic = "unwind"` is for
|
||||
# the native app shell). packaging/web/package.sh fails the build above 24 MiB. Issue #198:
|
||||
# this took the wasm from 26.3 MiB (release profile) to 18.8 MiB.
|
||||
# the native app shell). packaging/web/package.sh fails the build above 24 MiB.
|
||||
[profile.wasm-release]
|
||||
inherits = "release"
|
||||
opt-level = "s"
|
||||
@@ -96,6 +95,11 @@ strip = "debuginfo"
|
||||
[profile.wasm-release.package."*"]
|
||||
opt-level = "s"
|
||||
|
||||
# Keep the browser shell compact as shared panel controls grow. Pixel-processing crates below
|
||||
# retain their speed-oriented optimization level.
|
||||
[profile.wasm-release.package.photocraft-ui-egui]
|
||||
opt-level = "z"
|
||||
|
||||
[profile.wasm-release.package.photocraft-raster]
|
||||
opt-level = 3
|
||||
[profile.wasm-release.package.photocraft-color]
|
||||
|
||||
@@ -350,6 +350,8 @@ Installers and executables are code-signed.
|
||||
| Fedora/RHEL/openSUSE | `photocraft-<ver>-linux-x86_64.rpm` | `photocraft-<ver>-linux-aarch64.rpm` | |
|
||||
| Tarball | `photocraft-<ver>-linux-x86_64.tar.gz` | `photocraft-<ver>-linux-aarch64.tar.gz` | Unpack anywhere |
|
||||
|
||||
RISC-V (riscv64): `photocraft-<ver>-linux-riscv64.tar.gz` only, built against Ubuntu 24.04 (needs glibc 2.39+).
|
||||
|
||||
### FreeBSD
|
||||
|
||||
| Build | File |
|
||||
|
||||
@@ -227,7 +227,13 @@ pub fn missing_message(session: DisplaySession, missing: &[AnyOf], distro: Distr
|
||||
/// Library directories to search: `LD_LIBRARY_PATH`, then the usual system and Flatpak paths.
|
||||
fn search_dirs(ld_library_path: Option<&str>) -> Vec<PathBuf> {
|
||||
let mut dirs: Vec<PathBuf> = ld_library_path.unwrap_or("").split(':').filter(|d| !d.is_empty()).map(PathBuf::from).collect();
|
||||
let triplet = if cfg!(target_arch = "aarch64") { "aarch64-linux-gnu" } else { "x86_64-linux-gnu" };
|
||||
let triplet = if cfg!(target_arch = "aarch64") {
|
||||
"aarch64-linux-gnu"
|
||||
} else if cfg!(target_arch = "riscv64") {
|
||||
"riscv64-linux-gnu"
|
||||
} else {
|
||||
"x86_64-linux-gnu"
|
||||
};
|
||||
for d in ["/app/lib", "/usr/local/lib", "/usr/lib64", "/lib64", "/usr/lib", "/lib"] {
|
||||
dirs.push(PathBuf::from(d));
|
||||
}
|
||||
|
||||
+671
-203
File diff suppressed because it is too large.
Load diff
@@ -265,6 +265,15 @@ pub(crate) fn marquee_ants(xf: &ViewXform, tool: Tool, a: [f64; 2], b: [f64; 2])
|
||||
if tool != Tool::EllipseMarquee {
|
||||
return vec![at(x0, y0), at(x1, y0), at(x1, y1), at(x0, y1)];
|
||||
}
|
||||
// An axis-aligned view (rotation a multiple of 90 degrees) maps the ellipse onto the one
|
||||
// inscribed in the snapped screen box of two opposite corners. Draw that, unsnapped: snapping
|
||||
// each vertex on its own turns the nearly flat arcs at the edge midpoints into 1 px stairs,
|
||||
// whose antialiased steps wash the ants out to grey on white and black.
|
||||
let quarter = xf.rotation.rem_euclid(90.0);
|
||||
if quarter < 1e-4 || 90.0 - quarter < 1e-4 {
|
||||
let r = Rect::from_two_pos(at(x0, y0), at(x1, y1));
|
||||
return crate::tool_feedback::ellipse_points(r);
|
||||
}
|
||||
// As many vertices as the same ellipse would get drawn on screen (`ellipse_points`).
|
||||
let scr = Rect::from_points(&[xf.to_screen(x0 as f32, y0 as f32), xf.to_screen(x1 as f32, y1 as f32)]);
|
||||
let n = (((scr.width() + scr.height()) * 0.25) as usize).clamp(16, 256);
|
||||
|
||||
@@ -128,7 +128,7 @@ fn coverage(img: &Image, ppp: f32, a: Pos2, b: Pos2, test: impl Fn(u8) -> bool)
|
||||
let len = a.distance(b).max(1.0);
|
||||
let dir = (b - a) / len;
|
||||
let normal = egui::vec2(-dir.y, dir.x);
|
||||
// Skip rectangle corners, where other edges and the readout may be.
|
||||
// Skip the ends (corners, where the other edges and the readout may be).
|
||||
let n = (len as usize).saturating_sub(16);
|
||||
let mut hits = 0;
|
||||
for i in 0..n {
|
||||
@@ -142,31 +142,6 @@ fn coverage(img: &Image, ppp: f32, a: Pos2, b: Pos2, test: impl Fn(u8) -> bool)
|
||||
hits as f32 / n.max(1) as f32
|
||||
}
|
||||
|
||||
/// Sample eight dash periods along the actual ellipse, including its curvature.
|
||||
/// A short tangent segment can land on antialiasing ramps instead of the stroke's core.
|
||||
fn ellipse_coverage(images: &[&Image], ppp: f32, center: Pos2, radius: egui::Vec2, midpoint: Pos2, test: impl Fn(u8) -> bool) -> f32 {
|
||||
let (center, radius, midpoint) = (center * ppp, radius * ppp, midpoint * ppp);
|
||||
let horizontal = (midpoint.y - center.y).abs() > (midpoint.x - center.x).abs();
|
||||
let mut hits = 0;
|
||||
for offset in -32..32 {
|
||||
let p = if horizontal {
|
||||
let x = midpoint.x + offset as f32;
|
||||
let y = center.y + (midpoint.y - center.y).signum() * radius.y * (1.0 - ((x - center.x) / radius.x).powi(2)).max(0.0).sqrt();
|
||||
egui::pos2(x, y)
|
||||
} else {
|
||||
let y = midpoint.y + offset as f32;
|
||||
let x = center.x + (midpoint.x - center.x).signum() * radius.x * (1.0 - ((y - center.y) / radius.y).powi(2)).max(0.0).sqrt();
|
||||
egui::pos2(x, y)
|
||||
};
|
||||
let normal = if horizontal { egui::vec2(0.0, 1.0) } else { egui::vec2(1.0, 0.0) };
|
||||
hits += usize::from((-2..=2).any(|o| {
|
||||
let q = p + normal * o as f32;
|
||||
images.iter().any(|img| img.luma(q.x.round() as i64, q.y.round() as i64).is_some_and(&test))
|
||||
}));
|
||||
}
|
||||
hits as f32 / 64.0
|
||||
}
|
||||
|
||||
/// Ink that contrasts with `background`: dark on white, light on black.
|
||||
fn ink(background: &str) -> impl Fn(u8) -> bool {
|
||||
let white = background == "white";
|
||||
@@ -190,17 +165,8 @@ fn marquee_previews_show_while_dragging_on_white_and_black_at_1x_and_2x() {
|
||||
setup(&mut h, bg, tool);
|
||||
let (a, b) = ([100.0, 80.0], [300.0, 220.0]);
|
||||
let before = render(&mut h);
|
||||
let before_time = h.ctx.input(|input| input.time) + 0.4;
|
||||
h.input_mut().time = Some(before_time);
|
||||
h.step();
|
||||
let before_next = render(&mut h);
|
||||
drag_to(&mut h, a, b);
|
||||
let img = render(&mut h);
|
||||
if let Some(directory) = std::env::var_os("PHOTOCRAFT_DRAG_PREVIEW_FIXTURES") {
|
||||
let directory = std::path::PathBuf::from(directory);
|
||||
std::fs::create_dir_all(&directory).unwrap();
|
||||
h.render().expect("capture render").save(directory.join(format!("{tool}-{bg}-{ppp}x.png"))).unwrap();
|
||||
}
|
||||
if tool == "rectMarquee" {
|
||||
for (i, (p, q)) in edges(&h, a, b).into_iter().enumerate() {
|
||||
let was = coverage(&before, ppp, p, q, ink(bg));
|
||||
@@ -209,46 +175,23 @@ fn marquee_previews_show_while_dragging_on_white_and_black_at_1x_and_2x() {
|
||||
assert!(was < 0.05 && now > 0.3, "{tool} on {bg} @{ppp}x, edge {i}: {was:.2} → {now:.2} contrasting");
|
||||
}
|
||||
} else {
|
||||
// Sample both halves of the animated dash cycle while the pointer is held.
|
||||
// A single phase can put antialiasing ramps at a short arc's sample positions.
|
||||
let next_time = h.ctx.input(|input| input.time) + 0.4;
|
||||
h.input_mut().time = Some(next_time);
|
||||
h.step();
|
||||
let next = render(&mut h);
|
||||
if let Some(directory) = std::env::var_os("PHOTOCRAFT_DRAG_PREVIEW_FIXTURES") {
|
||||
h.render().expect("capture next phase").save(std::path::PathBuf::from(directory).join(format!("{tool}-{bg}-{ppp}x-next.png"))).unwrap();
|
||||
}
|
||||
// Check actual arcs around all four ellipse extrema at every display scale.
|
||||
let center = screen(&h, 200.0, 150.0);
|
||||
let radius = egui::vec2((screen(&h, 300.0, 150.0).x - center.x).abs(), (screen(&h, 200.0, 220.0).y - center.y).abs());
|
||||
// The ellipse touches its box at the edge midpoints: check short arcs there.
|
||||
// The arcs keep a physical length at any scale, so their sagitta stays inside
|
||||
// `coverage`'s ±2 physical px search.
|
||||
for (mx, my) in [(200.0, 80.0), (300.0, 150.0), (200.0, 220.0), (100.0, 150.0)] {
|
||||
let m = screen(&h, mx, my);
|
||||
let was = ellipse_coverage(&[&before, &before_next], ppp, center, radius, m, ink(bg));
|
||||
let now = ellipse_coverage(&[&img, &next], ppp, center, radius, m, ink(bg));
|
||||
assert!(was < 0.05 && now > 0.3, "{tool} on {bg} @{ppp}x at {m:?}: {was:.2} → {now:.2} contrasting");
|
||||
let along = if mx == 200.0 { egui::vec2(14.0 / ppp, 0.0) } else { egui::vec2(0.0, 14.0 / ppp) };
|
||||
let now = coverage(&img, ppp, m - along, m + along, ink(bg));
|
||||
assert!(now > 0.3, "{tool} on {bg} @{ppp}x at {m:?}: {now:.2} contrasting");
|
||||
}
|
||||
}
|
||||
// Each move's frame shows the outline where the pointer is now (no stale frame).
|
||||
let previous = img;
|
||||
pointer_move(&mut h, 340.0, 250.0);
|
||||
let img = render(&mut h);
|
||||
if tool == "rectMarquee" {
|
||||
let [top, right, ..] = edges(&h, a, [340.0, 250.0]);
|
||||
assert!(coverage(&img, ppp, top.0, top.1, ink(bg)) > 0.3, "{tool} {bg} @{ppp}x: top edge follows the pointer");
|
||||
assert!(coverage(&img, ppp, right.0, right.1, ink(bg)) > 0.3, "{tool} {bg} @{ppp}x: right edge follows the pointer");
|
||||
} else {
|
||||
let next_time = h.ctx.input(|input| input.time) + 0.4;
|
||||
h.input_mut().time = Some(next_time);
|
||||
h.step();
|
||||
let next = render(&mut h);
|
||||
assert_ne!(img.px, next.px, "held ellipse must animate between the sampled phases");
|
||||
let center = screen(&h, 220.0, 165.0);
|
||||
let radius = egui::vec2((screen(&h, 340.0, 165.0).x - center.x).abs(), (screen(&h, 220.0, 250.0).y - center.y).abs());
|
||||
for midpoint in [screen(&h, 340.0, 165.0), screen(&h, 220.0, 250.0)] {
|
||||
let old = ellipse_coverage(&[&previous], ppp, center, radius, midpoint, ink(bg));
|
||||
let now = ellipse_coverage(&[&img, &next], ppp, center, radius, midpoint, ink(bg));
|
||||
assert!(old < 0.05 && now > 0.3, "ellipse {bg} @{ppp}x follows current bounds: {old:.2} → {now:.2}");
|
||||
}
|
||||
}
|
||||
button(&mut h, 340.0, 250.0, false);
|
||||
h.run_steps(2);
|
||||
|
||||
+1
-1
@@ -351,7 +351,7 @@ trunk build --release # writes ../../dist/web (index.html, .js glue
|
||||
trunk serve --release # dev server on http://127.0.0.1:8765
|
||||
```
|
||||
|
||||
Any static file server works for `dist/web`, for example `python3 -m http.server 8765` run inside that directory. Trunk downloads the matching `wasm-bindgen` and `wasm-opt` itself. `trunk build --release` uses the `wasm-release` Cargo profile (`data-cargo-profile` in `index.html`: fat LTO, opt-level "s" except the pixel crates). The `.wasm` is about 18.8 MiB raw, 7.8 MiB gzipped and 5.6 MiB with Brotli; serve it with compression. Keep it under 24 MiB (`packaging/web/package.sh` enforces this; Cloudflare's per-file cap is 25 MiB). Pull-request CI also builds the actual browser app with the same pinned Trunk version as the release job and runs `packaging/web/package.sh`, including the relative-URL and 24 MiB checks. The `web build and wasm size gate` check runs on main and on PRs that change something the web build compiles or packages (`apps/photocraft-web`, `packaging/web`, crate sources and manifests, `Cargo.toml`/`Cargo.lock`, the CI workflow), and reports the resulting wasm size in the Actions job summary. The web build never embeds craft-fonts (see Fonts above). To see where the bytes go, run `twiggy top -n 40` on `target/wasm32-unknown-unknown/wasm-release/photocraft-web.wasm` (before wasm-opt strips the names).
|
||||
Any static file server works for `dist/web`, for example `python3 -m http.server 8765` run inside that directory. Trunk downloads the matching `wasm-bindgen` and `wasm-opt` itself. `trunk build --release` uses the `wasm-release` Cargo profile (`data-cargo-profile` in `index.html`: fat LTO, opt-level "z" for `photocraft-ui-egui`, "s" for other crates except pixel processing, which keeps level 3). The UI override reduces browser code size while retaining the speed-oriented settings for filters and compositing. Serve the `.wasm` with compression; its raw size varies with the source and compiler. Keep it under 24 MiB (`packaging/web/package.sh` enforces this; Cloudflare's per-file cap is 25 MiB). Pull-request CI also builds the actual browser app with the same pinned Trunk version as the release job and runs `packaging/web/package.sh`, including the relative-URL and 24 MiB checks. The `web build and wasm size gate` check runs on main and on PRs that change something the web build compiles or packages (`apps/photocraft-web`, `packaging/web`, crate sources and manifests, `Cargo.toml`/`Cargo.lock`, the CI workflow), and reports the resulting wasm size in the Actions job summary. The web build never embeds craft-fonts (see Fonts above). To see where the bytes go, run `twiggy top -n 40` on `target/wasm32-unknown-unknown/wasm-release/photocraft-web.wasm` (before wasm-opt strips the names).
|
||||
|
||||
URL flags: `?webgl` forces the WebGL2 backend, and `?cpu` forces the CPU canvas path.
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ in the dialog.
|
||||
| Windows 10+ x86 (32-bit) | `photocraft-<v>-windows-x86.msi`, `photocraft-<v>-windows-x86-portable.zip` | `windows-latest` |
|
||||
| Linux x86_64 | `photocraft-<v>-linux-x86_64.{AppImage,AppImage.zsync,deb,rpm,tar.gz,flatpak}` | `ubuntu-22.04` (Flatpak: `ubuntu-24.04`) |
|
||||
| Linux aarch64 | `photocraft-<v>-linux-aarch64.{AppImage,AppImage.zsync,deb,rpm,tar.gz,flatpak}` | `ubuntu-22.04-arm` (Flatpak: `ubuntu-24.04-arm`) |
|
||||
| Linux riscv64 (glibc 2.39+) | `photocraft-<v>-linux-riscv64.tar.gz` | cross-compiled on `ubuntu-24.04` (ports.ubuntu.com riscv64 libs); CLI smoke-tested under QEMU |
|
||||
| FreeBSD 14 x86_64 | `photocraft-<v>-freebsd-x86_64.tar.gz` | FreeBSD 14.3 VM on `ubuntu-latest` |
|
||||
| Web | `photocraft-web-<v>.zip` (static site; see [`packaging/web/README.md`](../packaging/web/README.md)) | `ubuntu-latest` |
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build and package PhotoCraft for Linux (<arch> is x86_64 or aarch64):
|
||||
# Build and package PhotoCraft for Linux (<arch> is x86_64, aarch64 or riscv64):
|
||||
#
|
||||
# $DIST/photocraft-<version>-linux-<arch>.AppImage any distro with glibc >= the build host's
|
||||
# $DIST/photocraft-<version>-linux-<arch>.AppImage.zsync delta updates (needs zsyncmake)
|
||||
@@ -13,6 +13,10 @@
|
||||
# (downloaded into $CARGO_TARGET_DIR if missing). Build on an old distro (CI: Ubuntu 22.04,
|
||||
# glibc 2.35) so the binaries run on newer ones. Optional: desktop-file-validate, appstreamcli,
|
||||
# zsyncmake (the zsync package) for the AppImage's .zsync.
|
||||
#
|
||||
# Cross builds (CI: riscv64, tar.gz only): set CROSS_ARCH (riscv64), CROSS_TARGET (the Rust
|
||||
# triple), CROSS_COMPILE (binutils prefix, for strip) and optionally EMULATOR (e.g. qemu-riscv64)
|
||||
# to smoke-test the CLI.
|
||||
set -euo pipefail
|
||||
# shellcheck source=../env.sh
|
||||
. "$(dirname "${BASH_SOURCE[0]}")/../env.sh"
|
||||
@@ -25,13 +29,14 @@ while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--skip-build) SKIP_BUILD=1; shift ;;
|
||||
--formats) FORMATS="$2"; shift 2 ;;
|
||||
-h | --help) sed -n '2,15p' "$0"; exit 0 ;;
|
||||
-h | --help) sed -n '2,19p' "$0"; exit 0 ;;
|
||||
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
ARCH="$(uname -m)"
|
||||
ARCH="${CROSS_ARCH:-$(uname -m)}"
|
||||
case "$ARCH" in
|
||||
riscv64) DEB_ARCH=riscv64 ;;
|
||||
x86_64) DEB_ARCH=amd64 ;;
|
||||
aarch64 | arm64) ARCH=aarch64; DEB_ARCH=arm64 ;;
|
||||
*) echo "unsupported architecture $ARCH" >&2; exit 2 ;;
|
||||
@@ -42,9 +47,13 @@ BASENAME="photocraft-$VERSION-linux-$ARCH"
|
||||
echo "==> PhotoCraft $VERSION for Linux $ARCH ($FORMATS)"
|
||||
|
||||
if [ "$SKIP_BUILD" = 0 ]; then
|
||||
(cd "$ROOT" && cargo build --release --locked -p photocraft -p photocraft-cli --features heif)
|
||||
if [ -n "${CROSS_TARGET:-}" ]; then
|
||||
(cd "$ROOT" && cargo build --release --locked -p photocraft -p photocraft-cli --features heif --target "$CROSS_TARGET")
|
||||
else
|
||||
(cd "$ROOT" && cargo build --release --locked -p photocraft -p photocraft-cli --features heif)
|
||||
fi
|
||||
fi
|
||||
BIN="$CARGO_TARGET_DIR/release"
|
||||
BIN="$CARGO_TARGET_DIR/${CROSS_TARGET:+$CROSS_TARGET/}release"
|
||||
WORK="$CARGO_TARGET_DIR/linux-package"
|
||||
STAGE="$WORK/root"
|
||||
rm -rf "$WORK"
|
||||
@@ -52,7 +61,7 @@ rm -rf "$WORK"
|
||||
# ---- stage an FHS tree (shared by every format) -------------------------------------------------
|
||||
install -Dm755 "$BIN/photocraft" "$STAGE/usr/bin/photocraft"
|
||||
install -Dm755 "$BIN/photocraft-cli" "$STAGE/usr/bin/photocraft-cli"
|
||||
strip "$STAGE/usr/bin/photocraft" "$STAGE/usr/bin/photocraft-cli" 2>/dev/null || true
|
||||
"${CROSS_COMPILE:-}strip" "$STAGE/usr/bin/photocraft" "$STAGE/usr/bin/photocraft-cli" 2>/dev/null || true
|
||||
install -Dm644 "$HERE/$APP_ID.desktop" "$STAGE/usr/share/applications/$APP_ID.desktop"
|
||||
install -Dm644 "$HERE/$APP_ID.mime.xml" "$STAGE/usr/share/mime/packages/$APP_ID.xml"
|
||||
mkdir -p "$STAGE/usr/share/metainfo"
|
||||
@@ -139,6 +148,10 @@ if has appimage; then
|
||||
fi
|
||||
fi
|
||||
|
||||
"$STAGE/usr/bin/photocraft-cli" --version
|
||||
if [ -z "${CROSS_TARGET:-}" ]; then
|
||||
"$STAGE/usr/bin/photocraft-cli" --version
|
||||
elif [ -n "${EMULATOR:-}" ]; then
|
||||
"$EMULATOR" "$STAGE/usr/bin/photocraft-cli" --version
|
||||
fi
|
||||
echo "==> done"
|
||||
ls -lh "$DIST"
|
||||
Reference in new issue
Block a user