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