Having difficulty displaying TIFF images and incorporating them into a Fabric Object

I have gone through the tutorials available at: and also familiarized myself with the Fabric Objects documentation.

While I was successful in loading JPG and PNG images onto the canvas, my current project requires me to load TIFF images and apply filters on them. Despite being able to render TIFF images using the canvas context, I am facing issues when 'renderAll()' is called as it clears the context along with my TIFF image. Additionally, I am unable to perform operations like zoom, pan, brightness, and contrast since I cannot render the TIFF image.

I would greatly appreciate if someone could guide me on how to convert a TIFF image into a Fabric Object so that I can carry out standard fabric.Object related operations on it.

Below are the steps I have followed:

  1. To load a mock TIFF image, I read it as an arraybuffer.

    public loadMockTiffImage() {
    // Creating a new XMLHttpRequest object to read the mock TIFF image as ArrayBuffer
    const xhr = new XMLHttpRequest();
    
    // Configuring it: GET-request for the URL
    xhr.open('GET', 'assets/tif/sample.tif', true);
    xhr.responseType = 'arraybuffer';
    xhr.timeout = 10000; // timeout in ms, set to 10 seconds
    
    // Sending the request over the network
    xhr.send();
    
    // Upon receiving the response, load it
    xhr.onload = () => {
      // Analyzing the HTTP status of the response
      if (xhr.status !== 200) {
        // Throw error in case status is not 200
        console.log(`Error ${xhr.status}: ${xhr.statusText}`);
      } else {
        // Display the result
        console.log(`Done, received ${xhr.response.byteLength} bytes`);
        console.log(xhr.response);
        // Adding the XHR response which is of type ArrayBuffer to the canvas
        this.addTiffImageOnCanvas(xhr.response);
      }
    };
    
    // Showing 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
      }
    };
    
    // Logging any network request errors
    xhr.onerror = () => {
      console.log('Request failed!');
    };
    }
    
  2. Next, I utilize UTIF.js to decode the ArrayBuffer and convert it to ImageBitmap so that I can use canvas.drawImage() to render it on the canvas. How do I convert this ImageBitmap/ArrayBuffer to a FabricJS object?

    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?
      });
    });
    

    }

Your assistance in this matter would be highly appreciated.

Answer №1

No references to ImageBitmap handling were found in fabric's github repository.

