This repository has been archived by the owner on Nov 16, 2017. It is now read-only.
forked from gillesdemey/go-dicom
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdicom.go
executable file
·138 lines (122 loc) · 3.84 KB
/
dicom.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package dicom
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
"github.com/yasushi-saito/go-dicom/dicomio"
)
// UID prefix for go-dicom. Provided by
// https://www.medicalconnections.co.uk/Free_UID
const GoDICOMImplementationClassUIDPrefix = "1.2.826.0.1.3680043.9.7133"
var GoDICOMImplementationClassUID = GoDICOMImplementationClassUIDPrefix + ".1.1"
const GoDICOMImplementationVersionName = "GODICOM_1_1"
// DataSet represents contents of one DICOM file.
type DataSet struct {
// Elements in the file, in order of appearance.
//
// Note: unlike pydicom, Elements also contains meta elements (those
// with Tag.Group==2).
Elements []*Element
}
func doassert(cond bool, values ...interface{}) {
if !cond {
var s string
for _, value := range values {
s += fmt.Sprintf("%v ", value)
}
panic(s)
}
}
// ReadOptions defines how DataSets and Elements are parsed.
type ReadOptions struct {
// If true, skip the PixelData element (bulk images) in ReadDataSet.
DropPixelData bool
}
// ReadDataSetInBytes is a shorthand for ReadDataSet(bytes.NewBuffer(data), len(data)).
func ReadDataSetInBytes(data []byte, options ReadOptions) (*DataSet, error) {
return ReadDataSet(bytes.NewBuffer(data), int64(len(data)), options)
}
// ReadDataSetFromFile parses file cotents into dicom.DataSet. It is a thin
// wrapper around ReadDataSet.
func ReadDataSetFromFile(path string, options ReadOptions) (*DataSet, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
st, err := file.Stat()
if err != nil {
return nil, err
}
return ReadDataSet(file, st.Size(), options)
}
// ReadDataSet reads a DICOM file from "io", up to "bytes". Returns a DICOM file struct.
func ReadDataSet(in io.Reader, bytes int64, options ReadOptions) (*DataSet, error) {
buffer := dicomio.NewDecoder(in, bytes, binary.LittleEndian, dicomio.ExplicitVR)
metaElems := ParseFileHeader(buffer)
if buffer.Error() != nil {
return nil, buffer.Error()
}
file := &DataSet{Elements: metaElems}
// Change the transfer syntax for the rest of the file.
endian, implicit, err := getTransferSyntax(file)
if err != nil {
return nil, err
}
buffer.PushTransferSyntax(endian, implicit)
defer buffer.PopTransferSyntax()
// Read the list of elements.
for buffer.Len() > 0 {
elem := ReadElement(buffer, options)
if buffer.Error() != nil {
break
}
if elem == nil {
// element is a pixel data and was dropped by options
break
}
if elem.Tag == TagSpecificCharacterSet {
// Set the []byte -> string decoder for the rest of the
// file. It's sad that SpecificCharacterSet isn't part
// of metadata, but is part of regular attrs, so we need
// to watch out for multiple occurrences of this type of
// elements.
encodingNames, err := elem.GetStrings()
if err != nil {
buffer.SetError(err)
} else {
// TODO(saito) SpecificCharacterSet may appear in a
// middle of a SQ or NA. In such case, the charset seem
// to be scoped inside the SQ or NA. So we need to make
// the charset a stack.
cs, err := dicomio.ParseSpecificCharacterSet(encodingNames)
if err != nil {
buffer.SetError(err)
} else {
buffer.SetCodingSystem(cs)
}
}
}
file.Elements = append(file.Elements, elem)
}
return file, buffer.Error()
}
func getTransferSyntax(ds *DataSet) (bo binary.ByteOrder, implicit dicomio.IsImplicitVR, err error) {
elem, err := ds.FindElementByTag(TagTransferSyntaxUID)
if err != nil {
return nil, dicomio.UnknownVR, err
}
transferSyntaxUID, err := elem.GetString()
if err != nil {
return nil, dicomio.UnknownVR, err
}
return dicomio.ParseTransferSyntaxUID(transferSyntaxUID)
}
func (f *DataSet) FindElementByName(name string) (*Element, error) {
return FindElementByName(f.Elements, name)
}
func (f *DataSet) FindElementByTag(tag Tag) (*Element, error) {
return FindElementByTag(f.Elements, tag)
}