Files
Unlucky-Launcher/crates/palette-extract/src/thumbnail.rs
T
AskaEth 0522a41a52
CI / fmt (rustfmt --check) (push) Waiting to run
CI / clippy (ubuntu-latest) (push) Waiting to run
CI / clippy (windows-latest) (push) Waiting to run
CI / test (ubuntu-latest) (push) Waiting to run
CI / test (windows-latest) (push) Waiting to run
CI / build release (ubuntu-latest) (push) Waiting to run
CI / build release (windows-latest) (push) Waiting to run
CI / runtime smoke (ubuntu x64, xvfb) (push) Waiting to run
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / update-e2e (windows x64) (push) Waiting to run
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Waiting to run
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Waiting to run
Guards / core 零 UI 守门 (push) Waiting to run
Guards / presenter 零 UI 守门 (push) Waiting to run
Guards / design 零第三方依赖守门 (push) Waiting to run
Guards / unsafe 落点守门(集合必须恰好等于期望) (push) Waiting to run
Guards / 文件行数 ≤400 守门 (push) Waiting to run
Guards / 依赖许可与来源(cargo-deny) (push) Waiting to run
Release guard / 发布标记语义守门(push tag → 稳定版) (push) Waiting to run
Signing status(播报,不是门禁) / 判据自测(三行/退出码/变异重放/接线) (push) Waiting to run
Signing status(播报,不是门禁) / 签名就绪度(播报) (push) Waiting to run
Release / 选槽位(默认四个:Windows 两档 + Linux 两档) (push) Waiting to run
release: v0.2.5
2026-11-12 12:06:59 +08:00

58 lines
2.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 缩略图:路径 → 限尺寸的 [`Rgba8`](D54 第 1 条,M251 · SAVESHOTS)。
//!
//! ## 为什么落在本 crate
//!
//! D54 定的分层没有变:图片解码**集中在 `palette-extract`**(`crates/design` 零第三方依赖的
//! 代价就是把解码摊到这里;`app-iced` 另有一份 `image` 只用于截图编码与背景图,见它自己的
//! `Cargo.toml` 注释)。截图是 PNG,本 crate 的 `image` 已经开了 `png`/`jpeg`/`bmp` 解码 feature,
//! 所以加这条路**零新依赖、零新 crate、零新 feature**——只是把「解码 + 限尺寸」这段已有的能力
//! 换个目标边长([`THUMBNAIL_MAX_EDGE`])暴露一次。
//!
//! ## 不落盘
//!
//! 这里**只返回像素**,不写任何缓存文件(D54 第 2 条):写 PNG 需要编码器,而编码器只为一份
//! 磁盘缓存引入不划算;内存缓存归调用方(presenter 的 `host::saves::thumbs`)。
//!
//! ## 失败不 panic
//!
//! 读不到 / 不是图片 / 头里写着 40000×40000,全都变成 [`ExtractError`](与取色那条路同一族
//! 错误)。调用方据此给「逐条可见」的失败原因——**不许**在这里「读不到就画个灰块」。
//!
//! 与 [`crate::load`] 的区别只有一条:目标边长。`load` 钉 `MAX_EDGE = 256`(取色只需要色彩分布),
//! 这里由调用方给(缩略图墙用 160)。
//!
//! ```no_run
//! use unlucky_palette_extract::{thumbnail, THUMBNAIL_MAX_EDGE};
//!
//! match thumbnail("screenshots/2024-05-01_10.00.00.png", THUMBNAIL_MAX_EDGE) {
//! Ok(thumb) => println!("{}×{}", thumb.width(), thumb.height()),
//! Err(error) => eprintln!("这张图没有缩略图:{error}"),
//! }
//! ```
use std::path::Path;
use crate::{decode_with_limits, fit, ExtractError, Rgba8};
/// 缩略图的最大边(像素)。D54 定 160。
///
/// 依据:一屏缩略图墙按 4 列排、详情列宽约 700px ⇒ 每格 ≈ 160px。再大只是多占内存
/// (160² × 4B ≈ 100KB/张,60 张 ≈ 6MB),肉眼在墙上看不出差别。
pub const THUMBNAIL_MAX_EDGE: u32 = 160;
/// 从文件路径解码并缩到**长边 ≤ `max_edge`**(等比、不放大),返回 RGBA8 像素。
///
/// 格式按**魔数**嗅探,不看扩展名(与 [`crate::load`] 同一条路:用户把 `.jpg` 改名成 `.png`
/// 也照样读得出来)。`max_edge = 0` 按 1 处理(防调用方传 0 得到 0×0 的图)。
///
/// # Errors
///
/// - [`ExtractError::Io`]:文件不存在 / 无权限 / 被占用 / 打不开;
/// - [`ExtractError::Decode`]:不是认得的图片、文件截断、或头尺寸超过 16384(解压炸弹)。
pub fn thumbnail(path: impl AsRef<Path>, max_edge: u32) -> Result<Rgba8, ExtractError> {
let max_edge = max_edge.max(1);
let reader = image::ImageReader::open(path).map_err(ExtractError::Io)?;
let reader = reader.with_guessed_format().map_err(ExtractError::Io)?;
Ok(fit(decode_with_limits(reader)?, max_edge))
}