Skip to content

Commit caa5339

Browse files
committed
ultrasound: replace JSON-in-tags sidecar with typed channel
Stop encoding UltrasoundRegions as a JSON string under a magic key on the DICOM tag pair array and decoding it back. Expose it as a typed property on MetaLoader, surface it on Chunk, and read it directly in DicomChunkImage. The tag pair array now only contains DICOM tag/value pairs.
1 parent 3775479 commit caa5339

7 files changed

Lines changed: 13 additions & 71 deletions

File tree

src/core/streaming/chunk.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ export class Chunk {
8686
return this.metaLoader.metaBlob;
8787
}
8888

89+
get ultrasoundRegions() {
90+
return this.metaLoader.ultrasoundRegions ?? null;
91+
}
92+
8993
get dataBlob() {
9094
return this.dataLoader.data;
9195
}

src/core/streaming/dicom/__tests__/ultrasoundRegion.spec.ts

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@ import { describe, it, expect } from 'vitest';
22
import type { DataElement } from '@/src/core/streaming/dicom/dicomParser';
33
import {
44
decodeUltrasoundRegion,
5-
encodeUltrasoundRegionMeta,
6-
getUltrasoundRegionFromMetadata,
75
parseUltrasoundRegionFromBlob,
86
unitToMm,
9-
US_REGION_META_KEY,
107
US_UNIT_CENTIMETERS,
118
} from '@/src/core/streaming/dicom/ultrasoundRegion';
129

@@ -153,41 +150,6 @@ describe('unitToMm', () => {
153150
});
154151
});
155152

156-
describe('encodeUltrasoundRegionMeta / getUltrasoundRegionFromMetadata', () => {
157-
it('round-trips through the metadata tag array', () => {
158-
const regions = {
159-
region: {
160-
physicalDeltaX: 0.05,
161-
physicalDeltaY: 0.1,
162-
physicalUnitsXDirection: US_UNIT_CENTIMETERS,
163-
physicalUnitsYDirection: US_UNIT_CENTIMETERS,
164-
},
165-
regionCount: 2,
166-
};
167-
const entry = encodeUltrasoundRegionMeta(regions);
168-
expect(entry[0]).toBe(US_REGION_META_KEY);
169-
170-
const meta: Array<[string, string]> = [
171-
['0008|0060', 'US'],
172-
entry,
173-
['0010|0010', 'PATIENT^NAME'],
174-
];
175-
expect(getUltrasoundRegionFromMetadata(meta)).toEqual(regions);
176-
});
177-
178-
it('returns null when the entry is absent', () => {
179-
expect(getUltrasoundRegionFromMetadata([])).toBeNull();
180-
expect(getUltrasoundRegionFromMetadata(null)).toBeNull();
181-
expect(getUltrasoundRegionFromMetadata(undefined)).toBeNull();
182-
});
183-
184-
it('returns null when the entry value is unparseable', () => {
185-
expect(
186-
getUltrasoundRegionFromMetadata([[US_REGION_META_KEY, 'not-json']])
187-
).toBeNull();
188-
});
189-
});
190-
191153
// Builds a minimal DICOM P10 byte stream containing only what the ultrasound
192154
// parser needs: preamble, DICM magic, a TransferSyntaxUID (Explicit VR LE),
193155
// and a SequenceOfUltrasoundRegions with one populated item.

src/core/streaming/dicom/dicomFileMetaLoader.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { MetaLoader } from '@/src/core/streaming/types';
33
import { Maybe } from '@/src/types';
44
import { Tags } from '@/src/core/dicomTags';
55
import {
6-
encodeUltrasoundRegionMeta,
76
parseUltrasoundRegionFromBlob,
7+
UltrasoundRegions,
88
} from '@/src/core/streaming/dicom/ultrasoundRegion';
99

