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