/
gdcmTag.h
298 lines (262 loc) · 9.73 KB
/
gdcmTag.h
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/*=========================================================================
Program: GDCM (Grassroots DICOM). A DICOM library
Copyright (c) 2006-2011 Mathieu Malaterre
All rights reserved.
See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#ifndef GDCMTAG_H
#define GDCMTAG_H
#include "gdcmTypes.h"
#include <iostream>
#include <iomanip>
namespace gdcm
{
/**
* \brief Class to represent a DICOM Data Element (Attribute) Tag (Group, Element).
* \details Basically an uint32_t which can also be expressed as two uint16_t (group and
* element)
* \note
* DATA ELEMENT TAG:
* A unique identifier for a Data Element composed of an ordered pair of
* numbers (a Group Number followed by an Element Number). GROUP NUMBER: The
* first number in the ordered pair of numbers that makes up a Data Element
* Tag.
* ELEMENT NUMBER: The second number in the ordered pair of numbers that
* makes up a Data Element Tag.
*/
class GDCM_EXPORT Tag
{
public:
/// \brief Constructor with 2*uint16_t
Tag(uint16_t group, uint16_t element) {
ElementTag.tags[0] = group; ElementTag.tags[1] = element;
}
/// \brief Constructor with 1*uint32_t
/// Prefer the cstor that takes two uint16_t
Tag(uint32_t tag = 0) {
SetElementTag(tag);
}
friend std::ostream& operator<<(std::ostream &_os, const Tag &_val);
friend std::istream& operator>>(std::istream &_is, Tag &_val);
/// \brief Returns the 'Group number' of the given Tag
uint16_t GetGroup() const { return ElementTag.tags[0]; }
/// \brief Returns the 'Element number' of the given Tag
uint16_t GetElement() const { return ElementTag.tags[1]; }
/// \brief Sets the 'Group number' of the given Tag
void SetGroup(uint16_t group) { ElementTag.tags[0] = group; }
/// \brief Sets the 'Element number' of the given Tag
void SetElement(uint16_t element) { ElementTag.tags[1] = element; }
/// \brief Sets the 'Group number' & 'Element number' of the given Tag
void SetElementTag(uint16_t group, uint16_t element) {
ElementTag.tags[0] = group; ElementTag.tags[1] = element;
}
/// \brief Returns the full tag value of the given Tag
uint32_t GetElementTag() const {
#ifndef GDCM_WORDS_BIGENDIAN
return (ElementTag.tag<<16) | (ElementTag.tag>>16);
#else
return ElementTag.tag;
#endif
}
/// \brief Sets the full tag value of the given Tag
void SetElementTag(uint32_t tag) {
#ifndef GDCM_WORDS_BIGENDIAN
tag = ( (tag<<16) | (tag>>16) );
#endif
ElementTag.tag = tag;
}
/// Returns the Group or Element of the given Tag, depending on id (0/1)
const uint16_t &operator[](const unsigned int &_id) const
{
assert(_id<2);
return ElementTag.tags[_id];
}
/// Returns the Group or Element of the given Tag, depending on id (0/1)
uint16_t &operator[](const unsigned int &_id)
{
assert(_id<2);
return ElementTag.tags[_id];
}
Tag &operator=(const Tag &_val)
{
ElementTag.tag = _val.ElementTag.tag;
return *this;
}
bool operator==(const Tag &_val) const
{
return ElementTag.tag == _val.ElementTag.tag;
}
bool operator!=(const Tag &_val) const
{
return ElementTag.tag != _val.ElementTag.tag;
}
/// DICOM Standard expects the Data Element to be sorted by Tags
/// All other comparison can be constructed from this one and operator ==
// FIXME FIXME FIXME TODO
// the following is pretty dumb. Since we have control over who is group
// and who is element, we should reverse them in little endian and big endian case
// since what we really want is fast comparison and not guarantee that group is in #0
// ...
bool operator<(const Tag &_val) const
{
#ifndef GDCM_WORDS_BIGENDIAN
if( ElementTag.tags[0] < _val.ElementTag.tags[0] )
return true;
if( ElementTag.tags[0] == _val.ElementTag.tags[0]
&& ElementTag.tags[1] < _val.ElementTag.tags[1] )
return true;
return false;
#else
// Plain comparison is enough!
return ( ElementTag.tag < _val.ElementTag.tag );
#endif
}
bool operator<=(const Tag &t2) const
{
const Tag &t1 = *this;
return t1 == t2 || t1 < t2;
}
Tag(const Tag &_val)
{
ElementTag.tag = _val.ElementTag.tag;
}
/// return the length of tag (read: size on disk)
uint32_t GetLength() const { return 4; }
/// STANDARD DATA ELEMENT: A Data Element defined in the DICOM Standard,
/// and therefore listed in the DICOM Data Element Dictionary in PS 3.6.
/// Is the Tag from the Public dict...well the implementation is buggy
/// it does not prove the element is indeed in the dict...
bool IsPublic() const { return !(ElementTag.tags[0] % 2); }
/// PRIVATE DATA ELEMENT: Additional Data Element, defined by an
/// implementor, to communicate information that is not contained in
/// Standard Data Elements. Private Data elements have odd Group Numbers.
bool IsPrivate() const { return !IsPublic(); }
//-----------------------------------------------------------------------------
/// Read a tag from binary representation
template <typename TSwap>
std::istream &Read(std::istream &is)
{
if( is.read(ElementTag.bytes, 4) )
TSwap::SwapArray(ElementTag.tags, 2);
return is;
}
/// Write a tag in binary rep
template <typename TSwap>
const std::ostream &Write(std::ostream &os) const
{
uint16_t copy[2];
copy[0]= ElementTag.tags[0];
copy[1]= ElementTag.tags[1];
TSwap::SwapArray(copy, 2);
return os.write((char*)(©), 4);
}
/// Return the Private Creator Data Element tag of a private data element
Tag GetPrivateCreator() const
{
// See PS 3.5 - 7.8.1 PRIVATE DATA ELEMENT TAGS
// eg: 0x0123,0x1425 -> 0x0123,0x0014
if( IsPrivate() && !IsPrivateCreator() )
{
Tag r = *this;
r.SetElement( (uint16_t)(GetElement() >> 8) );
return r;
}
if( IsPrivateCreator() ) return *this;
return Tag(0x0,0x0);
}
/// Set private creator:
void SetPrivateCreator(Tag const &t)
{
// See PS 3.5 - 7.8.1 PRIVATE DATA ELEMENT TAGS
// eg: 0x0123,0x0045 -> 0x0123,0x4567
assert( t.IsPrivate() /*&& t.IsPrivateCreator()*/ );
const uint16_t element = (uint16_t)(t.GetElement() << 8);
const uint16_t base = (uint16_t)(GetElement() << 8);
SetElement( (uint16_t)((base >> 8) + element) );
SetGroup( t.GetGroup() );
}
/// Returns if tag is a Private Creator (xxxx,00yy), where xxxx is odd number
/// and yy in [0x10,0xFF]
bool IsPrivateCreator() const
{
return IsPrivate() && (GetElement() <= 0xFF && GetElement() >= 0x10);
}
/// return if the tag is considered to be an illegal tag
bool IsIllegal() const
{
// DICOM reserved those groups:
return GetGroup() == 0x0001 || GetGroup() == 0x0003 || GetGroup() == 0x0005 || GetGroup() == 0x0007
// This is a very special case, in private group, one cannot use element [0x01,0x09] ...
// || (IsPrivate() && !IsPrivateCreator() && !IsGroupLength());
|| (IsPrivate() && GetElement() > 0x0 && GetElement() < 0x10 );
}
/// return whether the tag correspond to a group length tag:
bool IsGroupLength() const
{
return GetElement() == 0x0;
}
/// e.g 6002,3000 belong to groupXX: 6000,3000
bool IsGroupXX(const Tag &t) const
{
if( t.GetElement() == GetElement() )
{
if( t.IsPrivate() ) return false;
uint16_t group = (uint16_t)((GetGroup() >> 8 ) << 8);
return group == t.GetGroup();
}
return false;
}
/// Read from a comma separated string.
/// This is a highly user oriented function, the string should be formatted as:
/// 1234,5678 to specify the tag (0x1234,0x5678)
/// The notation comes from the DICOM standard, and is handy to use from a
/// command line program
bool ReadFromCommaSeparatedString(const char *str);
/// Read From XML formatted tag value eg. tag = "12345678"
/// It comes in useful when reading tag values from XML file(in NativeDICOMModel)
bool ReadFromContinuousString(const char *str);
/// Print tag value with no separating comma: eg. tag = "12345678"
/// It comes in useful when reading tag values from XML file(in NativeDICOMModel)
std::string PrintAsContinuousString() const;
/// Same as PrintAsContinuousString, but hexadecimal [a-f] are printed using upper case
std::string PrintAsContinuousUpperCaseString() const;
/// Read from a pipe separated string (GDCM 1.x compat only). Do not use in newer code
/// \see ReadFromCommaSeparatedString
bool ReadFromPipeSeparatedString(const char *str);
/// Print as a pipe separated string (GDCM 1.x compat only). Do not use in newer code
/// \see ReadFromPipeSeparatedString
std::string PrintAsPipeSeparatedString() const;
private:
union { uint32_t tag; uint16_t tags[2]; char bytes[4]; } ElementTag;
};
//-----------------------------------------------------------------------------
inline std::istream& operator>>(std::istream &_is, Tag &_val)
{
char c;
_is >> c;
uint16_t a, b;
_is >> std::hex >> a;
//_is >> std::hex >> _val[0];
//_is >> std::hex >> _val.ElementTag.tags[0];
_is >> c;
//_is >> _val[1];
//_is >> std::hex >> _val.ElementTag.tags[1];
_is >> std::hex >> b;
_is >> c;
_val.SetGroup( a );
_val.SetElement( b );
return _is;
}
inline std::ostream& operator<<(std::ostream &_os, const Tag &_val)
{
_os.setf( std::ios::right);
_os << std::hex << '(' << std::setw( 4 ) << std::setfill( '0' )
<< _val[0] << ',' << std::setw( 4 ) << std::setfill( '0' )
<< _val[1] << ')' << std::setfill( ' ' ) << std::dec;
return _os;
}
} // end namespace gdcm
#endif //GDCMTAG_H