Skip to content

Commit

Permalink
feat(transform-io): add writeTransformNode
Browse files Browse the repository at this point in the history
And implement related fixes.
  • Loading branch information
thewtex committed Nov 11, 2024
1 parent c5438d5 commit d4fcf16
Show file tree
Hide file tree
Showing 19 changed files with 208 additions and 49 deletions.
2 changes: 1 addition & 1 deletion include/itkWasmTransformIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class ITK_TEMPLATE_EXPORT WasmTransformIOTemplate : public TransformIOBaseTempla

/** Set the JSON representation of the image information. */
void
SetJSON(const TransformListJSON & json);
SetJSON(const TransformListJSON & json, bool inMemory=false);

/*-------- This part of the interfaces deals with writing data ----- */

Expand Down
73 changes: 41 additions & 32 deletions packages/mesh-io/typescript/src/write-mesh-node.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import path from 'path'
import path from "path";

import {
Mesh,
getFileExtension,
} from 'itk-wasm'
import { Mesh, getFileExtension } from "itk-wasm";

import mimeToMeshIo from './mime-to-mesh-io.js'
import extensionToMeshIo from './extension-to-mesh-io.js'
import meshIoIndexNode from './mesh-io-index-node.js'
import mimeToMeshIo from "./mime-to-mesh-io.js";
import extensionToMeshIo from "./extension-to-mesh-io.js";
import meshIoIndexNode from "./mesh-io-index-node.js";

import WriteMeshOptions from './write-mesh-options.js'
import WriteMeshOptions from "./write-mesh-options.js";

interface WriterOptions {
useCompression?: boolean
binaryFileType?: boolean
useCompression?: boolean;
binaryFileType?: boolean;
}
interface WriterResult {
couldWrite: boolean
couldWrite: boolean;
}
type Writer = (mesh: Mesh, serializedImage: string, options: WriterOptions) => Promise<WriterResult>

type Writer = (
mesh: Mesh,
serializedMesh: string,
options: WriterOptions
) => Promise<WriterResult>;

