Skip to content

Commit

Permalink
feat(TIFFReader): add vtkTIFFReader
Browse files Browse the repository at this point in the history
This PR adds support for loading TIFF image format

fixes #3169
  • Loading branch information
daker committed Nov 14, 2024
1 parent 0c3933d commit 4f9e166
Show file tree
Hide file tree
Showing 8 changed files with 437 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion Documentation/content/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ This will allow you to see the some live code running in your browser. Just pick
[![OfflineLocalView Example][OfflineLocalViewWithIcon]](./OfflineLocalView.html "Load a serialized scene (VTKSZ)")
[![G-Code Example][GCodeReaderWithIcon]](./GCodeReader.html "G-Code reader(gcode)")
[![HDRReader Example][HDRReaderWithIcon]](./HDRReader.html "Load an HDR image")
[![TGAReader Example][TGAReaderWithIcon]](./TGAReader.html "Load an TGA image")
[![TGAReader Example][TGAReaderWithIcon]](./TGAReader.html "Load a TGA image")
[![TIFFReader Example][TIFFReaderWithIcon]](./TGAReader.html "Load a TIFF image")

</div>

Expand All @@ -211,6 +212,7 @@ This will allow you to see the some live code running in your browser. Just pick
[GCodeReaderWithIcon]: ../docs/gallery/GCodeReaderWithIcon.jpg
[HDRReaderWithIcon]: ../docs/gallery/HDRReaderWithIcon.jpg
[TGAReaderWithIcon]: ../docs/gallery/TGAReaderWithIcon.jpg
[TIFFReaderWithIcon]: ../docs/gallery/TIFFReaderWithIcon.jpg

# Actors

Expand Down
122 changes: 122 additions & 0 deletions Sources/IO/Image/TIFFReader/example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import '@kitware/vtk.js/favicon';

// Load the rendering pieces we want to use (for both WebGL and WebGPU)
import '@kitware/vtk.js/Rendering/Profiles/Geometry';

import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
import vtkPlaneSource from '@kitware/vtk.js/Filters/Sources/PlaneSource';
import vtkTIFFReader from '@kitware/vtk.js/IO/Image/TIFFReader';
import vtkTexture from '@kitware/vtk.js/Rendering/Core/Texture';
import vtkURLExtract from '@kitware/vtk.js/Common/Core/URLExtract';

// ----------------------------------------------------------------------------
// Example code
// ----------------------------------------------------------------------------
const userParams = vtkURLExtract.extractURLParameters();

const reader = vtkTIFFReader.newInstance();
const texture = vtkTexture.newInstance();
const planeSource = vtkPlaneSource.newInstance();
const mapper = vtkMapper.newInstance();
const actor = vtkActor.newInstance();
mapper.setInputConnection(planeSource.getOutputPort());
actor.setMapper(mapper);

// ----------------------------------------------------------------------------
// Use a file reader to load a local file
// ----------------------------------------------------------------------------

const myContainer = document.querySelector('body');
const fileContainer = document.createElement('div');
fileContainer.innerHTML =
'<div>Select a tiff file.<br/><input type="file" class="file"/></div>';
myContainer.appendChild(fileContainer);

const fileInput = fileContainer.querySelector('input');

function zoomCameraToFitPlane(camera, planeWidth, planeHeight) {
const fov = 60; // Field of view in degrees

// Calculate the distance needed to fit the plane in view
const distance =
Math.max(planeWidth, planeHeight) /
(2 * Math.tan((fov * Math.PI) / 180 / 2));

// Set camera position
camera.setPosition(planeWidth / 2, planeHeight / 2, distance);
camera.setFocalPoint(planeWidth / 2, planeHeight / 2, 0);
camera.setViewUp(0, 1, 0);

// Set parallel scale for orthographic projection
camera.setParallelScale(planeHeight / 2);
}

function update() {
// Get the vtkImageData from the reader
const imageData = reader.getOutputData(0);

// Set the vtkImageData as the texture input
texture.setInputData(imageData);

// // Get the image's extent and spacing
const [xMin, xMax, yMin, yMax] = imageData.getExtent();
const [spacingX, spacingY] = imageData.getSpacing();

// // Calculate the plane's width and height based on the image's dimensions
const planeWidth = (xMax - xMin + 1) * spacingX;
const planeHeight = (yMax - yMin + 1) * spacingY;

// Set the plane's origin and corners based on calculated width and height
planeSource.setOrigin(0, 0, 0);
planeSource.setPoint1(planeWidth, 0, 0); // Horizontal edge
planeSource.setPoint2(0, planeHeight, 0); // Vertical edge

actor.addTexture(texture);

const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();
const camera = renderer.getActiveCamera();
const interactor = renderWindow.getInteractor();

// Disable default interactor style
interactor.setInteractorStyle(null);

renderer.addActor(actor);

// Adjust the camera to fit the plane in the view
zoomCameraToFitPlane(camera, planeWidth, planeHeight);
renderer.resetCameraClippingRange();

renderWindow.render();
}

