Canvas图片处理

前言

图片处理 在前端业务中并不陌生。例如手机自带相机拍出的照片通常好几兆,但如果只是用作头像就显然太大,需要 图片压缩 后再上传服务器;再例如前段时间比较火的迎国庆换头像,就用到了 图片与图片的合成。本文将介绍前端常见的 Canvas 图片处理方法。

日常用到的图片处理方式都有哪些

前端日常业务的图片处理大概分为以下几种:

  • 图片缩放
  • 图片剪裁
  • 图片与图片的合成
  • 图片插入画笔(手写签名)
  • 图片插入文字

图片缩放图片剪裁图片与图片的合成 主要用了 drawImage 方法;
图片插入画笔 主要用了 Canvas-路径;
图片插入文字 主要用了 fillText 方法。

图片处理相关的 Canvas 技术

CanvasRenderingContext2D.drawImage()

在画布上绘制图像、画布或视频。

void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
参数 描述
image 规定要使用的图像、画布或视频。
sx 可选。开始剪切的 x 坐标位置。
sy 可选。开始剪切的 y 坐标位置。
sWidth 可选。被剪切图像的宽度
sHeight 可选。被剪切图像的高度。
dx 在画布上放置图像的 x 坐标位置。
dy 在画布上放置图像的 y 坐标位置。
dWidth 可选。要使用的图像的宽度。(伸展或缩小图像)
dHeight 可选。要使用的图像的高度。(伸展或缩小图像)

CanvasRenderingContext2D.fillText()

fillText() 方法在画布上绘制填色的文本。文本的默认颜色是黑色。

void ctx.fillText(text, x, y [, maxWidth]);
参数 描述
text 规定在画布上输出的文本。
x 开始绘制文本的 x 坐标位置(相对于画布)。
y 开始绘制文本的 y 坐标位置(相对于画布)。
maxWidth 可选。允许的最大文本宽度,以像素计。

技术点讲解

图片缩放

void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

sx, sy, dx, dy 设置为 0;
sWidth, sHeight 设置为图片宽长;
dWidth, dHeight 设置为画布宽长;
等比例图片缩放:根据 image 的长宽,等比例调成画布的长宽;
不等比图片例缩放:任意的调整画布的长宽;

图片剪裁

void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

sx, sy, sWidth, sHeight 取其中一部分填充到画布上。

图片与图片的合成

使用多次drawImage会把多张图片绘制到一张画布。

注意: 因为本地图片和用户图片和成会有跨域问题 所以需要添加属性 crossOrigin 为 anonymous

图片插入画笔(手写签名)

利用鼠标事件操纵 Canvas 画出路线。

  1. ctx.beginPath(); // 开始
  2. ctx.moveTo(e.offsetX, e.offsetY); // 设置起点
  3. ctx.lineTo(e.offsetX, e.offsetY); // 移动到当前点
  4. ctx.stroke(); // 绘制
  5. ctx.closePath(); // 结束

事件流程:

  • mousedown 执行 1 2;
  • mousemove 执行 3 4;
  • mouseout 或 mouseup 时移除 mousemove,执行 5。

图片插入文字

void ctx.fillText(text, x, y [, maxWidth]);
var canvas = document.createElement('canvas');
canvas.width = uploadImg.width;
canvas.height = uploadImg.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(uploadImg, 0, 0, canvas.width, canvas.height);  // 图片画进画布
ctx.fillStyle = "#f00"; // 设置字体颜色
ctx.font = "14px Arial";  // 设置字体大小,字体样式
ctx.fillText("我是一段文字", 10, 10);  // 插入

实战栗子

迎国庆换头像

是将用户上传的图片和本地头像框子图片合成,用到了图片缩放,图片剪裁,图片和图片的合成。

在线演示Github地址

实现思路是

  1. 新建画布;
  2. new Image() 把头像框图片处理到缓存;
  3. 用户上传头像,用 FileReader 读出图片资源,然后用 new Image() 放至缓存;
  4. 计算用户上传头像的中间区域, 计算坐标和长宽(取正方形);
  5. 将 用户头像 Image 用 drawImage 绘制到画布(用算好的坐标取中间区域正方形);
  6. 将 头像框 Image 用 drawImage 绘制到画布;
  7. 把画布导出为图片。

头像框图片:

var imgFrame = new Image();  // 头像框图
imgFrame.setAttribute("crossOrigin", 'anonymous');
imgFrame.src = imgTopPathList[imgTopPathIndex];

用户上传图片:

// 用户上传图
var img = new Image();
// 读文件
var reader = new FileReader();
reader.onload = function (event) {
    img.src = event.target.result;
}
// input onchange
input.onchange = function (event) {
    reader.readAsDataURL(event.target.files[0]);
}

计算中间区域坐标(取最大中间区域):

var iw = img.width;   // 用户上传图片宽
var ih = img.height;  // 用户上传图片高
if (!iw || !ih) return;
var r = w / h;        // 目标图片宽高比

// 计算裁剪
var sx, sy, sWidth, sHeight;
if (iw / ih > r) {
sHeight = ih;
sWidth = sHeight * r;
} else {
sWidth = iw;
sHeight = sWidth / r;
}
sx = (iw - sWidth) / 2;
sy = (ih - sHeight) / 2;

合成:

const [w, h, s] = [150, 150, 3];  // 生成图片宽,  生成图片高,  生成图片放大倍数

var canvas = document.createElement('canvas');
canvas.width = w * s;
canvas.height = h * s;
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#ffffff';  // canvas 背景颜色
ctx.drawImage(img, sx, sy, sWidth, sHeight, 0, 0, w * s, h * s);  // canvas添加用户图
ctx.drawImage(imgTop, 0, 0, w * s, h * s);  // canvas添加头像框图

var src = canvas.toDataURL("image/png");
// src 拿到的就是合成图片的url

图片添加文字

上传图片,输入文字,可调整文字大小、样式、颜色、坐标。

在线演示; Github地址

图片编辑

模仿微信截图,上传图片后,可在图片上插入矩形(开发中)、插入画笔、插入文字。

在线演示; Github地址

whosmeya.

原文地址:https://www.cnblogs.com/whosmeya/p/12557598.html