From ac4f2abffe7ac92d79ce2f360b0d96ec2cae3023 Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Wed, 8 Jan 2025 14:04:13 -0500 Subject: [PATCH] WIP: add prototype decoding of HTJ2K DICOM Supplement 235 describes HTJ2K Transfer Syntax. OpenJPEG>=2.2 supports decoding HTJ2K. Update GDCM with additional HTJ2K transfer syntaxes and use existing JPEG200Codec to decode. --- .../gdcmTransferSyntax.cxx | 20 +++++++++++++++---- .../gdcmTransferSyntax.h | 3 +++ .../gdcmFileChangeTransferSyntax.cxx | 9 +++++++++ .../gdcmJPEG2000Codec.cxx | 5 ++++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx index 57a3abceb..866fe6d7e 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx @@ -81,9 +81,15 @@ static const char *TSStrings[] = { "1.2.840.10008.1.2.4.102", // MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1 "1.2.840.10008.1.2.4.103", + // High-Throughput JPEG 2000 Image Compression (Lossless Only) + "1.2.840.10008.1.2.4.201", + // High-Throughput JPEG 2000 with RPCL Options Image Compression (Lossless Only) + "1.2.840.10008.1.2.4.202", + // High-Throughput JPEG 2000 Image Compression + "1.2.840.10008.1.2.4.203", // Unknown - "Unknown Transfer Syntax", // Pretty sure we never use this case... - nullptr // Compilers have no obligation to finish by NULL, do it ourself + "Unknown Transfer Syntax", // Pretty sure we never use this case... until a new transfer syntax is added + nullptr // Compilers have no obligation to finish by NULL, do it ourselves }; TransferSyntax::TSType TransferSyntax::GetTSType(const char *cstr) @@ -162,7 +168,8 @@ bool TransferSyntax::IsLossy() const TSField == MPEG2MainProfile || TSField == MPEG2MainProfileHighLevel || TSField == MPEG4AVCH264HighProfileLevel4_1 || - TSField == MPEG4AVCH264BDcompatibleHighProfileLevel4_1 + TSField == MPEG4AVCH264BDcompatibleHighProfileLevel4_1 || + TSField == HTJ2K ) { return true; @@ -211,7 +218,8 @@ bool TransferSyntax::IsLossless() const TSField == MPEG2MainProfile || TSField == MPEG2MainProfileHighLevel || TSField == MPEG4AVCH264HighProfileLevel4_1 || - TSField == MPEG4AVCH264BDcompatibleHighProfileLevel4_1 + TSField == MPEG4AVCH264BDcompatibleHighProfileLevel4_1 || + TSField == HTJ2K ) { return false; @@ -300,6 +308,10 @@ bool TransferSyntax::IsEncapsulated() const case MPEG4AVCH264BDcompatibleHighProfileLevel4_1: //case ImplicitVRBigEndianACRNEMA: //case WeirdPapryus: + case HTJ2KLossless: + case HTJ2KRPCLLossless: + case HTJ2K: + ret = true; break; default: diff --git a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h index 8be7a3e5d..e94a3cc81 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h @@ -86,6 +86,9 @@ class GDCM_EXPORT TransferSyntax MPEG2MainProfileHighLevel, MPEG4AVCH264HighProfileLevel4_1, MPEG4AVCH264BDcompatibleHighProfileLevel4_1, + HTJ2KLossless, + HTJ2KRPCLLossless, + HTJ2K, TS_END } TSType; diff --git a/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx b/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx index cfd62a65d..74934b899 100644 --- a/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx +++ b/Source/MediaStorageAndFileFormat/gdcmFileChangeTransferSyntax.cxx @@ -454,6 +454,7 @@ bool FileChangeTransferSyntax::InitializeCopy() ISO_14495_1 = JPEG-LS Near-lossless Compression ISO_15444_1 = JPEG 2000 Irreversible Compression ISO_13818_2 = MPEG2 Compression + ISO_15444_15 = High-Throughput JPEG 2000 Irreversible Compression */ Attribute<0x0028,0x2114> at3; const TransferSyntax ts_orig = Internals->TS; @@ -467,6 +468,14 @@ bool FileChangeTransferSyntax::InitializeCopy() static const CSComp newvalues2[] = {"ISO_14495_1"}; at3.SetValues( newvalues2, 1 ); } + else if ( + ts_orig == TransferSyntax::HTJ2KLossless || + ts_orig == TransferSyntax::HTJ2KRPCLLossless || + ts_orig == TransferSyntax::HTJ2K ) + { + static const CSComp newvalues2[] = {"ISO_15444_15"}; + at3.SetValues( newvalues2, 1 ); + } else if ( ts_orig == TransferSyntax::JPEGBaselineProcess1 || ts_orig == TransferSyntax::JPEGExtendedProcess2_4 || diff --git a/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx b/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx index 430a24a87..027c72b50 100644 --- a/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx +++ b/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx @@ -493,7 +493,10 @@ bool JPEG2000Codec::CanDecode(TransferSyntax const &ts) const return ts == TransferSyntax::JPEG2000Lossless || ts == TransferSyntax::JPEG2000 || ts == TransferSyntax::JPEG2000Part2Lossless - || ts == TransferSyntax::JPEG2000Part2; + || ts == TransferSyntax::JPEG2000Part2 + || ts == TransferSyntax::HTJ2KLossless + || ts == TransferSyntax::HTJ2KRPCLLossless + || ts == TransferSyntax::HTJ2K; } bool JPEG2000Codec::CanCode(TransferSyntax const &ts) const