记一次修复移动端html2canvas加载图片失败

起因

事情的起因要从一个优化说起,项目要优化访问速度于是转而启用了阿里服务器。访问域名与静态资源域名不同。这导致html2canvas在请求图片资源时出现跨域的情况。当然官方文档也给出了相应的解决办法:

js 复制代码
html2canvas(selector, {useCORS: true // 跨域请求资源})
.then((canvas) => {
   ...});

当然移动端对于上述的方案也给出了新的问题

是的就是直接报错。这种情况在chrome上不会出现。安卓和ios环境下图片就会加载失败。img标签的 crossOrigin属性、路径加时间戳破除缓存等方法都不奏效。

初步的解决方案

因为看到页面内有些base64的图片可以完好的被转换出来。所以突发奇想既然插件请求不行。不如我就给他把图片都转成base64。 当然是借助canvas:

js 复制代码
let url = ''
const image = new Image()
image.onload = () => {
    const canvas = document.createElement('canvas')        
    const ctx = canvas.getContext('2d')             
    ctx.drawImage( image, 0, 0 )       
    url = canvas.toDataURL('image/png', 1)    }    
    image.crossOrigin = 'anonymous' // 跨域请求资源   
    image.src = xxx //图片地址
}

优化的版本

上述方法成功将图片转为base64格式,但是转出来的图片比例严重变形。是因为canvas有默认宽高。找到原因便很好的就可以解决了。我们可以设置canvas的宽高为图片元素的宽高。同时为了解决清晰度问题还添加了如下代码:

js 复制代码
const el = document.querySelector(selector)
const h = el.clientHeight
const w = el.clientWidth
image.onload = () => {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    const ratio =
          (window.devicePixelRatio || 1) /
          (ctx.backingStorePixelRatio ||
            ctx.webkitBackingStorePixelRatio ||
            ctx.mozBackingStorePixelRatio ||
            ctx.msBackingStorePixelRatio ||
            ctx.oBackingStorePixelRatio ||
            ctx.backingStorePixelRatio ||
            1)
            
    canvas.width = w * ratio        
    canvas.height = h * ratio

    ctx.drawImage(image, 0, 0, h * ratio, w * ratio) 
    url = canvas.toDataURL('image/png', 1)
}

新的问题

chrome测试完美,安卓浏览器测试也没问题,当我认为这样问题就完美解决了的时候。在safari那html2canvas甩给我一个新的报错

arduino 复制代码
RangeError: Maximum call stack size exceeded

于是去GitHub上找到了对应的issue,这个类似的问题在mac的浏览器上报过。页面中如果有太多base64图片时,会导致这个错误。我这边将常量SLICE_STACK_SIZE修改为3000可以避免这个报错。

相关推荐
11054654019 分钟前
37、需求预测与库存优化 (快消品) - /供应链管理组件/fmcg-inventory-optimization
前端·信息可视化·数据分析·js
nunumaymax32 分钟前
在图片没有加载完成时设置默认图片
前端
OEC小胖胖1 小时前
【React 设计模式】受控与非受控:解构 React 组件设计的核心模式
前端·react.js·设计模式·前端框架·web
你怎么知道我是队长1 小时前
C语言---编译的最小单位---令牌(Token)
java·c语言·前端
一枚前端小能手2 小时前
🔥 Vue状态管理越写越乱,Pinia拯救了我
前端
cloudcruiser2 小时前
Apache HTTP Server:深入探索Web世界的磐石基石!!!
前端·其他·http·apache
一个专注api接口开发的小白2 小时前
手把手教程:使用 Postman 测试与调试淘宝商品详情 API
前端·数据挖掘·api
织_网3 小时前
Electron 核心 API 全解析:从基础到实战场景
前端·javascript·electron
vvilkim3 小时前
深入理解 Spring Boot Starter:简化依赖管理与自动配置的利器
java·前端·spring boot
艾小码3 小时前
前端安全防护手册:对抗XSS、CSRF、点击劫持等攻击
前端·安全·xss