]> Creatis software - gdcm.git/blob - src/gdcmHeader.cxx
- ANSIfy gdcmDicomDir.cxx
[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     }
186    return false;
187 }
188
189 /**
190  * \ingroup gdcmHeader
191  * \brief  Determines if Transfer Syntax was already encountered
192  *          and if it corresponds to a JPEG Lossless one. 
193  *
194  * @return  True when RLE Lossless found. False in all
195  *          other cases. 
196  */
197 bool gdcmHeader::IsJPEGLossless(void) {
198    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
199     // faire qq chose d'intelligent a la place de ça
200    if ( !Element )
201       return false;
202    LoadHeaderEntrySafe(Element);
203
204    const char * Transfert = Element->GetValue().c_str();
205    if ( memcmp(Transfert+strlen(Transfert)-2 ,"70",2)==0) return true;
206    if ( memcmp(Transfert+strlen(Transfert)-2 ,"55",2)==0) return true;
207    if (Element->GetValue() == "1.2.840.10008.1.2.4.57")   return true;
208
209    return false;
210 }
211
212 /**
213  * \ingroup gdcmHeader
214  * \brief   Determines if the Transfer Syntax was already encountered
215  *          and if it corresponds to a JPEG200 one.0
216  *
217  * @return  True when JPEG2000 (Lossly or LossLess) found. False in all
218  *          other cases.
219  */
220 bool gdcmHeader::IsJPEG2000(void) {
221    gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
222    if ( !Element )
223       return false;
224    LoadHeaderEntrySafe(Element);
225
226    std::string Transfer = Element->GetValue();
227    if (    (Transfer == "1.2.840.10008.1.2.4.90") 
228         || (Transfer == "1.2.840.10008.1.2.4.91") )
229       return true;
230    return false;
231 }
232
233 /**
234  * \ingroup gdcmHeader
235  * \brief   Predicate for dicom version 3 file.
236  * @return  True when the file is a dicom version 3.
237  */
238 bool gdcmHeader::IsDicomV3(void) {
239    // Checking if Transfert Syntax exists is enough
240    return (GetHeaderEntryByNumber(0x0002, 0x0010) != NULL);
241 }
242
243 /**
244  * \ingroup gdcmHeader
245  * \brief   Retrieve the number of columns of image.
246  * @return  The encountered size when found, 0 by default.
247  *          0 means the file is NOT USABLE. The caller will have to check
248  */
249 int gdcmHeader::GetXSize(void) {
250    // We cannot check for "Columns" because the "Columns" tag is present
251    // both in IMG (0028,0011) and OLY (6000,0011) sections of the dictionary.
252    std::string StrSize = GetEntryByNumber(0x0028,0x0011);
253    if (StrSize == GDCM_UNFOUND)
254       return 0;
255    return atoi(StrSize.c_str());
256 }
257
258 /**
259  * \ingroup gdcmHeader
260  * \brief   Retrieve the number of lines of image.
261  * \warning The defaulted value is 1 as opposed to gdcmHeader::GetXSize()
262  * @return  The encountered size when found, 1 by default 
263  *          (The file contains a Signal, not an Image).
264  */
265 int gdcmHeader::GetYSize(void) {
266    // We cannot check for "Rows" because the "Rows" tag is present
267    // both in IMG (0028,0010) and OLY (6000,0010) sections of the dictionary.
268    std::string StrSize = GetEntryByNumber(0x0028,0x0010);
269    if (StrSize != GDCM_UNFOUND)
270       return atoi(StrSize.c_str());
271    if ( IsDicomV3() )
272       return 0;
273    else
274       // The Rows (0028,0010) entry was optional for ACR/NEMA. It might
275       // hence be a signal (1d image). So we default to 1:
276       return 1;
277 }
278
279 /**
280  * \ingroup gdcmHeader
281  * \brief   Retrieve the number of planes of volume or the number
282  *          of frames of a multiframe.
283  * \warning When present we consider the "Number of Frames" as the third
284  *          dimension. When absent we consider the third dimension as
285  *          being the "Planes" tag content.
286  * @return  The encountered size when found, 1 by default (single image).
287  */
288 int gdcmHeader::GetZSize(void) {
289    // Both  DicomV3 and ACR/Nema consider the "Number of Frames"
290    // as the third dimension.
291    std::string StrSize = GetEntryByNumber(0x0028,0x0008);
292    if (StrSize != GDCM_UNFOUND)
293       return atoi(StrSize.c_str());
294
295    // We then consider the "Planes" entry as the third dimension [we
296    // cannot retrieve by name since "Planes tag is present both in
297    // IMG (0028,0012) and OLY (6000,0012) sections of the dictionary]. 
298    StrSize = GetEntryByNumber(0x0028,0x0012);
299    if (StrSize != GDCM_UNFOUND)
300       return atoi(StrSize.c_str());
301    return 1;
302 }
303
304 /**
305  * \ingroup gdcmHeader
306  * \brief   Retrieve the number of Bits Stored (actually used)
307  *          (as opposite to number of Bits Allocated)
308  * 
309  * @return  The encountered number of Bits Stored, 0 by default.
310  *          0 means the file is NOT USABLE. The caller has to check it !
311  */
312 int gdcmHeader::GetBitsStored(void) { 
313    std::string StrSize = GetEntryByNumber(0x0028,0x0101);
314    if (StrSize == GDCM_UNFOUND)
315       return 0;  // It's supposed to be mandatory
316                  // the caller will have to check
317    return atoi(StrSize.c_str());
318 }
319
320 /**
321  * \ingroup gdcmHeader
322  * \brief   Retrieve the number of Bits Allocated
323  *          (8, 12 -compacted ACR-NEMA files, 16, ...)
324  * 
325  * @return  The encountered number of Bits Allocated, 0 by default.
326  *          0 means the file is NOT USABLE. The caller has to check it !
327  */
328 int gdcmHeader::GetBitsAllocated(void) { 
329    std::string StrSize = GetEntryByNumber(0x0028,0x0100);
330    if (StrSize == GDCM_UNFOUND)
331       return 0; // It's supposed to be mandatory
332                 // the caller will have to check
333    return atoi(StrSize.c_str());
334 }
335
336 /**
337  * \ingroup gdcmHeader
338  * \brief   Retrieve the number of Samples Per Pixel
339  *          (1 : gray level, 3 : RGB -1 or 3 Planes-)
340  * 
341  * @return  The encountered number of Samples Per Pixel, 1 by default.
342  *          (Gray level Pixels)
343  */
344 int gdcmHeader::GetSamplesPerPixel(void) { 
345    std::string StrSize = GetEntryByNumber(0x0028,0x0002);
346    if (StrSize == GDCM_UNFOUND)
347       return 1; // Well, it's supposed to be mandatory ...
348                 // but sometimes it's missing : we assume Gray pixels
349    return atoi(StrSize.c_str());
350 }
351
352 /**
353  * \ingroup gdcmHeader
354  * \brief   Retrieve the Planar Configuration for RGB images
355  *          (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane)
356  * 
357  * @return  The encountered Planar Configuration, 0 by default.
358  */
359 int gdcmHeader::GetPlanarConfiguration(void) { 
360    std::string StrSize = GetEntryByNumber(0x0028,0x0006);
361    if (StrSize == GDCM_UNFOUND)
362       return 0;
363    return atoi(StrSize.c_str());
364 }
365
366 /**
367  * \ingroup gdcmHeader
368  * \brief   Return the size (in bytes) of a single pixel of data.
369  * @return  The size in bytes of a single pixel of data; 0 by default
370  *          0 means the file is NOT USABLE; the caller will have to check        
371  */
372 int gdcmHeader::GetPixelSize(void) {
373    std::string PixelType = GetPixelType();
374    if (PixelType == "8U"  || PixelType == "8S")
375       return 1;
376    if (PixelType == "16U" || PixelType == "16S")
377       return 2;
378    if (PixelType == "32U" || PixelType == "32S")
379       return 4;
380    dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
381    return 0;
382 }
383
384 /**
385  * \ingroup gdcmHeader
386  * \brief   Build the Pixel Type of the image.
387  *          Possible values are:
388  *          - 8U  unsigned  8 bit,
389  *          - 8S    signed  8 bit,
390  *          - 16U unsigned 16 bit,
391  *          - 16S   signed 16 bit,
392  *          - 32U unsigned 32 bit,
393  *          - 32S   signed 32 bit,
394  * \warning 12 bit images appear as 16 bit.
395  * \        24 bit images appear as 8 bit
396  * @return  0S if nothing found. NOT USABLE file. The caller has to check
397  */
398 std::string gdcmHeader::GetPixelType(void) {
399    std::string BitsAlloc = GetEntryByNumber(0x0028, 0x0100); // Bits Allocated
400    if (BitsAlloc == GDCM_UNFOUND) {
401       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
402       BitsAlloc = std::string("16");
403    }
404    if (BitsAlloc == "12")            // It will be unpacked
405       BitsAlloc = std::string("16");
406    else if (BitsAlloc == "24")       // (in order no to be messed up
407       BitsAlloc = std::string("8");  // by old RGB images)
408      
409    std::string Signed = GetEntryByNumber(0x0028, 0x0103); // "Pixel Representation"
410    if (Signed == GDCM_UNFOUND) {
411       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
412       BitsAlloc = std::string("0");
413    }
414    if (Signed == "0")
415       Signed = std::string("U");
416    else
417       Signed = std::string("S");
418
419    return( BitsAlloc + Signed);
420 }
421
422 /**
423  * \ingroup gdcmHeader
424  * \brief   Recover the offset (from the beginning of the file) of the pixels.
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    guint16 grPixel;
435    guint16 numPixel;
436    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
437
438    if ( ImageLocation == GDCM_UNFOUND ) { // Image Location
439       grPixel = 0x7fe0;
440    } else {
441       grPixel = (guint16) atoi( ImageLocation.c_str() );
442    }
443    if (grPixel != 0x7fe0)
444       // This is a kludge for old dirty Philips imager.
445       numPixel = 0x1010;
446    else
447       numPixel = 0x0010;
448          
449    gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
450    if (PixelElement)
451       return PixelElement->GetOffset();
452    else
453       return 0;
454 }
455
456 /**
457  * \ingroup gdcmHeader
458  * \brief   Recover the pixel area length (in Bytes)
459  *  @return 0 by default. NOT USABLE file. The caller has to check.
460  */
461 size_t gdcmHeader::GetPixelAreaLength(void) {
462    // If this file complies with the norm we should encounter the
463    // "Image Location" tag (0x0028,  0x0200). This tag contains the
464    // the group that contains the pixel data (hence the "Pixel Data"
465    // is found by indirection through the "Image Location").
466    // Inside the group pointed by "Image Location" the searched element
467    // is conventionally the element 0x0010 (when the norm is respected).
468    // When the "Image Location" is absent we default to group 0x7fe0.
469    guint16 grPixel;
470    guint16 numPixel;
471    std::string ImageLocation = GetEntryByNumber(0x0028, 0x0200);
472    if ( ImageLocation == GDCM_UNFOUND ) {
473       grPixel = 0x7fe0;
474    } else {
475       grPixel = (guint16) atoi( ImageLocation.c_str() );
476    }
477    if (grPixel != 0x7fe0)
478       // This is a kludge for old dirty Philips imager.
479       numPixel = 0x1010;
480    else
481       numPixel = 0x0010;
482          
483    gdcmHeaderEntry* PixelElement = GetHeaderEntryByNumber(grPixel,numPixel);
484    if (PixelElement)
485       return PixelElement->GetLength();
486    else {
487       std::cout << "Big trouble : Pixel Element ("
488                 << std::hex << grPixel<<","<< numPixel<< ") NOT found" 
489                 << std::endl;
490       return 0;
491    }
492 }
493
494 /**
495   * \ingroup gdcmHeader
496   * \brief tells us if LUT are used
497   * \warning Right now, 'Segmented xxx Palette Color Lookup Table Data'
498   * \        are NOT considered as LUT, since nobody knows
499   * \        how to deal with them
500   * @return a Boolean 
501   */
502 bool gdcmHeader::HasLUT(void) {
503
504    // Check the presence of the LUT Descriptors 
505    if ( !GetHeaderEntryByNumber(0x0028,0x1101) )
506       return false;
507    // LutDescriptorGreen 
508    if ( !GetHeaderEntryByNumber(0x0028,0x1102) )
509       return false;
510    // LutDescriptorBlue 
511    if ( !GetHeaderEntryByNumber(0x0028,0x1103) )
512       return false;
513    //  It is not enough
514    // we check also 
515    if ( !GetHeaderEntryByNumber(0x0028,0x1201) )
516       return false;  
517    if ( !GetHeaderEntryByNumber(0x0028,0x1202) )
518       return false;
519    if ( !GetHeaderEntryByNumber(0x0028,0x1203) )
520       return false;   
521    return true;
522 }
523
524 /**
525   * \ingroup gdcmHeader
526   * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
527   * \           else 0
528   * @return Lookup Table number of Bits , 0 by default
529   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] 
530   */
531 int gdcmHeader::GetLUTNbits(void) {
532    std::vector<std::string> tokens;
533    //int LutLength;
534    //int LutDepth;
535    int LutNbits;
536    //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue
537    // Consistency already checked in GetLUTLength
538    std::string LutDescription = GetEntryByNumber(0x0028,0x1101);
539    if (LutDescription == GDCM_UNFOUND)
540       return 0;
541    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
542    Tokenize (LutDescription, tokens, "\\");
543    //LutLength=atoi(tokens[0].c_str());
544    //LutDepth=atoi(tokens[1].c_str());
545    LutNbits=atoi(tokens[2].c_str());
546    tokens.clear();
547    return LutNbits;
548 }
549
550 /**
551   * \ingroup gdcmHeader
552   * \brief builts Red/Green/Blue/Alpha LUT from Header
553   * \       when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
554   * \        and (0028,1101),(0028,1102),(0028,1102)  
555   * \          - xxx Palette Color Lookup Table Descriptor - are found
556   * \        and (0028,1201),(0028,1202),(0028,1202) 
557   * \          - xxx Palette Color Lookup Table Data - are found 
558   * \warning does NOT deal with :
559   * \ 0028 1100 Gray Lookup Table Descriptor (Retired)
560   * \ 0028 1221 Segmented Red Palette Color Lookup Table Data
561   * \ 0028 1222 Segmented Green Palette Color Lookup Table Data
562   * \ 0028 1223 Segmented Blue Palette Color Lookup Table Data 
563   * \ no known Dicom reader deals with them :-(
564   * @return a RGBA Lookup Table 
565   */ 
566 unsigned char * gdcmHeader::GetLUTRGBA(void) {
567 // Not so easy : see 
568 // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
569
570 //  if Photometric Interpretation # PALETTE COLOR, no LUT to be done
571    if (GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR ") {
572         return NULL;
573    }  
574    int lengthR, debR, nbitsR;
575    int lengthG, debG, nbitsG;
576    int lengthB, debB, nbitsB;
577    
578 // Get info from Lut Descriptors
579 // (the 3 LUT descriptors may be different)    
580    std::string LutDescriptionR = GetEntryByNumber(0x0028,0x1101);
581    if (LutDescriptionR == GDCM_UNFOUND)
582       return NULL;
583    std::string LutDescriptionG = GetEntryByNumber(0x0028,0x1102);
584    if (LutDescriptionG == GDCM_UNFOUND)
585       return NULL;   
586    std::string LutDescriptionB = GetEntryByNumber(0x0028,0x1103);
587    if (LutDescriptionB == GDCM_UNFOUND)
588       return NULL;
589       
590    std::vector<std::string> tokens;
591       
592    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
593    Tokenize (LutDescriptionR, tokens, "\\");
594    lengthR=atoi(tokens[0].c_str()); // Red LUT length in Bytes
595    debR   =atoi(tokens[1].c_str()); // subscript of the first Lut Value
596    nbitsR =atoi(tokens[2].c_str()); // Lut item size (in Bits)
597    tokens.clear();
598    
599    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
600    Tokenize (LutDescriptionG, tokens, "\\");
601    lengthG=atoi(tokens[0].c_str()); // Green LUT length in Bytes
602    debG   =atoi(tokens[1].c_str());
603    nbitsG =atoi(tokens[2].c_str());
604    tokens.clear();  
605    
606    tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
607    Tokenize (LutDescriptionB, tokens, "\\");
608    lengthB=atoi(tokens[0].c_str()); // Blue LUT length in Bytes
609    debB   =atoi(tokens[1].c_str());
610    nbitsB =atoi(tokens[2].c_str());
611    tokens.clear();
612  
613    // Load LUTs into memory, (as they were stored on disk)
614    unsigned char *lutR = (unsigned char *)
615                          GetEntryVoidAreaByNumber(0x0028,0x1201);
616    unsigned char *lutG = (unsigned char *)
617                          GetEntryVoidAreaByNumber(0x0028,0x1202);
618    unsigned char *lutB = (unsigned char *)
619                          GetEntryVoidAreaByNumber(0x0028,0x1203); 
620    
621    if (!lutR || !lutG || !lutB ) {
622         return NULL;
623    } 
624    // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT 
625    
626    unsigned char *LUTRGBA = (unsigned char *)calloc(1024,1); // 256 * 4 (R, G, B, Alpha) 
627    if (!LUTRGBA) {
628       return NULL;
629    }
630    memset(LUTRGBA, 0, 1024);
631         // Bits Allocated
632    int nb;
633    std::string str_nb = GetEntryByNumber(0x0028,0x0100);
634    if (str_nb == GDCM_UNFOUND ) {
635       nb = 16;
636    } else {
637       nb = atoi(str_nb.c_str() );
638    }  
639    int mult;
640
641    if (nbitsR==16 && nb==8) // when LUT item size is different than pixel size
642       mult=2;               // high byte must be = low byte 
643    else                     // See PS 3.3-2003 C.11.1.1.2 p 619
644       mult=1; 
645  
646    // if we get a black image, let's just remove the '+1'
647    // from 'i*mult+1' and check again 
648    // if it works, we shall have to check the 3 Palettes
649    // to see which byte is ==0 (first one, or second one)
650    // and fix the code
651    // We give up the checking to avoid some overhead 
652    unsigned char *a;      
653    int i;
654
655    a = LUTRGBA+0;
656    for(i=0;i<lengthR;i++) {
657       *a = lutR[i*mult+1]; 
658       a+=4;       
659    }        
660    a = LUTRGBA+1;
661    for(i=0;i<lengthG;i++) {
662       *a = lutG[i*mult+1]; 
663       a+=4;       
664    }  
665    a = LUTRGBA+2;
666    for(i=0;i<lengthB;i++) {
667       *a = lutB[i*mult+1]; 
668       a+=4;       
669    }  
670    a = LUTRGBA+3;
671    for(i=0;i<256;i++) {
672       *a = 1; // Alpha component
673       a+=4; 
674    } 
675    
676    //How to free the now useless LUTs?
677
678    //free(LutR); free(LutB); free(LutG); // Seg Fault when used
679    return(LUTRGBA);   
680
681
682 /**
683  * \ingroup gdcmHeader
684  * \brief gets the info from 0002,0010 : Transfert Syntax
685  * \      else 1.
686  * @return Transfert Syntax Name (as oposite to Transfert Syntax UID)
687  */
688 std::string gdcmHeader::GetTransfertSyntaxName(void) { 
689    // use the gdcmTS (TS : Transfert Syntax)
690    std::string TransfertSyntax = GetEntryByNumber(0x0002,0x0010);
691    if (TransfertSyntax == GDCM_UNFOUND) {
692       dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName: unfound Transfert Syntax (0002,0010)");
693       return "Uncompressed ACR-NEMA";
694    }
695    // we do it only when we need it
696    gdcmTS * ts = gdcmGlobal::GetTS();
697    std::string tsName=ts->GetValue(TransfertSyntax);
698    //delete ts; // Seg Fault when deleted ?!
699    return tsName;
700 }
701
702 /**
703  * \ingroup   gdcmFile
704  * \brief Sets the Pixel Area size in the Header
705  *        --> not-for-rats function
706  * 
707  * \warning WARNING doit-etre etre publique ? 
708  * TODO : y aurait il un inconvenient à fusionner ces 2 fonctions
709  *
710  * @param ImageDataSize new Pixel Area Size
711  *        warning : nothing else is checked
712  */
713 void gdcmHeader::SetImageDataSize(size_t ImageDataSize) {
714    std::string content1;
715    char car[20];        
716    // Assumes HeaderEntry (0x7fe0, 0x0010) exists ...   
717    sprintf(car,"%d",ImageDataSize);
718  
719    gdcmHeaderEntry *a = GetHeaderEntryByNumber(0x7fe0, 0x0010);
720    a->SetLength(ImageDataSize);
721                 
722    ImageDataSize+=8;
723    sprintf(car,"%d",ImageDataSize);
724    content1=car;        
725    SetEntryByNumber(content1, 0x7fe0, 0x0000);
726 }
727
728 //-----------------------------------------------------------------------------
729 // Protected
730
731 //-----------------------------------------------------------------------------
732 // Private
733
734 //-----------------------------------------------------------------------------