Skip to content

Commit bb29f53

Browse files
authored
Merge pull request #1411 from thewtex/emscripten-transform-output-array
emscripten transform output array
2 parents db4985c + 5187709 commit bb29f53

File tree

23 files changed

+767
-92
lines changed

23 files changed

+767
-92
lines changed

packages/core/python/itkwasm/itkwasm/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""itkwasm: Python interface to itk-wasm WebAssembly modules."""
22

3-
__version__ = "1.0b193"
3+
__version__ = "1.0b194"
44

55
from .interface_types import InterfaceTypes
66
from .image import Image, ImageType, ImageRegion

packages/core/python/itkwasm/itkwasm/image.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,16 @@ def __post_init__(self):
7171
] * dimension
7272

7373
if self.bufferedRegion is None:
74-
if self.data is not None:
74+
if self.data is not None and hasattr(self.data, 'shape'):
7575
self.bufferedRegion = ImageRegion(
7676
index=(0,) * dimension,
7777
size=self.data.shape[:dimension][::-1],
7878
)
7979
else:
8080
self.bufferedRegion = ImageRegion(
81-
index=[
81+
index=(
8282
0,
83-
]
83+
)
8484
* dimension,
8585
size=self.size,
8686
)

packages/core/python/itkwasm/itkwasm/pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ def run(
546546
data_ptr = ri.get_output_array_address(0, index, idx * 2)
547547
data_size = ri.get_output_array_size(0, index, idx * 2)
548548
transform.fixedParameters = buffer_to_numpy_array(
549-
transform.transformType.parametersValueType,
549+
FloatTypes.Float64,
550550
ri.wasmtime_lift(data_ptr, data_size),
551551
)
552552
if transform.numberOfParameters > 0:

packages/core/python/itkwasm/test/test_pyodide.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pytest_pyodide import run_in_pyodide, copy_files_to_pyodide
99

1010
#from itkwasm import __version__ as test_package_version
11-
test_package_version = '1.0b191'
11+
test_package_version = '1.0b194'
1212

1313

1414
def package_wheel():
Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,109 @@
1-
import * as itk from 'itk-wasm'
2-
globalThis.itk = itk
1+
import * as itk from "itk-wasm";
2+
globalThis.itk = itk;
33

44
function downloadFile(content, filename) {
5-
const url = URL.createObjectURL(new Blob([content]))
6-
const a = document.createElement('a')
7-
a.href = url
8-
a.download = filename || 'download'
9-
document.body.appendChild(a)
5+
// Handle shared ArrayBuffers by creating a copy
6+
let blobContent = content;
7+
if (content instanceof ArrayBuffer || ArrayBuffer.isView(content)) {
8+
// Create a copy to avoid shared ArrayBuffer issues
9+
const buffer = content instanceof ArrayBuffer ? content : content.buffer;
10+
const copy = new ArrayBuffer(buffer.byteLength);
11+
new Uint8Array(copy).set(new Uint8Array(buffer));
12+
blobContent = copy;
13+
}
14+
15+
const url = URL.createObjectURL(new Blob([blobContent]));
16+
const a = document.createElement("a");
17+
a.href = url;
18+
a.download = filename || "download";
19+
document.body.appendChild(a);
1020
function clickHandler(event) {
1121
setTimeout(() => {
12-
URL.revokeObjectURL(url)
13-
a.removeEventListener('click', clickHandler)
14-
}, 200)
15-
};
16-
a.addEventListener('click', clickHandler, false)
17-
a.click()
18-
return a
22+
URL.revokeObjectURL(url);
23+
a.removeEventListener("click", clickHandler);
24+
}, 200);
25+
}
26+
a.addEventListener("click", clickHandler, false);
27+
a.click();
28+
return a;
1929
}
20-
globalThis.downloadFile = downloadFile
30+
globalThis.downloadFile = downloadFile;
2131

22-
function interfaceTypeJsonReplacer (key, value) {
32+
function interfaceTypeJsonReplacer(key, value) {
2333
if (!!value && value.byteLength !== undefined) {
24-
return String(value.slice(0, 6)) + '...'
34+
return String(value.slice(0, 6)) + "...";
2535
}
26-
return value
36+
return value;
2737
}
28-
globalThis.interfaceTypeJsonReplacer = interfaceTypeJsonReplacer
38+
globalThis.interfaceTypeJsonReplacer = interfaceTypeJsonReplacer;
2939

3040
function escapeHtml(html) {
31-
const div = document.createElement('div');
41+
const div = document.createElement("div");
3242
div.textContent = html;
3343
const escaped = div.innerHTML;
34-
div.remove()
35-
return escaped
44+
div.remove();
45+
return escaped;
3646
}
37-
globalThis.escapeHtml = escapeHtml
47+
globalThis.escapeHtml = escapeHtml;
3848

39-
function notify(title, message, variant = 'primary', icon = 'info-circle', duration = 3000) {
40-
const slAlert = Object.assign(document.createElement('sl-alert'), {
49+
function notify(
50+
title,
51+
message,
52+
variant = "primary",
53+
icon = "info-circle",
54+
duration = 3000
55+
) {
56+
const slAlert = Object.assign(document.createElement("sl-alert"), {
4157
variant,
4258
closable: true,
4359
duration: duration,
4460
innerHTML: `
4561
<sl-icon name="${icon}" slot="icon"></sl-icon>
4662
<strong>${escapeHtml(title)}</strong><br />
4763
${escapeHtml(message)}
48-
`
64+
`,
4965
});
5066

5167
document.body.append(slAlert);
52-
setTimeout(() => slAlert.toast(), 300)
68+
setTimeout(() => slAlert.toast(), 300);
5369
}
54-
globalThis.notify = notify
70+
globalThis.notify = notify;
5571

5672
function disableInputs(inputId) {
57-
document.querySelectorAll(`#${inputId} sl-button`).forEach(button => {
58-
button.disabled = true
59-
})
60-
document.querySelector(`#${inputId} sl-button[name="run"]`).loading = true
61-
document.querySelectorAll(`#${inputId} sl-checkbox`).forEach(checkbox => {
62-
checkbox.disabled = true
63-
})
64-
document.querySelectorAll(`#${inputId} sl-input`).forEach(input => {
65-
input.disabled = true
66-
})
73+
document.querySelectorAll(`#${inputId} sl-button`).forEach((button) => {
74+
button.disabled = true;
75+
});
76+
document.querySelector(`#${inputId} sl-button[name="run"]`).loading = true;
77+
document.querySelectorAll(`#${inputId} sl-checkbox`).forEach((checkbox) => {
78+
checkbox.disabled = true;
79+
});
80+
document.querySelectorAll(`#${inputId} sl-input`).forEach((input) => {
81+
input.disabled = true;
82+
});
6783
}
68-
globalThis.disableInputs = disableInputs
84+
globalThis.disableInputs = disableInputs;
6985

7086
function enableInputs(inputId) {
71-
document.querySelectorAll(`#${inputId} sl-button`).forEach(button => {
72-
button.disabled = false
73-
})
74-
document.querySelector(`#${inputId} sl-button[name="run"]`).loading = false
75-
document.querySelectorAll(`#${inputId} sl-checkbox`).forEach(checkbox => {
76-
checkbox.disabled = false
77-
})
78-
document.querySelectorAll(`#${inputId} sl-input`).forEach(input => {
79-
input.disabled = false
80-
})
87+
document.querySelectorAll(`#${inputId} sl-button`).forEach((button) => {
88+
button.disabled = false;
89+
});
90+
document.querySelector(`#${inputId} sl-button[name="run"]`).loading = false;
91+
document.querySelectorAll(`#${inputId} sl-checkbox`).forEach((checkbox) => {
92+
checkbox.disabled = false;
93+
});
94+
document.querySelectorAll(`#${inputId} sl-input`).forEach((input) => {
95+
input.disabled = false;
96+
});
8197
}
82-
globalThis.enableInputs = enableInputs
98+
globalThis.enableInputs = enableInputs;
8399

84100
function applyInputParsedJson(inputElement, modelMap, parameterName) {
85101
try {
86-
const parsedJson = JSON.parse(inputElement.value)
87-
modelMap.set(parameterName, parsedJson)
88-
inputElement.setCustomValidity('')
102+
const parsedJson = JSON.parse(inputElement.value);
103+
modelMap.set(parameterName, parsedJson);
104+
inputElement.setCustomValidity("");
89105
} catch (error) {
90-
inputElement.setCustomValidity(error.message)
106+
inputElement.setCustomValidity(error.message);
91107
}
92108
}
93-
globalThis.applyInputParsedJson = applyInputParsedJson
109+
globalThis.applyInputParsedJson = applyInputParsedJson;

packages/core/typescript/itk-wasm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "itk-wasm",
3-
"version": "1.0.0-b.188",
3+
"version": "1.0.0-b.192",
44
"description": "High-performance spatial analysis in a web browser, Node.js, and reproducible execution across programming languages and hardware architectures.",
55
"type": "module",
66
"module": "./dist/index.js",

packages/core/typescript/itk-wasm/src/bindgen/typescript/resources/template.package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"author": "",
3434
"license": "Apache-2.0",
3535
"dependencies": {
36-
"itk-wasm": "1.0.0-b.188"
36+
"itk-wasm": "1.0.0-b.192"
3737
},
3838
"devDependencies": {
3939
"@itk-wasm/demo-app": "^0.2.0",

packages/core/typescript/itk-wasm/src/pipeline/internal/run-pipeline-emscripten.ts

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -313,21 +313,34 @@ function runPipelineEmscripten (
313313
case InterfaceTypes.TransformList: {
314314
const transformList = input.data as TransformList
315315
const transformListJSON: any = []
316-
transformList.forEach((transform, transformIndex) => {
317-
const fixedParameterPtr = setPipelineModuleInputArray(
318-
pipelineModule,
319-
transform.fixedParameters,
320-
index,
321-
transformIndex * 2
322-
)
323-
const fixedParameters = `data:application/vnd.itk.address,0:${fixedParameterPtr}`
324-
const parameterPtr = setPipelineModuleInputArray(
325-
pipelineModule,
326-
transform.parameters,
327-
index,
328-
transformIndex * 2 + 1
329-
)
330-
const parameters = `data:application/vnd.itk.address,0:${parameterPtr}`
316+
let inputArrayIndex = 0
317+
transformList.forEach((transform) => {
318+
let fixedParameters = ''
319+
let parameters = ''
320+
321+
// Skip setting input arrays for Composite transforms as they don't have array data
322+
if (
323+
transform.transformType.transformParameterization !== 'Composite'
324+
) {
325+
const fixedParameterPtr = setPipelineModuleInputArray(
326+
pipelineModule,
327+
transform.fixedParameters,
328+
index,
329+
inputArrayIndex
330+
)
331+
fixedParameters = `data:application/vnd.itk.address,0:${fixedParameterPtr}`
332+
inputArrayIndex += 1
333+
334+
const parameterPtr = setPipelineModuleInputArray(
335+
pipelineModule,
336+
transform.parameters,
337+
index,
338+
inputArrayIndex
339+
)
340+
parameters = `data:application/vnd.itk.address,0:${parameterPtr}`
341+
inputArrayIndex += 1
342+
}
343+
331344
const transformJSON = {
332345
transformType: transform.transformType,
333346
numberOfFixedParameters: transform.numberOfFixedParameters,
@@ -659,25 +672,33 @@ function runPipelineEmscripten (
659672
pipelineModule,
660673
index
661674
) as TransformList
675+
let outputArrayIndex = 0
662676
transformList.forEach((transform, transformIndex) => {
677+
if (
678+
transform.transformType.transformParameterization === 'Composite'
679+
) {
680+
return
681+
}
663682
if (transform.numberOfFixedParameters > 0) {
664683
transformList[transformIndex].fixedParameters =
665684
getPipelineModuleOutputArray(
666685
pipelineModule,
667686
index,
668-
transformIndex * 2,
669-
transform.transformType.parametersValueType
687+
outputArrayIndex,
688+
FloatTypes.Float64
670689
) as TypedArray
671690
}
672-
if (transform.numberOfFixedParameters > 0) {
691+
outputArrayIndex += 1
692+
if (transform.numberOfParameters > 0) {
673693
transformList[transformIndex].parameters =
674694
getPipelineModuleOutputArray(
675695
pipelineModule,
676696
index,
677-
transformIndex * 2 + 1,
697+
outputArrayIndex,
678698
transform.transformType.parametersValueType
679699
) as TypedArray
680700
}
701+
outputArrayIndex += 1
681702
})
682703
outputData = transformList
683704
break
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
const version = '1.0.0-b.188'
1+
const version = '1.0.0-b.192'
22

33
export default version

0 commit comments

Comments
 (0)