11 releases
| new 0.2.9 | Feb 5, 2026 |
|---|---|
| 0.2.8 | Feb 5, 2026 |
| 0.1.2 | Feb 2, 2026 |
#81 in Images
305KB
7.5K
SLoC
cryosnap
面向 CLI / Rust library / Node & TypeScript 绑定的代码与终端输出截图工具。 | Code and terminal screenshot tool for CLI / Rust library / Node & TypeScript bindings.
中文
功能概览
- 代码高亮(syntect 主题)
- ANSI 终端输出解析(含
--executePTY) - SVG / PNG / WebP 输出
- PNG 无损优化(oxipng)
- PNG 有损量化(libimagequant,可选,支持预设)
- 可选多输出:
out.{svg,png,webp} - 交互式配置(
--interactive) - 配置文件:
default / base / full / user / 自定义路径 - 字体嵌入(TTF/WOFF/WOFF2)
- Nerd Font 符号回退(按需自动下载,可配置)
- 标题栏(自动文件路径 / tmux 信息)
- 栅格化后端:纯 Rust / rsvg-convert(自动检测)
- 细节配置:padding/margin/border/shadow/line-height/lines/wrap/line-numbers
安装
crates.io 安装(推荐):
# CLI
cargo install cryosnap
# Rust 库
cargo add cryosnap-core
源码安装:
cargo install --path crates/cryosnap-cli
# 或
cargo build --release
CLI 使用
# 代码文件 -> PNG
cryosnap main.rs -o out.png
# stdin -> SVG
cat main.rs | cryosnap --language rust -o out.svg
# ANSI 命令输出
cryosnap --execute "eza -lah" -o out.png
# 一次生成多种格式
cryosnap main.rs --output out.{svg,png,webp}
# tmux capture-pane -> PNG (zsh 需转义 %)
cryosnap --tmux --tmux-args "-t %3 -S -200 -J" --config full -o out.png
默认行为:stdout 为 TTY 且未指定 --output/--format 时,会写入 cryosnap.png。
查看完整参数:
cryosnap --help
配置
内置配置:
cryosnap --config base
cryosnap --config full
cryosnap --config user
配置文件路径优先级:
CRYOSNAP_CONFIG_PATHCRYOSNAP_CONFIG_DIR(会读取user.json)- 系统配置目录(
ProjectDirs)
PNG 压缩
默认使用无损优化(不会影响画质):
# 关闭无损优化
cryosnap main.rs -o out.png --png-opt=false
# 调整优化级别(0-6)
cryosnap main.rs -o out.png --png-opt-level 4
# 控制元数据剥离
cryosnap main.rs -o out.png --png-strip safe
有损量化(体积更小,轻微画质损失):
# 开启量化
cryosnap main.rs -o out.png --png-quant
# 使用预设(fast/balanced/best)
cryosnap main.rs -o out.png --png-quant-preset balanced
# 自定义质量/速度/抖动
cryosnap main.rs -o out.png --png-quant-quality 85 --png-quant-speed 4 --png-quant-dither 1
栅格化后端
默认使用纯 Rust 渲染(resvg/tiny-skia)。如系统已安装 rsvg-convert,可选用:
# 自动检测(找到 rsvg-convert 则使用)
cryosnap main.rs -o out.png --raster.backend auto
# 强制使用 rsvg-convert(未安装会报错)
cryosnap main.rs -o out.png --raster.backend rsvg
# 强制使用纯 Rust
cryosnap main.rs -o out.png --raster.backend resvg
字体与 Nerd Font
默认字体为系统 monospace,不再内置任何字体。
当输入包含非 ASCII 脚本、Emoji、或 Nerd Font 私用区字符时,会按 Unicode Script
自动匹配 Noto 系列字体;若系统字体已覆盖则不下载,否则从 GitHub 官方仓库
自动下载到 ~/.cryosnap/fonts(可用 font.dirs 或 CRYOSNAP_FONT_DIRS 覆盖),随后渲染。
可用 font.fallbacks 指定回退链,font.system-fallback 控制系统字体加载
(auto/always/never),font.auto-download 控制自动下载;
font.cjk-region 指定 CJK 偏好(auto/sc/tc/hk/jp/kr,auto 会按 LANG/LC_CTYPE 推断);
font.force-update 可强制刷新已下载字体:
# 自动下载缺失字体(默认开启)
cryosnap main.rs -o out.png --font.auto-download true
# Nerd Font + 中文回退
cryosnap main.rs -o out.png --font.fallbacks "Symbols Nerd Font Mono, Noto Sans CJK SC" \
--font.system-fallback auto
# 指定 CJK 偏好
cryosnap main.rs -o out.png --font.cjk-region hk
# 禁用自动下载
cryosnap main.rs -o out.png --font.auto-download false
# 强制刷新已下载字体
cryosnap main.rs -o out.png --font.force-update true
标题栏
默认启用,文件输入时显示绝对路径;tmux 模式显示:
#{session_name}:#{window_index}.#{pane_index} #{pane_title}。
# 关闭标题
cryosnap main.rs -o out.png --title=false
# 覆盖标题文本
cryosnap main.rs -o out.png --title.text "hello"
# tmux 标题格式(自定义)
cryosnap --tmux --tmux-args "-t %7 -S -200 -J" \
--title.tmux-format "#{session_name}:#{window_name} · #{pane_current_path}" \
-o out.png
性能建议
# 降低栅格缩放
cryosnap main.rs -o out.png --raster.scale 2
# 限制最大像素数(0 表示不限制)
cryosnap main.rs -o out.png --raster.max-pixels 8000000
# 如需极致速度可关闭 PNG 优化
cryosnap main.rs -o out.png --png-opt=false
Rust 库用法
use cryosnap_core::{Config, InputSource, OutputFormat, RenderRequest};
let request = RenderRequest {
input: InputSource::Text("fn main() {}".to_string()),
config: Config::default(),
format: OutputFormat::Svg,
};
let result = cryosnap_core::render(&request).unwrap();
std::fs::write("out.svg", result.bytes).unwrap();
Node / TypeScript 绑定
cd crates/cryosnap-node
npm install
npm run build
发布版(npm):
npm install cryosnap
import { render, renderToFile } from "cryosnap";
const bytes = render({
input: "console.log('hi')",
inputKind: "text",
config: {
theme: "charm",
window: true,
showLineNumbers: true,
padding: [20, 40, 20, 20],
lineHeight: 1.2
},
format: "png"
});
require("fs").writeFileSync("out.png", bytes);
renderToFile(
{
input: "console.log('hi')",
inputKind: "text",
config: { theme: "charm" }
},
"out.webp"
);
开发与测试
cargo test --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo llvm-cov --workspace --ignore-filename-regex "cryosnap-node" --fail-under-lines 80
发布流程(cargo-release + cargo-dist)
# 预演
cargo release patch --workspace --dry-run
# 执行(会创建 tag vX.Y.Z)
cargo release patch --workspace --execute
# tag 会触发 GitHub Actions 的 cargo-dist 发布产物
crates.io 发布顺序:
cargo publish -p cryosnap-core
cargo publish -p cryosnap
npm 发布:
cd crates/cryosnap-node
npm publish
许可证
MIT,详见 LICENSE。
第三方许可证
- Noto 字体(含 CJK/多脚本/Emoji):SIL Open Font License 1.1(自动下载,来源 GitHub)
- Nerd Font(Symbols Nerd Font Mono):MIT(自动下载,来源 GitHub)
English
Overview
- Syntax highlighting (syntect themes)
- ANSI terminal capture (with
--executePTY) - SVG / PNG / WebP output
- PNG lossless optimization (oxipng)
- PNG lossy quantization (libimagequant, optional, with presets)
- Multi-output pattern:
out.{svg,png,webp} - Interactive config (
--interactive) - Config files:
default / base / full / user / custom - Font embedding (TTF/WOFF/WOFF2)
- Nerd Font symbol fallback (auto-download, configurable)
- Title bar (auto file path / tmux metadata)
- Raster backends: pure Rust / rsvg-convert (auto-detect)
- Detailed styling: padding/margin/border/shadow/line-height/lines/wrap/line-numbers
Install
From crates.io (recommended):
cargo install cryosnap
cargo add cryosnap-core
From source:
cargo install --path crates/cryosnap-cli
# or
cargo build --release
CLI Usage
# File -> PNG
cryosnap main.rs -o out.png
# stdin -> SVG
cat main.rs | cryosnap --language rust -o out.svg
# ANSI command output
cryosnap --execute "eza -lah" -o out.png
# Multi-format output
cryosnap main.rs --output out.{svg,png,webp}
# tmux capture-pane -> PNG (escape % in zsh)
cryosnap --tmux --tmux-args "-t %3 -S -200 -J" --config full -o out.png
Default behavior: when stdout is a TTY and --output/--format is not provided, it writes cryosnap.png.
Show all options:
cryosnap --help
Configuration
Built-in configs:
cryosnap --config base
cryosnap --config full
cryosnap --config user
Config path priority:
CRYOSNAP_CONFIG_PATHCRYOSNAP_CONFIG_DIR(readsuser.json)- System config directory (
ProjectDirs)
PNG Optimization
Lossless optimization (no quality loss):
# Disable lossless optimization
cryosnap main.rs -o out.png --png-opt=false
# Optimize level (0-6)
cryosnap main.rs -o out.png --png-opt-level 4
# Metadata stripping
cryosnap main.rs -o out.png --png-strip safe
Lossy quantization (smaller size with slight quality loss):
# Enable quantization
cryosnap main.rs -o out.png --png-quant
# Preset (fast/balanced/best)
cryosnap main.rs -o out.png --png-quant-preset balanced
# Custom quality/speed/dither
cryosnap main.rs -o out.png --png-quant-quality 85 --png-quant-speed 4 --png-quant-dither 1
Raster Backend
Default uses pure Rust (resvg/tiny-skia). If rsvg-convert is available, you can opt in:
cryosnap main.rs -o out.png --raster.backend auto
cryosnap main.rs -o out.png --raster.backend rsvg
cryosnap main.rs -o out.png --raster.backend resvg
Fonts & Nerd Font
Default font is system monospace, and no fonts are embedded.
When input contains non-ASCII scripts, emoji, or Nerd Font private-use glyphs, cryosnap
auto-maps to Noto families by Unicode Script. If system fonts already cover them it will not
download; otherwise it downloads from GitHub official repos into ~/.cryosnap/fonts
(override via font.dirs or CRYOSNAP_FONT_DIRS).
Use font.fallbacks to set a fallback chain, font.system-fallback for system font loading
(auto/always/never), font.auto-download to control auto download,
font.cjk-region to set CJK preference (auto/sc/tc/hk/jp/kr, auto uses LANG/LC_CTYPE),
and font.force-update to force refreshing downloaded fonts:
# Auto-download missing fonts (default on)
cryosnap main.rs -o out.png --font.auto-download true
# Nerd Font + CJK fallback
cryosnap main.rs -o out.png --font.fallbacks "Symbols Nerd Font Mono, Noto Sans CJK SC" \
--font.system-fallback auto
# Set CJK preference
cryosnap main.rs -o out.png --font.cjk-region hk
# Disable auto-download
cryosnap main.rs -o out.png --font.auto-download false
# Force refresh downloaded fonts
cryosnap main.rs -o out.png --font.force-update true
Title Bar
Enabled by default. For file input it shows the absolute path; for tmux it shows:
#{session_name}:#{window_index}.#{pane_index} #{pane_title}.
# Disable title
cryosnap main.rs -o out.png --title=false
# Override title text
cryosnap main.rs -o out.png --title.text "hello"
# Custom tmux title format
cryosnap --tmux --tmux-args "-t %7 -S -200 -J" \
--title.tmux-format "#{session_name}:#{window_name} · #{pane_current_path}" \
-o out.png
Performance Tips
# Lower raster scale
cryosnap main.rs -o out.png --raster.scale 2
# Limit max pixels (0 = no limit)
cryosnap main.rs -o out.png --raster.max-pixels 8000000
# Disable PNG optimization for max speed
cryosnap main.rs -o out.png --png-opt=false
Rust Library Usage
use cryosnap_core::{Config, InputSource, OutputFormat, RenderRequest};
let request = RenderRequest {
input: InputSource::Text("fn main() {}".to_string()),
config: Config::default(),
format: OutputFormat::Svg,
};
let result = cryosnap_core::render(&request).unwrap();
std::fs::write("out.svg", result.bytes).unwrap();
Node / TypeScript Bindings
cd crates/cryosnap-node
npm install
npm run build
Published version (npm):
npm install cryosnap
import { render, renderToFile } from "cryosnap";
const bytes = render({
input: "console.log('hi')",
inputKind: "text",
config: {
theme: "charm",
window: true,
showLineNumbers: true,
padding: [20, 40, 20, 20],
lineHeight: 1.2
},
format: "png"
});
require("fs").writeFileSync("out.png", bytes);
renderToFile(
{
input: "console.log('hi')",
inputKind: "text",
config: { theme: "charm" }
},
"out.webp"
);
Development & Testing
cargo test --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo llvm-cov --workspace --ignore-filename-regex "cryosnap-node" --fail-under-lines 80
Release Flow
cargo release patch --workspace --dry-run
cargo release patch --workspace --execute
Pushing the tag will trigger GitHub Actions to publish cargo-dist artifacts.
Publish to crates.io:
cargo publish -p cryosnap-core
cargo publish -p cryosnap
Publish to npm:
cd crates/cryosnap-node
npm publish
License
MIT, see LICENSE.
Third-party Licenses
- Noto fonts (including CJK/multi-script/emoji): SIL Open Font License 1.1 (auto-downloaded from GitHub)
- Nerd Font (Symbols Nerd Font Mono): MIT (auto-downloaded from GitHub)
Dependencies
~29–45MB
~669K SLoC