Thanks for writing this package, I have a couple of issues with the dcm_write function:
Invalid VR for tags accepting multiple VR
I have had some issues with writing back some DICOM image leading to the written image not being a valid DICOM anymore when a tag can be expressed with multiple vr, they are all written back instead of picking one.
For example, for (0x0040, 0x9211), the standard authorises either a VR of US or SS. In dcm_dict.jl, the data is set to:
(0x0040, 0x9211) => [:RealWorldValueLastValueMapped, "US or SS", "1"]
When writing, the VR is then set to "US or SS" overflowing on the length of the parameter. Further reads therefore try to read an incorrect amount of data, leading to an error.
Steps to reproduce:
using DICOM
empty_vr = Dict{Tuple{UInt16, UInt16}, String}();
io = IOBuffer();
DICOM.write_element(io, (0x0040, 0x9211), 0x0fff, true, empty_vr);
seek(io, 0);
read(io, String) # Show the overflow
seek(io, 0);
dcmdata = DICOM.DICOMData(Dict{Tuple{UInt16, UInt16}, Any}(), :little, true, empty_vr);
DICOM.read_element(io, dcmdata)
Result:
"@\0\x11\x92US or SS\x02\0\xff\x0f"
ERROR: EOFError: read end of file
Stacktrace:
[1] peek
@ Base .\iobuffer.jl:185 [inlined]
[2] read(from::IOBuffer, T::Type{UInt16})
@ Base .\iobuffer.jl:195
[3] numeric_parse(st::IOBuffer, T::DataType, sz::UInt16, endian::Symbol)
@ DICOM D:\Documents\Julia\DICOM.jl\src\DICOM.jl:351
[4] read_element(st::IOBuffer, dcm::DICOM.DICOMData)
@ DICOM D:\Documents\Julia\DICOM.jl\src\DICOM.jl:264
[5] top-level scope
@ REPL[88]:1
Passing an auxiliary VR when writing
When passing a custom VR value for a parameter, the auxiliary value will be ignored if the tag is in a sequence. PR #88 could solve this.
Trailing space in strings
Following: https://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html Values with VRs constructed of character strings, except in the case of the VR UI, shall be padded with SPACE characters (20H, in the Default Character Repertoire) when necessary to achieve even length.
When writing, the string values end up being padded with \0 instead of (space).**
using DICOM
empty_vr = Dict{Tuple{UInt16, UInt16}, String}();
io = IOBuffer();
DICOM.write_element(io, (0x0008, 0x1030), "BestImageEver", true, empty_vr);
seek(io, 0);
read(io, String)
Result (zero-padding):
"\b\x000\x10LO\x0e\0BestImageEver\0"
Writing sequences
The sequence must have (https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.5.2.html):
- 4 bytes Data Element Length (following the VR if explicit VR is used) with Undefined Length or Exact Length
- Item(s) with:
- Item tag (4 bytes) = (FFFE, E000)
- Item Length (4 bytes) either Undefined Length or Exact Length
- Item Value Data Set
- Item Delimiter tag (4 bytes) (FFFE, E00D) and Length (4 bytes) 0000 only if Item Length is Undefined Length
- Sequence Delimitation Tag (4 bytes) (FFFE, E00D) and Length (4 bytes) only if Data Element Length is Undefined Length
When writing the Data Element Length is not written and the Item Length provides the Exact Length while adding an item delimiter tag.
using DICOM
# Setup internal SQ DICOMData
empty_vr = Dict{Tuple{UInt16, UInt16}, String}();
sq_meta = Dict{Tuple{UInt16, UInt16}, Any}([(0x0008, 0x0100) => "UNDEFINED", (0x0008, 0x010b) => 'N', (0x0008, 0x0104) => "UNDEFINED"]);
sq_el = DICOM.DICOMData(sq_meta, :little, true, empty_vr);
# Setup external SQ DICOMData
meta = Dict{Tuple{UInt16, UInt16}, Any}((0x0040, 0x0260) => [sq_el]);
el = DICOM.DICOMData(meta, :little, true, empty_vr)
# Write
io = IOBuffer();
DICOM.write_element(io, (0x0040, 0x0260), el[(0x0040, 0x0260)], true, empty_vr);
seek(io, 0);
read(io, String)
Result:
"@\0`\x02SQ\0\0F\0\0\0\xfe\xff\0\xe06\0\0\0\b\0\0\x01SH\n\0UNDEFINED\0\b\0\x04\x01LO\n\0UNDEFINED\0\b\0\v\x01CS\x02\0N\0\xfe\xff\r\xe0\0\0\0\0\xfe\xff\xdd\xe0\0\0\0\0"
@\0`\x02 => Tag
SQ => VR
\0\0 => VR Length
F\0\0\0 => Exact Length
\xfe\xff\0\xe0 => Item Tag
6\0\0\0 => Exact Item Length
\b\0\0\x01SH\n\0UNDEFINED\0 => (0x0008, 0x0100) VR Length "UNDEFINED" \0
\b\0\x04\x01LO\n\0UNDEFINED\0 => (0x0008, 0x0104) VR Length "UNDEFINED" \0
\b\0\v\x01CS\x02\0N\0 => (0x0008, 0x0104) VR Length "N" \0
\xfe\xff\r\xe0 => Item Delimiter Tag
\0\0\0\0 => Zero Length
\xfe\xff\xdd\xe => Sequence Delimiter Tag
0\0\0\0\0 => Zero Length
Thanks for writing this package, I have a couple of issues with the
dcm_writefunction:Invalid VR for tags accepting multiple VR
I have had some issues with writing back some DICOM image leading to the written image not being a valid DICOM anymore when a tag can be expressed with multiple vr, they are all written back instead of picking one.
For example, for
(0x0040, 0x9211), the standard authorises either a VR ofUSorSS. In dcm_dict.jl, the data is set to:When writing, the VR is then set to "US or SS" overflowing on the length of the parameter. Further reads therefore try to read an incorrect amount of data, leading to an error.
Steps to reproduce:
Result:
Passing an auxiliary VR when writing
When passing a custom VR value for a parameter, the auxiliary value will be ignored if the tag is in a sequence. PR #88 could solve this.
Trailing space in strings
Following: https://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html
Values with VRs constructed of character strings, except in the case of the VR UI, shall be padded with SPACE characters (20H, in the Default Character Repertoire) when necessary to achieve even length.When writing, the string values end up being padded with
\0instead of(space).**Result (zero-padding):
Writing sequences
The sequence must have (https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.5.2.html):
When writing the Data Element Length is not written and the Item Length provides the Exact Length while adding an item delimiter tag.
Result:
@\0`\x02=> TagSQ=> VR\0\0=> VR LengthF\0\0\0=> Exact Length\xfe\xff\0\xe0=> Item Tag6\0\0\0=> Exact Item Length\b\0\0\x01SH\n\0UNDEFINED\0=> (0x0008, 0x0100) VR Length "UNDEFINED" \0\b\0\x04\x01LO\n\0UNDEFINED\0=> (0x0008, 0x0104) VR Length "UNDEFINED" \0\b\0\v\x01CS\x02\0N\0=> (0x0008, 0x0104) VR Length "N" \0\xfe\xff\r\xe0=> Item Delimiter Tag\0\0\0\0=> Zero Length\xfe\xff\xdd\xe=> Sequence Delimiter Tag0\0\0\0\0=> Zero Length