/**
* Write a mesh to a serialized file format and from an the itk-wasm Mesh
Expand All @@ -34,38 +34,47 @@ async function writeMeshNode(
mesh: Mesh,
serializedMesh: string,
options: WriteMeshOptions = {}
) : Promise<void> {
const absoluteFilePath = path.resolve(serializedMesh)
const mimeType = options.mimeType
const extension = getFileExtension(absoluteFilePath)
): Promise<void> {
const absoluteFilePath = path.resolve(serializedMesh);
const mimeType = options.mimeType;
const extension = getFileExtension(absoluteFilePath);

let inputMesh = mesh
let inputMesh = mesh;

let io = null
if (typeof mimeType !== 'undefined' && mimeToMeshIo.has(mimeType)) {
io = mimeToMeshIo.get(mimeType)
let io = null;
if (typeof mimeType !== "undefined" && mimeToMeshIo.has(mimeType)) {
io = mimeToMeshIo.get(mimeType);
} else if (extensionToMeshIo.has(extension)) {
io = extensionToMeshIo.get(extension)
io = extensionToMeshIo.get(extension);
} else {
for (const readerWriter of meshIoIndexNode.values()) {
if (readerWriter[1] !== null) {
let { couldWrite } = await (readerWriter[1] as Writer)(inputMesh, absoluteFilePath, { useCompression: options.useCompression, binaryFileType: options.binaryFileType })
let { couldWrite } = await (readerWriter[1] as Writer)(
inputMesh,
absoluteFilePath,
{
useCompression: options.useCompression,
binaryFileType: options.binaryFileType,
}
);
if (couldWrite) {
return
return;
}
}
}
}
if (io === null ) {
throw Error('Could not find IO for: ' + absoluteFilePath)
if (io === null) {
throw Error("Could not find IO for: " + absoluteFilePath);
}
const readerWriter = meshIoIndexNode.get(io as string)
const readerWriter = meshIoIndexNode.get(io as string);

const writer = (readerWriter as Array<Writer>)[1]
let { couldWrite } = await writer(inputMesh, absoluteFilePath, { useCompression: options.useCompression })
const writer = (readerWriter as Array<Writer>)[1];
let { couldWrite } = await writer(inputMesh, absoluteFilePath, {
useCompression: options.useCompression,
});
if (!couldWrite) {
throw Error('Could not write: ' + absoluteFilePath)
throw Error("Could not write: " + absoluteFilePath);
}
}

export default writeMeshNode
export default writeMeshNode;
6 changes: 3 additions & 3 deletions packages/transform-io/itkInputTransformIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ bool lexical_cast(const std::string &input, InputTransformIO<TParametersValueTyp
}

auto wasmTransformIO = WasmTransformIOType::New();
wasmTransformIO->SetJSON(transformListJSON);
constexpr bool inMemory = true;
wasmTransformIO->SetJSON(transformListJSON, inMemory);

auto wasmTransformIOBase = WasmTransformIOBaseType::New();
wasmTransformIOBase->SetTransformIO(wasmTransformIO, false);
wasmTransformIOBase->SetJSON(json);
wasmTransformIOBase->SetTransformIO(wasmTransformIO, inMemory);

inputTransformIO.Set(wasmTransformIOBase);
#else
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
6 changes: 3 additions & 3 deletions packages/transform-io/typescript/src/index-common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Generated file. To retain edits, remove this comment.

export { default as version } from "./version.js";
export { default as version } from './version.js'

export type { JsonCompatible } from "itk-wasm";
export type { TransformList } from "itk-wasm";
export type { JsonCompatible } from 'itk-wasm'
export type { TransformList } from 'itk-wasm'
6 changes: 6 additions & 0 deletions packages/transform-io/typescript/src/index-node-only.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ export type { ReadTransformOptions };
import readTransformNode from "./read-transform-node.js";
export { readTransformNode };

import WriteTransformOptions from "./write-transform-options.js";
export type { WriteTransformOptions };

import writeTransformNode from "./write-transform-node.js";
export { writeTransformNode };

import Hdf5ReadTransformNodeResult from "./hdf5-read-transform-node-result.js";
export type { Hdf5ReadTransformNodeResult };

Expand Down
82 changes: 82 additions & 0 deletions packages/transform-io/typescript/src/write-transform-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import path from "path";

import { TransformList, getFileExtension } from "itk-wasm";

import mimeToTransformIo from "./mime-to-transform-io.js";
import extensionToTransformIo from "./extension-to-transform-io.js";
import transformIoIndexNode from "./transform-io-index-node.js";

import WriteTransformOptions from "./write-transform-options.js";

interface WriterOptions {
useCompression?: boolean;
floatParameters?: boolean;
}
interface WriterResult {
couldWrite: boolean;
}
type Writer = (
transform: TransformList,
serializedTransform: string,
options: WriterOptions
) => Promise<WriterResult>;

/**
* Write a transform to a serialized file format and from an the itk-wasm Transform
*
* @param {Transform} transform - Input transform
* @param {string} serializedTransform - Output transform serialized in the file format.
* @param {WriteTransformOptions} options - options object
*
* @returns {void} - result object
*/
async function writeTransformNode(
transform: TransformList,
serializedTransform: string,
options: WriteTransformOptions = {}
): Promise<void> {
const absoluteFilePath = path.resolve(serializedTransform);
const mimeType = options.mimeType;
const extension = getFileExtension(absoluteFilePath);

let inputTransform = transform;

let io = null;
if (typeof mimeType !== "undefined" && mimeToTransformIo.has(mimeType)) {
io = mimeToTransformIo.get(mimeType);
} else if (extensionToTransformIo.has(extension)) {
io = extensionToTransformIo.get(extension);
} else {
for (const readerWriter of transformIoIndexNode.values()) {
if (readerWriter[1] !== null) {
let { couldWrite } = await (readerWriter[1] as Writer)(
inputTransform,
absoluteFilePath,
{
useCompression: options.useCompression,
floatParameters: options.floatParameters,
}
);
if (couldWrite) {
return;
}
}
}
}
if (io === null) {
throw Error("Could not find IO for: " + absoluteFilePath);
}
const readerWriter = transformIoIndexNode.get(io as string);

const writer = (readerWriter as Array<Writer>)[1];
console.log("writer", writer);
console.log("inputTransform", inputTransform);
let { couldWrite } = await writer(inputTransform, absoluteFilePath, {
useCompression: options.useCompression,
});
if (!couldWrite) {
throw Error("Could not write: " + absoluteFilePath);
}
}

export default writeTransformNode;
14 changes: 14 additions & 0 deletions packages/transform-io/typescript/src/write-transform-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { WorkerPoolFunctionOption } from "itk-wasm";

interface WriteTransformOptions extends WorkerPoolFunctionOption {
/** Use compression when writing the mesh if the IO formt supports it. */
useCompression?: boolean;

/** Use float for the parameter value type. The default is double. */
floatParameters?: boolean;

/** Mime type of the output mesh file. */
mimeType?: string;
}

export default WriteTransformOptions;
2 changes: 1 addition & 1 deletion packages/transform-io/typescript/test/node/hdf5-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ test("Test writing a HDF5 transform file", async (t) => {
t.true(couldWrite);

const { couldRead: couldReadBack, transform: transformBack } =
await hdf5ReadTransformNode(testInputFilePath);
await hdf5ReadTransformNode(testOutputFilePath);
t.true(couldReadBack);
verifyTestLinearTransform(t, transformBack);
});
33 changes: 31 additions & 2 deletions packages/transform-io/typescript/test/node/iwt-test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import test from "ava";
import path from "path";

import { wasmReadTransformNode } from "../../dist/index-node.js";
import {
wasmReadTransformNode,
wasmWriteTransformNode,
} from "../../dist/index-node.js";

import { testInputPath, verifyTestLinearTransform } from "./common.js";
import {
testInputPath,
testOutputPath,
verifyTestLinearTransform,
} from "./common.js";

