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