Skip to content

release: v10.17.0 — J2KDICOMHelpers Phase 1 (new SwiftPM product)#453

Merged
SureshKViswanathan merged 1 commit into
mainfrom
v10.17.0-release-candidate
May 26, 2026
Merged

release: v10.17.0 — J2KDICOMHelpers Phase 1 (new SwiftPM product)#453
SureshKViswanathan merged 1 commit into
mainfrom
v10.17.0-release-candidate

Conversation

@SureshKViswanathan

Copy link
Copy Markdown
Contributor

Summary

  • Ships a new public J2KDICOMHelpers SwiftPM library bridging DICOM Transfer Syntax UIDs to J2KEncodingConfiguration. Closes a long-standing product-layer gap: library consumers parsing DICOM with their own library (DICOMKit, pydicom-via-XPC, etc.) get a Transfer Syntax UID + Pixel Data bytes, and previously had to hand-roll the UID-to-config mapping.
  • ADR-004 compliant: no DICOM library dependency anywhere in J2KSwift. The new product depends only on J2KCore + J2KCodec. Consumers not importing J2KDICOMHelpers are completely unaffected.
  • MINOR per RELEASING.md — entirely additive: new product, zero touch to existing libraries, codestream bytes byte-identical to v10.16.0.

Public surface added

API Description
J2KDICOMTransferSyntax enum (7 cases) All 7 DICOM Part 5 Annex A JPEG 2000 / HTJ2K UIDs, CaseIterable, UID round-trip + classification flags (isLossless / isHTJ2K / isPart2)
J2KDICOMTransferSyntax.encodingConfiguration(bitDepth:psnrTarget:) Returns matching J2KEncodingConfiguration with htj2kBlockFormat: .conformant for DICOM interop
J2KDICOMCodestreamDetector.detect(_:) SOC + CAP sniff → .j2kLossless / .htj2kLossless; returns nil for non-J2K bytes
J2KDICOMPhotometricInterpretation enum (7 cases) DICOM PhotometricInterpretation mirror + bidirectional J2KColorSpace mapping

Correctness gate (release mode)

  • V10_29_TransferSyntaxRoundTripTests 9/9 PASS
  • V10_29_EncodingConfigurationParityTests 5/5 PASS (incl. bit-exact lossless round-trip)
  • V10_29_CodestreamDetectionTests 6/6 PASS
  • V10_29_PhotometricInterpretationTests 6/6 PASS
  • V10_29 total: 26/26 PASS
  • swift test --filter JP3D regression 528/528 PASS (1 pre-existing skip)
  • J2KMedicalCorpusEncodePerformanceTests 2/2 PASS
  • J2KMedicalCorpusPerformanceTests 2/2 PASS
  • J2KStrictCrossCodecValidationTests 3/3 PASS

Mandatory commit gate: 7/7 PASS release mode.

Phase 1 scope discipline

Phase 1 deliberately ships the smallest viable shape — UID-and-config bridge only. Phase 2 (likely v10.18+) would extract more of J2KCLI/DICOMSupport.swift's file-parsing logic or ship a DICOMKit adapter as a sibling opt-in product. AsyncSequence progress streams (originally Phase 3 of the v10.17.0 plan) deferred to a dedicated MINOR — the AsyncStream-vs-actor-stored-callback lifecycle has subtle correctness questions that warrant a focused ship rather than being squeezed in.

Test plan

  • Mandatory pre-release gate (release mode)
  • Full JP3D regression sweep (528/528 PASS)
  • New V10_29 parity tests (26/26 PASS, bit-exact lossless round-trip)
  • README.md updated (Current Version + Previous Release + Release Status paragraph)
  • getVersion() bumped 10.16.0 → 10.17.0
  • Package.swift: new product J2KDICOMHelpers + target + test target

🤖 Generated with Claude Code

Ships a new public J2KDICOMHelpers library that bridges DICOM Transfer
Syntax UIDs to J2KEncodingConfiguration. Closes a long-standing product-
layer gap: library consumers using their own DICOM parser (DICOMKit,
pydicom-via-XPC, etc.) get a Transfer Syntax UID + Pixel Data bytes, and
previously had to hand-roll the UID-to-config mapping.

Per ADR-004, J2KSwift core libraries don't depend on any DICOM library.
The CLI ships a DICOMSupport.swift for .dcm file loading, but the
DICOMTransferSyntax / DICOMTransferSyntaxInfo types there are CLI-private
— not surfaced to library consumers. v10.17.0 lifts the UID-bridge layer
into a new public SwiftPM library.

Public surface:

  * J2KDICOMTransferSyntax — CaseIterable enum over all 7 DICOM Part 5
    Annex A JPEG 2000 / HTJ2K UIDs (j2kLossless 90, j2kLossy 91,
    j2kPart2MulticompLossless 92, j2kPart2Multicomp 93, htj2kLossless 201,
    htj2kLossyConstant 202, htj2kLossy 203). init?(uid:) / var uid round-trip
    (whitespace + trailing-NUL tolerant per PS3.5 §6.2). isLossless /
    isHTJ2K / isPart2 classification flags.

  * J2KDICOMTransferSyntax.encodingConfiguration(bitDepth:psnrTarget:) —
    returns matching J2KEncodingConfiguration with htj2kBlockFormat:
    .conformant for DICOM interop.

  * J2KDICOMCodestreamDetector.detect(_:) — sniffs SOC + (optional) CAP
    markers in the first ~256 bytes to classify raw codestreams as
    .j2kLossless (Part 1, no CAP) or .htj2kLossless (Part 15, CAP present).
    Returns nil for non-J2K bytes (JPEG SOI, PNG sig, random bytes all
    correctly reject).

  * J2KDICOMPhotometricInterpretation — enum mirror of the 7 DICOM
    PhotometricInterpretation values relevant to J2K. Bidirectional
    J2KColorSpace mapping (greyscale ↔ MONOCHROME2, sRGB ↔ RGB,
    yCbCr ↔ YBR_FULL; hdr/hdrLinear/iccProfile/unknown return nil
    in reverse).

ADR-004 compliant: no DICOM library dependency anywhere in J2KSwift —
the new product depends only on J2KCore + J2KCodec. Consumers not
importing J2KDICOMHelpers are completely unaffected.

Phase 1 deliberately ships the smallest viable shape — UID-and-config
bridge only. Phase 2 (likely v10.18+) would extract more of
J2KCLI/DICOMSupport.swift's file-parsing logic or ship a DICOMKit
adapter as a sibling opt-in product.

AsyncSequence progress streams (originally Phase 3 of the v10.17.0
plan) deferred to a dedicated MINOR — the AsyncStream-vs-actor-stored-
callback lifecycle has subtle correctness questions that warrant a
focused ship rather than being squeezed in.

Validation:
- V10_29_TransferSyntaxRoundTripTests 9/9 PASS
- V10_29_EncodingConfigurationParityTests 5/5 PASS (incl. bit-exact
  lossless round-trip via helper-built configs)
- V10_29_CodestreamDetectionTests 6/6 PASS
- V10_29_PhotometricInterpretationTests 6/6 PASS
- V10_29 total: 26/26 PASS release mode
- swift test --filter JP3D regression 528/528 PASS (1 pre-existing skip)
- Mandatory commit gate (release mode) 7/7 PASS

MINOR per RELEASING.md — entirely additive: new product, zero touch to
existing libraries, codestream bytes byte-identical to v10.16.0, no
DICOM library dependency added anywhere. Also bumps getVersion()
constant 10.16.0 → 10.17.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@SureshKViswanathan SureshKViswanathan merged commit f8d3ace into main May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant