Skip to content

Commit

Permalink
Merge pull request #571 from Enet4/new/ts-registry/jpeg-xl
Browse files Browse the repository at this point in the history
[ts-registry] Add JPEG XL transfer syntaxes
  • Loading branch information
Enet4 authored Oct 24, 2024
2 parents 182db60 + 5d760ba commit 2f099b0
Show file tree
Hide file tree
Showing 13 changed files with 900 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
components: clippy
cache: true
# test project with default + extra features
- run: cargo test --features image,ndarray,sop-class,rle,cli
- run: cargo test --features image,ndarray,sop-class,rle,cli,jpegxl
# test dicom-pixeldata with openjp2
- run: cargo test -p dicom-pixeldata --features openjp2
# test dicom-pixeldata with openjpeg-sys and charls
Expand Down
153 changes: 153 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pixeldata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ image = ["dep:image"]
native = ["dicom-transfer-syntax-registry/native", "jpeg", "rle"]
# native JPEG codec implementation
jpeg = ["dicom-transfer-syntax-registry/jpeg"]
# native JPEG XL codec implementation
jpegxl = ["dicom-transfer-syntax-registry/jpegxl"]
# native RLE lossless codec implementation
rle = ["dicom-transfer-syntax-registry/rle"]
# JPEG 2000 decoding via OpenJPEG static linking
Expand Down
8 changes: 7 additions & 1 deletion pixeldata/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ You can use it to transcode a DICOM file to another transfer syntax,
transforming pixel data along the way.

