node图片处理工具gm的使用:图片水印、图片验证码、图片裁剪示例

2019-02-12 16:19:50

请在这里查看示例☞ gm示例


安装

GraphicsMagick和ImageMagick的区别

GraphicsMagick是从ImageMagick中分离出来的,推荐下载ImageMagick

加载GraphicsMagick(大小4.72 MB) 

var gm = require('gm')


加载ImageMagick(大小23.8 MB) 

var gm = require('gm').subClass({imageMagick: true})// 注意使用的区别


除了加载有区别,其他使用方式完全一样

window版本

下载imagemagick的window版本(在页面靠下方),如图: 


双击exe文件,进行安装,安装过程中要注意勾选以下选项 


linux版本(ubuntu 16.04)

ubuntu 安装imagemagick

要点

图片水印

var gm = require('gm').subClass({imageMagick: true})


gm('./public/images/a.png')// 原图路径

.font('./fonts/zhulangyingxingti.ttf')// 配置逐浪硬行体字库路径

.drawText(10, 10, '水印')

.write('./public/images/b.png', function (e) {// 输出的图片路径

    if(e) {

        console.log(e.message)

    }else {

        console.log('done')

    }

})

1

2

3

4

5

6

7

8

9

10

11

12

drawText()中文乱码

字体文件使用中文名称命名,运行时会报错,所以不要使用中文命名 


如果确保字库引入正确,还出现中文乱码,那一定是字库文件本身有问题,换一种字库就可以了

尝试过字库格式ttf、otf均支持 

详见: 

字库ttf和otf格式有什么区别?

图片验证码

准备一张背景杂乱的图片和艺术字体的英文字库 


index.html


<img src="/gm/captchaAdd"><!-- 前端通过img标签请求验证码 -->

1

app.js


var express = require('express')

var session = require('express-session')

...


var cap = {// 通过函数随机出一个验证码对象,包括文字和在杂乱背景上的位置(这里假如如下)

    text: 'ab12',

    pos: [20, 50],

}


// 生成验证码

app.all('/gm/captchaAdd', function(req, res, next) {

    var url = './public/images/'+(''+Math.cap()).replace('.', '')+'.png'// 设置验证码的输出路径,且给一个随机文件名


    gm('./lib/images/captchaBg.png')// 一张背景杂乱的图片作为验证码的背景

    .font('./lib/src/SelfRighteousness-Regular.ttf')// 一种略艺术的英文字库

    .fontSize(50)// 设置字体大小

    .drawText(cap.pos[0], cap.pos[1], cap.text)// 写入随机的验证码

    .crop(100, 40, cap.pos[0], cap.pos[1])// 将相应的文字部分裁剪出来,作为验证码

    .noise(1)// 加入噪点

    .write(url, function (e) {// 随机一个文件名,并输出验证码

        if(e) {

            console.log(e.message)

        }else {

            req.session.captcha = cap// 将验证码对象写入session,用来登录时跟用户输入的作比较

            res.download(url)// 这里用download方法发送图片,前端千万不能用ajax方式请求

        }

    })

})


// 用户登录

app.all('/user/login', function(req, res, next) {

    if(req.body.captcha.toLocaleLowerCase() != req.session.captcha.text.toLocaleLowerCase()) {

        res.send({message: '验证码不正确'})

    }else {

        ...

    }

})

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

效果如下 

 2.  3. 

最后可以通过AI开放平台提供的文字识别技术来测试机器识别的效果

升级版验证码(参考慕课网) 

用户使用某个用户名尝试登陆,如果错误,将给该用户名在数据库记录一次错误

该用户名错误次数达到3次,要求需等待半小时后才能再次尝试登录该用户名,且必须输入验证码

所以当用户来到登录页面时,在输入用户名之后(或从cookie拿到记录的用户名),需要发送一个请求去验证此用户名是否需要输入验证码,如需要,将验证码输入框显示出来

这个有个问题就是,其他用户可以通过故意错误的登录某些用户名,来使这些用户名永远处于等半小时的状态,导致永远无法登陆(不过为了用户安全,牺牲一点用户体验也是值得的)

详见: 

使用session实现一次性验证码


头像裁剪

下面我给出4种方式的思路

方式1(本篇提供的demo即使用此方法) 

前端使用上传插件Webuploader来提供上传图片的功能

前端使用Jcrop来提供裁剪的位置

后端使用gm根据给出的裁剪位置对上传的图片进行裁剪

方式2(可以借助jquery-plugins/h5Crop/插件,该插件我会继续完成) 

前端利用canvas实现裁剪和压缩,将处理后的base64传给后端

后端将base64转化成图片,返回给前端进行展示

方式3 

前端把图片传给后端

后端压缩处理过之后,返回给前端(附带图片唯一标识)

前端使用Jcrop获取图片的裁剪位置,将裁剪位置和图片唯一标识传给后端

后端对对应的图片进行裁剪

