记一次在react项目中使用头像裁剪插件react-avatar-editor的经历

1,999 阅读3分钟

一、前言

为什么选择使用react-avatar-editor这个插件?

由于最近在使用React写移动端项目,其中有一个需求是做一个头像裁剪功能(可以本地选择图片裁剪,也可以拉取远程图片进行裁剪)。

于是风风火火的去GitHub找相关插件。按star量来找,找到如下几个插件。

image.png

那我为什么要使用react-avatar-editor?

1.先看官方介绍:

Facebook like, avatar / profile picture component. Resize, crop and rotate your uploaded image using a clear user interface.

2.为什么使用?

  • 体积够小(只有几百k啊!啊喂!)
  • 方便扩展
  • Issues少(😂只有一个1个issue啊!)
  • 支持移动端
  • 方便压缩

二、使用

安装

npm install --save react-avatar-editor

官方示列

image.png

import React from 'react'
import AvatarEditor from 'react-avatar-editor'

class MyEditor extends React.Component {
  render() {
    return (
      <AvatarEditor
        image="http://example.com/initialimage.jpg"
        width={250}
        height={250}
        border={50}
        color={[255, 255, 255, 0.6]} // RGBA
        scale={1.2}
        rotate={0}
      />
    )
  }
}

export default MyEditor

官方demo

Props

值得注意prop:

  • image image.png

  • crossOrigin image.png

这两个prop是我实现拉取远程图片进行裁剪的关键,其他prop只要照着官方说明传就基本没啥问题

我一开始是做完了本地选取图片裁剪,然后接图片上传接口就直接成功。但到我使用远程图片裁剪完调用canvas.toDataURL()时控制台给我了一个意向不到的错误。

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

???什么玩意???

image.png

大意就是

无法在“ HTMLCanvasElement”上执行“ toDataURL”:可能无法导出污染的画布。

此时我还不知道出了什么问题,于是我默默的去google, 一顿操作以后,得知了

由于在 <canvas> 位图中的像素可能来自多种来源,包括从其他主机检索的图像或视频,因此不可避免的会出现安全问题。

尽管不通过 CORS 就可以在 <canvas> 中使用其他来源的图片,但是这会污染画布,并且不再认为是安全的画布,这将可能在 <canvas> 检索数据过程中引发异常。

使用 "硬编码" 图片网址可以很方便的允许图片来自任何地址。当开始下载图片时,我们使用 Image() 构造器创建新的 HTMLImageElement 对象,将图片的 crossOrigin 属性设置为"匿名"(即,允许对未经过验证的图像进行跨域下载)。添加图片的 load (en-US)事件的监听来判断图片数据是否已接收。最后,将图片的 src (en-US)属性设置为图片的URL以触发图片下载。

image.png

原来如此! 前面不是有个crossOrigin属性吗?整上!

插件源码里面这样写的:

export default function loadImageURL(imageURL, crossOrigin) {
  return new Promise((resolve, reject) => {
    const image = new Image()
    image.onload = () => resolve(image)
    image.onerror = reject
    if (isDataURL(imageURL) === false && crossOrigin) {
      image.crossOrigin = crossOrigin
    }
    image.src = imageURL
  })
}

搞定!刷新!

image.png

为什么图片访问不了??????

image.png

于是我又去仔细看了一遍MDN的文档:启用了CORS的图片

原来还需要服务端配置。

<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        <FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
            SetEnvIf Origin ":" IS_CORS
            Header set Access-Control-Allow-Origin "*" env=IS_CORS
        </FilesMatch>
    </IfModule>
</IfModule>

三、思考与延展

图片裁剪的原理

这个时候其实我有点模糊了,于是我去查自己的资料库,想起张鑫旭大神在18年写过一篇文章《图片纯前端JS压缩的实现》 具体内容我就不在这里赘述了。 原理的大意是:

就是使用canvas的drawImage()方法。Canvas本质上就是一张位图,而drawImage()方法可以把一张大大的图片绘制在小小的Canvas画布上,等同于图片尺寸压缩了

如果想要上传/下载图片的话可以使用:

  • canvas.toDataURL() 转成base64
  • canvas.toBlob() 转成二进制文件

最后

第一次写,单纯记录,欢迎提出意见,欢迎讨论👏,勿喷。