* fix(pt): resolve Philips PET private SUV bulkdata before scaling
When a DICOMweb server delivers the Philips PET private tags SUVScaleFactor
(7053,1000) / ActivityConcentrationScaleFactor (7053,1009) as bulkdata, dcmjs
naturalization leaves them as { BulkDataURI } objects. These were fed verbatim
to calculate-suv, which treats the object as a valid value and silently
corrupts the SUV scaling factors.
Resolve these scalar private tags to numbers during ingestion - in both the
lazy (async) and non-lazy (sync) DICOMweb metadata paths, before INSTANCES_ADDED
fires - by decoding the bulkdata (VR-aware: DS/IS text or little-endian FL/FD).
Harden getPTImageIdInstanceMetadata to coerce values to finite numbers (reusing
@ohif/core utils.toNumber) and reject unresolved bulkdata objects so they can
never reach calculate-suv. Share the bulkdata-attach helper between both
metadata paths. Adds unit tests for the bulkdata decoder/resolver and for
getPTImageIdInstanceMetadata.
* refactor(bulkdata): move PET bulkdata resolution to a generic core tag registry
Generalize resolvePETPrivateScalarBulkData into a datasource-agnostic
utils.resolveBulkDataTags in @ohif/core, backed by a static tag registry
seeded with the Philips PET SUV/activity-concentration scalar tags and
extensible via registerResolvedBulkDataTags.
* fix(bulkdata): strip NUL padding and refresh qido auth before resolution
Address review feedback:
- decodeText now strips NUL (0x00) padding, which String.trim() leaves
intact, so NUL-padded DS/IS values no longer decode as NaN. Adds a
regression test.
- refresh qidoDicomWebClient.headers before resolveBulkDataTags in both
series-metadata paths; retrieveBulkData is bound to qidoDicomWebClient,
matching every other qido op in this file.
* fix(dicomweb): await deferred metadata storage
* fix(dicomweb): support single-part bulkdata responses
32 lines
1.2 KiB
TypeScript
32 lines
1.2 KiB
TypeScript
/**
|
|
* A bindable function that retrieves bulkdata against `this` DICOMweb client
|
|
* and caches the resolved buffer on the given value element.
|
|
*
|
|
* @param value - A bound value that stores the retrieved buffer.
|
|
* @param options - Options such as the requested content type.
|
|
*/
|
|
export default function retrieveBulkData(value, options = {}) {
|
|
const { mediaType } = options;
|
|
const useOptions = {
|
|
// The bulkdata fetches work with either multipart or singlepart, so set
|
|
// multipart to false to let the server decide which type to respond with.
|
|
multipart: false,
|
|
BulkDataURI: value.BulkDataURI,
|
|
mediaTypes: mediaType ? [{ mediaType }, { mediaType: 'application/octet-stream' }] : undefined,
|
|
...options,
|
|
};
|
|
|
|
return this.retrieveBulkData(useOptions).then(val => {
|
|
// Single-part clients return a bare ArrayBuffer. Multipart clients return
|
|
// an array; DICOM PDF/video payloads may occupy different positions, so
|
|
// select the first non-empty part in that response shape.
|
|
const ret = Array.isArray(val)
|
|
? val.find(arrayBuffer => arrayBuffer?.byteLength)
|
|
: val?.byteLength
|
|
? val
|
|
: undefined;
|
|
value.Value = ret;
|
|
return ret;
|
|
});
|
|
}
|