Files
irc_web/src/views/trials/trials-panel/reading/visit-review/js/registerWebImageLoader.js
T

245 lines
5.7 KiB
JavaScript

import * as cornerstone from '@cornerstonejs/core'
const canvas = document.createElement('canvas')
let lastImageIdDrawn
// Todo: this loader should exist in a separate package in the same monorepo
/**
* creates a cornerstone Image object for the specified Image and imageId
*
* @param image - An Image
* @param imageId - the imageId for this image
* @returns Cornerstone Image Object
*/
function createImage(image, imageId) {
// extract the attributes we need
const rows = image.naturalHeight
const columns = image.naturalWidth
function getPixelData(targetBuffer) {
const imageData = getImageData()
let targetArray
// Check if targetBuffer is provided for volume viewports
if (targetBuffer) {
targetArray = new Uint8Array(
targetBuffer.arrayBuffer,
targetBuffer.offset,
targetBuffer.length
)
} else {
targetArray = new Uint8Array(imageData.width * imageData.height * 3)
}
// modify original image data and remove alpha channel (RGBA to RGB)
convertImageDataToRGB(imageData, targetArray)
return targetArray
}
function convertImageDataToRGB(imageData, targetArray) {
for (let i = 0, j = 0; i < imageData.data.length; i += 4, j += 3) {
targetArray[j] = imageData.data[i]
targetArray[j + 1] = imageData.data[i + 1]
targetArray[j + 2] = imageData.data[i + 2]
}
}
function getImageData() {
let context
if (lastImageIdDrawn === imageId) {
context = canvas.getContext('2d')
} else {
canvas.height = image.naturalHeight
canvas.width = image.naturalWidth
context = canvas.getContext('2d')
context.drawImage(image, 0, 0)
lastImageIdDrawn = imageId
}
return context.getImageData(0, 0, image.naturalWidth, image.naturalHeight)
}
function getCanvas() {
if (lastImageIdDrawn === imageId) {
return canvas
}
canvas.height = image.naturalHeight
canvas.width = image.naturalWidth
const context = canvas.getContext('2d')
context.drawImage(image, 0, 0)
lastImageIdDrawn = imageId
return canvas
}
// Extract the various attributes we need
return {
imageId,
minPixelValue: 0,
maxPixelValue: 255,
slope: 1,
intercept: 0,
windowCenter: 128,
windowWidth: 255,
getPixelData,
getCanvas,
getImage: () => image,
rows,
columns,
height: rows,
width: columns,
color: true,
// we converted the canvas rgba already to rgb above
rgba: false,
columnPixelSpacing: 1, // for web it's always 1
rowPixelSpacing: 1, // for web it's always 1
invert: false,
sizeInBytes: rows * columns * 3,
numberOfComponents: 3
}
}
function arrayBufferToImage(arrayBuffer) {
return new Promise((resolve, reject) => {
const image = new Image()
const arrayBufferView = new Uint8Array(arrayBuffer)
const blob = new Blob([arrayBufferView])
const urlCreator = window.URL || window.webkitURL
const imageUrl = urlCreator.createObjectURL(blob)
image.src = imageUrl
image.onload = () => {
resolve(image)
urlCreator.revokeObjectURL(imageUrl)
}
image.onerror = (error) => {
urlCreator.revokeObjectURL(imageUrl)
reject(error)
}
})
}
//
// This is a cornerstone image loader for web images such as PNG and JPEG
//
const options = {
// callback allowing customization of the xhr (e.g. adding custom auth headers, cors, etc)
beforeSend: (xhr) => {
// xhr
}
}
// Loads an image given a url to an image
function loadImage(uri, imageId) {
const xhr = new XMLHttpRequest()
xhr.open('GET', uri, true)
xhr.responseType = 'arraybuffer'
options.beforeSend(xhr)
xhr.onprogress = function(oProgress) {
if (oProgress.lengthComputable) {
// evt.loaded the bytes browser receive
// evt.total the total bytes set by the header
const loaded = oProgress.loaded
const total = oProgress.total
const percentComplete = Math.round((loaded / total) * 100)
const eventDetail = {
imageId,
loaded,
total,
percentComplete
}
cornerstone.triggerEvent(
cornerstone.eventTarget,
'cornerstoneimageloadprogress',
eventDetail
)
}
}
const promise = new Promise((resolve, reject) => {
xhr.onload = function() {
const imagePromise = arrayBufferToImage(this.response)
imagePromise
.then((image) => {
const imageObject = createImage(image, imageId)
resolve(imageObject)
}, reject)
.catch((error) => {
console.error(error)
})
}
xhr.onerror = function(error) {
reject(error)
}
xhr.send()
})
const cancelFn = () => {
xhr.abort()
}
return {
promise,
cancelFn
}
}
function registerWebImageLoader(imageLoader) {
imageLoader.registerImageLoader('web', _loadImageIntoBuffer)
}
/**
* Small stripped down loader from cornerstoneDICOMImageLoader
* Which doesn't create cornerstone images that we don't need
*/
function _loadImageIntoBuffer(imageId, options) {
const uri = imageId.replace('web:', '')
const promise = new Promise((resolve, reject) => {
// get the pixel data from the server
loadImage(uri, imageId)
.promise.then(
(image) => {
if (
!options?.targetBuffer?.length ||
!options?.targetBuffer?.offset
) {
resolve(image)
return
}
// @ts-ignore
image.getPixelData(options.targetBuffer)
resolve(true)
},
(error) => {
reject(error)
}
)
.catch((error) => {
reject(error)
})
})
return {
promise,
cancelFn: undefined
}
}
export default registerWebImageLoader