@krwu/img-resize-wasm
v0.3.0
Published
High-performance image resizing in WebAssembly - Built with Rust
Maintainers
Readme
img-resize-wasm
高性能 WebAssembly 图像缩放库,基于 Rust 构建
最新版本 v0.2.x - 使用
fast_image_resize重构,性能提升 2-5 倍,支持单边限制缩放
✨ 特性
- 🚀 超高性能: 使用
fast_image_resize库和 SIMD 优化,比传统实现快 2-5 倍 - 🎯 多格式支持: 支持 JPEG、PNG、GIF、WebP、BMP、TIFF 等主流格式
- 🔧 多种缩放算法: 支持 Nearest、Bilinear、CatmullRom、Lanczos3 等高质量算法
- 📐 等比例缩放: 自动保持图片宽高比,支持单边限制
- 🎬 动图保护: 自动检测 GIF/WebP 动图并保持原样,避免变成静态图
- 💾 格式保持: 输出保持原始图片格式
- 🌐 零依赖: 纯 WebAssembly 实现,无需额外的 JavaScript 库
- 🎛️ 单边限制: max_width 或 max_height 可设为 0,表示不限制该维度
📦 安装
npm install @krwu/img-resize-wasm🚀 快速开始
import init, { resize_image_aspect_ratio } from '@krwu/img-resize-wasm';
// 初始化 WASM 模块
await init();
// 读取图片
const file = document.querySelector('input[type="file"]').files[0];
const imageData = new Uint8Array(await file.arrayBuffer());
// 缩放图片(保持宽高比,最大 800×600)
const result = resize_image_aspect_ratio(imageData, 800, 600, 'lanczos3');
// 使用结果
console.log(`缩放后尺寸: ${result.width}×${result.height}`);
const blob = new Blob([result.data], { type: `image/${result.format}` });
const url = URL.createObjectURL(blob);📚 详细用法
在 Vite + Vue3 中使用
基础用法
import { resize_image_aspect_ratio } from '@krwu/img-resize-wasm';
// 读取图片文件
const file = document.getElementById('imageInput').files[0];
const arrayBuffer = await file.arrayBuffer();
const imageData = new Uint8Array(arrayBuffer);
// 等比例缩放(同时限制宽度和高度,取较小比例)
const result = resize_image_aspect_ratio(imageData, 800, 600, 'lanczos3');
console.log(`缩放完成: ${result.width}x${result.height}`);
// 单边限制缩放
// 只限制宽度,高度按比例自动计算
const result2 = resize_image_aspect_ratio(imageData, 800, 0, 'lanczos3');
// 只限制高度,宽度按比例自动计算
const result3 = resize_image_aspect_ratio(imageData, 0, 600, 'lanczos3');
// 不限制任何维度(返回原图)
const result4 = resize_image_aspect_ratio(imageData, 0, 0, 'lanczos3');
// ⚠️ 注意:GIF/WebP 动图会被自动检测并返回原图,避免丢失动画效果Vue3 组件示例
<template>
<div>
<input type="file" @change="handleImageUpload" accept="image/*">
<button @click="resizeImage" :disabled="!imageData">缩放图片</button>
<img v-if="resizedImage" :src="resizedImage" alt="缩放后的图片">
<div v-if="info">{{ info }}</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { resize_image_aspect_ratio, get_image_dimensions } from '@krwu/img-resize-wasm';
const imageData = ref(null);
const resizedImage = ref(null);
const info = ref('');
async function handleImageUpload(event) {
const file = event.target.files[0];
if (!file) {
return;
}
imageData.value = new Uint8Array(await file.arrayBuffer());
// 获取原始尺寸
const dimensions = get_image_dimensions(imageData.value);
info.value = `原始尺寸: ${dimensions.width}×${dimensions.height}`;
}
function resizeImage() {
if (!imageData.value) {
return;
}
try {
const startTime = performance.now();
const result = resize_image_aspect_ratio(
imageData.value,
800,
600,
'lanczos3'
);
const endTime = performance.now();
// 将图片数据转换为 Blob URL(自动使用原格式)
const mimeType = `image/${result.format}`;
const blob = new Blob([result.data], { type: mimeType });
resizedImage.value = URL.createObjectURL(blob);
info.value = `缩放后: ${result.width}×${result.height}, 格式: ${result.format}, 耗时: ${(endTime - startTime).toFixed(2)}ms`;
} catch (error) {
console.error('缩放失败:', error);
info.value = `缩放失败: ${error}`;
}
}
</script>高级用法示例
1. 响应式图片生成
import { resize_image_aspect_ratio } from '@krwu/img-resize-wasm';
// 生成多种尺寸的响应式图片
async function generateResponsiveImages(imageData) {
const sizes = [
{ name: 'thumbnail', width: 200, height: 0 },
{ name: 'small', width: 480, height: 0 },
{ name: 'medium', width: 800, height: 0 },
{ name: 'large', width: 1200, height: 0 },
];
const results = {};
for (const size of sizes) {
const result = resize_image_aspect_ratio(
imageData,
size.width,
size.height,
'lanczos3'
);
results[size.name] = {
data: result.data,
width: result.width,
height: result.height,
format: result.format,
};
}
return results;
}2. 图片上传前压缩
import { resize_image_aspect_ratio } from '@krwu/img-resize-wasm';
async function compressImageBeforeUpload(file, maxWidth = 1920, maxHeight = 1080) {
// 读取文件
const arrayBuffer = await file.arrayBuffer();
const imageData = new Uint8Array(arrayBuffer);
// 缩放压缩
const result = resize_image_aspect_ratio(
imageData,
maxWidth,
maxHeight,
'lanczos3'
);
// 转换为 File 对象
const blob = new Blob([result.data], { type: `image/${result.format}` });
const compressedFile = new File([blob], file.name, { type: blob.type });
console.log(`原始大小: ${file.size} bytes`);
console.log(`压缩后: ${compressedFile.size} bytes`);
console.log(`压缩率: ${((1 - compressedFile.size / file.size) * 100).toFixed(2)}%`);
return compressedFile;
}3. 批量处理图片
import { resize_image_aspect_ratio } from '@krwu/img-resize-wasm';
async function batchResizeImages(files, maxWidth = 800, maxHeight = 600) {
const results = [];
for (const file of files) {
try {
const arrayBuffer = await file.arrayBuffer();
const imageData = new Uint8Array(arrayBuffer);
const result = resize_image_aspect_ratio(
imageData,
maxWidth,
maxHeight,
'bilinear' // 批量处理使用较快的算法
);
results.push({
originalName: file.name,
width: result.width,
height: result.height,
format: result.format,
data: result.data,
});
} catch (error) {
console.error(`处理 ${file.name} 失败:`, error);
}
}
return results;
}API
resize_image_aspect_ratio(imageData, maxWidth, maxHeight, filter)
等比例缩放(保持宽高比)
参数:
imageData:Uint8Array- 图片二进制数据maxWidth:number- 最大宽度(可设为 0 表示不限制宽度)maxHeight:number- 最大高度(可设为 0 表示不限制高度)filter:string- 缩放算法("nearest","bilinear","catmullrom","lanczos3")- 兼容旧算法名:
"linear"→"bilinear","cubic"→"catmullrom","gaussian"→"lanczos3"
- 兼容旧算法名:
返回值: ResizeResult 对象
特殊行为:
- 🎬 动图保护:自动检测 GIF 和 WebP 动图,如果检测到动图会直接返回原图,避免丢失动画效果
- 📏 智能跳过:当图片尺寸未超过限制时,自动返回原图(重新编码)
- 🔄 等比例:始终保持图片的宽高比,不会产生拉伸变形
get_image_dimensions(imageData)
获取图片尺寸信息
参数:
imageData:Uint8Array- 图片二进制数据
返回值: ImageDimensions 对象
width:number- 图片宽度height:number- 图片高度
get_supported_formats()
获取支持的图片格式列表
返回值: string[] - 支持的格式数组
get_supported_algorithms()
获取支持的缩放算法列表
返回值: string[] - 支持的算法数组
ResizeResult
属性:
data:Uint8Array- 编码后的图片数据(保持原格式)width:number- 实际宽度height:number- 实际高度format:string- 图片格式("jpeg","png","gif","webp","bmp","tiff")
技术特性
动图检测与保护
本库内置智能动图检测功能,确保动画不会在缩放过程中丢失:
🎬 自动检测机制
GIF 动图检测:
- 使用
imagecrate 的AnimationDecoder解析 GIF 文件 - 检测帧数:超过 1 帧即判定为动图
- 准确率 100%,不会误报或漏报
WebP 动图检测:
- 验证 WebP 文件头(RIFF + WEBP 标记)
- 在文件的 chunks 区域搜索
ANIMchunk 标记 - 符合 WebP 格式规范,所有动画 WebP 必须包含 ANIM chunk
⚡ 处理流程
输入图片
↓
检测格式 (GIF/WebP?)
↓
├─ 是动图 → 直接返回原图(保护动画)
└─ 是静态图 → 进行缩放处理💡 为什么这样设计?
- 技术限制:
imagecrate 在解码动图时只会读取第一帧,如果进行缩放会导致动图变成静态图 - 性能考虑:逐帧处理动图性能开销大,在浏览器中可能导致卡顿
- 用户体验:保持原始动图总比变成静态图好
- 简单可靠:检测并跳过的方案实现简单,不会出错
格式处理
- 保持原格式输出:缩放后的图片保持原始格式,避免不必要的格式转换
- JPEG → JPEG(质量 85)
- PNG → PNG(高压缩率)
- GIF/WebP 动图 → 原图(保护动画)
- 其他格式也会保持不变
- 避免文件膨胀:JPEG 图片不会被强制转换为 PNG,保持较小的文件体积
- 保留颜色信息:保持原始图片的颜色空间和压缩特性
缩放流程
图片解码 (image crate) → 高性能缩放 (fast_image_resize) → 格式编码 (image crate)智能优化
- 自动跳过不必要的缩放:当图片尺寸未超限时,直接返回原图
- 内存高效:优化的内存分配和复用策略
- SIMD 加速:自动利用 CPU 的 SIMD 指令集
🚀 性能优势
重构后的性能提升
- 使用
fast_image_resize库:专为高性能设计,使用 SIMD 指令优化 - 性能提升 2-5 倍:相比之前的
imagecrate 实现 - 更好的算法支持:优化的缩放算法映射,质量更高
算法性能对比
| 算法 | 质量 | 速度 | 适用场景 |
|------|------|------|----------|
| nearest | 低 | 最快 | 像素艺术、图标 |
| bilinear | 中 | 快 | 一般用途、实时预览 |
| catmullrom | 高 | 中 | 照片缩放 |
| lanczos3 | 最高 | 慢 | 高质量照片处理 |
算法名称更新(推荐)
虽然旧算法名仍然兼容,但推荐更新为新的标准名称:
| 旧名称 | 新名称 | 说明 |
|--------|--------|------|
| "linear" | "bilinear" | 双线性插值 |
| "cubic" | "catmullrom" | Catmull-Rom 三次插值 |
| "gaussian" | "lanczos3" | Lanczos3 算法 |
🧪 开发和测试
构建项目
# 安装依赖
cargo build
# 构建 WebAssembly
wasm-pack build --target web --out-dir pkg
# 运行测试
cargo test本地测试
# 启动本地服务器
python -m http.server 8000
# 访问测试页面
# http://localhost:8000/test-new-features.html性能测试
在测试页面中可以:
- 测试不同算法的性能差异
- 测试单边限制功能
- 对比不同尺寸图片的处理速度
- 查看详细的处理时间和输出信息
📂 项目结构
img-resize-wasm/
├── src/
│ └── lib.rs # 核心 Rust 代码(使用 fast_image_resize)
├── pkg/ # 构建输出目录(wasm-pack 生成)
├── example/ # 示例文件
├── test-new-features.html # 新功能测试页面
├── Cargo.toml # Rust 项目配置
├── README.md # 项目文档
├── CHANGELOG.md # 更新日志
├── REFACTOR_SUMMARY.md # 重构总结
└── build-npm.sh # NPM 构建脚本📊 性能基准
基于实际测试的性能数据(参考值,实际性能因设备而异):
| 场景 | 原实现 | 新实现 | 提升倍数 | |------|--------|--------|----------| | 大图缩放 (4K→1080p) | ~200ms | ~50ms | 4x | | 中图缩放 (1080p→720p) | ~80ms | ~20ms | 4x | | 小图缩放 (720p→480p) | ~30ms | ~10ms | 3x |
❓ 常见问题
Q: 为什么要使用 WebAssembly 而不是纯 JavaScript?
A: WebAssembly 提供接近原生的性能,特别是在图像处理这种计算密集型任务中,性能优势明显。本库使用 Rust + WASM,比纯 JS 实现快 2-5 倍。
Q: 支持哪些图片格式?
A: 支持 JPEG、PNG、GIF、WebP、BMP、TIFF 等主流格式。可以通过 get_supported_formats() 函数查看完整列表。
Q: 如何选择合适的缩放算法?
A:
- nearest: 最快,适合像素艺术、图标等不需要平滑的场景
- bilinear: 速度快,质量中等,适合实时预览
- catmullrom: 质量高,速度中等,适合照片缩放
- lanczos3: 质量最高,速度较慢,适合高质量照片处理
Q: 单边限制有什么用?
A: 单边限制允许你只限制宽度或高度,另一边自动按比例缩放。例如:
- 制作固定宽度的响应式图片(高度自适应)
- 制作固定高度的横幅图片(宽度自适应)
- 更灵活地控制输出尺寸
Q: 会改变图片格式吗?
A: 不会。本库会自动保持原始图片格式,JPEG 输出 JPEG,PNG 输出 PNG,GIF/WebP 动图会保持原样,避免不必要的格式转换和文件膨胀。
Q: 为什么动图不能缩放?
A: GIF 和 WebP 动图包含多帧,如果使用常规方法缩放会丢失动画效果,只剩下第一帧。为了保护动画,本库会自动检测动图并返回原图。如果需要缩放动图,建议:
- 使用专门的动图处理工具
- 在服务端使用支持动图的库(如
ffmpeg) - 或者接受静态化的结果
Q: 如何判断返回的是原图还是缩放后的图?
A: 可以对比返回结果的尺寸与原图尺寸,或检查控制台日志。当检测到动图时,控制台会输出 "检测到动图,跳过处理,返回原图"。
Q: 如何处理大图片?
A: 本库使用高效的内存管理和 SIMD 优化,可以处理大图片。但建议在浏览器环境中处理超大图片(如 8K)时注意内存限制。
Q: 性能提升是如何实现的?
A: 主要通过以下方式:
- 使用
fast_image_resize库,专门为高性能设计 - SIMD 指令集优化,充分利用 CPU 并行计算能力
- 优化的内存管理,减少不必要的内存分配
- WebAssembly 的接近原生性能
Q: 兼容性如何?
A: 支持所有现代浏览器(Chrome、Firefox、Safari、Edge)。需要浏览器支持 WebAssembly。
🤝 贡献
欢迎提交 Issue 和 Pull Request!
贡献指南
- Fork 本仓库
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启 Pull Request
📄 许可证
MIT License - 详见 LICENSE 文件
🔗 相关链接
- fast_image_resize - 高性能图像缩放库
- image-rs - Rust 图像处理库
- wasm-pack - Rust WebAssembly 工具链
Made with ❤️ using Rust and WebAssembly
