使用 Node.js 实现图片的动态裁切及算法实例代码详解

2020-06-17 05:52:13易采站长站整理

背景&概览

目前常见的图床服务都会有图片动态裁切的功能,主要的应用场景用以为各种终端和业务形态输出合适尺寸的图片。

一张动辄以 MB 为计量单位的原始大图,通常不会只设置一下显示尺寸就直接输出到终端中,因为体积太大加载体验会很差,除了影响加载速度还会增加终端设备的内存占用。所以要想在各种终端下都能保证图片质量的同时又确保输出合适的尺寸,那么此时就需要根据图片 URL 来对原始图片进行裁切,然后动态生成并输出一张新的图片。

URL 的设计

图片 URL 需要包含图片 id、尺寸、质量等信息。有两种类型的图片 URL,分别是原图 URL 和带动态裁切信息的 URL。


// 原图 URL
http://example.com/$imgId

// 带裁切信息的图片 URL
http://example.com/$cropType/$width_$height_$quality/$imgId

来分析一下上面 URL 中的变量:

$imgId
$cropType
$width
$height
$quality

那么一张图片 id 为 4b2d4edcc1f82452 的原图 URL 应该是:

http://example.com/4b2d4edcc1f82452.jpg

如果想要一张该图 800×600 的版本,裁切的 URL 大致是下面这样的:

http://example.com/es/800_600_/4b2d4edcc1f82452.jpg

裁切算法

该来说说以上 URL 背后的算法了。在 Node.js 中可以使用著名的图片裁切库 GM ,该库是基于 imagemagick 和 graphicsmagick 底层库的封装。

最常见的裁切算法是等比例裁切,等比裁切的算法需要至少给出裁切目标图片的宽度和高度的其中一个,如果图片限宽就给出宽度,限高就给出高度,如果两个参数都有,就需要确保裁切的目标宽高相对于原始的宽高是按比例计算的,否则裁切的结果就会出现拉伸。


var gm = require('gm');
// 裁切的最小尺寸
var minSize = 48;
var defaultQuality = 90;
/**
* 等比例缩放 equal scaling
* @param { String } 原文件路径
* @param { String } 新文件路径
* @param { String } 缩放规则
* @return { promise }
*/
var es = function(src, dest, rules) {
return new Promise(function(resolve, reject) {
// 900_600_90 => 宽度900/高度600/品质90
rules = rules.split('_');
if (rules.length !== 3) {
return reject(new Error('Resize rules invalid'));
}
// 解析裁切的目标宽高
let resizeWidth = parseInt(rules[0]);
let resizeHeight = parseInt(rules[1]);
let quality = parseInt(rules[2]) || defaultQuality;
const readStream = fs.createReadStream(src);
const writeStream = fs.createWriteStream(dest);
gm(readStream)
.size({
bufferStream: true
}, function(err, size) {