随着 html5 canvas 的 api支持,我们现在可以轻松的对图片进行一些处理,比如图片的放大,缩小,图片的裁剪和旋转。因为它可以接触到像素级别的操作,进行更加复杂的操作。
在 canvas 中绘制一张图片 只需要利用到 drawImage 这个方法就可以实现。
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
drawImage 它可以接受九个参数(不一定全部传入)
image: 它可以是一个 图片的 Image 元素,或者 Video ,Canvas 元素。
dx 表示在画布 x 轴的坐标值
dy 表示在画布 y 轴的坐标值
dWidth 表示在画布绘制的长度
dHeight 表示在画布绘制的高度
sx 表示在画布所绘制图片本身的 x轴 距离
sy 表示在画布所绘制图片本身的 y轴 距离
sWidth 表示所绘制图片的宽度范围,一般默认是图片的完整大小,你也可以将图片的某一部分开始绘制。
sHeight 表示所绘制图片的高度范围,一般默认是图片的完整大小,你也可以将图片的某一部分开始绘制。
一般我们实现 canvas 裁剪图片的就是利用这个方法, 来实现对于图片某些区域的裁剪。可以参考 crop方法。
实现旋转图片我们需要使用 rotate 方法,然后传图响应的角度即可。
rotate 只支持传入角度的参数 angle ,它表示传入的弧度值,比如我们如果需要选择90度,我们需要将其转换为弧度值
const angle = 90 * Math.PI / 180;
ctx.rotate(angle);
旋转的角度参考坐标顶点是canvas 的笛卡尔坐标系的原点,如果你需要改变选择的角度参考坐标原点的话,你可以使用 translate 进行画布平移。
我们先列举较为常见的使用场景,就是 90度的递增旋转(0,90,180,270)这种情况。
当然0度的时候,非常好理解,就是简单的图片绘制在画布上。
这是绘制的 开始坐标点 (0,0)。
再看下面的图,简单的顺时针旋转90度后的情况:
旋转90度的情况,坐标轴会进行旋转,这个时候如果我们还是按照 (0,0) 进行绘制,图片的情况如图蓝色区域,这个时候我们需要进行初始也就是(dx, dy)的设置,这个时候需要从(0, -h) 开始进行绘制。
如果是旋转180度的话,效果如下:
这个时候我们需要将起点平移到(-w, -h) 开始。
同理,如果逆时针旋转90度后的效果如下:
这个时候需要我们在绘制图片的时候将起点移动到(0, -h)即可。
函数实现如下:
/**
* compress image
* reference https://github.com/brunobar79/J-I-C
**/
export default {
// .... some other methods
_getImageType(str) {
let mimeType = 'image/jpeg';
const outputType = str.match(/(image\/[\w]+)\.*/)[0];
if (typeof outputType !== 'undefined'){
mimeType = outputType;
}
return mimeType;
},
rotate(src, degrees, callback) {
this._loadImage(src, (image) => {
let w = image.naturalWidth;
let h = image.naturalHeight;
const canvasWidth = Math.max(w, h);
let cvs = this._getCanvas(w, h);
let ctx = cvs.getContext('2d');
ctx.save();
let x = 0;
degrees %= 360;
if (degrees === 0) {
return callback(src, w, h);
}
let y = 0;
if ((degrees % 180) !== 0) {
if (degrees === -90 || degrees === 270) {
x = -h;
} else {
y = -w;
}
const c = w;
w = h;
h = c;
cvs.width = w;
cvs.height = h;
} else {
x = -w;
y = -h;
}
ctx.rotate(degrees * (Math.PI / 180));
ctx.drawImage(image, x, y);
ctx.restore();
const mimeType = this._getImageType(image.src);
const data = cvs.toDataURL(mimeType, 1);
callback(data, w, h);
cvs = null;
ctx = null;
});
},
_loadImage(data, callback) {
const image = new Image();
image.src = data;
image.onload = function () {
callback(image);
};
image.onerror = function () {
console.log('Error: image error!');
};
},
_getCanvas(width, height) {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
},
};
但是上面的实现会存在一个问题,就是你需要去改变画布的范围,应为大多数图片长宽高都是不一致的,因此在旋转后 canvas 能够重合旋转的图片的趋于。
比如上图旋转90后,你会发现
旋转后画布的坐标范围是覆盖不了图像的。
我们可以在初始化的时候,将画布设置为一个最大正方形。
const canvasWidth = Math.max(w, h);
const cvs = this._getCanvas(canvasWidth, canvasWidth);
const ctx = cvs.getContext('2d');
这个时候我们的 canvas 的大小无论怎么旋转都能够确保角度的覆盖。这个时候我们在试着将旋转的中心移到画布的中心开始。
ctx.translate(canvasWidth / 2, canvasWidth / 2);
这个时候如果旋转90度整个坐标系效果如图:
图中情况是 图片宽度小于高度,因此画布大小为 h x h
这个时候我们在绘制图片的起点就应该变成了(- h/2, h/2 - h ) 才能保证所绘制的图片位置能够完全放在画布顶部(放在顶部有利于我们使用另外一个canvas 进行多余空白的裁剪)。
x = - canvasWidth/2;
y = canvasWidth/2 - h;
同理我们可以通过平移算法获得在180度的情况下我们的绘制其实坐标。
这个时候我们的绘制坐标起点会是(-h/2 - h, h/2 - w)这个是后我们的代码可以是这样:
x = canvasWidth / 2 - h;
y = canvasWidth / 2 - w;
如果旋转270度的坐标系便是这样:
这个时候我们的坐标起点便是(-2/h, h/2 - w);
x = -canvasWidth / 2;
y = canvasWidth / 2 - w;
这个时候我们在旋转的图片的时候输出的 canvas 还是 h x h 的宽度大小,效果类似下面:
不过之前我们说过 drawImage 可以实现图片的裁剪,我们只需生成一个新的画布,然后进行裁剪并进行数据输出
var cvs2 = _this._getCanvas(w, h);
var ctx2 = cvs2.getContext('2d');
ctx2.drawImage(cvs, 0, 0, w, h, 0, 0, w, h);
var mimeType = _this._getImageType(image.src);
var data = cvs2.toDataURL(mimeType, 1);
虽然日常需求90度的比较多,但是这个还未结束,下一篇写支持任意角度的图片旋转,并且进行最小面积切割。
原文来自:JackPu
声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com
涉农贷款地址识别,支持对私和对公两种方式。输入地址的行政区划越完整,识别准确度越高。
根据给定的手机号、姓名、身份证、人像图片核验是否一致
通过企业关键词查询企业涉讼详情,如裁判文书、开庭公告、执行公告、失信公告、案件流程等等。
IP反查域名是通过IP查询相关联的域名信息的功能,它提供IP地址历史上绑定过的域名信息。
结合权威身份认证的精准人脸风险查询服务,提升人脸应用及身份认证生态的安全性。人脸风险情报库,覆盖范围广、准确性高,数据权威可靠。