]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
to allow Python wrapping
[gdcm.git] / src / gdcmHeader.cxx
1 // gdcmHeader.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmHeader.h"
4
5 #include <stdio.h>
6 #include <cerrno>
7 #include <cctype>    // for isalpha
8
9 #include "gdcmUtil.h"
10 #include "gdcmTS.h"
11
12 //-----------------------------------------------------------------------------
13 // Refer to gdcmHeader::CheckSwap()
14 //const unsigned int gdcmHeader::HEADER_LENGTH_TO_READ = 256;
15
16 // Refer to gdcmHeader::SetMaxSizeLoadEntry()
17 //const unsigned int gdcmHeader::MAX_SIZE_LOAD_ELEMENT_VALUE = 4096;
18
19 //-----------------------------------------------------------------------------
20 // Constructor / Destructor
21 /**
22  * \ingroup gdcmHeader
23  * \brief   
24  * @param   InFilename
25  * @param   exception_on_error
26  * @param   enable_sequences = true to allow the header 
27  *          to be parsed *inside* the SeQuences, 
28  *          when they have an actual length 
29  * @param   ignore_shadow = true if user wants to skip shadow groups 
30             during parsing, to save memory space
31  *\TODO : may be we need one more bool, 
32  *         to allow skipping the private elements while parsing the header
33  *         in order to save space         
34  */
35 gdcmHeader::gdcmHeader(const char *InFilename, 
36                        bool exception_on_error,
37                        bool enable_sequences, 
38                        bool ignore_shadow):
39    gdcmParser(InFilename,exception_on_error,enable_sequences,ignore_shadow)
40 {
41 }
42
43 /**
44  * \ingroup gdcmHeader
45  * \brief   
46  * @param   exception_on_error
47  */
48 gdcmHeader::gdcmHeader(bool exception_on_error) :
49    gdcmParser(exception_on_error)
50 {
51 }
52
53 /**
54  * \ingroup gdcmHeader
55  * \brief   Canonical destructor.
56  */
57 gdcmHeader::~gdcmHeader (void) {
58 }
59
60 //-----------------------------------------------------------------------------
61 // Print
62
63 //-----------------------------------------------------------------------------
64 // Public
65 /**
66  * \ingroup gdcmHeader
67  * \brief  This predicate, based on hopefully reasonable heuristics,
68  *         decides whether or not the current gdcmParser was properly parsed
69  *         and contains the mandatory information for being considered as
70  *         a well formed and usable Dicom/Acr File.
71  * @return true when gdcmParser is the one of a reasonable Dicom/Acr file,
72  *         false otherwise. 
73  */
74 bool gdcmHeader::IsReadable(void) {
75    if(!gdcmParser::IsReadable())
76       return(false);
77
78    std::string res = GetEntryByNumber(0x0028, 0x0005);
79    if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) 
80       return false; // Image Dimensions
81
82    if ( !GetHeaderEntryByNumber(0x0028, 0x0100) )
83       return false; // "Bits Allocated"
84    if ( !GetHeaderEntryByNumber(0x0028, 0x0101) )
85       return false; // "Bits Stored"
86    if ( !GetHeaderEntryByNumber(0x0028, 0x0102) )
87       return false; // "High Bit"
88    if ( !GetHeaderEntryByNumber(0x0028, 0x0103) )
89       return false; // "Pixel Representation"
90    return true;
91 }
92
93 /**
94  * \ingroup gdcmHeader
95  * \brief   Determines if the Transfer Syntax was already encountered
96  *          and if it corresponds to a JPEGBaseLineProcess1 one.
97  *
98  * @return  True when JPEGBaseLineProcess1found. False in all other cases.
99  */
100 bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
101    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
102    if ( !Element )
103       return false;
104    LoadHeaderEntrySafe(Element);
105
106    std::string Transfer = Element->GetValue();
107    if ( Transfer == "1.2.840.10008.1.2.4.50" )
108       return true;
109    return false;
110 }
111
112 /**
113  * \ingroup gdcmHeader
114  * \brief   Determines if the Transfer Syntax was already encountered
115  *          and if it corresponds to a JPEGExtendedProcess2-4 one.
116  *
117  * @return  True when JPEGExtendedProcess2-4 found. False in all other cases.
118  */
119 bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) {
120    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
121    if ( !Element )
122       return false;
123    LoadHeaderEntrySafe(Element);
124
125    std::string Transfer = Element->GetValue();
126    if ( Transfer == "1.2.840.10008.1.2.4.51" )
127       return true;
128    return false;
129 }
130
131 /**
132  * \ingroup gdcmHeader
133  * \brief   Determines if the Transfer Syntax was already encountered
134  *          and if it corresponds to a JPEGExtendeProcess3-5 one.
135  *
136  * @return  True when JPEGExtendedProcess3-5 found. False in all other cases.
137  */
138 bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
139    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
140    if ( !Element )
141       return false;
142    LoadHeaderEntrySafe(Element);
143
144    std::string Transfer = Element->GetValue();
145    if ( Transfer == "1.2.840.10008.1.2.4.52" )
146       return true;
147    return false;
148 }
149
150 /**
151  * \ingroup gdcmHeader
152  * \brief   Determines if the Transfer Syntax was already encountered
153  *          and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
154  *
155  * @return  True when JPEGSpectralSelectionProcess6-8 found. False in all
156  *          other cases.
157  */
158 bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
159    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
160    if ( !Element )
161       return false;
162    LoadHeaderEntrySafe(Element);
163
164    std::string Transfer = Element->GetValue();
165    if ( Transfer == "1.2.840.10008.1.2.4.53" )
166       return true;
167    return false;
168 }
169
170 /**
171  * \ingroup gdcmHeader
172  * \brief   Determines if the Transfer Syntax was already encountered
173  *          and if it corresponds to a RLE Lossless one.
174  *
175  * @return  True when RLE Lossless found. False in all
176  *          other cases.
177  */
178 bool gdcmHeader::IsRLELossLessTransferSyntax(void) {
179    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
180    if ( !Element )
181       return false;
182    LoadHeaderEntrySafe(Element);
183
184    std::string Transfer = Element->GetValue();
185    if ( Transfer == "1.2.840.10008.1.2.5" ) {
186       return true;
187     }
188    return false;
189 }
190
191 /**
192  * \ingroup gdcmHeader
193  * \brief  Determines if Transfer Syntax was already encountered
194  *          and if it corresponds to a JPEG Lossless one. 
195  *
196  * @return  True when RLE Lossless found. False in all
197  *          other cases. 
198  */
199 bool gdcmHeader::IsJPEGLossless(void) {
200    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
201     // faire qq chose d'intelligent a la place de ça
202    if ( !Element )
203       return false;
204    LoadHeaderEntrySafe(Element);
205
206    const char * Transfert = Element->GetValue().c_str();
207    if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true;
208    if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true;
209    if (Element->GetValue() == "1.2.840.10008.1.2.4.57")   return true;
210
211    return false;
212 }
213
214 /**
215  * \ingroup gdcmHeader
216  * \brief   Determines if the Transfer Syntax was already encountered
217  *          and if it corresponds to a JPEG200 one.0
218  *
219  * @return  True when JPEG2000 (Lossly or LossLess) found. False in all
220  *          other cases.
221  */
222 bool gdcmHeader::IsJPEG2000(void) {
223    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
224    if ( !Element )
225       return false;
226    LoadHeaderEntrySafe(Element);
227
228    std::string Transfer = Element->GetValue();
229    if (    (Transfer == "1.2.840.10008.1.2.4.90") 
230         || (Transfer == "1.2.840.10008.1.2.4.91") )
231       return true;
232    return false;
233 }
234
235 /**
236  * \ingroup gdcmHeader
237  * \brief   Predicate for dicom version 3 file.
238  * @return  True when the file is a dicom version 3.
239  */
240 bool gdcmHeader::IsDicomV3(void) {
241    // Checking if Transfert Syntax exists is enough
242    return (GetHeaderEntryByNumber(0x0002, 0x0010) != NULL);
243 }
244
245 /**
246  * \ingroup gdcmHeader
247  * \brief   Retrieve the number of columns of image.
248  * @return  The encountered size when found, 0 by default.
249  *          0 means the file is NOT USABLE. The caller will have to check
250  */
251 int gdcmHeader::GetXSize(void) {
252    std::string StrSize;
253    StrSize = GetEntryByNumber(0x0028,0x0011);
254    if (StrSize == GDCM_UNFOUND)
255       return 0;
256    return atoi(StrSize.c_str());
257 }
258
259 /**
260  * \ingroup gdcmHeader
261  * \brief   Retrieve the number of lines of image.
262  * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize()
263  * @return  The encountered size when found, 1 by default 
264  *          (The file contains a Signal, not an Image).
265  */
266 int gdcmHeader::GetYSize(void) {
267    std::string StrSize = GetEntryByNumber(0x0028,0x0010);
268    if (StrSize != GDCM_UNFOUND)
269       return atoi(StrSize.c_str());
270    if ( IsDicomV3() )
271       return 0;
272    else
273       // The Rows (0028,0010) entry was optional for ACR/NEMA. It might
274       // hence be a signal (1d image). So we default to 1:
275       return 1;
276 }
277
278 /**
279  * \ingroup gdcmHeader
280  * \brief   Retrieve the number of planes of volume or the number
281  *          of frames of a multiframe.
282  * \warning When present we consider the "Number of Frames" as the third
283  *          dimension. When absent we consider the third dimension as
284  *          being the "Planes" tag content.
285  * @return  The encountered size when found, 1 by default (single image).
286  */
287 int gdcmHeader::GetZSize(void) {
288    // Both  DicomV3 and ACR/Nema consider the "Number of Frames"
289    // as the third dimension.
290    std::string StrSize = GetEntryByNumber(0x0028,0x0008);
291    if (StrSize != GDCM_UNFOUND)
292       return atoi(StrSize.c_str());
293
294    // We then consider the "Planes" entry as the third dimension [we
295    // cannot retrieve by name since "Planes tag is present both in
296    // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary]. 
297    StrSize = GetEntryByNumber(0x0028,0x0012);
298    if (StrSize != GDCM_UNFOUND)
299       return atoi(StrSize.c_str());
300    return 1;
301 }
302
303 /**
304  * \ingroup gdcmHeader
305  * \brief   Retrieve the number of Bits Stored (actually used)
306  *          (as opposite to number of Bits Allocated)
307  * 
308  * @return  The encountered number of Bits Stored, 0 by default.
309  *          0 means the file is NOT USABLE. The caller has to check it !
310  */
311 int gdcmHeader::GetBitsStored(void) { 
312    std::string StrSize = GetEntryByNumber(0x0028,0x0101);
313    if (StrSize == GDCM_UNFOUND)
314       return 0;  // It's supposed to be mandatory
315                  // the caller will have to check
316    return atoi(StrSize.c_str());
317 }
318
319 /**
320  * \ingroup gdcmHeader
321  * \brief   Retrieve the number of Bits Allocated
322  *          (8, 12 -compacted ACR-NEMA files, 16, ...)
323  * 
324  * @return  The encountered number of Bits Allocated, 0 by default.
325  *          0 means the file is NOT USABLE. The caller has to check it !
326  */
327 int gdcmHeader::GetBitsAllocated(void) { 
328    std::string StrSize = GetEntryByNumber(0x0028,0x0100);
329    if (StrSize == GDCM_UNFOUND)
330       return 0; // It's supposed to be mandatory
331                 // the caller will have to check
332    return atoi(StrSize.c_str());
333 }
334
335 /**
336  * \ingroup gdcmHeader
337  * \brief   Retrieve the number of Samples Per Pixel
338  *          (1 : gray level, 3 : RGB -1 or 3 Planes-)
339  * 
340  * @return  The encountered number of Samples Per Pixel, 1 by default.
341  *          (Gray level Pixels)
342  */
343 int gdcmHeader::GetSamplesPerPixel(void) { 
344    std::string StrSize = GetEntryByNumber(0x0028,0x0002);
345    if (StrSize == GDCM_UNFOUND)
346       return 1; // Well, it's supposed to be mandatory ...
347                 // but sometimes it's missing : we assume Gray pixels
348    return atoi(StrSize.c_str());
349 }
350
351 /**
352  * \ingroup gdcmHeader
353  * \brief   Retrieve the Planar Configuration for RGB images
354  *          (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane)
355  * 
356  * @return  The encountered Planar Configuration, 0 by default.
357  */
358 int gdcmHeader::GetPlanarConfiguration(void) { 
359    std::string StrSize = GetEntryByNumber(0x0028,0x0006);
360    if (StrSize == GDCM_UNFOUND)
361       return 0;
362    return atoi(StrSize.c_str());
363 }
364
365 /**
366  * \ingroup gdcmHeader
367  * \brief   Return the size (in bytes) of a single pixel of data.
368  * @return  The size in bytes of a single pixel of data; 0 by default
369  *          0 means the file is NOT USABLE; the caller will have to check        
370  */
371 int gdcmHeader::GetPixelSize(void) {
372    std::string PixelType = GetPixelType();
373    if (PixelType == "8U"  || PixelType == "8S")
374       return 1;
375    if (PixelType == "16U" || PixelType == "16S")
376       return 2;
377    if (PixelType == "32U" || PixelType == "32S")
378       return 4;
379    dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
380    return 0;
381 }
382
383 /**
384  * \ingroup gdcmHeader
385  * \brief   Build the Pixel Type of the image.
386  *          Possible values are:
387  *          - 8U  unsigned  8 bit,
388  *          - 8S    signed  8 bit,
389  *          - 16U unsigned 16 bit,
390  *          - 16S   signed 16 bit,
391  *          - 32U unsigned 32 bit,
392  *          - 32S   signed 32 bit,
393  * \warning 12 bit images appear as 16 bit.
394  * \        24 bit images appear as 8 bit
395  * @return  0S if nothing found. NOT USABLE file. The caller has to check
396  */
397 std::string gdcmHeader::GetPixelType(void) {
398    std::string BitsAlloc = GetEntryByNumber(0x0028, 0x0100); // Bits Allocated
399    if (BitsAlloc == GDCM_UNFOUND) {
400       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
401       BitsAlloc = std::string("16");
402    }
403    if (BitsAlloc == "12")            // It will be unpacked
404       BitsAlloc = std::string("16");
405    else if (BitsAlloc == "24")       // (in order no to be messed up
406       BitsAlloc = std::string("8");  // by old RGB images)
407      
408    std::string Signed = GetEntryByNumber(0x0028, 0x0103); // "Pixel Representation"
409    if (Signed == GDCM_UNFOUND) {
410       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
411       BitsAlloc = std::string("0");
412    }
413    if (Signed == "0")
414       Signed = std::string("U");
415    else
416       Signed = std::string("S");
417
418    return( BitsAlloc + Signed);
419 }
420
421 /**
422  * \ingroup gdcmHeader
423  * \brief   Recover the offset (from the beginning of the file) 
424  * \        of *image* pixels (not *icone* pixels, if any !)
425  */
426 size_t gdcmHeader::GetPixelOffset(void) {
427    // If this file complies with the norm we should encounter the
428    // "Image Location" tag (0x0028, 0x0200). This tag contains the
429    // the group that contains the pixel data (hence the "Pixel Data"
430    // is found by indirection through the "Image Location").
431    // Inside the group pointed by "Image Location" the searched element
432    // is conventionally the element 0x0010 (when the norm is respected).
433    // When the "Image Location" is absent we default to group 0x7fe0.
434    // If the element (0x0088,0x0200) 'icone image sequence' is found
435    // (grPixel,numPixel) is stored twice : the first one for the icon
436    // the second one for the image ...
437    // pb : sometimes , (0x0088,0x0200) exists, but doesn't contain *anything*
438    // see gdcmData/MxTwinLossLess.dcm ...
439    guint16 grPixel;
440    guint16 numPixel;
441    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
442
443    if ( ImageLocation == GDCM_UNFOUND ) { // Image Location
444       grPixel = 0x7fe0;                   // default value
445    } else {
446       grPixel = (guint16) atoi( ImageLocation.c_str() );
447    }
448    
449    if (grPixel == 0xe07f) // sometimes Image Location value doesn't follow 
450       grPixel = 0x7fe0;   // the supposed processor endianity. 
451                           // see gdcmData/cr172241.dcm
452       
453    if (grPixel != 0x7fe0) 
454       // This is a kludge for old dirty Philips imager.
455       numPixel = 0x1010;
456    else
457       numPixel = 0x0010;
458       
459    IterHT it = GetHeaderEntrySameNumber(grPixel,numPixel);          
460    //std::string icone = GetEntryByNumber(0x0088,0x0200); //icone image sequence
461    TagKey key = gdcmDictEntry::TranslateToKey(grPixel,numPixel);
462    gdcmHeaderEntry* PixelElement;
463   
464    if (tagHT.count(key) == 1)   
465       PixelElement = (it.first)->second;
466    else
467       PixelElement = (++it.first)->second;
468    
469    if (PixelElement) {
470       return PixelElement->GetOffset();
471    }
472    else
473       return 0;
474 }
475 // TODO : unify those two (previous one and next one)
476 /**
477  * \ingroup gdcmHeader
478  * \brief   Recover the pixel area length (in Bytes)
479  *  @return 0 by default. NOT USABLE file. The caller has to check.
480  */
481 size_t gdcmHeader::GetPixelAreaLength(void) {
482    // If this file complies with the norm we should encounter the
483    // "Image Location" tag (0x0028,  0x0200). This tag contains the
484    // the group that contains the pixel data (hence the "Pixel Data"
485    // is found by indirection through the "Image Location").
486    // Inside the group pointed by "Image Location" the searched element
487    // is conventionally the element 0x0010 (when the norm is respected).
488    // When the "Image Location" is absent we default to group 0x7fe0.
489    guint16 grPixel;
490    guint16 numPixel;
491    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
492    if ( ImageLocation == GDCM_UNFOUND ) { // Image Location
493       grPixel = 0x7fe0;                   // default value
494    } else {
495       grPixel = (guint16) atoi( ImageLocation.c_str() );
496    }
497    if (grPixel == 0xe07f) // sometimes group doesn't follow 
498       grPixel = 0x7fe0;   // the supposed processor endianity. see cr172241.dcm
499       
500    if (grPixel != 0x7fe0)
501       // This is a kludge for old dirty Philips imager.
502       numPixel = 0x1010;
503    else
504       numPixel = 0x0010;
505               
506    IterHT it = GetHeaderEntrySameNumber(grPixel,numPixel);          
507    //std::string icone = GetEntryByNumber(0x0088,0x0200); //icone image sequence
508    TagKey key = gdcmDictEntry::TranslateToKey(grPixel,numPixel);
509    gdcmHeaderEntry* PixelElement;
510   
511    if (tagHT.count(key) == 1)   
512       PixelElement = (it.first)->second;
513    else
514       PixelElement = (++it.first)->second;
515    
516    if (PixelElement)
517       return PixelElement->GetLength();
518    else {
519       std::cout << "Big trouble : Pixel Element ("
520                 << std::hex << grPixel<<","<< numPixel<< ") NOT found" 
521                 << std::endl;
522       return 0;
523    }
524 }
525
526 /**
527   * \ingroup gdcmHeader
528   * \brief tells us if LUT are used
529   * \warning Right now, 'Segmented xxx Palette Color Lookup Table Data'
530   * \        are NOT considered as LUT, since nobody knows
531   * \        how to deal with them
532   * @return a Boolean 
533   */
534 bool gdcmHeader::HasLUT(void) {
535
536    // Check the presence of the LUT Descriptors 
537    
538    // LutDescriptorRed    
539    if ( !GetHeaderEntryByNumber(0x0028,0x1101) )
540       return false;
541    // LutDescriptorGreen 
542    if ( !GetHeaderEntryByNumber(0x0028,0x1102) )
543       return false;
544    // LutDescriptorBlue 
545    if ( !GetHeaderEntryByNumber(0x0028,0x1103) )
546       return false;
547       
548    //  It is not enough
549    //  we check also 
550    
551    // Red Palette Color Lookup Table Data
552    if ( !GetHeaderEntryByNumber(0x0028,0x1201) )
553       return false; 
554    // Green Palette Color Lookup Table Data       
555    if ( !GetHeaderEntryByNumber(0x0028,0x1202) )
556       return false;
557    // Blue Palette Color Lookup Table Data      
558    if ( !GetHeaderEntryByNumber(0x0028,0x1203) )
559       return false;   
560    return true;
561 }
562
563 /**
564   * \ingroup gdcmHeader
565   * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
566   * \           else 0
567   * @return Lookup Table number of Bits , 0 by default
568   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] 
569   */
570 int gdcmHeader::GetLUTNbits(void) {
571    std::vector<std::string> tokens;
572    //int LutLength;
573    //int LutDepth;
574    int LutNbits;
575    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue
576    // Consistency already checked in GetLUTLength
577    std::string LutDescription = GetEntryByNumber(0x0028,0x1101);
578    if (LutDescription == GDCM_UNFOUND)
579       return 0;
580    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
581    Tokenize (LutDescription, tokens, "\\");
582    //LutLength=atoi(tokens[0].c_str());
583    //LutDepth=atoi(tokens[1].c_str());
584    LutNbits=atoi(tokens[2].c_str());
585    tokens.clear();
586    return LutNbits;
587 }
588
589 /**
590   * \ingroup gdcmHeader
591   * \brief builts Red/Green/Blue/Alpha LUT from Header
592   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
593   * \        and (0028,1101),(0028,1102),(0028,1102)  
594   * \          - xxx Palette Color Lookup Table Descriptor - are found
595   * \        and (0028,1201),(0028,1202),(0028,1202) 
596   * \          - xxx Palette Color Lookup Table Data - are found 
597   * \warning does NOT deal with :
598   * \ 0028 1100 Gray Lookup Table Descriptor (Retired)
599   * \ 0028 1221 Segmented Red Palette Color Lookup Table Data
600   * \ 0028 1222 Segmented Green Palette Color Lookup Table Data
601   * \ 0028 1223 Segmented Blue Palette Color Lookup Table Data 
602   * \ no known Dicom reader deals with them :-(
603   * @return a RGBA Lookup Table 
604   */ 
605 unsigned char * gdcmHeader::GetLUTRGBA(void) {
606 // Not so easy : see 
607 // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
608
609 //  if Photometric Interpretation # PALETTE COLOR, no LUT to be done
610    if (GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") {
611         return NULL;
612    }  
613    int lengthR, debR, nbitsR;
614    int lengthG, debG, nbitsG;
615    int lengthB, debB, nbitsB;
616    
617 // Get info from Lut Descriptors
618 // (the 3 LUT descriptors may be different)    
619    std::string LutDescriptionR = GetEntryByNumber(0x0028,0x1101);
620    if (LutDescriptionR == GDCM_UNFOUND)
621       return NULL;
622    std::string LutDescriptionG = GetEntryByNumber(0x0028,0x1102);
623    if (LutDescriptionG == GDCM_UNFOUND)
624       return NULL;   
625    std::string LutDescriptionB = GetEntryByNumber(0x0028,0x1103);
626    if (LutDescriptionB == GDCM_UNFOUND)
627       return NULL;
628       
629    std::vector<std::string> tokens;
630       
631    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
632    Tokenize (LutDescriptionR, tokens, "\\");
633    lengthR=atoi(tokens[0].c_str()); // Red LUT length in Bytes
634    debR   =atoi(tokens[1].c_str()); // subscript of the first Lut Value
635    nbitsR =atoi(tokens[2].c_str()); // Lut item size (in Bits)
636    tokens.clear();
637    
638    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
639    Tokenize (LutDescriptionG, tokens, "\\");
640    lengthG=atoi(tokens[0].c_str()); // Green LUT length in Bytes
641    debG   =atoi(tokens[1].c_str()); // subscript of the first Lut Value
642    nbitsG =atoi(tokens[2].c_str()); // Lut item size (in Bits)
643    tokens.clear();  
644    
645    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
646    Tokenize (LutDescriptionB, tokens, "\\");
647    lengthB=atoi(tokens[0].c_str()); // Blue LUT length in Bytes
648    debB   =atoi(tokens[1].c_str()); // subscript of the first Lut Value
649    nbitsB =atoi(tokens[2].c_str()); // Lut item size (in Bits)
650    tokens.clear();
651  
652    // Load LUTs into memory, (as they were stored on disk)
653    unsigned char *lutR = (unsigned char *)
654                          GetEntryVoidAreaByNumber(0x0028,0x1201);
655    unsigned char *lutG = (unsigned char *)
656                          GetEntryVoidAreaByNumber(0x0028,0x1202);
657    unsigned char *lutB = (unsigned char *)
658                          GetEntryVoidAreaByNumber(0x0028,0x1203); 
659    
660    if (!lutR || !lutG || !lutB ) {
661         return NULL;
662    } 
663    // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT 
664    
665    unsigned char *LUTRGBA = (unsigned char *)calloc(1024,1); // 256 * 4 (R, G, B, Alpha) 
666    if (!LUTRGBA) {
667       return NULL;
668    }
669    memset(LUTRGBA, 0, 1024);
670         // Bits Allocated
671    int nb;
672    std::string str_nb = GetEntryByNumber(0x0028,0x0100);
673    if (str_nb == GDCM_UNFOUND ) {
674       nb = 16;
675    } else {
676       nb = atoi(str_nb.c_str() );
677    }  
678    int mult;
679
680    if (nbitsR==16 && nb==8) // when LUT item size is different than pixel size
681       mult=2;               // high byte must be = low byte 
682    else                     // See PS 3.3-2003 C.11.1.1.2 p 619
683       mult=1; 
684  
685    // if we get a black image, let's just remove the '+1'
686    // from 'i*mult+1' and check again 
687    // if it works, we shall have to check the 3 Palettes
688    // to see which byte is ==0 (first one, or second one)
689    // and fix the code
690    // We give up the checking to avoid some overhead 
691    unsigned char *a;      
692    int i;
693
694    a = LUTRGBA+0;
695    for(i=0;i<lengthR;i++) {
696       *a = lutR[i*mult+1]; 
697       a+=4;       
698    }        
699    a = LUTRGBA+1;
700    for(i=0;i<lengthG;i++) {
701       *a = lutG[i*mult+1]; 
702       a+=4;       
703    }  
704    a = LUTRGBA+2;
705    for(i=0;i<lengthB;i++) {
706       *a = lutB[i*mult+1]; 
707       a+=4;       
708    }  
709    a = LUTRGBA+3;
710    for(i=0;i<256;i++) {
711       *a = 1; // Alpha component
712       a+=4; 
713    } 
714    
715    //How to free the now useless LUTs?
716
717    //free(LutR); free(LutB); free(LutG); // Seg Fault when used
718    return(LUTRGBA);   
719
720
721 /**
722  * \ingroup gdcmHeader
723  * \brief gets the info from 0002,0010 : Transfert Syntax
724  * \      else 1.
725  * @return Transfert Syntax Name (as oposite to Transfert Syntax UID)
726  */
727 std::string gdcmHeader::GetTransfertSyntaxName(void) { 
728    // use the gdcmTS (TS : Transfert Syntax)
729    std::string TransfertSyntax = GetEntryByNumber(0x0002,0x0010);
730    if (TransfertSyntax == GDCM_UNFOUND) {
731       dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName: unfound Transfert Syntax (0002,0010)");
732       return "Uncompressed ACR-NEMA";
733    }
734    // we do it only when we need it
735    gdcmTS * ts = gdcmGlobal::GetTS();
736    std::string tsName=ts->GetValue(TransfertSyntax);
737    //delete ts; // Seg Fault when deleted ?!
738    return tsName;
739 }
740
741 /**
742  * \ingroup   gdcmFile
743  * \brief Sets the Pixel Area size in the Header
744  *        --> not-for-rats function
745  * 
746  * \warning WARNING doit-etre etre publique ? 
747  * TODO : y aurait il un inconvenient à fusionner ces 2 fonctions
748  *
749  * @param ImageDataSize new Pixel Area Size
750  *        warning : nothing else is checked
751  */
752 void gdcmHeader::SetImageDataSize(size_t ImageDataSize) {
753    std::string content1;
754    char car[20];        
755    // Assumes HeaderEntry (0x7fe0, 0x0010) exists ...   
756    sprintf(car,"%d",ImageDataSize);
757  
758    gdcmHeaderEntry *a = GetHeaderEntryByNumber(0x7fe0, 0x0010);
759    a->SetLength(ImageDataSize);
760                 
761    ImageDataSize+=8;
762    sprintf(car,"%d",ImageDataSize);
763    content1=car;        
764    SetEntryByNumber(content1, 0x7fe0, 0x0000);
765 }
766
767 //-----------------------------------------------------------------------------
768 // Protected
769
770 //-----------------------------------------------------------------------------
771 // Private
772
773 //-----------------------------------------------------------------------------