Skip to content

v0.28.0

Choose a tag to compare

@xbmlz xbmlz released this 24 Aug 03:28
· 10 commits to main since this release
e787c3d

Changed

  • BREAKING: Diagnostic.Path is now []PathStep instead 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 reads in (0008,1140)[1] > (0008,1110)[1] in Diagnostic.Error() and in the sequence_path log attribute. Item is -1, and the subscript is dropped, when the sequence was entered but no item was: the item header itself was unreadable. Callers comparing d.Path[0] to a Tag compare it to PathStep{Tag: t, Item: i} instead, or read d.Path[0].Tag
  • Internal: the read and write chains carry the encoding triple (isImplicitVR, isLittleEndian, charsets) as one codecContext instead 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 as SH when the dictionary says PN, or a known tag sent as UN. The new DiagnosticVRMismatch kind carries the encoded VR in Diagnostic.VR and the dictionary's in the new Diagnostic.ExpectedVR field. 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, so PixelData does not report on every image. The check costs a dictionary lookup per element, so it is skipped unless an OnDiagnostic hook is set or warn-level logging is on

  • Write diagnostics: WriteOptions.OnDiagnostic func(Diagnostic) error mirrors ReadOptions.OnDiagnostic and reports values the writer would otherwise encode silently even though godicom's own reader raises a diagnostic on the result — a fractional float64 in an IS (1.5 is not an integer string), a DS longer than the 16 bytes PS3.5 allows, an IS outside [-2^31, 2^31). The new DiagnosticInvalidValue kind identifies them; they carry no Offset, since nothing was read. Returning nil keeps 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 / RAISE in config.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 DS element holding a plain float64 — what SetFloat / SetFloats store, since DS is a float VR — was written with an unbounded %g while PS3.5 caps DS at 16 bytes. SetFloat(SliceThickness, 1.0/3.0) wrote "0.3333333333333333" (18 bytes), which godicom's own IsValidDS rejects and a strict receiver may refuse. The writer now applies the same FormatNumberAsDS truncation the DS type and pydicom's format_number_as_ds use, so a value stored as a float64 reaches the file identically to the same value stored as a DS. A DS parsed from a file still round-trips its original string byte for byte, over-long or not
  • NaN and the infinities were written into a DS as the literal bytes "NaN" / "+Inf" / "-Inf" with no error reported anywhere, and godicom's tolerant ParseDS read them back — a decimal string has no spelling for any of them. SetFloat / SetFloats now reject them for a DS tag at the call site, and the writer refuses them rather than emitting an invalid DS or IS. FD and FL are unaffected: they represent all three exactly, per IEEE 754