FabricJS:使用 Image 子类时无法执行“drawImage”

Posted

技术标签:

【中文标题】FabricJS:使用 Image 子类时无法执行“drawImage”【英文标题】:FabricJS: Failed to execute 'drawImage' when using an Image subclass 【发布时间】:2021-03-14 15:45:35 【问题描述】:

对于一个项目,我需要将各种类型的图像添加到画布,保存到 JSON 并再次加载。不同的类型没有任何特定的属性,我只需要类型不同。

我创建了一个基于 fabric.Image 的新类,如下所示:

fabric.Icon = fabric.util.createClass(fabric.Image, 
      type: "icon",
      initialize: function (element, options) 
        this.callSuper("initialize", element, options);
      ,
      _render: function (ctx) 
        this.callSuper("_render", ctx);
      ,
    );
    fabric.Icon.fromObject = function (object, callback) 
      return fabric.Object._fromObject("Icon", object, callback);
    ;

在此之后,我使用 SVG 图像添加这种新类型的新对象:

let newImage = new Image();    //html Image type, not FabricJS
newImage.onload = () => 
   let icon = new fabric.Icon(newImage);   //my subclass of fabric.Image class
   this.canvas.add(icon);
;
newImage.src = "image.svg";

当我将画布导出为 JSON 时

let savedJSON = canvas.toJSON()

并将其加载回来

canvas.loadFromJSON(savedJSON, function () 
    canvas.requestRenderAll();

我收到以下错误

未捕获的类型错误:无法在“CanvasRenderingContext2D”上执行“drawImage”:提供的值不是类型“(CSSImageValue 或 HTMLImageElement 或 SVGImageElement 或 HTMLVideoElement 或 HTMLCanvasElement 或 ImageBitmap 或 OffscreenCanvas)”

当我使用标准的 fabric.Image 类时,一切正常。我应该覆盖我的子类中的其他方法吗?还是应该以其他方式区分各种图像类型?

【问题讨论】:

【参考方案1】:

好吧,这并不是真正解决这个问题的方法,但我找到了区分保存和加载过程中持续存在的对象的正确方法 - 通过覆盖其 toObject 方法来设置 Object.prototype 上的自定义属性,如下所示: Fabric js extending toObject with custom properties, loses default ones 问题解决了!

【讨论】:

【参考方案2】:

fabric Image 类有一个稍微复杂的恢复机制,因为它需要在构造函数中有一个不可序列化的图像元素。

这是在fabricJS中的实现方式:

  /**
   * Creates an instance of fabric.Image from its object representation
   * @static
   * @param Object object Object to create an instance from
   * @param Function callback Callback to invoke when an image instance is created
   */
  fabric.Image.fromObject = function(_object, callback) 
    var object = fabric.util.object.clone(_object);
    fabric.util.loadImage(object.src, function(img, isError) 
      if (isError) 
        callback && callback(null, true);
        return;
      
      fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) 
        object.filters = filters || [];
        fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) 
          object.resizeFilter = resizeFilters[0];
          fabric.util.enlivenObjects([object.clipPath], function(enlivedProps) 
            object.clipPath = enlivedProps[0];
            var image = new fabric.Image(img, object);
            callback(image, false);
          );
        );
      );
    , null, object.crossOrigin);
  ;

恐怕你必须复制它并将fabric.Image与fabric.Icon交换

【讨论】:

感谢您的回复,最终我不需要这样做,因为我找到了使用另一个自定义属性来区分对象的正确方法。

以上是关于FabricJS:使用 Image 子类时无法执行“drawImage”的主要内容,如果未能解决你的问题,请参考以下文章

FabricJS - 从 JSON 加载 Canvas 时出错

关闭 fabricjs 图像对象的缓存

无法将 FabricJS svg 或组对象移动到画布左上角

在 FabricJS 中转换视口时边界对象错误,单击对象时用户无法选择对象

将fabricjs画布转换为base64图像

角度的FabricJS自定义过滤器