IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    详解fabric.js图片跨域

    秦少卫发表于 2024-04-10 13:57:28
    love 0

    大家好,我是vue-fabric-editor开源图片编辑器项目的作者,很多开发者都会问我图片跨域的问题如何处理,今天就详细的跟大家分享一下fabric.js图片跨域怎么处理。

    问题现象

    会报两种错误,要么保存新图片时报错,要么插入图片时报错:

    1. 图片插入到画布成功了,画布保存新图片时报错。
    2. 图片无法插入到画布,直接提示CORS报错。

    image.png

    image-1.png

    先说结论:必须后端设置跨域,然后前端也设置跨越,才能正常将图片插入画布,并保存为新图片。

    跨域的设置

    跨域区分前端跨域与后端跨域设置,我通过http-server模拟跨域,8080下的HTML文件 访问8081的图片,测试视频,得出如下结果:

    1. 都不设置跨域:渲染正常,保存不正常。
    2. 仅前端设置跨域:渲染不正常。
    3. 仅后端设置跨域:渲染正常,保存不正常。
    4. 前后端均设置跨域:渲染正常,保存正常。

      4种插入图片的方式

      fabric.js 提供了多种插入图片的方式,主要流程都是将原生的Img对象转换成fabric.Image对象,然后插入到画布中。

    5. fabric.Image.fromURL:通过回调直接返回fabric的img对象,直接插入到画布中。
    6. fabric.util.loadImage:通过回调返回原生img对象,转换为fabric对象后插入画布中。
    7. new Image() 与 document.createElement('img'):创建原生img对象,转换为fabric对象后插入画布中。
    8. <img />:将页面中的img元素,通过选择器获取到原生img对象,转换为fabric对象后插入画布中。

      // 1. 通过fabric.Image.fromURL插入图片
      function addImgByUrl(url) {
       fabric.Image.fromURL(
           url,
           (imgEl) => {
           imgEl.set({
               left: 100,
               top: 100,
           });
           // 设置缩放
           canvas.add(imgEl);
           canvas.setActiveObject(imgEl);
           canvas.renderAll();
           },
           { crossOrigin: 'anonymous' }
       );
      }
      // 2. fabric.util.loadImage
      function addImgByUtils(url) {
       fabric.util.loadImage(url, function(catImg) {
           const mycatImg = new fabric.Image(catImg)
           mycatImg.set({ left: 180, top: 180, });
           canvas.add(mycatImg);
           canvas.setActiveObject(mycatImg);
           canvas.renderAll();
        }, null, {crossOrigin: 'Anonymous'});
      }
      
      // 3. new Image() 与 document.createElement('img')是等价的方式
      // MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLImageElement/Image
      function addImgByNewImage(url) {
       const image = new Image()
       image.setAttribute('crossOrigin', 'anonymous')
       image.onload = function () {
           fabricImage = new fabric.Image(image)
           fabricImage.set({ left: 150, top: 150, });
           canvas.add(fabricImage);
           canvas.setActiveObject(fabricImage);
           canvas.renderAll();
       }
       image.src = url
      }
      function addImgByCreateTag(url) {
       const tagImg = document.createElement('img')
       tagImg.crossOrigin = 'anonymous'
       tagImg.src = url
       // 等待图片加载完
       tagImg.onload = function() {
           const myTagImg = new fabric.Image(tagImg)
           myTagImg.set({ left: 190, top: 190, });
           canvas.add(myTagImg);
           canvas.setActiveObject(myTagImg);
           canvas.renderAll();
       }
      }
      
      // 4.<img />
      // <img id="imgTag" src="http://127.0.0.1:8081/1.png" crossorigin="anonymous" alt="">
      function addImgByTag() {
       const catImg = document.getElementById('imgTag')
       // 等待图片加载完
       catImg.onload = function() {
           const mycatImg = new fabric.Image(catImg)
           mycatImg.set({ left: 190, top: 190, });
           canvas.add(mycatImg);
           canvas.setActiveObject(mycatImg);
           canvas.renderAll();
       }
      }

    源码实现

    源码中原生Img对象与fabric.Image对象的关系

    • new fabric.Image() 只接收原生image对象。

    image-2.png

    • fabric.Image.fromURL(url) 等于 fabric.util.loadImage + new fabric.Image,在源码内部实现了转换的操作。

    image-3.png

    • fabric.util.loadImage() 等于 fabric.util.createImage = document.createElement('img'),等同于手动创建原生img对象。

    image-4.png

    image-5.png

    image-6.png

    其他

    vue-fabric-editor开源图片编辑器项目



沪ICP备19023445号-2号
友情链接