const testInputFilePath = path.join(testInputPath, "LinearTransform.iwt.cbor");
const testOutputFilePath = path.join(
testOutputPath,
"wasm-test-write-LinearTransform.iwt.cbor"
);

test("Test reading a .iwt.cbor file", async (t) => {
const { couldRead, transform } = await wasmReadTransformNode(
Expand All @@ -14,3 +25,21 @@ test("Test reading a .iwt.cbor file", async (t) => {
t.true(couldRead);
verifyTestLinearTransform(t, transform);
});

test("Test writing .iwt.cbor transform file", async (t) => {
const { couldRead, transform } = await wasmReadTransformNode(
testInputFilePath
);
t.true(couldRead);

const { couldWrite } = await wasmWriteTransformNode(
transform,
testOutputFilePath
);
t.true(couldWrite);

const { couldRead: couldReadBack, transform: transformBack } =
await wasmReadTransformNode(testOutputFilePath);
t.true(couldReadBack);
verifyTestLinearTransform(t, transformBack);
});
2 changes: 1 addition & 1 deletion packages/transform-io/typescript/test/node/mat-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ test("Test writing .mat transform file", async (t) => {
t.true(couldWrite);

const { couldRead: couldReadBack, transform: transformBack } =
await matReadTransformNode(testInputFilePath);
await matReadTransformNode(testOutputFilePath);
t.true(couldReadBack);
verifyTestLinearTransform(t, transformBack);
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { testInputPath, verifyTestLinearTransform } from "./common.js";

const testInputFilePath = path.join(testInputPath, "LinearTransform.mat");

test("readTransformNode reads a fil epath given on the local filesystem", async (t) => {
test("readTransformNode reads a file path given on the local filesystem", async (t) => {
const transform = await readTransformNode(testInputFilePath);
verifyTestLinearTransform(t, transform);
});
2 changes: 1 addition & 1 deletion packages/transform-io/typescript/test/node/txt-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ test("Test writing an Insight Legacy TXT transform file", async (t) => {
t.true(couldWrite);

const { couldRead: couldReadBack, transform: transformBack } =
await txtReadTransformNode(testInputFilePath);
await txtReadTransformNode(testOutputFilePath);
t.true(couldReadBack);
verifyTestLinearTransform(t, transformBack);
});
27 changes: 23 additions & 4 deletions src/itkWasmTransformIO.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "itkWasmIOCommon.h"
#include "itktransformParameterizationString.h"
#include "itkMetaDataDictionaryJSON.h"
#include "itkTransformFactoryBase.h"

#include "itkMetaDataObject.h"
#include "itkIOCommon.h"
Expand Down Expand Up @@ -460,7 +461,7 @@ WasmTransformIOTemplate<TParametersValueType>::GetJSON(bool inMemory) -> Transfo

template <typename TParametersValueType>
void
WasmTransformIOTemplate<TParametersValueType>::SetJSON(const TransformListJSON & json)
WasmTransformIOTemplate<TParametersValueType>::SetJSON(const TransformListJSON & json, bool inMemory)
{
// iterate over the JSON and set the transform list
TransformListType transformList;
Expand Down Expand Up @@ -496,13 +497,31 @@ WasmTransformIOTemplate<TParametersValueType>::SetJSON(const TransformListJSON &
TransformPointer transform;
this->CreateTransform(transform, transformType);
transform->SetObjectName(transformJSON.name);
// todo: ITK 5.4.1
// transform->SetInputSpaceName(transformJSON.inputSpaceName);
// transform->SetOutputSpaceName(transformJSON.outputSpaceName);

auto dictionary = transform->GetMetaDataDictionary();
jsonToMetaDataDictionary(transformJSON.metadata, dictionary);

// todo: ITK 5.4.1
// transform->SetInputSpaceName(transformJSON.inputSpaceName);
// transform->SetOutputSpaceName(transformJSON.outputSpaceName);
if (inMemory)
{
if (transformJSON.transformType.transformParameterization == JSONTransformParameterizationEnum::Composite)
{
continue;
}

using ParametersValueType = TParametersValueType;

FixedParametersValueType * fixedPtr = reinterpret_cast< FixedParametersValueType * >( std::strtoull(transformJSON.fixedParameters.substr(35).c_str(), nullptr, 10) );
transform->CopyInFixedParameters(fixedPtr, fixedPtr + transformJSON.numberOfFixedParameters);
ParametersValueType * paramsPtr = reinterpret_cast< ParametersValueType * >( std::strtoull(transformJSON.parameters.substr(35).c_str(), nullptr, 10) );
transform->CopyInParameters(paramsPtr, paramsPtr + transformJSON.numberOfParameters);

auto dictionary = transform->GetMetaDataDictionary();
jsonToMetaDataDictionary(transformJSON.metadata, dictionary);
}

this->GetReadTransformList().push_back(transform);
}
}
Expand Down

0 comments on commit d4fcf16

Please sign in to comment.