图片canvas编辑,截图,裁剪,生成图片,跨域绘图模糊, 高斯模糊,解决方案

615 阅读2分钟

前言

Canvas转图片操作,比如截取,裁剪,合成图片,等一系列操作必踩坑解析

跨域问题


  • 当你想用canva操作图片,在将结果转base64进行渲染时,由于图片地址与页面不同源时
 const myCan = document.createElement('.my-canvas')
 const context = canvas1.getContext('2d')
 const oImg = new Image()
 oImg.src = 'https://xxxx.png'
 hrame.onload = () => {
  context.drawImage(oImg, 0, 0, myCan.width, myCan.height)
  // 生成base64位链接对img src 进行赋值
  console.log(myCan.toDataURL('image/png'))
}
画布被污染篇
  • 当调用toDataURL('image/png')转Base64进行导出时, 浏览器会抛出,画布被污染无法导出

  • 大白话本因为导出canvas绘制的图片地址与当前页面不同源

  • 为防止类似XSS/CSRF攻击这种典型的跨站攻击,此时定义画布是被污染的,不能导出

    5Yya0zJfGQ.jpg Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported

  • 尝试从根本上修改 <img> 资源请求方式为跨域形式,不考虑同源,这样可以吗?浏览器

oImg.setAttribute('crossOrigin', 'Anonymous')

L5nOjFNKoe.jpg

  • 至此污染问题结束,先告一段落,污染报错消失
此时浏览器又抛出新的问题
  • 跨域报错

37bce2d14530672a550507d4a737111.png

  • 原来之前的操作图片已经被浏览器缓存

  • <img crossOrigin>跨域资源请求时,先请求的浏览器缓存,但是缓存的图片根本就没有跨域配置

  • 浏览器就直接判定跨域,请求都懒得发

  • 设置随机参数,强制跳过访问浏览器缓存直接访问服务器 这样肯定没有问题

    var img = new Image()
    img.crossOrigin = 'anonymous' 
    img.src = '图片地址' + '?v=' + Math.random()
    img.onload = function () {
      // 绘图代码
    }
    
  • 如果此时还报错,客户端的能做工作已经结束

  • 检查服务端资源服务器基础设置,否则无论怎么努力都是会显示跨域

  • 以下以阿里云设置为例

image.png

跨域分享结束,最后一些解决思路,匹配其他场景
  • 服务端设置资源请求方式是必然要做得
  • 不要在 http://localhost:9528 本地域名开发会导致 出现跨域 使用 ip 192.xxx.xxx.xxx:9528
  • 直接将图片资源转成Base64类型,在进行后续操作,避免跨域问题
  • IE10浏览器不支持CORS解决方案,使用ajax防止,设置返回类型为二进制类型
    xhr.responseType = 'blob';
    

高斯模糊效果

  • 在网看了很多方案,表示比较复杂,如果只是图片处理使用这个方案

context1.filter = "blur(5px)";

canvas 渲染图片,比原图模糊问题处理


    const getPixelRatio = (context) => {
      var backingStore =
          context.FD ||
          context.webkitBackingStorePixelRatio ||
          context.mozBackingStorePixelRatio ||
          context.msBackingStorePixelRatio ||
          context.oBackingStorePixelRatio ||
          context.backingStorePixelRatio ||
          1
          /* 
          window.devicePixelRatio告诉浏览器需要多少物理像素来绘制一个 CSS 像素。
          这个属性可以用来区分视网膜设备和非视网膜设备。
          */
      return (window.devicePixelRatio || 1) / backingStore
    }
    const ratio = getPixelRatio()
    canvas.width = options.w * ratio 
    canvas.height = options.h * ratio
    context.drawImage(img, 0, 0, options.w * ratio, options.h * ratio)

截图操作


// canvas1 先画出图片
const canvas1 = document.createElement('canvas')
const context1 = canvas.getContext('2d')
context1.drawImage(img, 0, 0, options.w, options.h)


// canvas2 在canavs1截取
const canvas2 = document.createElement('canvas')
const context2 = canvas.getContext('2d')
// 获取信息
const data = clip.drawCanvasCtx.getImageData(x, y, options.sw, options.sh)
context.putImageData(data, 0, 0)
// 转 base64
canvas.toDataURL('image/png')