function handleFile(event) {
event.preventDefault();
const dataTransfer = event.dataTransfer;
const files = event.target.files || dataTransfer.files;
if (files.length === 1) {
const file = files[0];
const fileReader = new FileReader();
fileReader.onload = () => {
reader.parse(fileReader.result);
update();
};
fileReader.readAsArrayBuffer(file);
}
}

fileInput.addEventListener('change', handleFile);

// ----------------------------------------------------------------------------
// Use the reader to download a file
// ----------------------------------------------------------------------------
if (userParams.fileURL) {
reader.setUrl(userParams.fileURL).then(() => {
reader.loadData().then(() => {
update();
});
});
}
133 changes: 133 additions & 0 deletions Sources/IO/Image/TIFFReader/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { vtkAlgorithm, vtkObject } from '../../../interfaces';
import HtmlDataAccessHelper from '../../Core/DataAccessHelper/HtmlDataAccessHelper';
import HttpDataAccessHelper from '../../Core/DataAccessHelper/HttpDataAccessHelper';
import JSZipDataAccessHelper from '../../Core/DataAccessHelper/JSZipDataAccessHelper';
import LiteHttpDataAccessHelper from '../../Core/DataAccessHelper/LiteHttpDataAccessHelper';

interface ITIFFReaderOptions {
compression?: string;
progressCallback?: any;
flipY?: boolean;
}

/**
*
*/
export interface ITIFFReaderInitialValues {}

type vtkTIFFReaderBase = vtkObject &
Omit<
vtkAlgorithm,
| 'getInputData'
| 'setInputData'
| 'setInputConnection'
| 'getInputConnection'
| 'addInputConnection'
| 'addInputData'
>;

export interface vtkTIFFReader extends vtkTIFFReaderBase {
/**
* Get the base url.
*/
getBaseURL(): string;

/**
* Get if the image is flipped vertically.
*/
getFlipY(): boolean;

/**
* Get the dataAccess helper.
*/
getDataAccessHelper():
| HtmlDataAccessHelper
| HttpDataAccessHelper
| JSZipDataAccessHelper
| LiteHttpDataAccessHelper;

/**
* Get the url of the object to load.
*/
getUrl(): string;

/**
* Load the object data.
* @param {ITIFFReaderOptions} [options]
*/
loadData(options?: ITIFFReaderOptions): Promise<any>;

/**
* Parse data.
* @param {ArrayBuffer} content The content to parse.
*/
parse(content: ArrayBuffer): void;

/**
* Parse data as ArrayBuffer.
* @param {ArrayBuffer} content The content to parse.
*/
parseAsArrayBuffer(content: ArrayBuffer): void;

/**
*
* @param inData
* @param outData
*/
requestData(inData: any, outData: any): void;

/**
* Flip the image vertically.
* @param {String} flipY If true, flip the image vertically.
*/
setFlipY(flipY: boolean): boolean;

/**
*
* @param dataAccessHelper
*/
setDataAccessHelper(
dataAccessHelper:
| HtmlDataAccessHelper
| HttpDataAccessHelper
| JSZipDataAccessHelper
| LiteHttpDataAccessHelper
): boolean;

/**
* Set the url of the object to load.
* @param {String} url the url of the object to load.
* @param {ITIFFReaderOptions} [option] The PLY reader options.
*/
setUrl(url: string, option?: ITIFFReaderOptions): Promise<string | any>;
}

/**
* Method used to decorate a given object (publicAPI+model) with vtkTIFFReader characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {ITIFFReaderInitialValues} [initialValues] (default: {})
*/
export function extend(
publicAPI: object,
model: object,
initialValues?: ITIFFReaderInitialValues
): void;

/**
* Method used to create a new instance of vtkTIFFReader
* @param {ITIFFReaderInitialValues} [initialValues] for pre-setting some of its content
*/
export function newInstance(
initialValues?: ITIFFReaderInitialValues
): vtkTIFFReader;

/**
* vtkTIFFReader is a source object that reads TIFF files.
*/
export declare const vtkTIFFReader: {
newInstance: typeof newInstance;
extend: typeof extend;
};
export default vtkTIFFReader;
Loading

0 comments on commit 4f9e166

Please sign in to comment.