1010
export class DicomFileMetaLoader implements MetaLoader {
1111
public tags: Maybe<Array<[string, string]>>;
12+
public ultrasoundRegions: UltrasoundRegions | null = null;
1213
private file: File;
1314

1415
constructor(
@@ -32,10 +33,7 @@ export class DicomFileMetaLoader implements MetaLoader {
3233

3334
const modality = new Map(this.tags).get(Tags.Modality)?.trim();
3435
if (modality === 'US') {
35-
const regions = await parseUltrasoundRegionFromBlob(this.file);
36-
if (regions) {
37-
this.tags.push(encodeUltrasoundRegionMeta(regions));
38-
}
36+
this.ultrasoundRegions = await parseUltrasoundRegionFromBlob(this.file);
3937
}
4038
}
4139

src/core/streaming/dicom/dicomMetaLoader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { FILE_EXT_TO_MIME } from '@/src/io/mimeTypes';
1111
import { Tags } from '@/src/core/dicomTags';
1212
import {
1313
decodeUltrasoundRegion,
14-
encodeUltrasoundRegionMeta,
1514
SEQUENCE_OF_ULTRASOUND_REGIONS,
1615
UltrasoundRegions,
1716
} from '@/src/core/streaming/dicom/ultrasoundRegion';
@@ -34,6 +33,7 @@ export class DicomMetaLoader implements MetaLoader {
3433
private fetcher: Fetcher;
3534
private readDicomTags: ReadDicomTagsFunction;
3635
private blob: Blob | null;
36+
public ultrasoundRegions: UltrasoundRegions | null = null;
3737

3838
constructor(fetcher: Fetcher, readDicomTags: ReadDicomTagsFunction) {
3939
this.fetcher = fetcher;
@@ -131,7 +131,7 @@ export class DicomMetaLoader implements MetaLoader {
131131
this.tags = await this.readDicomTags(metadataFile);
132132

133133
if (modality === 'US' && ultrasoundRegions) {
134-
this.tags.push(encodeUltrasoundRegionMeta(ultrasoundRegions));
134+
this.ultrasoundRegions = ultrasoundRegions;
135135
}
136136
}
137137

src/core/streaming/dicom/ultrasoundRegion.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import {
44
} from '@/src/core/streaming/dicom/dicomParser';
55
import { Tags, tagToGroupElement } from '@/src/core/dicomTags';
66

7-
export const US_REGION_META_KEY = '__volview_us_region';
8-
97
// DICOM unit codes for PhysicalUnitsXDirection / YDirection.
108
// See DICOM PS3.3 C.8.5.5.1.15. The only spatial spacing code defined for
119
// this field is 3 (cm). Other codes (0=none, 1=percent, 2=dB, 4=seconds,
@@ -144,22 +142,3 @@ export async function parseUltrasoundRegionFromBlob(
144142

145143
return regions;
146144
}
147-
148-
export function encodeUltrasoundRegionMeta(
149-
regions: UltrasoundRegions
150-
): [string, string] {
151-
return [US_REGION_META_KEY, JSON.stringify(regions)];
152-
}
153-
154-
export function getUltrasoundRegionFromMetadata(
155-
meta: ReadonlyArray<readonly [string, string]> | null | undefined
156-
): UltrasoundRegions | null {
157-
if (!meta) return null;
158-
const entry = meta.find(([key]) => key === US_REGION_META_KEY);
159-
if (!entry) return null;
160-
try {
161-
return JSON.parse(entry[1]) as UltrasoundRegions;
162-
} catch {
163-
return null;
164-
}
165-
}

src/core/streaming/dicomChunkImage.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ import {
2626
import { ensureError } from '@/src/utils';
2727
import { computed } from 'vue';
2828
import vtkITKHelper from '@kitware/vtk.js/Common/DataModel/ITKHelper';
29-
import {
30-
getUltrasoundRegionFromMetadata,
31-
unitToMm,
32-
} from '@/src/core/streaming/dicom/ultrasoundRegion';
29+
import { unitToMm } from '@/src/core/streaming/dicom/ultrasoundRegion';
3330

3431
const { fastComputeRange } = vtkDataArray;
3532

@@ -289,7 +286,7 @@ export default class DicomChunkImage
289286
private applyUltrasoundSpacing() {
290287
if (this.getModality() !== 'US') return;
291288

292-
const regions = getUltrasoundRegionFromMetadata(this.getDicomMetadata());
289+
const regions = this.chunks[0]?.ultrasoundRegions ?? null;
293290
if (!regions?.region) return;
294291

295292
// VTK image data has a single global spacing, so multi-region images

src/core/streaming/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Maybe } from '@/src/types';
22
import { Awaitable } from '@vueuse/core';
3+
import type { UltrasoundRegions } from '@/src/core/streaming/dicom/ultrasoundRegion';
34

45
export type LoaderEvents = {
56
error: any;
@@ -17,6 +18,7 @@ interface Loader {
1718
export interface MetaLoader extends Loader {
1819
meta: Maybe<Array<[string, string]>>;
1920
metaBlob: Maybe<Blob>;
21+
ultrasoundRegions?: UltrasoundRegions | null;
2022
}
2123

2224
/**

0 commit comments

Comments
 (0)