However, it is possible to create a Fabric.Image from an HTMLCanvasElement. You will need to draw the ImageBitmap on a canvas first, and since we are already using a canvas, it is better to do this at the initial step when obtaining an 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) {
// Utilizing UTIF.js for decoding the array buffer and converting it to ImageData
const ifds = UTIF.decode(buffer);
UTIF.decodeImage(buffer, ifds[0]);
const timage = ifds[0];
const array = new Uint8ClampedArray(UTIF.toRGBA8(timage));
// Creating image Data
const imageData = new ImageData(array, timage.width, timage.height);
// Temporary canvas element
const canvas = document.createElement('canvas');
canvas.width = timage.width;
canvas.height = timage.height;
// Drawing the ImageData on the canvas
canvas.getContext('2d')
.putImageData(imageData, 0, 0);
// 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using RxJS v5 for Sending a POST Request with Parameters

Snippet of my RxJS code: .mergeMap(action => { const user = store.getState().user; return ajax.post(`${config.API_BASE_URL}/api/v1/rsvps`, { rsvp: { meetup_id: action.payload, user_id: user.id, } }) .map(action => calenda ...

Is there a way to stop the automatic triggering of the form submit action?

This form has an action event that triggers when a button is clicked. <form id="prefForm4" enctype="multipart/form-data" method="post" class="masters" action="/Preferences/Preferences/RISSave"> </form> There are two buttons in this form, ...

When using Typescript, ENUMs can be passed as interface values without any issues. However, errors may occur

To ensure consistency in sizes and colors within my UI library, I decided to create an ENUM for each value. export enum sizes { small = 'small', medium = 'medium', large = 'large', } export enum colors { orange = ...

JQuery Tic Tac Toe Duel: Face Off Against Your Friend in a Thr

Looking for some advice here. I'm new to game development and currently working on a 2 Player Tic Tac Toe game. I need help with implementing the game functionality. Any suggestions? I want to disable the "div" once a player clicks on it, but I' ...

unpredictable actions resulting in an ajax timeout

I'm working on a web project and using jQuery to make an AJAX request. However, I need to prolong the timeout to almost 10 minutes. Strangely, it keeps timing out after only 2 minutes. Is there a limit in jQuery for waiting for responses to requests? ...

While working on a project in React, I successfully implemented an async function to fetch data from an API. However, upon returning the data, I encountered an issue where it was displaying as a

I am working with React and TypeScript and have the following code snippet: const fetchData = async () => { const res: any = await fetch("https://api.spotify.com/v1/search?q=thoughtsofadyingatheist&type=track&limit=30", { met ...

Converting CSV data to a specific file type using Reactjs

My goal is to transform JSON data into CSV format, then convert that CSV data into a CSV file, and finally upload the file onto Firebase. Although I have successfully converted the JSON to CSV, I am currently facing difficulties in converting the data in ...

What is the best way to assign JSON values to my class property?

I've been working on a weather application that showcases the current weather of 5 different cities. By clicking on each city, users can access a detailed view displaying the 5-day forecast for that particular location. Currently, I have defined a we ...

Monitor modifications to a DOM element's ClientRect dimensions

I have developed a component that utilizes the context feature to register a DOM node and include it in a QuadTree. export default class SelectableGroup extends React.PureComponent { getChildContext() { return { register: this.register, ...

What is the best way to fetch all messages from a channel and share them on Hastebin using discord.js?

Currently, I am conceptualizing a questioning bot. With this in mind, I want to clarify that once the member's question is answered, the created channel should be closed. Prior to closing the channel, the bot is expected to share a link from hastebin. ...

How to access a controller function within a recursive directive template in Angular version 1.3?

In my parent directive, I am able to access controller functions using the $parent operator. However, this method does not work in recursive child directives. Here is a shortened example of the issue: // Sample controller code (using controllerAs):--- va ...

Unresolved issue with RxJS - Finalize not triggering

When attempting a logout request, I have encountered an issue where the same actions need to be dispatched regardless of whether the request is successful or fails. My initial plan was to utilize the finalize() operator for this purpose. Unfortunately, I ...

Using Chartjs to Dynamically Update Data from Database Values

I'm encountering some difficulties while attempting to refresh my Chartjs doughnut chart with data retrieved from my database. Below is the ajax call that I've implemented successfully: $.ajax({ url: "<!--#include virtual="../include/e ...

What steps can be taken to fix a syntax error in a NodeJS express server code?

I am currently facing a syntax error in the code below, and I'm struggling to fix it. The specific error message is as follows: node staticapi.js /Users/v/Desktop/CS-Extra/EIP/A5/staticapi.js:123 res.status(200).send("Api is running") ...

Blending synchronous and asynchronous testing with Mocha

There is a function that calculates certain values and informs the user about events using callbacks: function returnAndCallback(callback) { callback(5); // not always called return 3; } Incorporating Mocha and Should.js, a test was created: descri ...

What is the proper way to implement if-else statements in JSX?

Is there a way to implement if else statements in JSX? I am currently using the following code snippet <h2 className='font-bold text-lx'>$ {item?.price == null && item?.type =='Sell' ? 'Please contact agency' : ...

tslint issues detected within a line of code in a function

I am a novice when it comes to tslint and typescript. Attempting to resolve the error: Unnecessary local variable - stackThird. Can someone guide me on how to rectify this issue? Despite research, I have not been successful in finding a solution. The err ...

I am currently working on an Angular 8 project and experiencing difficulties with displaying a specific value from a JSON object in my template using an ngFor loop

Apologies if I am not familiar with all the terms, as I am mostly self-taught. I started with Udemy and then turned to Stack Overflow to tackle the more challenging aspects. This platform has been incredibly valuable and I am truly grateful for it. Now, l ...

Importing components in real-time to generate static sites

My website has a dynamic page structure with each page having its unique content using various components. During the build process, I am statically pre-rendering the pages using Next.js' static site generation. To manage component population, I have ...

Tips for efficiently loading data in a sequence using rxjs: within each sequence, there could be multiple calls made

const dates = [{start:'03/06/2020', end: '03/09/2020'}, {start:'03/12/2020', end: '03/03/2021'}, ...] const fetchData = service.get(page = 1, dates[0]) and service.get(page = 2, dates[0]) retrieves the necessary d ...