把工作中做过的一些小东西或者功能总结记录,分享学习

最近做了一个需求,是做视频封面裁剪的,涉及到的一个功能点是自动裁剪,就是拿到一张图片,自动裁剪图片的中间区域成 一个正方形

其实这个挺简单的,说到前端裁剪,无非就是使用 ,但是也避免不了会忘记其中的细节,所以要写文章记录一下

我就挑按顺序来详细记录一下

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;

}

最后

鉴于本人能力有限,难免会有疏漏错误的地方,请大家多多包涵, 如果有任何描述不当的地方,欢迎后台联系本人,领取红包