【项目】前端图片裁剪
把工作中做过的一些小东西或者功能总结记录,分享学习
最近做了一个需求,是做视频封面裁剪的,涉及到的一个功能点是自动裁剪,就是拿到一张图片,自动裁剪图片的中间区域成 一个正方形
其实这个挺简单的,说到前端裁剪,无非就是使用 ,但是也避免不了会忘记其中的细节,所以要写文章记录一下
我就挑按顺序来详细记录一下
1、api 简单介绍
2、api 详细介绍
3、裁减中间区域
4、详细代码
1
api 简单介绍
没错,用的就是.这个api完成我们的截图功能,看起来好像没有涉及到什么复杂的东西
但是实际上也的确没有什么复杂的东西,只不过使用的时候会难以避免碰到一些坑而已
兼容性
.这个方法 的兼容性我们再来看一下,现在基本大部分浏览器已经兼容了,就除了IE6-8吧
但是据我们公司统计,IE的使用人数都几乎为0了
IE9 :0.0%
IE10:0.1%
IE11:0.1%
IE9都统计为0了,那以下的几乎就可以忽略不计了,所以大胆放心使用
成功率
如果你可能还是会有些不放心,心里总是好像没有什么底,不知道在别人电脑手机是否能正常展现
我们对这个功能也做了监控,截图的成功率高达99.5%!
所以我们大可以放心使用这个进行我们的前端截图
2
api 详细介绍
的参数还是挺多的,挺容易弄混的,所以这里必须要花大力气写清楚,反正每次用都是要看一次的
我也没想着能够一劳永逸
先来看下这个完整的 api(其实他的参数有很多个用法,这里只介绍我们这里截图用到的)
里面涉及的是图片的位置宽高,的位置宽高
这几个参数如果不仔细想一下的话,是有一点弄混的第一个参数,,就是Image生成的实例
后面四个参数,表示的就是图片的位置,宽高信息
以你的图片为底图,以imgX和imgY找到起始点,然后再以你想要的宽高裁出大小
比如这样一张图片,红色区域就是我们裁剪出来的地方
紧接着,最后四个参数,表示的就是画布的位置,宽高信息
为什么需要这四个参数?
在上面四个图片参数中,我们已经裁减出了我们需要的图片部分
我们要把图片放到 上,所以我们需要确定我们要放在哪里啊!!
第一,要知道放置的起点,所以有了,
第二,要知道绘制的大小(用于缩放)
虽然我们已经有了裁减出来的图片大小,但是我们也要确定该图片在上绘制多大
可以以此来完成缩放功能,如果你想原样绘制在上面,那么你就大小设置成裁减的大小就ok
步骤就相当于是
先裁减图片,然后再绘制到上
3
裁减中间区域
好了,上面我们介绍完了,就说这次我们的需求了,就是要裁减图片中间区域因为我们在用户上传图片做封面的时候,图片是用户上传的五花八门的图片
所以我们需要首先自动裁减成正方形做成封面,比如这样
如果是宽>高,那么就高占满
如果是高>宽,那么就宽占满
所以我们需要获取到以下这些数据
1、图片的原始宽高
2、裁减的图片位置
3、裁减的图片大小
首先拿到图片原始宽高,比较一下是更长还是更高照片视频怎么裁剪,从而确定裁减的大小
高>宽,裁减的宽高=图片的宽
宽>高,裁减的宽高=图片的高
知道了裁减的宽高之后,就可以知道裁减的起始位置
像这样
让我们看一下大概的代码
const image = new Image();
// 允许图片跨域,不然cavnas输出图片会报错
image.crossOrigin = "anonymous";
image.src = imgUrl;
image.onload = () => {
const imgWidth = image.naturalWidth;
const imgHeight = image.naturalHeight;
let cutWidth = 0;
let cutHeight = 0;
if (imgWidth > imgHeight) {
cutWidth = imgHeight;
cutHeight = imgHeight;
} else {
cutWidth = imgWidth;
cutHeight = imgWidth;
}
const y = (imgHeight - cutHeight) / 2;
const x = (imgWidth - cutWidth) / 2;
const canvas = document.createElement("canvas");
canvas.width = cutWidth;
canvas.height = cutHeight;
const ctx = canvas.getContext("2d");
// 绘制的大小就是 裁减的图片大小,
并且从左上角起始点开始绘制
ctx.drawImage(
image,
x, y,
cutWidth, cutHeight,
0, 0,
cutWidth, cutHeight
);
// 输出图片
const dataUrl = canvas.toDataURL("image/png");
console.log("裁减的结果", dataUrl);
};
碰到的问题
1、图片跨域问题
当我们使用导出图片的时候,如果图片对象没有设置可以跨域,那么就会报错
如果在新建Image对象的时候,如果加上跨域属性
image.crossOrigin = "anonymous";
有时候设置了属性还是一样会报错,可能是命中了缓存,所以我们最好还要在图片访问路径加一个时间戳
img.src = `xxxx?time=${Date.now()}`;
4
详细代码
但是实际使用中,需要处理更多的问题,并且要封装更加通用一些,我大概分了三个方法
,用来新建图片示例
,根据图片url和位置裁减出想要的区域
照片视频怎么裁剪,根据图片url和比例,裁减出中间区域
所以在这里我们只需要直接调用,传入一个url就可以了,就会返回裁剪好的
function imgUpload(url) {
const image = new Image();
image.crossOrigin = "anonymous";
return new Promise((resolve, reject) => {
const loaded = (event) => {
image.onload = null;
resolve(
Object.assign(event, {
naturalWidth: image.naturalWidth,
naturalHeight: image.naturalHeight,
imageObj: image,
})
);
};
const errored = (event) => {
image.onerror = null;
console.log("img 加载error", event);
reject(event);
};
image.onload = loaded;
image.onerror = errored;
image.onabort = errored;
// 如果路径是 base64 就不用加上时间戳,
如果是http,防止跨域报错所以加上 time
image.src =
url?.indexOf?.("data:image") > -1 ?
url :
`${url}?time=${Date.now()}`;
});
}
async function getImageCutArea(url, position) {
let imgInfo = await imgUpload(url);
const { imageObj } = imgInfo;
const { x, y, width, height } = position;
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
ctx.drawImage(
imageObj,
x, y, width, height,
0, 0, width, height
);
try {
const dataUrl = canvas.toDataURL("image/jpeg");
return Promise.resolve(dataUrl);
} catch (e) {
return Promise.reject(e);
}
}
async function getImageCenterArea(url, aspect = 1) {
const imgInfo = await imgUpload(url);
const { naturalWidth, naturalHeight } = imgInfo;
const imgHeight = naturalHeight;
const imgWidth = naturalWidth;
const imgRatio = imgWidth / imgHeight;
const isImgMoreHigh = imgRatio < aspect;
let width = 0;
let height = 0;
// 如果图片更高,那么默认宽度100%占满。
否则宽度就是 以 aspect 为准占满高度后的 适配宽度
if (isImgMoreHigh) {
width = imgWidth;
height = imgWidth / aspect;
} else if (!isImgMoreHigh) {
height = imgHeight;
width = imgHeight * aspect;
}
const y = (imgHeight - height) / 2;
const x = (imgWidth - width) / 2;
const result = await getImageCutArea(imgInfo, {
x,
y,
width,
height,
});
return result;
}
最后
鉴于本人能力有限,难免会有疏漏错误的地方,请大家多多包涵, 如果有任何描述不当的地方,欢迎后台联系本人,领取红包
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。