由于项目中需要用户上传的头像的功能,所以就参照一些网站实现在线图片裁切的功能。
经过朋友推荐和多方比较,前端采用 Jcrop 和 jQuery Form 实现用户界面,把用户要裁切的图片区域和图片异步的方式提交后端。
而后端则负责对图片的裁切,输出并保存为用户头像。
这篇主要以Express框架为例介绍如何在Node.js开发环境中使用sharp库处理图片。
sharp是由伦敦的一位开发者lovell开发的基于libvips的一款轻快的图片处理库。
以下是原文介绍,详情可以戳上面的Github链接了解更多。
The fastest Node.js module for resizing JPEG, PNG, WebP and TIFF images. Uses the libvips library.
安装
关于安装需要注意除了基本的Node.js开发环境之外,还需要预装libvips库。关于如何在各个平台上安装vips,其GitHub页面已经给出详细的参考,我在CentOS和Mac OS上都已成功预装。不过在Mac上安装时遇到一些问题,已经在之前的文章中给出相应的解决过程。
按照官方提示安装好sharp之后就可以开始对图片进行裁切、缩放、旋转,并且可以更改图片的输出格式,质量等。这些已经完全能满足裁切头像的需求了!
使用
首先自然是需要引入sharp库
|
|
风格
sharp使用的是跟jQuery类似的链式操作风格:sharp('input.jpg').resize(300, 300).max() ...
示例
下面代码(有省略)就是根据前台传送过来的裁切数据,进行裁切的片段:
|
|
通过上面的一段代码,就可以实现对用户前一步上传的图片进行制定范围的裁切。
开始裁切图片之前需要检查图片是否存在,如果已经丢失或未保存则返回错误信息告知前端用户。
接下来就是使用sharp对图片进行实际的操作,sharp API的链式调用方式使得处理图片如同工厂里的流水线拼接。
首先,把图片路径imagePath
传递给sharp把这张图片送入车间;
然后是调用extract(top, left, width, height)
按照裁切图纸,也就是裁切坐标对图片进行粗加工。这里需要注意的是需要对坐标进行简单的置换——第一个参数对应图片的起始纵坐标data.y
,第二个参数则对应裁切区域的起始横坐标data.x
;
接下来是通过resize(width, height)
将图片按照制定规格进行缩放;
当然加工的图片还需要对其质量进行控制,这里通过sharpen()
和quality()
分别对图片进行锐化和设定输出质量。quality()
针对JPEG, WebP 和 TIFF三种可以控制输出质量的格式进行控制,范围为1~100,默认为80,似乎和Photoshop默认的JPEG输出质量一致;
最后一步就是对加工完成的图片进行输出,sharp提供了pipe和文件两种方式,这里用到的是直接另存为图片的方式,使用toFile()
完成最后的出厂工作。指定的输出图片路径可以是已经存在的图片,只要有文件写入权限sharp会覆盖旧的文件。但是目标文件不能是输入源,也就是不能把加工出来的成品和加工原材料放在同一个位置;toFile()
还接受另一个参数即回调函数,这个回调函数只接收一个错误信息作为参数,从而可以判断图片处理是否成功。这里选择在成功保存头像后将裁切数据保存在数据库中,这样就可以实现帮助用户重新载入裁切区域的功能。
常见错误
Bad extract area
在使用extract()
对图片进行裁切时,主要注意裁切坐标只能在图片自身的范围内,比如起点横坐标left加上裁切横长width超过了图片的右边界,sharp会报出Bad extract area
非法裁切区域的错误,特别注意前面提到的左上横高的参数顺序。当然我们可以在裁切前,通过sharp提供的另外一个接口先获取图片的尺寸。
获取图片信息
在对图片进行处理之前,往往需要先获取图片的尺寸格式等基本进行。sharp中可以通过metadata()
获取图片的一些重要的元数据,比如尺寸、格式和颜色空间等。用法可以参考官方的示例:
|
|
上面的例子,输出的Buffer信息是一个源图片宽和高各缩小一半的WebP格式图片。
关于sharp的性能,可以参考官方给出的同imagemagick-native,imagemagick,gm进行对比测试样本:Performance
gm是另一个Node.js开发环境下的图形处理库(包),不过gm所使用的底层库是更加常见 GraphicsMagick,相信对于开发过图片处理模块的PHPer来说很熟悉了。我在选择包的时候比较看重其效率,在看到sharp简述中的Fast后就决定试用一下。如果你也正在寻找一个在Node.js中高性能的图片处理方式,不妨试试sharp!