From e6957b94de5ff5334aff8d6df927e20d6232595f Mon Sep 17 00:00:00 2001 From: Suyash Kumar Date: Sat, 1 Jun 2024 15:54:22 -0400 Subject: [PATCH] Initial stab at deflate transfer syntax support --- parse.go | 10 +++++++--- pkg/dicomio/reader.go | 17 +++++++++++++++++ pkg/uid/uid.go | 2 +- testdata/data_details.md | 8 +++++--- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/parse.go b/parse.go index ef15c863..be5e6a72 100644 --- a/parse.go +++ b/parse.go @@ -161,12 +161,16 @@ func NewParser(in io.Reader, bytesToRead int64, frameChannel chan *frame.Frame, if err != nil { debug.Log("WARN: could not find transfer syntax uid in metadata, proceeding with little endian implicit") } else { - bo, implicit, err = uid.ParseTransferSyntaxUID(MustGetStrings(ts.Value)[0]) + tsStr := MustGetStrings(ts.Value)[0] + bo, implicit, err = uid.ParseTransferSyntaxUID(tsStr) if err != nil { // TODO(suyashkumar): should we attempt to parse with LittleEndian // Implicit here? debug.Log("WARN: could not parse transfer syntax uid in metadata") } + if tsStr == uid.DeflatedExplicitVRLittleEndian { + p.reader.rawReader.SetDeflate() + } } p.SetTransferSyntax(bo, implicit) @@ -281,8 +285,8 @@ func SkipPixelData() ParseOption { // a PixelData element will be added to the dataset with the // PixelDataInfo.IntentionallyUnprocessed = true, and the raw bytes of the // entire PixelData element stored in PixelDataInfo.UnprocessedValueData. -// -// In the future, we may be able to extend this functionality to support +// +// In the future, we may be able to extend this functionality to support // on-demand processing of elements elsewhere in the library. func SkipProcessingPixelDataValue() ParseOption { return func(set *parseOptSet) { diff --git a/pkg/dicomio/reader.go b/pkg/dicomio/reader.go index fe683ef8..605b1057 100644 --- a/pkg/dicomio/reader.go +++ b/pkg/dicomio/reader.go @@ -2,6 +2,7 @@ package dicomio import ( "bufio" + "compress/flate" "encoding/binary" "errors" "fmt" @@ -71,7 +72,16 @@ type Reader interface { // SetCodingSystem sets the charset.CodingSystem to be used when ReadString // is called. SetCodingSystem(cs charset.CodingSystem) + // ByteOrder returns the current byte order. ByteOrder() binary.ByteOrder + // SetDeflate applies deflate decompression to the underlying reader for all + // subsequent reads. This should be set when working with a deflated + // transfer syntax. Right now this is expected to be called once when + // parsing the top level dicom data, and there is no facility to swap + // between deflate and non-deflate reading. + // This also sets the current limit to LimitReadUntilEOF, since the original + // limits (if any) will be based on uncompressed bytes. + SetDeflate() } type reader struct { @@ -234,6 +244,13 @@ func (r *reader) SetTransferSyntax(bo binary.ByteOrder, implicit bool) { r.implicit = implicit } +func (r *reader) SetDeflate() { + r.in = bufio.NewReader(flate.NewReader(r.in)) + // TODO(https://github.com/suyashkumar/dicom/issues/320): consider always + // having the top level limit read until EOF. + r.limit = LimitReadUntilEOF // needed because original limits may not apply to the deflated reader +} + func (r *reader) IsImplicit() bool { return r.implicit } func (r *reader) SetCodingSystem(cs charset.CodingSystem) { diff --git a/pkg/uid/uid.go b/pkg/uid/uid.go index cd21562d..f0eff51f 100644 --- a/pkg/uid/uid.go +++ b/pkg/uid/uid.go @@ -56,7 +56,7 @@ func ParseTransferSyntaxUID(uid string) (bo binary.ByteOrder, implicit bool, err case ImplicitVRLittleEndian: return binary.LittleEndian, true, nil case DeflatedExplicitVRLittleEndian: - fallthrough + return binary.LittleEndian, false, nil case ExplicitVRLittleEndian: return binary.LittleEndian, false, nil case ExplicitVRBigEndian: diff --git a/testdata/data_details.md b/testdata/data_details.md index 40c37d48..7247df43 100644 --- a/testdata/data_details.md +++ b/testdata/data_details.md @@ -32,6 +32,8 @@ be mentioned in one of them for brevity. * Modality: CT * Multiple frames * Native pixel data +* [6.dcm](6.dcm) + * Deflated Little Endian Transfer Syntax (Explicit VR) ### Relevant Citations #### For files 1.dcm, 2.dcm: ##### Data Citation: @@ -58,6 +60,6 @@ Desai, S., Baghal, A., Wongsurawat, T., Al-Shukri, S., Gates, K., Farmer, P., Ru #### TCIA Citation Clark K, Vendt B, Smith K, Freymann J, Kirby J, Koppel P, Moore S, Phillips S, Maffitt D, Pringle M, Tarbox L, Prior F. The Cancer Imaging Archive (TCIA): Maintaining and Operating a Public Information Repository, Journal of Digital Imaging, Volume 26, Number 6, December, 2013, pp 1045-1057. DOI: 10.1007/s10278-013-9622-7 -#### File 5.dcm -This file was sourced from [cornerstone](https://github.com/cornerstonejs/dicomParser/blob/master/testImages/encapsulated/multi-frame/CT0012.explicit_little_endian.dcm) -(which is MIT licensed, see the license reproduced in included_licenses.md) +#### File 5.dcm & 6.dcm +This file was sourced from cornerstone [5.dcm from here](https://github.com/cornerstonejs/dicomParser/blob/master/testImages/encapsulated/multi-frame/CT0012.explicit_little_endian.dcm), and [6.dcm from here](https://github.com/cornerstonejs/dicomParser/blob/7d2084349bf2bdaffe74021e27b286a6c295ca66/testImages/deflate/image_dfl). +(Cornerstone is MIT licensed, see the license reproduced in included_licenses.md).