5.3 KiB
5.3 KiB
Report: DICOMweb proxy recommendation
- Todo:
todo/01-dicom-web-proxy-recommendation.md - Detail:
todo/01-dicom-web-proxy-recommendation.detail.md - Branch:
feature/dicomweb-proxy-recommendation - Commits:
0c680b6,3ac04f9 - Status: implemented, build + lint + tests pass
What was implemented
P0 - metadata display correctness
The hand-built metadata subset in parseMeta.ts was replaced with a
VR-aware DICOM-to-DICOM-JSON converter (src/dimse/dicomJson.ts).
| Requirement | Result |
|---|---|
| Stop fabricating Window Center (0028,1050) | Done |
| Stop fabricating Window Width (0028,1051) | Done |
| Stop fabricating Rescale Intercept (0028,1052) | Done |
| Stop fabricating Rescale Slope (0028,1053) | Done |
| Preserve multi-valued WC/WW and rescale | Done |
| Preserve VOI/LUT/presentation/padding tags | Done |
Omit absent optional tags (no [undefined]) |
Done |
Converter behavior:
- Uses explicit
element.vr, then the DICOM dictionary as fallback. - Resolves ambiguous dictionary VRs (for example
US or SSfor padding). - Handles string, numeric,
DS/IS,AT,PNand binary VRs. - Recursively converts
SQitems and keeps LUT sequences. - Encodes binary LUT payloads as
InlineBinary(base64). - Excludes Pixel Data, float pixel data and overlay data.
- Excludes private (odd-group) tags by default.
P1 - WADO-RS frame correctness
| Requirement | Result |
|---|---|
| Validate frame as positive 1-based integer | Done |
| Return 400 for invalid values | Done |
Thread frame into doWadoRs/buffer builder |
Done |
| Return only requested uncompressed frame | Done |
| Explicit unsupported response for compressed | Done (415) |
| Never fall back to full Pixel Data | Done |
JPEG only on /rendered and /thumbnail |
Done |
Frame log with jpegRendererUsed=false |
Done |
Frame slicing details:
NumberOfFrames(0028,0008) defaults to 1 only when absent.- Validates
1 <= frame <= NumberOfFrames. - Frame size uses Rows, Columns, SamplesPerPixel and BitsAllocated.
- Supports 1-bit and byte-aligned BitsAllocated.
- Too-short Pixel Data is a 500 server error, not a full-buffer fallback.
- Compressed or encapsulated Pixel Data is rejected with 415.
- Frame
Content-Locationuses the canonical/instances/.../frames/{n}URL.
P2 - tests and verification
| Requirement | Result |
|---|---|
| Synthetic non-PHI CR and multi-frame fixtures | Done |
| Absent WC/WW stays absent | Done |
| Absent rescale stays absent | Done |
| Multi-valued WC/WW preserved | Done |
/frames/1 and /frames/2 differ |
Done |
| Invalid frame numbers return 400 | Done |
| Compressed extraction returns 415/501 | Done |
npm run build and test suite |
Done |
Files changed
| File | Change |
|---|---|
src/dimse/dicomJson.ts |
New DICOM-to-DICOM-JSON converter |
src/dimse/frameExtractor.ts |
New native frame slicing + param parser |
src/dimse/errors.ts |
New status-bearing error types |
src/dimse/parseMeta.ts |
Uses the converter instead of a static map |
src/dimse/wadoRs.ts |
Threads frame, logs, frame Content-Location |
src/routes/routes.ts |
Validates frame, maps error status codes |
tests/dicomJson.test.ts |
Metadata regression tests |
tests/frameExtractor.test.ts |
Frame extraction tests |
tests/helpers/dicomWriter.ts |
Synthetic DICOM writer (test-only) |
package.json |
Added npm test script |
tsconfig.json |
Added skipLibCheck |
Deviations from the plan
- The plan's "preferred end state" converter is implemented, but the
metadata route still returns an array of per-instance datasets to keep
the existing
fetchMetacontract intact. - Private tags are excluded from metadata output. The plan did not require them; excluding them keeps responses small and avoids site-private data.
convertToJpegremains untouched on the rendered/thumbnail paths.- No integration test exercises the Fastify HTTP routes, because that path
imports
dicom-dimse-nativeand needs a live PACS. Route-level frame validation is covered throughparseFrameParamand service errors. skipLibCheckwas enabled intsconfig.json. Without itnpm run buildfails on a pre-existing@types/glob/minimatchmismatch in dependencies.
Verification
npm run build-> passnpm test-> 16 tests, 16 pass, 0 failnpx eslinton changed files -> no errors
Manual visual verification of a Jam-like CR fixture was not possible in this
environment: the original study data is not available. The synthetic CR
fixture proves no 40/80 window is fabricated, which is the stated root cause.
Documentation Updates Needed
This repository has no docs/ directory. Optional updates:
README.md
Add a test section after the "Setup Instructions - source" block:
## Testing
* run the unit tests (uses node:test):
```npm test```