Skip to content

Commit

Permalink
feat(imagesRenderingMachineOptions): add downloadImage action
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulHax committed Dec 12, 2023
1 parent 0644851 commit e4c18b9
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 24 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Rendering/Images/createImagesRenderingMachine.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ function createImagesRenderingMachine(options, context) {
to: (c, e) => `imageRenderingActor-${e.data}`,
}),
},
DOWNLOAD_IMAGE: {
actions: ['downloadImage'],
},
...makeTransitions(
[
'IMAGE_GRADIENT_OPACITY_CHANGED',
Expand Down
34 changes: 34 additions & 0 deletions src/Rendering/VTKJS/Images/imagesRenderingMachineOptions.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { convertVtkToItkImage } from 'vtk.js/Sources/Common/DataModel/ITKHelper'
import { writeImageArrayBuffer, copyImage } from 'itk-wasm'
import createImageRenderer from './createImageRenderer'
import toggleLayerVisibility from './toggleLayerVisibility'
import toggleLayerBBox from './toggleLayerBBox'
Expand Down Expand Up @@ -64,6 +66,23 @@ const isTargetScaleLoaded = context => {
return loadedScale === targetScale
}

function downloadArray(content, filename = 'download') {
const url = URL.createObjectURL(new Blob([content]))
const a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
function clickHandler() {
setTimeout(() => {
URL.revokeObjectURL(url)
a.removeEventListener('click', clickHandler)
}, 200)
}
a.addEventListener('click', clickHandler, false)
a.click()
return a
}

const imagesRenderingMachineOptions = {
imageRenderingActor: {
services: {
Expand Down Expand Up @@ -117,6 +136,21 @@ const imagesRenderingMachineOptions = {

actions: {
selectImageLayer,
downloadImage: (context, event) => {
const { name, format } = event.data
const fileName = `${name}.${format}`
const actorContext = context.images.actorContext.get(name)
const fusedImage = actorContext.fusedImage
if (!fusedImage) {
console.warn('No image to download')
}
const itkImage = copyImage(convertVtkToItkImage(fusedImage, true))
writeImageArrayBuffer(null, itkImage, fileName).then(
({ arrayBuffer }) => {
downloadArray(arrayBuffer, fileName)
}
)
},
},
}

Expand Down
3 changes: 3 additions & 0 deletions src/Rendering/createRenderingMachine.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ const createRenderingMachine = (options, context) => {
TOGGLE_LAYER_BBOX: {
actions: forwardTo('images'),
},
DOWNLOAD_IMAGE: {
actions: forwardTo('images'),
},
},
},
},
Expand Down
7 changes: 4 additions & 3 deletions src/UI/reference-ui/dist/referenceUIMachineOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10895,11 +10895,12 @@ function createLayerEntry(context, name, layer) {
)
.concat(
extensions
.map(function(extension) {
.map(function(extension, i) {
return '<label>\n <md-radio name="format" value="'
.concat(extension, '" ')
.concat(
extension,
'" touch-target="wrapper"></md-radio>\n <span aria-hidden="true">'
i === 0 ? 'checked' : '',
' touch-target="wrapper"></md-radio>\n <span aria-hidden="true">'
)
.concat(extension, '</span>\n </label>')
})
Expand Down
6 changes: 4 additions & 2 deletions src/UI/reference-ui/src/Layers/createLayerInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ function createLayerEntry(context, name, layer) {
<form id="save-form" slot="content" method="dialog">
${extensions
.map(
extension =>
(extension, i) =>
`<label>
<md-radio name="format" value="${extension}" touch-target="wrapper"></md-radio>
<md-radio name="format" value="${extension}" ${
i === 0 ? 'checked' : ''
} touch-target="wrapper"></md-radio>
<span aria-hidden="true">${extension}</span>
</label>`
)
Expand Down
3 changes: 0 additions & 3 deletions src/createViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,6 @@ const createViewer = async (
break
case 'TAKE_SCREENSHOT':
break
case 'SAVE_ROI':
eventEmitter.emit('saveRoi', event.data)
break
default:
throw new Error(`Unexpected event type: ${event.type}`)
}
Expand Down
5 changes: 1 addition & 4 deletions src/createViewerMachine.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,7 @@ const createViewerMachine = (options, context, eventEmitterCallback) => {
actions: [forwardTo('ui'), forwardTo('rendering')],
},
DOWNLOAD_IMAGE: {
actions: ['downloadImage'],
},
SAVE_ROI: {
actions: [forwardTo('eventEmitter')],
actions: [forwardTo('rendering')],
},
},
},
Expand Down
11 changes: 0 additions & 11 deletions src/viewerMachineOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,6 @@ const ViewerMachineOptions = {
actions: {
createRenderingViewContainers,
styleRenderingViewContainers,
downloadImage: (context, event) => {
const { croppingPlanes } = context.main
context.service.send({
type: 'SAVE_ROI',
data: {
name: event.data.name,
layerName: event.data.layerName,
croppingPlanes,
},
})
},
},

ui: referenceUIMachineOptions,
Expand Down

0 comments on commit e4c18b9

Please sign in to comment.