【问题标题】:Unable to render TIFF images and add it as a Fabric Object无法渲染 TIFF 图像并将其添加为 Fabric 对象
【发布时间】:2020-02-01 05:36:27
【问题描述】:

我已阅读教程:http://fabricjs.com/articles 和有关 Fabric Objects 的文档。

我能够加载 JPG 和 PNG 图像,但在我的项目中,我需要将 TIFF 图像加载到画布上并能够在其上应用过滤器。我可以使用画布上下文渲染 TIFF 图像,但是每当调用“renderAll()”时,它都会清除上下文并清除我的 TIFF 图像。由于无法渲染,我也无法执行缩放、平移、亮度和对比度等其他操作。

谁能帮我了解如何将 TIFF 图像转换为 Fabric 对象,以便我可以对其执行所有标准的 fabric.Object 相关操作。

这是我遵循的步骤:

  1. 要加载模拟 TIFF 图像,我将其作为数组缓冲区读取。

    public loadMockTiffImage() {
    // Create a new XMLHttpRequest object to read the mock TIFF image as ArrayBuffer
    const xhr = new XMLHttpRequest();
    
    // Configure it: GET-request for the URL
    xhr.open('GET', 'assets/tif/sample.tif', true);
    xhr.responseType = 'arraybuffer';
    xhr.timeout = 10000; // timeout in ms, 10 seconds
    
    // Send the request over the network
    xhr.send();
    
    // After the response is received, load it
    xhr.onload = () => {
      // analyze HTTP status of the response
      if (xhr.status !== 200) {
        // throw error incase status is not 200
        console.log(`Error ${xhr.status}: ${xhr.statusText}`);
      } else {
        // Show the result
        console.log(`Done, got ${xhr.response.byteLength} bytes`);
        console.log(xhr.response);
        // Add to canvas the XHR response which is of type ArrayBuffer
        this.addTiffImageOnCanvas(xhr.response);
      }
    };
    
    // Show progress of loading the bytes
    xhr.onprogress = event => {
      if (event.lengthComputable) {
        console.log(`Received ${event.loaded} of ${event.total} bytes`);
      } else {
        console.log(`Received ${event.loaded} bytes`); // no Content-Length
      }
    };
    
    // Log any network request errors
    xhr.onerror = () => {
      console.log('Request failed!');
    };
    }
    
  2. 接下来我使用 UTIF.js 解码 ArrayBuffer 并将其转换为 ImageBitmap,以便我可以使用 canvas.drawImage() 在画布上呈现它。 如何将此 ImageBitmap/ArrayBuffer 转换为 FabricJS 对象?

    private addTiffImageOnCanvas(buffer: ArrayBuffer) {
    // Using UTIF.js to decode the array buffer and convert it to ImageBitmap
    const ifds = UTIF.decode(buffer);
    UTIF.decodeImage(buffer, ifds[0]);
    const timage = ifds[0];
    const array = new Uint8ClampedArray(UTIF.toRGBA8(timage));
    // Forming image Data
    const imageData = new ImageData(array, timage.width, timage.height);
    let ibm: ImageBitmap = null;
    const bmPromise: Promise<ImageBitmap> = createImageBitmap(imageData);
    
    bmPromise.then(bitmap => {
      ibm = bitmap;
      fabric.Image.fromObject(ibm, image => {
         // TODO: How or What should I do now?
      });
    });
    

    }

感谢您的帮助。

【问题讨论】:

标签: javascript typescript fabricjs tiff


【解决方案1】:

我在 fabric 的 github 存储库中没有发现任何能够处理 ImageBitmap 的内容。

但是,您可以很好地从 HTMLCanvasElement 创建 Fabric.Image。 所以你必须在画布上绘制这个 ImageBitmap,如果我们仍然要使用画布,最好在上一步得到 ImageData 时这样做:

var scene = new fabric.Canvas('fabric');
scene.setHeight(500);
scene.setWidth(500);

fetch( "https://upload.wikimedia.org/wikipedia/commons/d/d8/Example.tiff" )
  .then( (resp) => resp.arrayBuffer() )
  .then( makeFabricImageFromTiff )
  .then( (fabricImage) => scene.add( fabricImage ) );

function makeFabricImageFromTiff( buffer ) {
  // Using UTIF.js to decode the array buffer and convert it to ImageData
  const ifds = UTIF.decode( buffer );
  UTIF.decodeImage( buffer, ifds[ 0 ] );
  const timage = ifds[ 0 ];
  const array = new Uint8ClampedArray( UTIF.toRGBA8( timage ) );
  // Forming image Data
  const imageData = new ImageData( array, timage.width, timage.height );
  // a temporary canvas element
  const canvas = document.createElement( 'canvas' );
  canvas.width = timage.width;
  canvas.height = timage.height;
  // on which we draw the ImageData
  canvas.getContext( '2d' )
    .putImageData( imageData, 0, 0 );
  // before converting it to a Fabric.Image instance
  return new fabric.Image( canvas, { left: 50, top: 50 } );
}
canvas { border: 1px solid; }
<script src="https://cdn.jsdelivr.net/gh/photopea/UTIF.js/UTIF.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.4/fabric.min.js"></script>
<canvas id="fabric"></canvas>

【讨论】:

  • 非常感谢!所以它在我们有 putImageData 的 2d 上下文中工作得很好,但是当我将它与 webgl 一起使用时,我应该使用 drawPixels 吗?使用 webgl 时的替代方案是什么?
  • 你为什么要在这里使用 webgl?您将在此画布上执行的唯一操作是将 ImageData 放在其上。 2d 上下文将与 webgl 一样快,甚至更快(webgl 上下文的初始化往往更慢)。
  • 我有 8MB TIFF 图像要在画布上渲染。在某些情况下,我将在同一画布上渲染多个(最多 9 个)TIFF 图像,不同的不透明度相互叠加。我对 webgl 的要求是弄清楚 2d 和 webgl 实现之间是否存在任何性能问题。谢谢。
猜你喜欢
  • 2011-07-12
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
相关资源
最近更新 更多