LibRaw Node.js
一个使用 LibRaw 库处理 RAW 图像文件的高性能 Node.js 原生插件。
功能特性
- ✅ 100+ RAW 格式 - Canon、Nikon、Sony、Adobe DNG 等
- ✅ 全面的元数据 - EXIF 数据、相机设置、尺寸、镜头信息
- ✅ 高级色彩信息 - 色彩矩阵、白平衡、校准数据
- ✅ 图像处理管道 - 完整的 dcraw 兼容处理链
- ✅ 缩略图提取 - 高质量嵌入式缩略图提取
- ✅ RAW 转 JPEG 转换 - 🆕 高性能 JPEG 导出与优化
- ✅ 批量处理 - 🆕 使用智能设置处理数百个文件
- ✅ AI 驱动设置 - 🆕 基于图像分析的自动质量优化
- ✅ 内存操作 - 完全在内存中处理图像
- ✅ 多种输出格式 - PPM、TIFF、JPEG 与高级压缩选项
- ✅ 缓冲区创建 API - 🆕 直接在内存中创建图像缓冲区(JPEG、PNG、WebP、AVIF、TIFF、PPM、缩略图)
- ✅ 基于流的处理 - 🆕 返回数据流而不是写入文件
- ✅ 缓冲区支持 - 从内存缓冲区加载 RAW 数据
- ✅ 配置控制 - 伽马、亮度、色彩空间设置
- ✅ 高性能 - 原生 C++ 处理与 JavaScript 便利性
- ✅ 内存高效 - 适当的资源管理和清理
- ✅ 基于 Promise 的 API - 现代 async/await 支持
- ✅ 跨平台 - Windows、macOS、Linux 支持(已测试 Windows)
- ✅ 1000+ 相机支持 - LibRaw 的广泛相机数据库
- ✅ 全面测试 - 使用真实 RAW 文件 100% 测试覆盖
- ✅ 生产就绪 - 经过多种相机格式实战测试
支持的格式
LibRaw 支持 100+ RAW 格式,包括:
制造商 | 格式 |
---|---|
佳能 | .CR2 , .CR3 , .CRW |
尼康 | .NEF , .NRW |
索尼 | .ARW , .SRF , .SR2 |
Adobe | .DNG |
富士 | .RAF |
奥林巴斯 | .ORF |
松下 | .RW2 |
宾得 | .PEF |
徕卡 | .DNG , .RWL |
还有更多... | 总共 100+ 格式 |
安装
📦 从 NPM 注册表
npm install librawspeed
版本 1.0.18 现已在 npmjs.com 上可用!🎉
🛠️ 构建要求
- Node.js 14.0.0 或更高版本
- Python 2.7 或 3.x(用于 node-gyp)
- C++ 编译器:
- Windows: Visual Studio Build Tools 或 Visual Studio Community
- macOS: Xcode Command Line Tools 或 Xcode
- Linux: build-essential 包
💡 提示:node-gyp 会自动处理构建工具,无需手动安装 make 等工具
🔧 环境检查
安装前可以检查环境是否满足要求:
npm run check:env
⚠️ 故障排除
如果安装失败,请尝试:
# 清理并重新安装
npm run clean
npm run rebuild
# 或强制重新构建
npm install --force
常见问题:
Python 未找到
npm config set python python3
编译器未找到
# Windows npm install --global windows-build-tools # macOS xcode-select --install # Linux sudo apt-get install build-essential
🚀 快速验证
安装后,验证包是否正常工作:
node -e "const LibRaw = require('librawspeed'); console.log('LibRaw version:', LibRaw.getVersion());"
预期输出:LibRaw version: 0.21.4-Release
先决条件(从源码构建)
- Node.js 14.0.0 或更高版本
- Python 3.x(用于 node-gyp)
- Visual Studio Build Tools(Windows)
- Xcode Command Line Tools(macOS)
- build-essential(Linux)
🛠️ 交叉编译支持
此项目支持多平台交叉编译。有关详细工具链要求和设置说明,请参阅交叉编译指南。
支持的平台:
- ✅ Windows x64
- ✅ macOS x64(Intel)
- ✅ macOS ARM64(Apple Silicon)
- ✅ Linux x64
- ✅ Linux ARM64
快速设置:
# 安装所有交叉编译工具链
brew install mingw-w64 aarch64-apple-darwin24-gcc-15 musl-cross
# 构建所有平台
npm run cross-compile:all
快速开始
const LibRaw = require("librawspeed");
async function processRAW() {
// 🆕 检查文件是否为 LibRaw 支持的 RAW 格式
const checkResult = LibRaw.isRawFile('photo.cr2');
if (!checkResult.isRawFile) {
console.log('不是支持的 RAW 文件:', checkResult.message);
return;
}
const processor = new LibRaw();
try {
// 加载 RAW 文件
await processor.loadFile("photo.cr2");
// 🆕 新功能:缓冲区创建 API - 直接在内存中创建图像
// 首先处理 RAW 数据
await processor.processImage();
// 创建 JPEG 缓冲区而不写入文件
const jpegBuffer = await processor.createJPEGBuffer({
quality: 85,
width: 1920,
progressive: true,
});
console.log(`JPEG 缓冲区已创建:${jpegBuffer.buffer.length} 字节`);
// 并行创建多种格式
const [pngResult, webpResult, thumbResult] = await Promise.all([
processor.createPNGBuffer({ width: 1200, compressionLevel: 6 }),
processor.createWebPBuffer({ quality: 80, width: 1200 }),
processor.createThumbnailJPEGBuffer({ maxSize: 300 }),
]);
// 直接使用缓冲区(例如,通过 HTTP 发送、存储到数据库等)
// 无需临时文件!
console.log(`PNG:${pngResult.buffer.length} 字节`);
console.log(`WebP:${webpResult.buffer.length} 字节`);
console.log(`缩略图:${thumbResult.buffer.length} 字节`);
// 🆕 新功能:高性能 JPEG 转换(传统方法仍然可用)
// 使用高级选项将 RAW 转换为 JPEG
const jpegResult = await processor.convertToJPEG("output.jpg", {
quality: 85, // JPEG 质量(1-100)
width: 1920, // 调整到 1920px 宽度
progressive: true, // 用于网络的渐进式 JPEG
mozjpeg: true, // 使用 MozJPEG 获得更好的压缩
chromaSubsampling: "4:2:0", // 优化文件大小
});
console.log(
`JPEG 已保存:${jpegResult.metadata.fileSize.compressed / 1024}KB`
);
console.log(
`压缩率:${jpegResult.metadata.fileSize.compressionRatio}x`
);
console.log(`处理时间:${jpegResult.metadata.processing.timeMs}ms`);
// 🆕 AI 驱动的优化设置
const analysis = await processor.getOptimalJPEGSettings({ usage: "web" });
console.log(`推荐质量:${analysis.recommended.quality}`);
console.log(`图像类别:${analysis.imageAnalysis.category}`);
// 应用优化设置
await processor.convertToJPEG("optimized.jpg", analysis.recommended);
// 提取全面的元数据
const [metadata, advanced, lens, color] = await Promise.all([
processor.getMetadata(),
processor.getAdvancedMetadata(),
processor.getLensInfo(),
processor.getColorInfo(),
]);
console.log("相机:", metadata.make, metadata.model);
console.log("镜头:", lens.lensName || "未知");
console.log(
"设置:",
`ISO ${metadata.iso}, f/${metadata.aperture}, ${metadata.focalLength}mm`
);
console.log(
"色彩:",
`${color.colors} 通道,黑电平 ${color.blackLevel}`
);
// 传统处理管道(仍然可用)
await processor.setOutputParams({
bright: 1.1, // 亮度调整
gamma: [2.2, 4.5], // 伽马曲线
output_bps: 16, // 16 位输出
no_auto_bright: false, // 启用自动亮度
});
// 处理图像
await processor.raw2Image();
await processor.processImage();
// 在内存中创建处理后的图像
const imageData = await processor.createMemoryImage();
console.log(
`已处理:${imageData.width}x${imageData.height},${imageData.dataSize} 字节`
);
// 导出到文件
await processor.writeTIFF("output.tiff");
await processor.writeThumbnail("thumbnail.jpg");
// 提取高质量缩略图
const thumbnailData = await processor.createMemoryThumbnail();
console.log(`缩略图:${thumbnailData.width}x${thumbnailData.height}`);
// 始终清理资源
await processor.close();
} catch (error) {
console.error("错误:", error.message);
}
}
processRAW();
完整的 API 覆盖
此包装器提供全面的 LibRaw 功能,包含 50+ 方法,分为 8 个类别:
🔧 核心操作(10 个方法)
- 文件加载(
loadFile
、loadBuffer
) - 处理管道(
raw2Image
、processImage
、subtractBlack
) - 资源管理(
close
、freeImage
)
📊 元数据和信息(12 个方法)
- 基本元数据(
getMetadata
、getImageSize
、getFileInfo
) - 高级元数据(
getAdvancedMetadata
、getLensInfo
、getColorInfo
) - 相机矩阵(
getCameraColorMatrix
、getRGBCameraMatrix
)
🖼️ 图像处理(8 个方法)
- 内存操作(
createMemoryImage
、createMemoryThumbnail
) - 格式转换(
getMemImageFormat
、copyMemImage
) - 处理控制(
adjustMaximum
、adjustSizesInfoOnly
)
📄 文件写入器(6 个方法)
- 输出格式(
writePPM
、writeTIFF
、writeThumbnail
) - 格式验证和质量控制
⚙️ 配置(4 个方法)
- 参数控制(
setOutputParams
、getOutputParams
) - 处理设置和色彩空间管理
🔍 扩展实用工具(8 个方法)
- 格式检测(
isFloatingPoint
、isFujiRotated
、isSRAW
) - 相机特定功能(
isNikonSRAW
、isCoolscanNEF
)
🎨 色彩操作(3 个方法)
- 色彩分析(
getColorAt
、convertFloatToInt
) - 白平衡和色彩矩阵操作
📈 静态方法(4 个方法)
- 库信息(
getVersion
、getCapabilities
) - 相机数据库(
getCameraList
、getCameraCount
)
所有方法都经过全面测试,可用于生产环境!
🆕 缓冲区创建 API(新功能)
直接内存缓冲区创建
直接在内存中创建图像缓冲区,无需写入文件。非常适合 Web 应用程序、API 和流式工作流程。
可用的缓冲区方法
const processor = new LibRaw();
await processor.loadFile("photo.cr2");
await processor.processImage();
// 创建不同格式的缓冲区
const jpegBuffer = await processor.createJPEGBuffer(options);
const pngBuffer = await processor.createPNGBuffer(options);
const webpBuffer = await processor.createWebPBuffer(options);
const avifBuffer = await processor.createAVIFBuffer(options);
const tiffBuffer = await processor.createTIFFBuffer(options);
const ppmBuffer = await processor.createPPMBuffer();
// 无需完整处理即可提取缩略图缓冲区
const processor2 = new LibRaw();
await processor2.loadFile("photo.cr2");
const thumbBuffer = await processor2.createThumbnailJPEGBuffer(options);
缓冲区创建选项
JPEG 缓冲区选项
{
quality: 85, // 1-100(默认:85)
width: 1200, // 目标宽度
height: 800, // 目标高度
progressive: true, // 渐进式 JPEG
fastMode: false, // 速度与质量权衡
effort: 4 // 编码努力程度 1-8
}
PNG 缓冲区选项
{
width: 1200, // 目标宽度
height: 800, // 目标高度
compressionLevel: 6, // 0-9(默认:6)
fastMode: false // 速度与大小权衡
}
WebP 缓冲区选项
{
quality: 80, // 1-100(默认:80)
width: 1200, // 目标宽度
height: 800, // 目标高度
lossless: false, // 无损模式
effort: 4, // 编码努力程度 0-6
fastMode: false // 速度优化
}
AVIF 缓冲区选项
{
quality: 50, // 1-100(默认:50)
width: 1200, // 目标宽度
height: 800, // 目标高度
lossless: false, // 无损模式
effort: 4 // 编码努力程度 0-9
}
TIFF 缓冲区选项
{
width: 1200, // 目标宽度
height: 800, // 目标高度
compression: 'lzw', // 'none', 'lzw', 'zip'
predictor: 'horizontal' // 压缩预测器
}
缩略图缓冲区选项
{
maxSize: 300, // 最大尺寸
quality: 85, // JPEG 质量 1-100
fastMode: false // 速度优化
}
使用示例
Web API 响应
app.get("/api/photo/:id/thumbnail", async (req, res) => {
const processor = new LibRaw();
try {
await processor.loadFile(`photos/${req.params.id}.cr2`);
const result = await processor.createThumbnailJPEGBuffer({
maxSize: 300,
quality: 85,
});
res.set({
"Content-Type": "image/jpeg",
"Content-Length": result.buffer.length,
"Cache-Control": "public, max-age=86400",
});
res.send(result.buffer);
} finally {
await processor.close();
}
});
多格式生成
async function generateFormats(rawFile, outputDir) {
const processor = new LibRaw();
await processor.loadFile(rawFile);
await processor.processImage();
// 并行生成所有格式
const [jpeg, png, webp, avif] = await Promise.all([
processor.createJPEGBuffer({ quality: 85, width: 1920 }),
processor.createPNGBuffer({ width: 1200, compressionLevel: 6 }),
processor.createWebPBuffer({ quality: 80, width: 1920 }),
processor.createAVIFBuffer({ quality: 50, width: 1200 }),
]);
// 根据需要保存或处理缓冲区
fs.writeFileSync(`${outputDir}/image.jpg`, jpeg.buffer);
fs.writeFileSync(`${outputDir}/image.png`, png.buffer);
fs.writeFileSync(`${outputDir}/image.webp`, webp.buffer);
fs.writeFileSync(`${outputDir}/image.avif`, avif.buffer);
await processor.close();
}
流式上传
async function uploadToCloud(rawFile) {
const processor = new LibRaw();
await processor.loadFile(rawFile);
await processor.processImage();
const webpResult = await processor.createWebPBuffer({
quality: 80,
width: 1600,
});
// 直接将缓冲区上传到云存储
const uploadResult = await cloudStorage.upload(webpResult.buffer, {
contentType: "image/webp",
fileName: "processed-image.webp",
});
await processor.close();
return uploadResult;
}
缓冲区结果结构
所有缓冲区创建方法都返回一致的结果结构:
{
success: true,
buffer: Buffer, // 创建的图像缓冲区
metadata: {
format: "JPEG", // 输出格式
outputDimensions: { // 最终图像尺寸
width: 1920,
height: 1280
},
fileSize: {
original: 50331648, // 原始处理图像大小
compressed: 245760, // 缓冲区大小
compressionRatio: "204.8" // 压缩比
},
processing: {
timeMs: "45.23", // 处理时间
throughputMBps: "15.4" // 处理吞吐量
},
options: { // 应用的选项
quality: 85,
width: 1920,
// ... 其他选项
}
}
}
性能特征
格式 | 典型大小(1920px) | 创建时间 | 压缩比 |
---|---|---|---|
JPEG | 80-400KB | 200-500ms | 50-200x |
PNG | 1-4MB | 400-800ms | 12-50x |
WebP | 50-300KB | 100-300ms | 60-300x |
AVIF | 30-150KB | 300-800ms | 100-500x |
TIFF (LZW) | 2-8MB | 100-200ms | 6-25x |
PPM | 11-45MB | 50-100ms | 1x(未压缩) |
缩略图 | 5-50KB | 50-150ms | 200-1000x |
🆕 JPEG 转换(增强功能)
高性能 RAW 转 JPEG 转换
将 RAW 文件转换为优化的 JPEG 格式,具有高级压缩选项和智能设置分析。
基本 JPEG 转换
const processor = new LibRaw();
await processor.loadFile("photo.cr2");
// 使用默认设置的基本转换
const result = await processor.convertToJPEG("output.jpg");
// 使用自定义选项的高质量转换
const result = await processor.convertToJPEG("high-quality.jpg", {
quality: 95, // JPEG 质量(1-100)
chromaSubsampling: "4:2:2", // 更好的色度用于打印
trellisQuantisation: true, // 高级压缩
optimizeCoding: true, // 霍夫曼优化
});
console.log(`文件大小:${result.metadata.fileSize.compressed / 1024}KB`);
console.log(`压缩率:${result.metadata.fileSize.compressionRatio}x`);
console.log(`处理时间:${result.metadata.processing.timeMs}ms`);
网络优化的调整大小转换
// 为网络使用转换和调整大小
const webResult = await processor.convertToJPEG("web-optimized.jpg", {
quality: 80, // 网络使用的良好质量
width: 1920, // 调整到 1920px 宽度(保持宽高比)
progressive: true, // 渐进式加载
mozjpeg: true, // 卓越的压缩算法
optimizeScans: true, // 优化以更快加载
});
// 创建缩略图
const thumbResult = await processor.convertToJPEG("thumbnail.jpg", {
quality: 85,
width: 400,
height: 300,
chromaSubsampling: "4:2:2", // 小图像的更好质量
});
AI 驱动的优化设置
// 分析图像并获取推荐设置
const analysis = await processor.getOptimalJPEGSettings({ usage: "web" });
console.log("推荐设置:", analysis.recommended);
console.log("图像分析:", analysis.imageAnalysis);
// 应用推荐设置
const optimizedResult = await processor.convertToJPEG(
"optimized.jpg",
analysis.recommended
);
批量转换
// 使用优化设置转换多个 RAW 文件
const inputFiles = ["photo1.cr2", "photo2.nef", "photo3.arw"];
const outputDir = "./jpeg-output";
const batchResult = await processor.batchConvertToJPEG(inputFiles, outputDir, {
quality: 80,
width: 1920,
progressive: true,
mozjpeg: true,
});
console.log(
`已处理:${batchResult.summary.processed}/${batchResult.summary.total}`
);
console.log(
`成功率:${(
(batchResult.summary.processed / batchResult.summary.total) *
100
).toFixed(1)}%`
);
console.log(
`节省空间:${(
(batchResult.summary.totalOriginalSize -
batchResult.summary.totalCompressedSize) /
1024 /
1024
).toFixed(1)}MB`
);
JPEG 转换选项
选项 | 类型 | 默认值 | 描述 |
---|---|---|---|
quality |
number | 85 | JPEG 质量(1-100,越高质量越好) |
width |
number | - | 目标宽度(像素,保持宽高比) |
height |
number | - | 目标高度(像素,保持宽高比) |
progressive |
boolean | false | 启用渐进式 JPEG 用于网络优化 |
mozjpeg |
boolean | true | 使用 MozJPEG 编码器获得卓越压缩 |
chromaSubsampling |
string | '4:2:0' | 色度子采样('4:4:4', '4:2:2'*, '4:2:0') |
trellisQuantisation |
boolean | false | 高级压缩技术 |
optimizeScans |
boolean | false | 优化扫描顺序用于渐进式加载 |
optimizeCoding |
boolean | true | 优化霍夫曼编码表 |
colorSpace |
string | 'srgb' | 输出色彩空间('srgb', 'rec2020', 'p3', 'cmyk') |
*注意:由于 Sharp 库限制,'4:2:2' 色度子采样自动映射到 '4:4:4'。
性能特征
- 处理速度:在现代硬件上 70-140 MB/s
- 压缩比:典型压缩 2-10x(因内容而异)
- 内存效率:大文件的流式处理
- 质量保持:Q85+ 设置下视觉无损
使用预设
网络优化
{
quality: 80,
width: 1920,
progressive: true,
mozjpeg: true,
chromaSubsampling: '4:2:0',
optimizeScans: true
}
打印质量
{
quality: 95,
chromaSubsampling: '4:2:2',
trellisQuantisation: true,
optimizeCoding: true,
mozjpeg: true
}
归档/最大质量
{
quality: 98,
chromaSubsampling: '4:4:4',
trellisQuantisation: true,
optimizeCoding: true
}
缩略图生成
{
quality: 85,
width: 800,
chromaSubsampling: '4:2:2',
mozjpeg: true
}
命令行工具
单个文件转换
node examples/jpeg-conversion-example.js photo.cr2
批量转换
# 网络优化的批量转换
node scripts/batch-jpeg-conversion.js ./raw-photos ./web-gallery 1
# 打印质量转换
node scripts/batch-jpeg-conversion.js ./raw-photos ./print-gallery 2
# 归档质量转换
node scripts/batch-jpeg-conversion.js ./raw-photos ./archive-gallery 3
NPM 脚本
# 运行 JPEG 转换测试
npm run test:jpeg-conversion
# 使用 CLI 界面批量转换
npm run convert:jpeg <input-dir> [output-dir] [preset]
## API 参考
### 文件操作
#### `new LibRaw()`
创建一个新的 LibRaw 处理器实例。
#### `loadFile(filename)`
从文件系统加载 RAW 文件。
- **filename** `{string}` - RAW 文件路径
- **返回** `{Promise<boolean>}` - 成功状态
#### `loadBuffer(buffer)`
从内存缓冲区加载 RAW 数据。
- **buffer** `{Buffer}` - 包含 RAW 数据的缓冲区
- **返回** `{Promise<boolean>}` - 成功状态
#### `close()`
关闭处理器并释放所有资源。
- **返回** `{Promise<boolean>}` - 成功状态
### 元数据和信息
#### `getMetadata()`
从加载的 RAW 文件中提取基本元数据。
- **返回** `{Promise<Object>}` - 包含以下内容的元数据对象:
```javascript
{
make: 'Canon', // 相机制造商
model: 'EOS R5', // 相机型号
software: '1.3.1', // 相机软件版本
width: 8192, // 处理后的图像宽度
height: 5464, // 处理后的图像高度
rawWidth: 8280, // RAW 传感器宽度
rawHeight: 5520, // RAW 传感器高度
colors: 3, // 颜色通道数
filters: 0x94949494, // 颜色滤镜模式
iso: 800, // ISO 感光度
shutterSpeed: 0.004, // 快门速度(秒)
aperture: 2.8, // 光圈 f 值
focalLength: 85, // 焦距(毫米)
timestamp: 1640995200 // 拍摄时间戳(Unix)
}
getImageSize()
获取详细的图像尺寸和边距信息。
- 返回
{Promise<Object>}
- 尺寸信息:{ width: 8192, // 处理后的图像宽度 height: 5464, // 处理后的图像高度 rawWidth: 8280, // RAW 传感器宽度 rawHeight: 5520, // RAW 传感器高度 topMargin: 16, // 顶部边距(像素) leftMargin: 24, // 左侧边距(像素) iWidth: 8192, // 内部处理宽度 iHeight: 5464 // 内部处理高度 }
getAdvancedMetadata()
获取高级元数据,包括色彩矩阵和校准数据。
- 返回
{Promise<Object>}
- 包含色彩矩阵、黑电平等的高级元数据
getLensInfo()
从 RAW 文件中获取镜头信息。
- 返回
{Promise<Object>}
- 包含名称、焦距范围、序列号的镜头信息
getColorInfo()
获取色彩信息,包括白平衡和色彩矩阵。
- 返回
{Promise<Object>}
- 包含 RGB 矩阵和乘数的色彩信息
图像处理
subtractBlack()
从 RAW 数据中减去黑电平。
- 返回
{Promise<boolean>}
- 成功状态
raw2Image()
将 RAW 数据转换为图像格式。
- 返回
{Promise<boolean>}
- 成功状态
adjustMaximum()
调整图像数据中的最大值。
- 返回
{Promise<boolean>}
- 成功状态
processImage()
使用当前设置执行完整的图像处理。
- 返回
{Promise<boolean>}
- 成功状态
unpackThumbnail()
从 RAW 文件中解包缩略图数据。
- 返回
{Promise<boolean>}
- 成功状态
内存操作
createMemoryImage()
在内存中创建处理后的图像。
- 返回
{Promise<Object>}
- 图像数据对象:{ type: 2, // 图像类型(1=JPEG, 2=TIFF) width: 8192, // 图像宽度 height: 5464, // 图像高度 colors: 3, // 颜色通道数 bits: 16, // 每样本位数 dataSize: 268435456, // 数据大小(字节) data: Buffer // 图像数据缓冲区 }
createMemoryThumbnail()
在内存中创建缩略图图像。
- 返回
{Promise<Object>}
- 与上述结构相同的缩略图数据对象
文件写入器
writePPM(filename)
将处理后的图像写入为 PPM 文件。
- filename
{string}
- 输出文件名 - 返回
{Promise<boolean>}
- 成功状态
writeTIFF(filename)
将处理后的图像写入为 TIFF 文件。
- filename
{string}
- 输出文件名 - 返回
{Promise<boolean>}
- 成功状态
writeThumbnail(filename)
将缩略图写入文件。
- filename
{string}
- 输出文件名 - 返回
{Promise<boolean>}
- 成功状态
配置
setOutputParams(params)
设置图像处理的输出参数。
- params
{Object}
- 参数对象:{ gamma: [2.2, 4.5], // 伽马校正 [功率, 斜率] bright: 1.0, // 亮度调整 output_color: 1, // 输出色彩空间 (0=raw, 1=sRGB, 2=Adobe RGB) output_bps: 8, // 输出每样本位数 (8 或 16) user_mul: [1,1,1,1], // 用户白平衡乘数 no_auto_bright: false, // 禁用自动亮度 highlight: 0, // 高光恢复模式 (0-9) output_tiff: false // 输出 TIFF 格式 }
- 返回
{Promise<boolean>}
- 成功状态
getOutputParams()
获取当前输出参数。
- 返回
{Promise<Object>}
- 当前参数设置
实用工具函数
isFloatingPoint()
检查图像是否使用浮点数据。
- 返回
{Promise<boolean>}
- 浮点状态
isFujiRotated()
检查图像是否为富士旋转(45度传感器旋转)。
- 返回
{Promise<boolean>}
- 富士旋转状态
isSRAW()
检查图像是否为 sRAW 格式。
- 返回
{Promise<boolean>}
- sRAW 格式状态
isJPEGThumb()
检查缩略图是否为 JPEG 格式。
- 返回
{Promise<boolean>}
- JPEG 缩略图状态
errorCount()
获取处理过程中遇到的错误数量。
- 返回
{Promise<number>}
- 错误计数
静态方法
LibRaw.getVersion()
获取 LibRaw 库版本。
- 返回
{string}
- 版本字符串(例如:"0.21.4-Release")
LibRaw.getCapabilities()
获取 LibRaw 库功能作为位掩码。
- 返回
{number}
- 功能标志
LibRaw.getCameraList()
获取所有支持的相机型号列表。
- 返回
{string[]}
- 相机型号名称数组
LibRaw.getCameraCount()
获取支持的相机型号数量。
- 返回
{number}
- 相机数量(通常 1000+)
LibRaw.isRawFile(filePath)
🆕
检查文件是否为 LibRaw 支持的 RAW 格式。
- filePath
{string}
- 要检查的文件路径 - 返回
{Object}
- 检查结果对象:{ isRawFile: boolean, // 是否为 LibRaw 支持的 RAW 文件 success: boolean, // 检查是否成功 message: string, // 详细信息 errorCode?: number // 错误代码(仅失败时) }
示例:
// 检查单个文件
const result = LibRaw.isRawFile('photo.cr2');
if (result.isRawFile) {
console.log('✅ 这是 LibRaw 支持的 RAW 文件');
} else {
console.log('❌ 不是支持的 RAW 文件:', result.message);
}
// 过滤目录中的 RAW 文件
const files = fs.readdirSync(dir);
const rawFiles = files.filter(file =>
LibRaw.isRawFile(path.join(dir, file)).isRawFile
);
// 上传前验证
if (!LibRaw.isRawFile(uploadedFile).isRawFile) {
throw new Error('请上传 LibRaw 支持的 RAW 格式文件');
}
优势:
- ✅ 智能识别 - 利用 LibRaw 内部机制,支持 100+ 种 RAW 格式
- ✅ 无需维护 - 不需要手动维护扩展名列表
- ✅ 轻量级 - 只进行格式识别,不完全加载文件
- ✅ 准确可靠 - 基于文件内容判断,而非仅靠扩展名
测试
该库包含涵盖所有主要功能的全面测试套件:
快速测试
# 基本功能测试
npm run test:quick
# 全面的 API 覆盖测试
npm run test:comprehensive
# 新的缓冲区创建方法测试
npm run test:buffer-creation
# 单独的测试套件
npm run test:image-processing # 图像转换和处理
npm run test:format-conversion # 输出格式和色彩空间
npm run test:thumbnail-extraction # 缩略图操作
高级测试
# 使用示例图像测试(如果可用)
npm run test:samples
npm run test:compare
# 性能基准测试
npm run test:performance
# 测试所有支持的格式
npm run test:formats
# 缓冲区创建测试套件
npm run test:buffer-creation # 全面的缓冲区方法测试
# 使用您自己的 RAW 文件测试
npm test path/to/your/photo.cr2
测试覆盖
测试套件提供全面的验证:
- ✅ 测试了 21 个 RAW 文件(佳能 CR3、尼康 NEF、索尼 ARW、富士 RAF、松下 RW2、徕卡 DNG)
- ✅ 100% 缩略图提取成功率
- ✅ 100% 缓冲区创建成功率(7 个新的缓冲区方法)
- ✅ 验证了 6 个相机品牌(佳能、尼康、索尼、富士、松下、徕卡)
- ✅ 测试了多种输出格式(PPM、TIFF、JPEG、PNG、WebP、AVIF 缓冲区)
- ✅ 色彩空间转换(sRGB、Adobe RGB、宽色域、ProPhoto、XYZ)
- ✅ 位深度变化(8 位、16 位处理)
- ✅ 内存操作(缓冲区管理、图像复制、直接缓冲区创建)
- ✅ 错误处理(无效文件、损坏数据、参数验证)
- ✅ 性能基准测试(缓冲区创建速度和压缩比)
缩略图提取
从 RAW 文件中提取高质量缩略图:
const LibRaw = require("librawspeed");
async function extractThumbnails() {
const processor = new LibRaw();
try {
await processor.loadFile("photo.cr2");
// 检查缩略图是否存在
const hasThumb = await processor.thumbOK();
if (hasThumb) {
// 提取缩略图
await processor.unpackThumbnail();
// 获取缩略图数据
const thumbData = await processor.createMemoryThumbnail();
console.log(
`缩略图:${thumbData.width}x${thumbData.height},${thumbData.dataSize} 字节`
);
// 保存到文件
await processor.writeThumbnail("thumbnail.jpg");
}
await processor.close();
} catch (error) {
console.error("错误:", error.message);
}
}
批量缩略图提取
从所有 RAW 文件中提取缩略图:
# 从 sample-images/ 中的所有 RAW 文件提取缩略图
npm run extract:thumbnails
这将创建:
- 在
sample-images/thumbnails/
中的单独 JPEG 缩略图 - 交互式画廊查看器(
index.html
) - 全面的提取报告
示例结果:
- 21/21 文件成功处理(100% 成功率)
- 格式: CR3、NEF、ARW、RAF、RW2、DNG
- 质量: 380KB - 13.4MB 缩略图(保持原始质量)
- 性能: 平均提取时间约 50ms
示例输出
📁 加载 RAW 文件:DSC_0006.NEF
📊 提取元数据...
📷 相机信息:
制造商:尼康
型号:D5600
📐 图像尺寸:
处理后:6016 x 4016
RAW:6016 x 4016
🎯 拍摄参数:
ISO:200
光圈:f/6.3
快门速度:1/250s
焦距:300mm
🎨 色彩信息:
颜色:3
滤镜:0xb4b4b4b4
📅 拍摄日期:2025-06-05T09:48:18.000Z
✅ 完成!
项目结构
librawspeed/
├── src/ # C++ 源文件
│ ├── addon.cpp # 主要插件入口点
│ ├── libraw_wrapper.cpp # LibRaw C++ 包装器(50+ 方法)
│ └── libraw_wrapper.h # 头文件
├── lib/ # JavaScript 接口
│ └── index.js # 主要模块导出
├── test/ # 全面的测试套件
│ ├── image-processing.test.js # 图像转换测试
│ ├── format-conversion.test.js # 格式和色彩空间测试
│ ├── thumbnail-extraction.test.js # 缩略图操作测试
│ ├── comprehensive.test.js # 组合测试运行器
│ ├── performance.test.js # 性能基准测试
│ └── all-formats.test.js # 多格式验证
├── scripts/ # 实用工具脚本
│ └── extract-thumbnails.js # 批量缩略图提取器
├── examples/ # 使用示例
│ ├── basic-example.js # 基本使用演示
│ └── advanced-demo.js # 高级处理示例
├── sample-images/ # 示例 RAW 文件和结果
│ ├── thumbnails/ # 提取的缩略图画廊
│ │ ├── index.html # 交互式查看器
│ │ ├── README.md # 提取文档
│ │ └── *.jpg # 21 个提取的缩略图
│ └── *.{CR3,NEF,ARW,RAF,RW2,DNG} # 测试 RAW 文件
├── docs/ # 文档
│ └── TESTING.md # 全面的测试指南
├── deps/ # 依赖项
│ └── LibRaw-Source/ # LibRaw 源代码(跨平台)
│ └── LibRaw-0.21.4/
│ └── build/ # 交叉编译的库
│ ├── win32/ # Windows x64
│ ├── darwin-x64/ # macOS Intel
│ ├── darwin-arm64/ # macOS Apple Silicon
│ ├── linux-x64/ # Linux x64
│ └── linux-arm64/ # Linux ARM64
├── binding.gyp # 构建配置
├── package.json # 项目配置
└── README.md # 此文件
开发
从源码构建
# 清理之前的构建
npm run clean
# 重新构建
npm run build
# 测试构建
npm run test:quick
添加新功能
- 在
src/
中添加 C++ 实现 - 在
lib/
中更新 JavaScript 包装器 - 在
test/
中添加测试 - 更新文档
贡献
- Fork 仓库
- 创建功能分支(
git checkout -b feature/amazing-feature
) - 提交您的更改(
git commit -m 'Add amazing feature'
) - 推送到分支(
git push origin feature/amazing-feature
) - 打开 Pull Request
路线图
版本 1.0(当前 - 生产就绪)
- ✅ RAW 文件加载和元数据提取
- ✅ 全面的 EXIF 数据访问
- ✅ 内存高效处理
- ✅ 基于 Promise 的 API
- ✅ 缩略图提取(100% 成功率)
- ✅ 图像处理管道
- ✅ 多种输出格式(PPM、TIFF)
- ✅ 实现了 50+ LibRaw 方法
- ✅ 全面的测试覆盖
- ✅ 验证了 6 个相机品牌
- ✅ 生产就绪的稳定性
版本 2.0(计划中)
- 🔄 高级图像滤镜和调整
- 🔄 批量处理优化
- 🔄 额外的输出格式(JPEG、PNG)
- 🔄 色彩配置文件管理
- 🔄 实时预览生成
版本 3.0(未来)
- 📋 批量处理功能
- 📋 大文件的流式支持
- 📋 高级色彩管理
- 📋 自定义处理器的插件系统
性能
LibRaw Node.js 为 RAW 处理提供卓越的性能:
真实世界基准测试(已测试 Windows)
操作 | 文件大小 | 处理时间 | 吞吐量 | 成功率 |
---|---|---|---|---|
文件加载 | 25MB RAW | 15-30ms | 800MB/s+ | 100% |
元数据提取 | 任何 RAW | 1-5ms | - | 100% |
缩略图提取 | 160x120 - 4K | 20-50ms | 400KB/s+ | 100% |
完整图像处理 | 6000x4000 16位 | 1000-2000ms | 70-140MB/s | 95%+ |
格式写入 (PPM) | 144MB 输出 | 200-500ms | 300MB/s+ | 100% |
格式写入 (TIFF) | 144MB 输出 | 800-1200ms | 120MB/s+ | 100% |
内存效率
操作 | 峰值内存 | 缓冲区大小 | 清理 |
---|---|---|---|
RAW 加载 | ~50MB | 25MB 文件缓冲区 | ✅ 自动 |
图像处理 | ~200MB | 144MB 图像缓冲区 | ✅ 自动 |
缩略图提取 | ~5MB | 2-13MB 缩略图缓冲区 | ✅ 自动 |
批量处理 | 恒定 | 无内存泄漏 | ✅ 完美 |
测试结果摘要
- ✅ 21/21 RAW 文件已处理 跨越 6 个相机品牌
- ✅ 100% 缩略图提取成功(总共 2.5GB 缩略图)
- ✅ 95%+ 图像处理成功(管道工作流程正常)
- ✅ 0 内存泄漏 在广泛测试中检测到
- ✅ 亚秒级 所有格式的元数据提取
故障排除
构建问题
错误:找不到模块 'node-addon-api'
npm install node-addon-api
错误:MSBuild.exe 失败,退出代码:1
- 安装 Visual Studio Build Tools
- 确保 Python 3.x 可用
错误:找不到 libraw.dll
npm run build # 重新构建并复制 DLL
运行时问题
错误:无法打开文件
- 检查文件路径和权限
- 验证文件是否为有效的 RAW 格式
- 确保文件未损坏
🚀 NPM 发布状态
✅ 已发布到 NPM 注册表!
- 包:
librawspeed@1.0.8
- 发布日期:2025年8月30日
- 总文件数:487 个文件(4.0 MB 包,18.1 MB 解压后)
- 注册表:npmjs.com
安装命令
npm install librawspeed
下载统计
- 初始发布:生产就绪,具有全面的测试覆盖
- 平台:Windows(已测试)、macOS、Linux
- Node.js:14.0.0+ 兼容
许可证
此项目在 MIT 许可证下授权 - 有关详细信息,请参阅 LICENSE 文件。
致谢
- LibRaw - 强大的 RAW 处理库
- Node-API - Node.js 原生插件接口
- node-gyp - Node.js 原生插件构建工具
- 摄影社区 - 提供多样化的 RAW 文件进行全面测试
- 相机制造商 - 佳能、尼康、索尼、富士、松下、徕卡提供优秀的 RAW 格式
测试贡献者
特别感谢使用真实世界 RAW 文件进行的全面测试:
- 21 个 RAW 文件 跨越 6 个主要相机品牌
- 100% 缩略图提取成功 验证
- 生产级稳定性 测试和验证
支持
为摄影和 Node.js 社区用心制作 ❤️