这个高速 Node.js 模块的典型用例是将常见格式(支持读取 JPEG、PNG、WebP、AVIF、TIFF、GIF 和 SVG 图像)的大图像转换为较小的、对网络友好的 JPEG、PNG、AVIF 和不同尺寸的 WebP 图像,输出图像可以是 JPEG、PNG、WebP、AVIF 和 TIFF 格式以及未压缩的原始像素数据。
除了图像调整大小外,还可以进行旋转、提取、合成和伽马校正等操作。
由于使用libvips , 调整图像大小通常比使用最快的 ImageMagick 和 GraphicsMagick 设置快 4 到 5 倍。一次只将一小块未压缩的图像数据保存在内存中并进行处理,充分利用了多个 CPU 内核和 L1/L2/L3 缓存。由于libuv,一切都保持非阻塞,没有产生子进程并且支持 Promises/async/await。
文档:https://sharp.pixelplumbing.com/
如下案例展示了获取图片元数据和图片缩放、裁剪以及格式转换的功能
const path = require('path');
const fs = require('fs-extra');
const sharp = require('sharp');
module.exports = {
/**
* 获取图片元数据
* @param {String} src 图片地址
* @see https://sharp.pixelplumbing.com/api-input
* @returns {Object}
*/
async getMetadata(src) {
// 源文件不存在
const isExist = await fs.pathExists(src)
if (!isExist ) {
return {};
}
const metadata = await sharp(src).metadata();
return metadata || {};
}
/**
* 调整图像大小
* @param {String} src 源图片地址
* @param {String} dest 目标图片地址
* @param {Object} resizeOpts 裁剪图片参数 { width, height, fit, position, background }
* @summary fit: {0:'cover', 1:'contain', 2:'fill', 3: 'inside', 4: 'outside'}
* cover:裁剪以覆盖两个提供的尺寸(默认值)。
* contain:嵌入两个提供的尺寸。
* fill:忽略输入的纵横比并拉伸到两个提供的尺寸。
* inside:保留纵横比,将图像调整为尽可能大,同时确保其尺寸小于或等于指定的尺寸。
* outside:保留纵横比,将图像调整为尽可能小,同时确保其尺寸大于或等于指定的尺寸。
* @summary {String} position: top,right top,right,right bottom,bottom,left bottom,left,left top
* @summary background: 背景颜色 { r, g, b, alpha }
* @param {Object} outputOpts 目标图片参数 { quality: jpg/webp的压缩质量, lossless: webp无损压缩, compressionLevel: png的zlib压实级别 }
* @see https://sharp.pixelplumbing.com/api-output
*/
async resizeAndCrop(options, outputOpts) {
const { src, dest, destAbsolutePath, width, height, fit, position, background } = options;
const fileSrc = path.join(think.RESOURCE_PATH, src);
// 目标地址或源文件不存在
const isExist = await fs.pathExists(fileSrc)
if (!dest || !isExist) {
return '';
}
let result;
const extname = path.extname(dest); // 目标文件后缀
// 先创建目标目录结构,才能输出图片
try {
await fs.ensureDir(path.dirname(destAbsolutePath));
} catch (err) {
console.error(err);
return '';
}
// 先调整图像大小
const fitEnum = ['cover', 'contain', 'fill', 'inside', 'outside'];
const hasBackgroundEnum = ['.png', '.webp', '.tile'];
const image = await sharp(fileSrc)
.resize(width, height, {
fit: fitEnum[fit] || 'cover',
position,
background: background || (
hasBackgroundEnum.includes(extname)
? { r: 255, g: 255, b: 255, alpha: 0 }
: { r: 255, g: 255, b: 255, alpha: 1 }
)
});
// 再根据输出格式生成文件
switch (extname) {
case '.png':
result = await image.png(outputOpts)
.toFile(destAbsolutePath)
.catch(error => console.error(error, fileSrc));
break;
case '.webp':
result = await image.webp(outputOpts)
.toFile(destAbsolutePath)
.catch(error => console.error(error, fileSrc));
break;
default:
const jpgOptions = {
...outputOpts,
mozjpeg: true
};
result = await image.jpeg(jpgOptions)
.toFile(destAbsolutePath)
.catch(error => console.error(error, fileSrc));
}
return result ? dest : '';
}
};
还没有评论,快来抢第一吧