Bug: OW values have leading 0-bytes equal to their vl
bpeake-illuscio opened this issue · comments
bpeake-illuscio commented
Hello!
As mentioned in #198, I've found some odd behavior with how OW values are either being parsed or written:
Here is quick example:
package main
import (
"bytes"
"github.com/suyashkumar/dicom"
"github.com/suyashkumar/dicom/pkg/tag"
"github.com/suyashkumar/dicom/pkg/uid"
"log"
)
func mustNewElement(t tag.Tag, data interface{}) *dicom.Element {
elem, err := dicom.NewElement(t, data)
if err != nil {
log.Panic(err)
}
return elem
}
func main() {
// THIS IS THE ELEMENT WE CARE ABOUT. IT HAS 4 BYTES.
owElmOriginal := mustNewElement(tag.RedPaletteColorLookupTableData, []byte{0x1, 0x2, 0x3, 0x4})
dataset := dicom.Dataset{Elements: []*dicom.Element{
mustNewElement(tag.MediaStorageSOPClassUID, []string{"1.2.840.10008.5.1.4.1.1.1.2"}),
mustNewElement(tag.MediaStorageSOPInstanceUID, []string{"1.2.3.4.5.6.7"}),
mustNewElement(tag.TransferSyntaxUID, []string{uid.ImplicitVRLittleEndian}),
owElmOriginal,
}}
// Set up a buffer
buffer := bytes.NewBuffer(nil)
// Write the data
err := dicom.Write(buffer, dataset, dicom.SkipValueTypeVerification(), dicom.SkipVRVerification())
if err != nil {
log.Fatal("error writing data:", err)
}
// Read back the data
datasetRead, err := dicom.Parse(buffer, int64(buffer.Len()), nil)
if err != nil {
log.Fatal("error parsing dataset:", err)
}
// Get our OW element
owElmRead, err := datasetRead.FindElementByTag(tag.RedPaletteColorLookupTableData)
if err != nil {
log.Fatal("error getting test OW RedPaletteColorLookupTableData element:", err)
}
// Print a comparison between the original and the written/parsed value.
log.Println("RedPaletteColorLookupTableData source:", owElmOriginal.Value.GetValue())
log.Println("RedPaletteColorLookupTableData read :", owElmRead.Value.GetValue())
// OUTPUT:
//
// 2021/04/02 15:27:19 RedPaletteColorLookupTableData source: [1 2 3 4]
// 2021/04/02 15:27:19 RedPaletteColorLookupTableData read : [0 0 0 0 1 2 3 4]
}
As you can see, on read-in the value has 4 extra zero-bytes at the head.
I've isolated the issue to here (read.go, line 371):
func readBytes(r dicomio.Reader, t tag.Tag, vr string, vl uint32) (Value, error) {
// TODO: add special handling of PixelData
if vr == vrraw.OtherByte {
...
} else if vr == vrraw.OtherWord {
...
data := make([]byte, vl) // <------- ISSUE IS HERE ---------
buf := bytes.NewBuffer(data)
numWords := int(vl / 2)
for i := 0; i < numWords; i++ {
word, err := r.ReadUInt16()
if err != nil {
return nil, err
}
// TODO: support bytes.BigEndian byte ordering
err = binary.Write(buf, binary.LittleEndian, word)
if err != nil {
return nil, err
}
}
return &bytesValue{value: buf.Bytes()}, nil
}
return nil, ErrorUnsupportedVR
}
When allocating the buffer for the OW value, the internal []byte is created with a length equal to the value length. The buffer then appends to that slice as it reads in the value.
data := make([]byte, vl)
... needs to be changed to:
data := make([]byte, 0, vl)
So that the slice is created with the right capacity but a starting length of 0. I have a PR ready to go for this. Will put it up shortly.