1 /*=========================================================================
2
3 Program: GDCM (Grassroots DICOM). A DICOM library
4
5 Copyright (c) 2006-2011 Mathieu Malaterre
6 All rights reserved.
7 See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notice for more information.
12
13 =========================================================================*/
14 #include "gdcmPixelFormat.h"
15 #include "gdcmTrace.h"
16 #include "gdcmTransferSyntax.h"
17
18 #include <stdlib.h>
19
20 namespace gdcm
21 {
22 static const char *ScalarTypeStrings[] = {
23 "UINT8",
24 "INT8",
25 "UINT12",
26 "INT12",
27 "UINT16",
28 "INT16",
29 "UINT32",
30 "INT32",
31 "UINT64",
32 "INT64",
33 "FLOAT16",
34 "FLOAT32",
35 "FLOAT64",
36 "SINGLEBIT",
37 "UNKNOWN",
38 nullptr,
39 };
40
PixelFormat(ScalarType st)41 PixelFormat::PixelFormat(ScalarType st)
42 {
43 SamplesPerPixel = 1;
44 SetScalarType( st );
45 }
46
GetSamplesPerPixel() const47 unsigned short PixelFormat::GetSamplesPerPixel() const
48 {
49 // \postcondition
50 assert( SamplesPerPixel == 1 || SamplesPerPixel == 3 || SamplesPerPixel == 4 );
51 return SamplesPerPixel;
52 }
53
SetScalarType(ScalarType st)54 void PixelFormat::SetScalarType(ScalarType st)
55 {
56 SamplesPerPixel = 1;
57 switch(st)
58 {
59 case PixelFormat::UINT8:
60 BitsAllocated = 8;
61 PixelRepresentation = 0;
62 break;
63 case PixelFormat::INT8:
64 BitsAllocated = 8;
65 PixelRepresentation = 1;
66 break;
67 case PixelFormat::UINT12:
68 BitsAllocated = 12;
69 PixelRepresentation = 0;
70 break;
71 case PixelFormat::INT12:
72 BitsAllocated = 12;
73 PixelRepresentation = 1;
74 break;
75 case PixelFormat::UINT16:
76 BitsAllocated = 16;
77 PixelRepresentation = 0;
78 break;
79 case PixelFormat::INT16:
80 BitsAllocated = 16;
81 PixelRepresentation = 1;
82 break;
83 case PixelFormat::UINT32:
84 BitsAllocated = 32;
85 PixelRepresentation = 0;
86 break;
87 case PixelFormat::INT32:
88 BitsAllocated = 32;
89 PixelRepresentation = 1;
90 break;
91 case PixelFormat::UINT64:
92 BitsAllocated = 64;
93 PixelRepresentation = 0;
94 break;
95 case PixelFormat::INT64:
96 BitsAllocated = 64;
97 PixelRepresentation = 1;
98 break;
99 case PixelFormat::FLOAT16:
100 BitsAllocated = 16;
101 // secret code:
102 PixelRepresentation = 2;
103 break;
104 case PixelFormat::FLOAT32:
105 BitsAllocated = 32;
106 // secret code:
107 PixelRepresentation = 3;
108 break;
109 case PixelFormat::FLOAT64:
110 BitsAllocated = 64;
111 // secret code:
112 PixelRepresentation = 4;
113 break;
114 case PixelFormat::SINGLEBIT:
115 BitsAllocated = 1;
116 PixelRepresentation = 0;
117 break;
118 case PixelFormat::UNKNOWN:
119 BitsAllocated = 0;
120 PixelRepresentation = 0;
121 break;
122 default:
123 assert(0);
124 break;
125 }
126 BitsStored = BitsAllocated;
127 HighBit = (uint16_t)(BitsStored - 1);
128 }
129
GetScalarType() const130 PixelFormat::ScalarType PixelFormat::GetScalarType() const
131 {
132 ScalarType type = PixelFormat::UNKNOWN;
133 switch( BitsAllocated )
134 {
135 case 0:
136 type = PixelFormat::UNKNOWN;
137 break;
138 case 1:
139 type = PixelFormat::SINGLEBIT;
140 break;
141 case 8:
142 type = PixelFormat::UINT8;
143 break;
144 case 12:
145 type = PixelFormat::UINT12;
146 break;
147 case 16:
148 type = PixelFormat::UINT16;
149 break;
150 case 32:
151 type = PixelFormat::UINT32;
152 break;
153 case 64:
154 type = PixelFormat::UINT64;
155 break;
156 case 24:
157 gdcmDebugMacro( "This is illegal in DICOM, assuming a RGB image" );
158 type = PixelFormat::UINT8;
159 break;
160 default:
161 gdcmErrorMacro( "I have never seen this before BitsAllocated "
162 << BitsAllocated );
163 type = PixelFormat::UNKNOWN;
164 }
165 if( type != PixelFormat::UNKNOWN )
166 {
167 if( PixelRepresentation == 0 )
168 {
169 // all set !
170 }
171 else if( PixelRepresentation == 1 )
172 {
173 assert( type <= INT64 );
174 // That's why you need to order properly type in ScalarType
175 type = ScalarType(int(type)+1);
176 }
177 else if( PixelRepresentation == 2 )
178 {
179 assert( BitsAllocated == 16 );
180 return FLOAT16;
181 }
182 else if( PixelRepresentation == 3 )
183 {
184 assert( BitsAllocated == 32 );
185 return FLOAT32;
186 }
187 else if( PixelRepresentation == 4 )
188 {
189 assert( BitsAllocated == 64 );
190 return FLOAT64;
191 }
192 else
193 {
194 assert(0);
195 }
196 }
197 return type;
198 }
199
GetScalarTypeAsString() const200 const char *PixelFormat::GetScalarTypeAsString() const
201 {
202 return ScalarTypeStrings[GetScalarType()];
203 }
204
GetPixelSize() const205 uint8_t PixelFormat::GetPixelSize() const
206 {
207 uint8_t pixelsize = (uint8_t)(BitsAllocated / 8);
208 if( BitsAllocated == 12 )
209 {
210 pixelsize = 2; // fake a short value
211 }
212 else
213 {
214 assert( !(BitsAllocated % 8) );
215 }
216 pixelsize *= SamplesPerPixel;
217
218 return pixelsize;
219 }
220
GetMin() const221 int64_t PixelFormat::GetMin() const
222 {
223 assert( BitsAllocated ); // cannot be unknown
224 if( BitsStored <= 32 )
225 {
226 if( PixelRepresentation == 1 )
227 {
228 return (int64_t)(~(((1ull << BitsStored) - 1) >> 1));
229 }
230 else if( PixelRepresentation == 0 )
231 {
232 return 0;
233 }
234 }
235 // else
236 gdcmAssertAlwaysMacro( 0 ); // throw "PixelFormat bad representation";
237 }
238
GetMax() const239 int64_t PixelFormat::GetMax() const
240 {
241 assert( BitsAllocated ); // cannot be unknown
242 if( BitsStored <= 32 )
243 {
244 if( PixelRepresentation == 1 )
245 {
246 return (int64_t)(((1ull << BitsStored) - 1) >> 1);
247 }
248 else if( PixelRepresentation == 0 )
249 {
250 return (int64_t)((1ull << BitsStored) - 1);
251 }
252 }
253 // else
254 gdcmAssertAlwaysMacro( 0 ); // throw "PixelFormat bad representation";
255 }
256
IsValid() const257 bool PixelFormat::IsValid() const
258 {
259 if( PixelRepresentation != 0 && PixelRepresentation != 1 )
260 {
261 return false;
262 }
263 if( BitsAllocated < BitsStored ) return false;
264 if( BitsAllocated < HighBit ) return false;
265 if( BitsStored > 32 ) return false;
266 return true;
267 }
268
Validate()269 bool PixelFormat::Validate()
270 {
271 if( !IsValid() ) return false;
272 //assert( BitsStored >= HighBit ); // DigitexAlpha_no_7FE0.dcm
273 assert( PixelRepresentation == 0 || PixelRepresentation == 1 );
274 assert( SamplesPerPixel == 1 || SamplesPerPixel == 3 || SamplesPerPixel == 4 );
275 if ( BitsStored == 0 )
276 {
277 gdcmDebugMacro( "Bits Stored is 0. Setting is to max value" );
278 BitsStored = BitsAllocated;
279 }
280 if ( BitsAllocated == 24 )
281 {
282 gdcmDebugMacro( "ACR-NEMA way of storing RGB data. Updating" );
283 if( BitsStored == 24 && HighBit == 23 && SamplesPerPixel == 1 )
284 {
285 BitsAllocated = 8;
286 BitsStored = 8;
287 HighBit = 7;
288 SamplesPerPixel = 3;
289 return true;
290 }
291 // all other case, simply give up
292 return false;
293 }
294 return true;
295 }
296
Print(std::ostream & os) const297 void PixelFormat::Print(std::ostream &os) const
298 {
299 os << "SamplesPerPixel :" << SamplesPerPixel << "\n";
300 os << "BitsAllocated :" << BitsAllocated << "\n";
301 os << "BitsStored :" << BitsStored << "\n";
302 os << "HighBit :" << HighBit << "\n";
303 os << "PixelRepresentation:" << PixelRepresentation << "\n";
304 os << "ScalarType found :" << GetScalarTypeAsString() << "\n";
305 }
306
IsCompatible(const TransferSyntax & ts) const307 bool PixelFormat::IsCompatible(const TransferSyntax & ts ) const
308 {
309 if( ts == TransferSyntax::JPEGBaselineProcess1 && BitsAllocated != 8 ) return false;
310 // FIXME are we missing any ?
311 return true;
312 }
313
314 } // end namespace gdcm
315