方式4(这个需要借助我的另一个裁剪插件,提供了2种方式进行裁剪,效果跟qq裁剪头像一样,以后会开源) 

前端裁剪 

前端通过js对图片进行平移、缩放操作

再通过canvas的drawImage方法绘制操作后的图片

再通过canvas的toDataURL进行压缩同时获取最终的base64

传base64到后端,后端转为图片,返回图片路径,前端进行展示

后端裁剪 

前端通过js对图片进行平移、缩放操作

将操作后获取的裁剪参数(裁剪框的大小、缩放的比率、压缩的比率)和图片文件一同传给后端

后端对上传的文件进行裁剪,返回图片路径,前端进行展示

需使用到的ImageMagick小细节 

读取本地图片资源gm('upload\\temp\\crop\\20180601\\49076530-6584-11e8-9542-0d60dcc7daa8.jpg'))

读取外链图片资源gm('http://localhost:3000/upload/temp/crop/20180601/49076530-6584-11e8-9542-0d60dcc7daa8.jpg'))

读取base64图片资源'inline:' + 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBD...')(注意不适用超过5000个字符的base64字符串,否则会转换失败)

为了解决base64过长时ImageMagick处理会失败,我们使用node来转换base64为图片

缩放图片传入百分比gm('xxx.png').resize('50%'))

压缩图片传入值gm('xxx.png').quality(50))

不管是前端canvas压缩还是后端ImageMagick压缩,最后的输出的格式都要是jpeg或jpg,否则压缩后的大小很可能会变大

效果展示(动图较大,请耐心等待) 


优缺点对比 

方式1:后端只要写1个接口(Webuploader对图片可以进行压缩)

方式2:兼容性IE>=10,减少后端工作量

方式3:适中,后端需要写2个接口(上传图片接口和裁剪图片接口)

方式4:编写复杂,但是扩展性好,可自由选择一种方式

参考

gm官方文档

nodejs图片处理工具gm用法

nodejs gm drawText使用(中文、字体、大小及颜色)

ImageMagick常用操作


  • 2018-08-20 15:26:19

    关于OnTouch 和OnClick同时调用冲突的解决方案

    大家在搞轮播图的时候会碰到这样的情况,点击进入webview界面,长按轮播图停止轮播,手松开图又开始轮播,这里就涉及到了OnTouch 和OnClick同时调用。两者是有冲突的。这里简单介绍,给大家提供思路。

  • 2018-08-20 15:29:11

    揭开RecyclerView的神秘面纱(二):处理RecyclerView的点击事件

    主要讲述了RecyclerView的基本使用方法,不同的布局管理器而造成的多样化展示方式,展示了数据之后,一般都会与用户进行交互,因此我们需要处理用户的点击事件。在ListView和GridView提供了onItemClickListener这个监听器,然而我们查找RecyclerView的API却没有类似的监听器,因此我们需要自己手动处理它的点击事件。 以下提供两种方法来实现处理RecyclerView点击事件的功能,以下代码均基于上一篇文章的代码做出修改。

  • 2018-08-20 22:58:46

    onInterceptTouchEvent和onTouchEvent调用关系详解 ...

    老实说,这两个小东东实在是太麻烦了,很不好懂,我自己那api文档都头晕,在网上找到很多资料,才知道是怎么回事,这里总结一下,记住这个原则就会很清楚了:

  • 2018-08-23 15:32:18

    map对象拷贝问题

    最后面是使用序列化的方式,发现,更改引用类型的数据的时候,mapNew对象并没有发生变化,所以产生了深拷贝。 上述的工具类,可以实现对象的深拷贝,不仅限于HashMap,前提是实现了Serlizeable接口。

  • 2018-08-24 11:33:17

    总结和分析几种判断 RecyclerView 到达底部的方法

    SwipeRefreshLayout 写一个 RecyclerView 的上下拉 ,里面有一个判断 RecyclerView 是否到达底部的方法 isBottom。我的同事用了这个上下拉之后发现有些小 bug,没考虑周全,譬如各个子项高度不统一的时候,然后我找到原因是因为这个判断上下拉的问题。所以,我就去网上查到几种判断 RecyclerView 到达底部的方法,发现各有千秋。以下的分析都以上一篇文章的 SwipeRecyclerView 为例

  • 2018-08-26 00:18:04

    RecyclerView 图片错位空白的问题

    1.图片错位的原因是因为图片异步记载返回去展示出的问题。图片空白,是item刷新,请求图片时间上的问题。 2。viewHolder.setIsRecyclable(false); 就没有tag,不设置 就有tag,但是有没有没啥区别 设置tag,

  • 2018-08-28 10:00:24

    laravel使用队列的简单步骤

    最近需要导入大量的excel文件,数量达到十万之多。 而我又不想修改服务器的超时时间,因为这样可能影响服务器的堵塞。 而php又没有很好的异步。 后来发现了令laravel最为骄傲的部分,队列。具体文档参考下方链接。