Skip to content

Commit

Permalink
feat(JsonObject): Add JSON_OUTPUT as output type
Browse files Browse the repository at this point in the history
Add JSON_OUTPUT as a possible output type which will be generated
by an operation (.cxx) as a string, but will be parsed as a
generic Javascript object when receiving results on the JS
side of the pipeline.

Use JSON_OUTPUT for the second output of applyPresentationStateToImage operation.

Add convenience command 'npm run bindgen' to package.json.
  • Loading branch information
jadh4v committed Nov 1, 2022
1 parent d057456 commit ec4176f
Show file tree
Hide file tree
Showing 14 changed files with 45 additions and 19 deletions.
2 changes: 1 addition & 1 deletion dist/dicom/src/ApplyPresentationStateToImageNodeResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Image } from 'itk-wasm'

interface ApplyPresentationStateToImageNodeResult {
/** Output overlay information */
presentationStateOutStream: string
presentationStateOutStream: Object

/** Output image */
outputImage: Image
Expand Down
2 changes: 1 addition & 1 deletion dist/dicom/src/ApplyPresentationStateToImageResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ interface ApplyPresentationStateToImageResult {
webWorker: Worker | null

/** Output overlay information */
presentationStateOutStream: string
presentationStateOutStream: Object

/** Output image */
outputImage: Image
Expand Down
6 changes: 3 additions & 3 deletions dist/dicom/src/applyPresentationStateToImage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
TextStream,
JsonObject,
Image,
InterfaceTypes,
PipelineInput,
Expand All @@ -23,7 +23,7 @@ async function applyPresentationStateToImage(
: Promise<ApplyPresentationStateToImageResult> {

const desiredOutputs = [
{ type: InterfaceTypes.TextStream },
{ type: InterfaceTypes.JsonObject },
{ type: InterfaceTypes.Image },
]
const inputs: [ PipelineInput ] = [
Expand Down Expand Up @@ -76,7 +76,7 @@ async function applyPresentationStateToImage(

const result = {
webWorker: usedWebWorker as Worker,
presentationStateOutStream: (outputs[0].data as TextStream).data,
presentationStateOutStream: (outputs[0].data as JsonObject).data,
outputImage: outputs[1].data as Image,
}
return result
Expand Down
6 changes: 3 additions & 3 deletions dist/dicom/src/applyPresentationStateToImageNode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
TextStream,
JsonObject,
Image,
InterfaceTypes,
PipelineInput,
Expand All @@ -24,7 +24,7 @@ async function applyPresentationStateToImageNode( imageIn: Uint8Array,
: Promise<ApplyPresentationStateToImageNodeResult> {

const desiredOutputs = [
{ type: InterfaceTypes.TextStream },
{ type: InterfaceTypes.JsonObject },
{ type: InterfaceTypes.Image },
]
const inputs: [ PipelineInput ] = [
Expand Down Expand Up @@ -75,7 +75,7 @@ async function applyPresentationStateToImageNode( imageIn: Uint8Array,
}

const result = {
presentationStateOutStream: (outputs[0].data as TextStream).data,
presentationStateOutStream: (outputs[0].data as JsonObject).data,
outputImage: outputs[1].data as Image,
}
return result
Expand Down
15 changes: 8 additions & 7 deletions dist/dicom/test/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ test('Apply presentation state to dicom image.', async t => {
const pstateFileBuffer = fs.readFileSync(pstateFilePath)
const inputPState = new Uint8Array(pstateFileBuffer)

const { presentationStateOutStream, outputImage } = await applyPresentationStateToImageNode(inputImage, {presentationStateFile: inputPState})
const { presentationStateOutStream: pstateJsonOut, outputImage } = await applyPresentationStateToImageNode(inputImage, {presentationStateFile: inputPState})

t.assert(presentationStateOutStream != null)
t.assert(pstateJsonOut != null)
t.assert(outputImage != null)

t.assert(outputImage.imageType.dimension === 2)
Expand All @@ -138,14 +138,15 @@ test('Apply presentation state to dicom image.', async t => {
t.assert(arrayEquals(outputImage.direction, [1, 0, 0, 1]))
t.assert(arrayEquals(outputImage.size, [512, 512]))

const baselineJson = 'gsps-pstate-baseline.json'
const baselineJsonFilePath = `../../build-emscripten/ExternalData/test/Input/${baselineJson}`
const baselineJsonFile = 'gsps-pstate-baseline.json'
const baselineJsonFilePath = `../../build-emscripten/ExternalData/test/Input/${baselineJsonFile}`
const baselineJsonFileBuffer = fs.readFileSync(baselineJsonFilePath)
// the slice operation removes the last EOF char from the baseline file.
const baselineJsonString = baselineJsonFileBuffer.toString().slice(0, -1)

t.assert(baselineJsonString === presentationStateOutStream)
t.assert(baselineJsonString.length === presentationStateOutStream.length)
const baselineJsonObject = JSON.parse(baselineJsonString)
t.assert(baselineJsonObject.PresentationLabel === pstateJsonOut.PresentationLabel)
t.assert(baselineJsonObject.PresentationSizeMode === pstateJsonOut.PresentationSizeMode)
t.assert(baselineJsonObject.toString() === pstateJsonOut.toString())

const baselineImage = 'gsps-pstate-image-baseline.pgm'
const baselineImageFilePath = `../../build-emscripten/ExternalData/test/Input/${baselineImage}`
Expand Down
6 changes: 6 additions & 0 deletions doc/content/api/JsonObject.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
title: JsonObject
---

A `JsonObject` represents a javascript object parsed from an arbitrary JSON string. `JsonObject` is a JavaScript object with the following properties:

**data**: Of type `Object`, contains the javascript object parsed from a generated JSON text/string.
3 changes: 2 additions & 1 deletion doc/content/docs/interface_types.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
title: Interface Types
---

itk-wasm execution pipelines support the following [interface types](https://github.com/InsightSoftwareConsortum/itk-wasm/tree/master/src/core/InterfaceTypes.ts):
itk-wasm execution pipelines support the following [interface types](https://github.com/InsightSoftwareConsortium/itk-wasm/tree/master/src/core/InterfaceTypes.ts):

- [TextFile](../api/TextFile.html)
- [BinaryFile](../api/BinaryFile.html)
Expand All @@ -10,6 +10,7 @@ itk-wasm execution pipelines support the following [interface types](https://git
- [Image](../api/Image.html)
- [Mesh](../api/Mesh.html)
- [PolyData](../api/PolyData.html)
- [JsonObject](../api/JsonObject.html)

These interfaces types are supported in the [Emscripten interface](../api/runPipeline.html), WASI embedding interfaces, and native or virtual [filesystem IO](./file_formats.html).

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"doc": "kw-doc -c ./doc/config.cjs",
"doc:www": "kw-doc -c ./doc/config.cjs -s",
"commit": "git cz",
"bindgen": "node ./src/itk-wasm-cli.js bindgen ./dist/dicom/src ./dist/dicom/public/pipelines/*.wasm",
"build": "npm run build:emscripten && npm run build:tsc && npm run build:tscWorkersModuleLoader && npm run build:tscWebWorkers && npm run build:workerBundles && npm run build:workerMinBundles && npm run build:webpack && node ./src/io/internal/packages/package-json-gen.cjs",
"build:debug": "npm run build:emscripten -- --debug && npm run build:tsc && npm run build:tscWorkersModuleLoader && npm run build:tscWebWorkers && npm run build:workerBundles && npm run build:workerMinBundles && npm run build:webpack -- --mode development",
"build:tsc": "tsc --pretty",
Expand Down
3 changes: 2 additions & 1 deletion src/core/InterfaceTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const InterfaceTypes = {
BinaryStream: 'InterfaceBinaryStream',
Image: 'InterfaceImage',
Mesh: 'InterfaceMesh',
PolyData: 'InterfacePolyData'
PolyData: 'InterfacePolyData',
JsonObject: 'InterfaceJsonObject',
} as const

export default InterfaceTypes
5 changes: 5 additions & 0 deletions src/core/JsonObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface JsonObject {
data: Object
}

export default JsonObject
1 change: 1 addition & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { default as TextStream } from './TextStream.js'
export { default as BinaryStream } from './BinaryStream.js'
export { default as TextFile } from './TextFile.js'
export { default as BinaryFile } from './BinaryFile.js'
export { default as JsonObject } from './JsonObject.js'

export { default as TypedArray } from './TypedArray.js'
export { default as IntTypes } from './IntTypes.js'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ int main(int argc, char *argv[])
// Outputs
// Metadata output regarding overlays
itk::wasm::OutputTextStream pstateOutStream;
pipeline.add_option("presentation-state-out-stream", pstateOutStream, "Output overlay information")->type_name("OUTPUT_TEXT_STREAM");
pipeline.add_option("presentation-state-out-stream", pstateOutStream, "Output overlay information")->type_name("OUTPUT_JSON");
// Processed output image
constexpr unsigned int Dimension = 2;
using PixelType = unsigned char;
Expand Down
4 changes: 3 additions & 1 deletion src/itk-wasm-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ const interfaceJsonTypeToTypeScriptType = new Map([
['BOOL', 'boolean'],
['TEXT', 'string'],
['INT', 'number'],
['OUTPUT_JSON', 'Object'],
])

const interfaceJsonTypeToInterfaceType = new Map([
Expand All @@ -262,6 +263,7 @@ const interfaceJsonTypeToInterfaceType = new Map([
['OUTPUT_MESH', 'Mesh'],
['INPUT_POLYDATA', 'PolyData'],
['OUTPUT_POLYDATA', 'PolyData'],
['OUTPUT_JSON', 'JsonObject'],
])

function typescriptBindings(srcOutputDir, buildDir, wasmBinaries, forNode=false) {
Expand Down Expand Up @@ -511,7 +513,7 @@ function typescriptBindings(srcOutputDir, buildDir, wasmBinaries, forNode=false)
interfaceJson.outputs.forEach((output, index) => {
const camel = camelCase(output.name)
const interfaceType = interfaceJsonTypeToInterfaceType.get(output.type)
if (interfaceType.includes('Text') || interfaceType.includes('Binary')) {
if (interfaceType.includes('Text') || interfaceType.includes('Binary') || interfaceType.includes('JsonObject')) {
functionContent += ` ${camel}: (outputs[${index.toString()}].data as ${interfaceType}).data,\n`
} else {
functionContent += ` ${camel}: outputs[${index.toString()}].data as ${interfaceType},\n`
Expand Down
8 changes: 8 additions & 0 deletions src/pipeline/internal/runPipelineEmscripten.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,14 @@ function runPipelineEmscripten (pipelineModule: PipelineEmscriptenModule, args:
outputData = { data: decoder.decode(dataArrayView) }
break
}
case InterfaceTypes.JsonObject:
{
const dataPtr = pipelineModule.ccall('itk_wasm_output_array_address', 'number', ['number', 'number', 'number'], [0, index, 0])
const dataSize = pipelineModule.ccall('itk_wasm_output_array_size', 'number', ['number', 'number', 'number'], [0, index, 0])
const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize)
outputData = { data: JSON.parse(decoder.decode(dataArrayView)) }
break
}
case InterfaceTypes.BinaryStream:
{
// const jsonPtr = pipelineModule.ccall('itk_wasm_output_json_address', 'number', ['number', 'number'], [0, index])
Expand Down

0 comments on commit ec4176f

Please sign in to comment.