suyashkumar / dicom

⚡High Performance DICOM Medical Image Parser in Go.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bug: OW values have leading 0-bytes equal to their vl

bpeake-illuscio opened this issue · comments

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.