Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ DICOMKit is a pure Swift DICOM (Digital Imaging and Communications in Medicine)
- Any new dependency must be justified and reviewed
- Use Swift Package Manager for dependency management

## J2KSwift Bug Handling Policy

**IMPORTANT**: When working on JPEG 2000 functionality backed by J2KSwift:

- **Do not add DICOMKit-side fixes, fallbacks, masking logic, or workarounds** for confirmed J2KSwift bugs unless the user explicitly requests a temporary workaround.
- If a bug is found in J2KSwift, **reproduce it, keep the failure visible, and report it** rather than hiding it behind ImageIO or alternate codec paths.
- Document the issue in `J2KSWIFT_BUG_REPORT.md` and update the relevant milestone or integration plan to mark the work as blocked upstream.
- Prefer upstream fixes in `Raster-Lab/J2KSwift` over downstream behavior changes in DICOMKit.
- If a temporary mitigation is ever explicitly approved by the user, it must be clearly labeled as temporary and must not replace the upstream bug report.

This policy exists to ensure DICOMKit does not silently diverge from J2KSwift behavior and that codec defects are fixed at the correct layer.

## Performance Considerations

- DICOM files can be large - optimize for memory efficiency
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ Package.resolved
docker-compose.override.yml
orthanc-db-data/
dcm4chee-db-data/

# Local datasets
LocalDatasets/
40 changes: 40 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,46 @@
"target": "DICOMStudioApp",
"configuration": "release",
"preLaunchTask": "swift: Build Release DICOMStudioApp"
},
{
"type": "swift",
"request": "launch",
"args": [],
"cwd": "${workspaceFolder:DICOMKit}",
"name": "Debug dicom-jpip",
"target": "dicom-jpip",
"configuration": "debug",
"preLaunchTask": "swift: Build Debug dicom-jpip"
},
{
"type": "swift",
"request": "launch",
"args": [],
"cwd": "${workspaceFolder:DICOMKit}",
"name": "Release dicom-jpip",
"target": "dicom-jpip",
"configuration": "release",
"preLaunchTask": "swift: Build Release dicom-jpip"
},
{
"type": "swift",
"request": "launch",
"args": [],
"cwd": "${workspaceFolder:DICOMKit}",
"name": "Debug dicom-j2k",
"target": "dicom-j2k",
"configuration": "debug",
"preLaunchTask": "swift: Build Debug dicom-j2k"
},
{
"type": "swift",
"request": "launch",
"args": [],
"cwd": "${workspaceFolder:DICOMKit}",
"name": "Release dicom-j2k",
"target": "dicom-j2k",
"configuration": "release",
"preLaunchTask": "swift: Build Release dicom-j2k"
}
]
}
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added — J2KSwift v3.2.0 Integration (Phases 1–9)

- **J2KSwift v3.2.0 codec stack** (`Sources/DICOMCore/J2KSwiftCodec.swift`, `HTJ2KCodec.swift`, `JP3DCodec.swift`): Replaces Apple ImageIO as the primary JPEG 2000 path on all platforms, enabling full Linux support via a pure-Swift scalar backend.
- `J2KSwiftCodec`: Handles JPEG 2000 Lossless (`.90`), JPEG 2000 Lossy (`.91`), Part 2 Lossless (`.92`), Part 2 Lossy (`.93`) with 8/12/16-bit grayscale and RGB support.
- `HTJ2KCodec`: Full HTJ2K Lossless (`.201`), HTJ2K RPCL Lossless (`.202`), HTJ2K Lossy (`.203`). Fast-path transcoder via `J2KTranscoder` (no pixel decode); 5.4× decode speedup over J2K on macOS arm64.
- `JP3DCodec`: ISO/IEC 15444-10 volumetric encoding/decoding for multi-frame CT/MR/PET series with lossless, lossless-HTJ2K, and lossy modes.
- **JPIP streaming** (`Sources/DICOMKit/DICOMJPIPClient.swift`): Progressive 2D and 3D tile streaming for large remote studies; transfer syntaxes JPIP Referenced (`.94`) and JPIP Referenced Deflate (`.95`) registered.
- `dicom-jpip` CLI tool with `fetch`, `uri`, `serve`, and `info` subcommands.
- `DICOMFile.openVolumeProgressively(serverURL:sliceJPIPURIs:qualityLayers:)` API for huge CT/MR datasets.
- **JP3D volume bridge** (`Sources/DICOMKit/JP3DVolumeBridge.swift`): Converts multi-frame DICOM series ↔ `J2KVolume`; preserves `SliceLocation`, `ImagePositionPatient`, `SeriesInstanceUID`.
- `JP3DVolumeDocument`: Encapsulated document SOP (private SOP `1.2.826.0.1.3680043.10.511.10`) with `.jp3d` payload + JSON sidecar; MIME type `application/x-jp3d`.
- `DICOMFile.openVolume(from:)` / `openVolume(from:jpipServerURL:)` for unified volume access.
- **Hardware acceleration** (`CodecBackend` enum): Metal (Apple GPU), Accelerate (SIMD), scalar fallback; `CodecBackendProbe` selects best available at runtime. `--backend` flag on `dicom-compress` and `dicom-3d`.
- **`dicom-j2k` CLI tool** (8 subcommands): `info`, `validate`, `transcode`, `reduce`, `roi`, `benchmark`, `compare`, `completions`. 53 tests.
- **DICOMStudio enhancements**:
- Progressive decoding with `ProgressiveDecodeModel` / `ProgressiveImageView` (AsyncStream-driven `.quarter → .half → .complete` state machine).
- ROI decoding wired to pinch-zoom gestures.
- JP3D MPR views (axial / sagittal / coronal) via `JP3DMPRViewModel` / `JP3DMPRView`.
- JPIP loader with quality-layer slider.
- **Transfer syntaxes** added to registry, `DICOMValidator`, and `StorageSCP` presentation contexts: `.htj2kLossless`, `.htj2kRPCLLossless`, `.htj2kLossy`, `.jpip`, `.jpipDeflate`, `.jpeg2000Part2Lossless`, `.jpeg2000Part2`.
- **DICOMweb HTJ2K media types**: `image/jph` and `image/jphc` advertised in capability; WADO-RS accept headers updated.
- **`dicom-compress`**, **`dicom-convert`**, **`dicom-send`**, **`dicom-retrieve`**, **`dicom-viewer`**, **`dicom-info`**, **`dicom-validate`** extended for HTJ2K, JP3D, and JPIP transfer syntaxes.
- **Codec Inspector panel** in DICOMStudio: shows decoder name, backend (Metal/Accelerate/scalar), and decode timing.