```none
Usage: dicom-transcode [OPTIONS] <--ts <TS>|--expl-vr-le|--impl-vr-le|--jpeg-baseline> <FILE>
Transcode a DICOM file
Usage: dicom-transcode [OPTIONS] <--ts <TS>|--expl-vr-le|--impl-vr-le|--jpeg-baseline|--jpeg-ls-lossless|--jpeg-ls|--jpeg-xl-lossless|--jpeg-xl> <FILE>
Arguments:
<FILE>
Expand All @@ -31,6 +33,10 @@ Options:
--expl-vr-le Transcode to Explicit VR Little Endian
--impl-vr-le Transcode to Implicit VR Little Endian
--jpeg-baseline Transcode to JPEG baseline (8-bit)
--jpeg-ls-lossless Transcode to JPEG-LS lossless
--jpeg-ls Transcode to JPEG-LS near-lossless
--jpeg-xl-lossless Transcode to JPEG XL lossless
--jpeg-xl Transcode to JPEG XL
--retain-implementation Retain the original implementation class UID and version name
-v, --verbose Verbose mode
-h, --help Print help
Expand Down
116 changes: 90 additions & 26 deletions pixeldata/src/bin/dicom-transcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct App {

/// Specifier for the target transfer syntax
#[derive(Debug, Parser)]
#[group(required = true, multiple = false)]
#[group(required = true, multiple = false, id = "transfer_syntax")]
struct TargetTransferSyntax {
/// Transcode to the Transfer Syntax indicated by UID
#[clap(long = "ts")]
Expand All @@ -66,41 +66,105 @@ struct TargetTransferSyntax {
implicit_vr_le: bool,

/// Transcode to JPEG baseline (8-bit)
#[cfg(feature = "jpeg")]
#[clap(long = "jpeg-baseline")]
jpeg_baseline: bool,

/// Transcode to JPEG-LS lossless
#[cfg(feature = "charls")]
#[clap(long = "jpeg-ls-lossless")]
jpeg_ls_lossless: bool,

/// Transcode to JPEG-LS near-lossless
#[cfg(feature = "charls")]
#[clap(long = "jpeg-ls")]
jpeg_ls: bool,

/// Transcode to JPEG XL lossless
#[cfg(feature = "jpegxl")]
#[clap(long = "jpeg-xl-lossless")]
jpeg_xl_lossless: bool,

/// Transcode to JPEG XL
#[cfg(feature = "jpegxl")]
#[clap(long = "jpeg-xl")]
jpeg_xl: bool,
}

impl TargetTransferSyntax {
fn resolve(&self) -> Result<&'static TransferSyntax, Whatever> {
// explicit VR little endian
if self.explicit_vr_le {
return Ok(TransferSyntaxRegistry
match self {
// none specified
TargetTransferSyntax {
ts: None,
explicit_vr_le: false,
implicit_vr_le: false,
#[cfg(feature = "jpeg")]
jpeg_baseline: false,
#[cfg(feature = "charls")]
jpeg_ls_lossless: false,
#[cfg(feature = "charls")]
jpeg_ls: false,
#[cfg(feature = "jpegxl")]
jpeg_xl_lossless: false,
#[cfg(feature = "jpegxl")]
jpeg_xl: false,
} => snafu::whatever!("No target transfer syntax specified"),
// explicit VR little endian
TargetTransferSyntax {
explicit_vr_le: true,
..
} => Ok(TransferSyntaxRegistry
.get(uids::EXPLICIT_VR_LITTLE_ENDIAN)
.expect("Explicit VR Little Endian is missing???"));
}

// implicit VR little endian
if self.implicit_vr_le {
return Ok(TransferSyntaxRegistry
.expect("Explicit VR Little Endian is missing???")),
// implicit VR little endian
TargetTransferSyntax {
implicit_vr_le: true,
..
} => Ok(TransferSyntaxRegistry
.get(uids::IMPLICIT_VR_LITTLE_ENDIAN)
.expect("Implicit VR Little Endian is missing???"));
}

// JPEG baseline
if self.jpeg_baseline {
return TransferSyntaxRegistry
.expect("Implicit VR Little Endian is missing???")),
// JPEG baseline
#[cfg(feature = "jpeg")]
TargetTransferSyntax {
jpeg_baseline: true,
..
} => TransferSyntaxRegistry
.get(uids::JPEG_BASELINE8_BIT)
.whatever_context("Missing specifier for JPEG Baseline (8-bit)");
.whatever_context("Missing specifier for JPEG Baseline (8-bit)"),
// JPEG-LS lossless
#[cfg(feature = "charls")]
TargetTransferSyntax {
jpeg_ls_lossless: true,
..
} => TransferSyntaxRegistry
.get(uids::JPEGLS_LOSSLESS)
.whatever_context("Missing specifier for JPEG-LS Lossless"),
// JPEG-LS near-lossless
#[cfg(feature = "charls")]
TargetTransferSyntax {
jpeg_ls: true,
..
} => TransferSyntaxRegistry
.get(uids::JPEGLS_NEAR_LOSSLESS)
.whatever_context("Missing specifier for JPEG-LS Near-Lossless"),
// JPEG XL lossless
#[cfg(feature = "jpegxl")]
TargetTransferSyntax {
jpeg_xl_lossless: true,
..
} => TransferSyntaxRegistry
.get(uids::JPEGXL_LOSSLESS)
.whatever_context("Missing specifier for JPEG XL Lossless"),
// JPEG XL
#[cfg(feature = "jpegxl")]
TargetTransferSyntax { jpeg_xl: true, .. } => TransferSyntaxRegistry
.get(uids::JPEGXL)
.whatever_context("Missing specifier for JPEG XL"),
TargetTransferSyntax { ts: Some(ts), .. } => TransferSyntaxRegistry
.get(ts)
.whatever_context("Unknown transfer syntax"),
}

// by TS UID
let Some(ts) = &self.ts else {
snafu::whatever!("No target transfer syntax specified");
};

TransferSyntaxRegistry
.get(ts)
.whatever_context("Unknown transfer syntax")
}
}

Expand Down
2 changes: 1 addition & 1 deletion toimage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ keywords = ["cli", "dicom", "image", "image-conversion"]
readme = "README.md"

[features]
default = ['dicom-object/inventory-registry', 'dicom-pixeldata/native']
default = ['dicom-object/inventory-registry', 'dicom-pixeldata/native', 'dicom-pixeldata/jpegxl']

[dependencies]
clap = { version = "4.0.18", features = ["derive"] }
Expand Down
5 changes: 5 additions & 0 deletions toimage/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ fn convert_single_file(
| uids::JPEGLS_NEAR_LOSSLESS => {
output.set_extension("jls");
}
uids::JPEGXL
| uids::JPEGXLJPEG_RECOMPRESSION
| uids::JPEGXL_LOSSLESS => {
output.set_extension("jxl");
}
_ => {
output.set_extension("data");
}
Expand Down
Loading

0 comments on commit 2f099b0

Please sign in to comment.