前言
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攻击这种典型的跨站攻击,此时定义画布是被污染的,不能导出
Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported
-
尝试从根本上修改
<img>资源请求方式为跨域形式,不考虑同源,这样可以吗?浏览器
oImg.setAttribute('crossOrigin', 'Anonymous')
- 至此
污染问题结束,先告一段落,污染报错消失
此时浏览器又抛出新的问题
- 跨域报错
-
原来之前的操作
图片已经被浏览器缓存 -
当
<img crossOrigin>跨域资源请求时,先请求的浏览器缓存,但是缓存的图片根本就没有跨域配置 -
浏览器就直接判定跨域,请求都懒得发
-
设置随机参数,
强制跳过访问浏览器缓存直接访问服务器 这样肯定没有问题var img = new Image() img.crossOrigin = 'anonymous' img.src = '图片地址' + '?v=' + Math.random() img.onload = function () { // 绘图代码 } -
如果此时还报错,客户端的能做工作已经结束 -
检查服务端资源服务器基础设置,
否则无论怎么努力都是会显示跨域 -
以下以阿里云设置为例
跨域分享结束,最后一些解决思路,匹配其他场景
- 服务端设置资源请求方式是必然要做得
- 不要在 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')