### Fixed
- **JPEG 2000 16-bit rendering pipeline**: Fixed near-black output after conversion when preserving original bit depth
- Normalized ImageIO-decoded 16-bit JPEG 2000 samples back to the DICOM `Bits Stored` range in `NativeJPEG2000Codec`
Expand Down
34 changes: 34 additions & 0 deletions CLI_TOOLS_COMPLETION_SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,3 +568,37 @@ Phase 2 enhancement is **IN PROGRESS**. The dicom-diff tool has been successfull
✅ **Comprehensive documentation**

🎉 **Mission Accomplished!** 🎉

---

## Phase 9 — J2KSwift v3 CLI Tools

### `dicom-j2k` (Phase 9.1) ✅

JPEG 2000 / HTJ2K codestream operations on DICOM files. All subcommands bridge the synchronous `ParsableCommand.run()` API to J2KSwift's async codec via a reusable `runAsync` helper.

| Subcommand | Purpose |
|------------|---------|
| `info` | Show J2K/HTJ2K codestream metadata (text or JSON) |
| `validate` | ISO/IEC 15444-4 conformance using `HTJ2KConformanceTestHarness` + `J2KHTInteroperabilityValidator` |
| `transcode` | J2K ↔ HTJ2K re-encode while preserving DICOM metadata |
| `reduce` | Re-encode at fewer wavelet levels or quality layers |
| `roi` | Crop a frame to a region of interest and re-wrap as DICOM |
| `benchmark` | Decode-speed timing via `J2KBenchmark` (avg, median, min, max, std dev) |
| `compare` | Pixel-level PSNR / MSE / MAE between two DICOM images |
| `completions` | Generate bash / zsh / fish shell completion scripts |

- **Lines of code**: ~670 (`Sources/dicom-j2k/main.swift`)
- **Tests**: 53 tests across 8 suites (`Tests/dicom-j2kTests/DicomJ2KTests.swift`)
- **Dependencies**: `J2KCore`, `J2KCodec`, `J2KFileFormat`, `DICOMKit`, `DICOMCore`, `DICOMDictionary`, `ArgumentParser`

---

### Phase 9.2 — Existing CLI Tool Updates ✅

| Tool | What Changed |
|------|-------------|
| `dicom-info` | Auto J2K section (`=== JPEG 2000 Codestream Info ===`) when `--statistics` used on J2K file; `J2KCore` + `J2KCodec` dependencies added to target |
| `dicom-validate` | Level 5 validation (`--level 5`): full ISO 15444-4 codestream check via `HTJ2KConformanceTestHarness` + `J2KHTInteroperabilityValidator`; `J2KCore` dependency added |
| `dicom-compress` | HTJ2K codec names (`htj2k`, `htj2k-lossless`, `htj2k-rpcl`) documented in `Compress` discussion text; HTJ2K label shown in `info` output |
| `dicom-convert` | HTJ2K target syntaxes already present (no change needed) |
26 changes: 13 additions & 13 deletions DICOMStudio.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,6 @@
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXResourcesBuildPhase section */
DA0A00000000000000000032 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DA0A00000000000000000022 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXGroup section */
DA0A00000000000000000002 = {
isa = PBXGroup;
Expand Down Expand Up @@ -135,6 +124,17 @@
};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
DA0A00000000000000000032 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DA0A00000000000000000022 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
DA0A00000000000000000030 /* Sources */ = {
isa = PBXSourcesBuildPhase;
Expand Down Expand Up @@ -198,7 +198,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 15.6;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -254,7 +254,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MACOSX_DEPLOYMENT_TARGET = 15.6;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
Expand Down
Loading
Loading