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