v0.28.0
Changed
- BREAKING:
Diagnostic.Pathis now[]PathStepinstead of[]Tag, so it names which item of each enclosing sequence the anomaly came from and not merely which sequence. PS3.5 gives sequence items an ordinal position and nothing else to identify them by, so a forty-item sequence used to produce forty diagnostics that read identically.PathStep{Tag, Item}renders the way DICOM tooling spells it —(0040,0100)[0]— and a whole path readsin (0008,1140)[1] > (0008,1110)[1]inDiagnostic.Error()and in thesequence_pathlog attribute.Itemis -1, and the subscript is dropped, when the sequence was entered but no item was: the item header itself was unreadable. Callers comparingd.Path[0]to aTagcompare it toPathStep{Tag: t, Item: i}instead, or readd.Path[0].Tag - Internal: the read and write chains carry the encoding triple (
isImplicitVR,isLittleEndian,charsets) as onecodecContextinstead of three parameters threaded through fourteen signatures. The two bools are adjacent and interchangeable, so a transposed call site used to compile and silently encode or parse a file in the wrong byte order
Added
-
VR disagreement diagnostics: reading now reports an explicit VR the data dictionary cannot reconcile with its tag — a
(0010,0010)encoded asSHwhen the dictionary saysPN, or a known tag sent asUN. The newDiagnosticVRMismatchkind carries the encoded VR inDiagnostic.VRand the dictionary's in the newDiagnostic.ExpectedVRfield. The parse is unchanged — godicom still keeps the VR the file gave it, because what the file says is what the file means — so this is pure information about interoperability, and returning the diagnostic from the hook turns it into a read failure. Private tags, tags absent from the dictionary, and implicit VR are excluded: they have no dictionary VR to fall short of. A dictionary entry naming more than one permitted VR ("OB or OW","US or SS") is satisfied by any of them, soPixelDatadoes not report on every image. The check costs a dictionary lookup per element, so it is skipped unless anOnDiagnostichook is set or warn-level logging is on -
Write diagnostics:
WriteOptions.OnDiagnostic func(Diagnostic) errormirrorsReadOptions.OnDiagnosticand reports values the writer would otherwise encode silently even though godicom's own reader raises a diagnostic on the result — a fractionalfloat64in anIS(1.5is not an integer string), aDSlonger than the 16 bytes PS3.5 allows, anISoutside[-2^31, 2^31). The newDiagnosticInvalidValuekind identifies them; they carry noOffset, since nothing was read. Returningnilkeeps the old behaviour and writes the value as it stands, so no existing caller changes; returning the diagnostic fails the write:opts := &WriteOptions{OnDiagnostic: func(d Diagnostic) error { return d }}
This is the three-way choice pydicom spells
IGNORE/WARN/RAISEinconfig.settings.writing_validation_mode, without a mode enum: whether the hook is set, and what it returns, says which one the caller wants. Values written back from the bytes they were read as are not offered — they are not re-encoded, and the read had its own chance to report them
Fixed
- A
DSelement holding a plainfloat64— whatSetFloat/SetFloatsstore, sinceDSis a float VR — was written with an unbounded%gwhile PS3.5 capsDSat 16 bytes.SetFloat(SliceThickness, 1.0/3.0)wrote"0.3333333333333333"(18 bytes), which godicom's ownIsValidDSrejects and a strict receiver may refuse. The writer now applies the sameFormatNumberAsDStruncation theDStype and pydicom'sformat_number_as_dsuse, so a value stored as afloat64reaches the file identically to the same value stored as aDS. ADSparsed from a file still round-trips its original string byte for byte, over-long or not NaNand the infinities were written into aDSas the literal bytes"NaN"/"+Inf"/"-Inf"with no error reported anywhere, and godicom's tolerantParseDSread them back — a decimal string has no spelling for any of them.SetFloat/SetFloatsnow reject them for aDStag at the call site, and the writer refuses them rather than emitting an invalidDSorIS.FDandFLare unaffected: they represent all three exactly, per IEEE 754