]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
503fea29fb85f2c13e750c3fd95190572233b89d
[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  *\TODO : may be we need one more bool, 
30  *         to allow skipping the private elements while parsing the header
31  *         in order to save space         
32  */
33 gdcmHeader::gdcmHeader(const char *InFilename, 
34                        bool exception_on_error,
35                        bool enable_sequences ):
36    gdcmParser(InFilename,exception_on_error,enable_sequences)
37 {
38 }
39
40 /**
41  * \ingroup gdcmHeader
42  * \brief   
43  * @param   exception_on_error
44  */
45 gdcmHeader::gdcmHeader(bool exception_on_error) :
46    gdcmParser(exception_on_error)
47 {
48 }
49
50 /**
51  * \ingroup gdcmHeader
52  * \brief   Canonical destructor.
53  */
54 gdcmHeader::~gdcmHeader (void) {
55 }
56
57 //-----------------------------------------------------------------------------
58 // Print
59
60 //-----------------------------------------------------------------------------
61 // Public
62 /**
63  * \ingroup gdcmHeader
64  * \brief  This predicate, based on hopefully reasonable heuristics,
65  *         decides whether or not the current gdcmParser was properly parsed
66  *         and contains the mandatory information for being considered as
67  *         a well formed and usable Dicom/Acr File.
68  * @return true when gdcmParser is the one of a reasonable Dicom/Acr file,
69  *         false otherwise. 
70  */
71 bool gdcmHeader::IsReadable(void) 
72 {
73    if(!gdcmParser::IsReadable())
74       return(false);
75
76    std::string res = GetEntryByNumber(0x0028, 0x0005);
77    if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) 
78       return false; // Image Dimensions
79
80    if ( !GetHeaderEntryByNumber(0x0028, 0x0100) )
81       return false; // "Bits Allocated"
82    if ( !GetHeaderEntryByNumber(0x0028, 0x0101) )
83       return false; // "Bits Stored"
84    if ( !GetHeaderEntryByNumber(0x0028, 0x0102) )
85       return false; // "High Bit"
86    if ( !GetHeaderEntryByNumber(0x0028, 0x0103) )
87       return false; // "Pixel Representation"
88    return true;
89 }
90
91 /**
92  * \ingroup gdcmHeader
93  * \brief   Determines if the Transfer Syntax was already encountered
94  *          and if it corresponds to a JPEGBaseLineProcess1 one.
95  *
96  * @return  True when JPEGBaseLineProcess1found. False in all other cases.
97  */
98 bool gdcmHeader::IsJPEGBaseLineProcess1TransferSyntax(void) {
99    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
100    if ( !Element )
101       return false;
102    LoadHeaderEntrySafe(Element);
103
104    std::string Transfer = Element->GetValue();
105    if ( Transfer == "1.2.840.10008.1.2.4.50" )
106       return true;
107    return false;
108 }
109
110 /**
111  * \ingroup gdcmHeader
112  * \brief   Determines if the Transfer Syntax was already encountered
113  *          and if it corresponds to a JPEGExtendedProcess2-4 one.
114  *
115  * @return  True when JPEGExtendedProcess2-4 found. False in all other cases.
116  */
117 bool gdcmHeader::IsJPEGExtendedProcess2_4TransferSyntax(void) {
118    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
119    if ( !Element )
120       return false;
121    LoadHeaderEntrySafe(Element);
122
123    std::string Transfer = Element->GetValue();
124    if ( Transfer == "1.2.840.10008.1.2.4.51" )
125       return true;
126    return false;
127 }
128
129 /**
130  * \ingroup gdcmHeader
131  * \brief   Determines if the Transfer Syntax was already encountered
132  *          and if it corresponds to a JPEGExtendeProcess3-5 one.
133  *
134  * @return  True when JPEGExtendedProcess3-5 found. False in all other cases.
135  */
136 bool gdcmHeader::IsJPEGExtendedProcess3_5TransferSyntax(void) {
137    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
138    if ( !Element )
139       return false;
140    LoadHeaderEntrySafe(Element);
141
142    std::string Transfer = Element->GetValue();
143    if ( Transfer == "1.2.840.10008.1.2.4.52" )
144       return true;
145    return false;
146 }
147
148 /**
149  * \ingroup gdcmHeader
150  * \brief   Determines if the Transfer Syntax was already encountered
151  *          and if it corresponds to a JPEGSpectralSelectionProcess6-8 one.
152  *
153  * @return  True when JPEGSpectralSelectionProcess6-8 found. False in all
154  *          other cases.
155  */
156 bool gdcmHeader::IsJPEGSpectralSelectionProcess6_8TransferSyntax(void) {
157    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
158    if ( !Element )
159       return false;
160    LoadHeaderEntrySafe(Element);
161
162    std::string Transfer = Element->GetValue();
163    if ( Transfer == "1.2.840.10008.1.2.4.53" )
164       return true;
165    return false;
166 }
167
168 /**
169  * \ingroup gdcmHeader
170  * \brief   Determines if the Transfer Syntax was already encountered
171  *          and if it corresponds to a RLE Lossless one.
172  *
173  * @return  True when RLE Lossless found. False in all
174  *          other cases.
175  */
176 bool gdcmHeader::IsRLELossLessTransferSyntax(void) {
177    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
178    if ( !Element )
179       return false;
180    LoadHeaderEntrySafe(Element);
181
182    std::string Transfer = Element->GetValue();
183    if ( Transfer == "1.2.840.10008.1.2.5" )
184       return true;
185    return false;
186 }
187
188 /**
189  * \ingroup gdcmHeader
190  * \brief  Determines if Transfer Syntax was already encountered
191  *          and if it corresponds to a JPEG Lossless one. 
192  *
193  * @return  True when RLE Lossless found. False in all
194  *          other cases. 
195  */
196 bool gdcmHeader::IsJPEGLossless(void) {
197    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
198     // faire qq chose d'intelligent a la place de ça
199    if ( !Element )
200       return false;
201    LoadHeaderEntrySafe(Element);
202
203    const char * Transfert = Element->GetValue().c_str();
204    if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true;
205    if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true;
206    if (Element->GetValue() == "1.2.840.10008.1.2.4.57")   return true;
207
208    return false;
209 }
210
211 /**
212  * \ingroup gdcmHeader
213  * \brief   Determines if the Transfer Syntax was already encountered
214  *          and if it corresponds to a JPEG200 one.0
215  *
216  * @return  True when JPEG2000 (Lossly or LossLess) found. False in all
217  *          other cases.
218  */
219 bool gdcmHeader::IsJPEG2000(void) {
220    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
221    if ( !Element )
222       return false;
223    LoadHeaderEntrySafe(Element);
224
225    std::string Transfer = Element->GetValue();
226    if (    (Transfer == "1.2.840.10008.1.2.4.90") 
227         || (Transfer == "1.2.840.10008.1.2.4.91") )
228       return true;
229    return false;
230 }
231
232 /**
233  * \ingroup gdcmHeader
234  * \brief   Predicate for dicom version 3 file.
235  * @return  True when the file is a dicom version 3.
236  */
237 bool gdcmHeader::IsDicomV3(void) {
238    // Checking if Transfert Syntax exists is enough
239    return (GetHeaderEntryByNumber(0x0002, 0x0010) != NULL);
240 }
241
242 /**
243  * \ingroup gdcmHeader
244  * \brief   Retrieve the number of columns of image.
245  * @return  The encountered size when found, 0 by default.
246  *          0 means the file is NOT USABLE. The caller will have to check
247  */
248 int gdcmHeader::GetXSize(void) {
249    // We cannot check for "Columns" because the "Columns" tag is present
250    // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary.
251    std::string StrSize = GetEntryByNumber(0x0028,0x0011);
252    if (StrSize == GDCM_UNFOUND)
253       return 0;
254    return atoi(StrSize.c_str());
255 }
256
257 /**
258  * \ingroup gdcmHeader
259  * \brief   Retrieve the number of lines of image.
260  * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize()
261  * @return  The encountered size when found, 1 by default 
262  *          (The file contains a Signal, not an Image).
263  */
264 int gdcmHeader::GetYSize(void) {
265    // We cannot check for "Rows" because the "Rows" tag is present
266    // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary.
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) of the pixels.
424  */
425 size_t gdcmHeader::GetPixelOffset(void) {
426    // If this file complies with the norm we should encounter the
427    // "Image Location" tag (0x0028, 0x0200). This tag contains the
428    // the group that contains the pixel data (hence the "Pixel Data"
429    // is found by indirection through the "Image Location").
430    // Inside the group pointed by "Image Location" the searched element
431    // is conventionally the element 0x0010 (when the norm is respected).
432    // When the "Image Location" is absent we default to group 0x7fe0.
433    guint16 grPixel;
434    guint16 numPixel;
435    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
436
437    if ( ImageLocation == GDCM_UNFOUND ) { // Image Location
438       grPixel = 0x7fe0;
439    } else {
440       grPixel = (guint16) atoi( ImageLocation.c_str() );
441    }
442    if (grPixel != 0x7fe0)
443       // This is a kludge for old dirty Philips imager.
444       numPixel = 0x1010;
445    else
446       numPixel = 0x0010;
447          
448    gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
449    if (PixelElement)
450       return PixelElement->GetOffset();
451    else
452       return 0;
453 }
454
455 /**
456  * \ingroup gdcmHeader
457  * \brief   Recover the pixel area length (in Bytes)
458  *  @return 0 by default. NOT USABLE file. The caller has to check.
459  */
460 size_t gdcmHeader::GetPixelAreaLength(void) {
461    // If this file complies with the norm we should encounter the
462    // "Image Location" tag (0x0028,  0x0200). This tag contains the
463    // the group that contains the pixel data (hence the "Pixel Data"
464    // is found by indirection through the "Image Location").
465    // Inside the group pointed by "Image Location" the searched element
466    // is conventionally the element 0x0010 (when the norm is respected).
467    // When the "Image Location" is absent we default to group 0x7fe0.
468    guint16 grPixel;
469    guint16 numPixel;
470    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
471    if ( ImageLocation == GDCM_UNFOUND ) {
472       grPixel = 0x7fe0;
473    } else {
474       grPixel = (guint16) atoi( ImageLocation.c_str() );
475    }
476    if (grPixel != 0x7fe0)
477       // This is a kludge for old dirty Philips imager.
478       numPixel = 0x1010;
479    else
480       numPixel = 0x0010;
481          
482    gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
483    if (PixelElement)
484       return PixelElement->GetLength();
485    else
486       return 0;
487 }
488
489 /**
490   * \ingroup gdcmHeader
491   * \brief tells us if LUT are used
492   * \warning Right now, 'Segmented xxx Palette Color Lookup Table Data'
493   * \        are NOT considered as LUT, since nobody knows
494   * \        how to deal with them
495   * @return a Boolean 
496   */
497 bool gdcmHeader::HasLUT(void) {
498
499    // Check the presence of the LUT Descriptors 
500    if ( !GetHeaderEntryByNumber(0x0028,0x1101) )
501       return false;
502    // LutDescriptorGreen 
503    if ( !GetHeaderEntryByNumber(0x0028,0x1102) )
504       return false;
505    // LutDescriptorBlue 
506    if ( !GetHeaderEntryByNumber(0x0028,0x1103) )
507       return false;
508    //  It is not enough
509    // we check also 
510    if ( !GetHeaderEntryByNumber(0x0028,0x1201) )
511       return false;  
512    if ( !GetHeaderEntryByNumber(0x0028,0x1202) )
513       return false;
514    if ( !GetHeaderEntryByNumber(0x0028,0x1203) )
515       return false;   
516    return true;
517 }
518
519 /**
520   * \ingroup gdcmHeader
521   * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
522   * \           else 0
523   * @return Lookup Table number of Bits , 0 by default
524   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] 
525   */
526 int gdcmHeader::GetLUTNbits(void) {
527    std::vector<std::string> tokens;
528    //int LutLength;
529    //int LutDepth;
530    int LutNbits;
531    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue
532    // Consistency already checked in GetLUTLength
533    std::string LutDescription = GetEntryByNumber(0x0028,0x1101);
534    if (LutDescription == GDCM_UNFOUND)
535       return 0;
536    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
537    Tokenize (LutDescription, tokens, "\\");
538    //LutLength=atoi(tokens[0].c_str());
539    //LutDepth=atoi(tokens[1].c_str());
540    LutNbits=atoi(tokens[2].c_str());
541    tokens.clear();
542    return LutNbits;
543 }
544
545 /**
546   * \ingroup gdcmHeader
547   * \brief builts Red/Green/Blue/Alpha LUT from Header
548   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
549   * \        and (0028,1101),(0028,1102),(0028,1102)  
550   * \          - xxx Palette Color Lookup Table Descriptor - are found
551   * \        and (0028,1201),(0028,1202),(0028,1202) 
552   * \          - xxx Palette Color Lookup Table Data - are found 
553   * \warning does NOT deal with :
554   * \ 0028 1100 Gray Lookup Table Descriptor (Retired)
555   * \ 0028 1221 Segmented Red Palette Color Lookup Table Data
556   * \ 0028 1222 Segmented Green Palette Color Lookup Table Data
557   * \ 0028 1223 Segmented Blue Palette Color Lookup Table Data 
558   * \ no known Dicom reader deals with them :-(
559   * @return a RGBA Lookup Table 
560   */ 
561 unsigned char * gdcmHeader::GetLUTRGBA(void) {
562 // Not so easy : see 
563 // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
564
565 //  if Photometric Interpretation # PALETTE COLOR, no LUT to be done
566    if (GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") {
567         return NULL;
568    }  
569    int lengthR, debR, nbitsR;
570    int lengthG, debG, nbitsG;
571    int lengthB, debB, nbitsB;
572    
573 // Get info from Lut Descriptors
574 // (the 3 LUT descriptors may be different)    
575    std::string LutDescriptionR = GetEntryByNumber(0x0028,0x1101);
576    if (LutDescriptionR == GDCM_UNFOUND)
577       return NULL;
578    std::string LutDescriptionG = GetEntryByNumber(0x0028,0x1102);
579    if (LutDescriptionG == GDCM_UNFOUND)
580       return NULL;   
581    std::string LutDescriptionB = GetEntryByNumber(0x0028,0x1103);
582    if (LutDescriptionB == GDCM_UNFOUND)
583       return NULL;
584       
585    std::vector<std::string> tokens;
586       
587    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
588    Tokenize (LutDescriptionR, tokens, "\\");
589    lengthR=atoi(tokens[0].c_str()); // Red LUT length in Bytes
590    debR   =atoi(tokens[1].c_str()); // subscript of the first Lut Value
591    nbitsR =atoi(tokens[2].c_str()); // Lut item size (in Bits)
592    tokens.clear();
593    
594    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
595    Tokenize (LutDescriptionG, tokens, "\\");
596    lengthG=atoi(tokens[0].c_str()); // Green LUT length in Bytes
597    debG   =atoi(tokens[1].c_str());
598    nbitsG =atoi(tokens[2].c_str());
599    tokens.clear();  
600    
601    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
602    Tokenize (LutDescriptionB, tokens, "\\");
603    lengthB=atoi(tokens[0].c_str()); // Blue LUT length in Bytes
604    debB   =atoi(tokens[1].c_str());
605    nbitsB =atoi(tokens[2].c_str());
606    tokens.clear();
607  
608    // Load LUTs into memory, (as they were stored on disk)
609    unsigned char *lutR = (unsigned char *)
610                          GetEntryVoidAreaByNumber(0x0028,0x1201);
611    unsigned char *lutG = (unsigned char *)
612                          GetEntryVoidAreaByNumber(0x0028,0x1202);
613    unsigned char *lutB = (unsigned char *)
614                          GetEntryVoidAreaByNumber(0x0028,0x1203); 
615    
616    if (!lutR || !lutG || !lutB ) {
617         return NULL;
618    } 
619    // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT 
620    
621    unsigned char *LUTRGBA = (unsigned char *)calloc(1024,1); // 256 * 4 (R, G, B, Alpha) 
622    if (!LUTRGBA) {
623       return NULL;
624    }
625    memset(LUTRGBA, 0, 1024);
626         // Bits Allocated
627    int nb;
628    std::string str_nb = GetEntryByNumber(0x0028,0x0100);
629    if (str_nb == GDCM_UNFOUND ) {
630       nb = 16;
631    } else {
632       nb = atoi(str_nb.c_str() );
633    }  
634    int mult;
635
636    if (nbitsR==16 && nb==8) // when LUT item size is different than pixel size
637       mult=2;               // high byte must be = low byte 
638    else                     // See PS 3.3-2003 C.11.1.1.2 p 619
639       mult=1; 
640  
641    // if we get a black image, let's just remove the '+1'
642    // from 'i*mult+1' and check again 
643    // if it works, we shall have to check the 3 Palettes
644    // to see which byte is ==0 (first one, or second one)
645    // and fix the code
646    // We give up the checking to avoid some overhead 
647    unsigned char *a;      
648    int i;
649
650    a = LUTRGBA+0;
651    for(i=0;i<lengthR;i++) {
652       *a = lutR[i*mult+1]; 
653       a+=4;       
654    }        
655    a = LUTRGBA+1;
656    for(i=0;i<lengthG;i++) {
657       *a = lutG[i*mult+1]; 
658       a+=4;       
659    }  
660    a = LUTRGBA+2;
661    for(i=0;i<lengthB;i++) {
662       *a = lutB[i*mult+1]; 
663       a+=4;       
664    }  
665    a = LUTRGBA+3;
666    for(i=0;i<256;i++) {
667       *a = 1; // Alpha component
668       a+=4; 
669    } 
670    
671    //How to free the now useless LUTs?
672
673    //free(LutR); free(LutB); free(LutG); // Seg Fault when used
674    return(LUTRGBA);   
675
676
677 /**
678  * \ingroup gdcmHeader
679  * \brief gets the info from 0002,0010 : Transfert Syntax
680  * \      else 1.
681  * @return Transfert Syntax Name (as oposite to Transfert Syntax UID)
682  */
683 std::string gdcmHeader::GetTransfertSyntaxName(void) { 
684    // use the gdcmTS (TS : Transfert Syntax)
685    std::string TransfertSyntax = GetEntryByNumber(0x0002,0x0010);
686    if (TransfertSyntax == GDCM_UNFOUND) {
687       dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName: unfound Transfert Syntax (0002,0010)");
688       return "Uncompressed ACR-NEMA";
689    }
690    // we do it only when we need it
691    gdcmTS * ts = gdcmGlobal::GetTS();
692    std::string tsName=ts->GetValue(TransfertSyntax);
693    //delete ts; // Seg Fault when deleted ?!
694    return tsName;
695 }
696
697 /**
698  * \ingroup   gdcmFile
699  * \brief Sets the Pixel Area size in the Header
700  *        --> not-for-rats function
701  * 
702  * \warning WARNING doit-etre etre publique ? 
703  * TODO : y aurait il un inconvenient à fusionner ces 2 fonctions
704  *
705  * @param ImageDataSize new Pixel Area Size
706  *        warning : nothing else is checked
707  */
708 void gdcmHeader::SetImageDataSize(size_t ImageDataSize) {
709    std::string content1;
710    char car[20];        
711    // Assumes HeaderEntry (0x7fe0, 0x0010) exists ...   
712    sprintf(car,"%d",ImageDataSize);
713  
714    gdcmHeaderEntry *a = GetHeaderEntryByNumber(0x7fe0, 0x0010);
715    a->SetLength(ImageDataSize);
716                 
717    ImageDataSize+=8;
718    sprintf(car,"%d",ImageDataSize);
719    content1=car;        
720    SetEntryByNumber(content1, 0x7fe0, 0x0000);
721 }
722
723 //-----------------------------------------------------------------------------
724 // Protected
725
726 //-----------------------------------------------------------------------------
727 // Private
728
729 //-----------------------------------------------------------------------------