]> Creatis software - gdcm.git/blob - src/gdcmPixelReadConvert.cxx
ENH: Getting toward a nice gdcmDecompressor. Now RLE and JPEG are getting similar...
[gdcm.git] / src / gdcmPixelReadConvert.cxx
1 /*=========================================================================
2
3   Program:   gdcm
4   Module:    $RCSfile: gdcmPixelReadConvert.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/01/31 05:24:21 $
7   Version:   $Revision: 1.41 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmDebug.h"
20 #include "gdcmFile.h"
21 #include "gdcmGlobal.h"
22 #include "gdcmTS.h"
23 #include "gdcmPixelReadConvert.h"
24 #include "gdcmDocEntry.h"
25 #include "gdcmRLEFramesInfo.h"
26 #include "gdcmJPEGFragmentsInfo.h"
27
28 #include <fstream>
29 #include <stdio.h> //for sscanf
30
31 namespace gdcm
32 {
33 #define str2num(str, typeNum) *((typeNum *)(str))
34
35
36 //-----------------------------------------------------------------------------
37 // Constructor / Destructor
38 PixelReadConvert::PixelReadConvert() 
39 {
40    RGB = 0;
41    RGBSize = 0;
42    Raw = 0;
43    RawSize = 0;
44    LutRGBA = 0;
45    LutRedData = 0;
46    LutGreenData = 0;
47    LutBlueData =0;
48 }
49
50 void PixelReadConvert::Squeeze() 
51 {
52    if ( RGB )
53       delete [] RGB;
54    RGB = 0;
55
56    if ( Raw )
57       delete [] Raw;
58    Raw = 0;
59
60    if ( LutRGBA )
61       delete [] LutRGBA;
62    LutRGBA = 0;
63 }
64
65 PixelReadConvert::~PixelReadConvert() 
66 {
67    Squeeze();
68 }
69
70 void PixelReadConvert::AllocateRGB()
71 {
72   if ( RGB )
73      delete [] RGB;
74   RGB = new uint8_t[RGBSize];
75 }
76
77 void PixelReadConvert::AllocateRaw()
78 {
79   if ( Raw )
80      delete [] Raw;
81   Raw = new uint8_t[RawSize];
82 }
83
84 /**
85  * \brief Read from file a 12 bits per pixel image and decompress it
86  *        into a 16 bits per pixel image.
87  */
88 void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream *fp )
89                throw ( FormatError )
90 {
91    int nbPixels = XSize * YSize;
92    uint16_t* localDecompres = (uint16_t*)Raw;
93
94    for( int p = 0; p < nbPixels; p += 2 )
95    {
96       uint8_t b0, b1, b2;
97
98       fp->read( (char*)&b0, 1);
99       if ( fp->fail() || fp->eof() )
100       {
101          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
102                                 "Unfound first block" );
103       }
104
105       fp->read( (char*)&b1, 1 );
106       if ( fp->fail() || fp->eof())
107       {
108          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
109                                 "Unfound second block" );
110       }
111
112       fp->read( (char*)&b2, 1 );
113       if ( fp->fail() || fp->eof())
114       {
115          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
116                                 "Unfound second block" );
117       }
118
119       // Two steps are necessary to please VC++
120       //
121       // 2 pixels 12bit =     [0xABCDEF]
122       // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
123       //                        A                     B                 D
124       *localDecompres++ =  ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
125       //                        F                     C                 E
126       *localDecompres++ =  ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
127
128       /// \todo JPR Troubles expected on Big-Endian processors ?
129    }
130 }
131
132
133 /**
134  * \brief Swap the bytes, according to \ref SwapCode.
135  */
136 void PixelReadConvert::ConvertSwapZone()
137 {
138    unsigned int i;
139
140    if( BitsAllocated == 16 )
141    {
142       uint16_t *im16 = (uint16_t*)Raw;
143       switch( SwapCode )
144       {
145          case 1234:
146             break;
147          case 3412:
148          case 2143:
149          case 4321:
150             for( i = 0; i < RawSize / 2; i++ )
151             {
152                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
153             }
154             break;
155          default:
156             gdcmVerboseMacro("SwapCode value (16 bits) not allowed.");
157       }
158    }
159    else if( BitsAllocated == 32 )
160    {
161       uint32_t s32;
162       uint16_t high;
163       uint16_t low;
164       uint32_t* im32 = (uint32_t*)Raw;
165       switch ( SwapCode )
166       {
167          case 1234:
168             break;
169          case 4321:
170             for( i = 0; i < RawSize / 4; i++ )
171             {
172                low     = im32[i] & 0x0000ffff;  // 4321
173                high    = im32[i] >> 16;
174                high    = ( high >> 8 ) | ( high << 8 );
175                low     = ( low  >> 8 ) | ( low  << 8 );
176                s32     = low;
177                im32[i] = ( s32 << 16 ) | high;
178             }
179             break;
180          case 2143:
181             for( i = 0; i < RawSize / 4; i++ )
182             {
183                low     = im32[i] & 0x0000ffff;   // 2143
184                high    = im32[i] >> 16;
185                high    = ( high >> 8 ) | ( high << 8 );
186                low     = ( low  >> 8 ) | ( low  << 8 );
187                s32     = high;
188                im32[i] = ( s32 << 16 ) | low;
189             }
190             break;
191          case 3412:
192             for( i = 0; i < RawSize / 4; i++ )
193             {
194                low     = im32[i] & 0x0000ffff; // 3412
195                high    = im32[i] >> 16;
196                s32     = low;
197                im32[i] = ( s32 << 16 ) | high;
198             }
199             break;
200          default:
201             gdcmVerboseMacro("SwapCode value (32 bits) not allowed." );
202       }
203    }
204 }
205
206 /**
207  * \brief Deal with endianness i.e. re-arange bytes inside the integer
208  */
209 void PixelReadConvert::ConvertReorderEndianity()
210 {
211    if ( BitsAllocated != 8 )
212    {
213       ConvertSwapZone();
214    }
215
216    // Special kludge in order to deal with xmedcon broken images:
217    if ( BitsAllocated == 16
218      && BitsStored < BitsAllocated
219      && !PixelSign )
220    {
221       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
222       uint16_t *deb = (uint16_t *)Raw;
223       for(int i = 0; i<l; i++)
224       {
225          if( *deb == 0xffff )
226          {
227            *deb = 0;
228          }
229          deb++;
230       }
231    }
232 }
233
234 /**
235  * \brief     Reads from disk the Pixel Data of JPEG Dicom encapsulated
236  *            file and decompress it.
237  * @param     fp File Pointer
238  * @return    Boolean
239  */
240 bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp )
241 {
242    if ( IsJPEG2000 )
243    {
244       gdcmVerboseMacro( "Sorry, JPEG2000 not yet taken into account" );
245       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
246 //    if ( ! gdcm_read_JPEG2000_file( fp,Raw ) )
247           return false;
248    }
249
250    if ( IsJPEGLS )
251    {
252       gdcmVerboseMacro( "Sorry, JPEG-LS not yet taken into account" );
253       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
254 //    if ( ! gdcm_read_JPEGLS_file( fp,Raw ) )
255          return false;
256    }
257
258    // else ??
259    // Precompute the offset localRaw will be shifted with
260    int length = XSize * YSize * SamplesPerPixel;
261    int numberBytes = BitsAllocated / 8;
262
263    JPEGInfo->DecompressFromFile(fp, Raw, BitsStored, numberBytes, length );
264    return true;
265 }
266
267 /**
268  * \brief  Re-arrange the bits within the bytes.
269  * @return Boolean
270  */
271 bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError )
272 {
273    if ( BitsStored != BitsAllocated )
274    {
275       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
276       if ( BitsAllocated == 16 )
277       {
278          uint16_t mask = 0xffff;
279          mask = mask >> ( BitsAllocated - BitsStored );
280          uint16_t* deb = (uint16_t*)Raw;
281          for(int i = 0; i<l; i++)
282          {
283             *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask;
284             deb++;
285          }
286       }
287       else if ( BitsAllocated == 32 )
288       {
289          uint32_t mask = 0xffffffff;
290          mask = mask >> ( BitsAllocated - BitsStored );
291          uint32_t* deb = (uint32_t*)Raw;
292          for(int i = 0; i<l; i++)
293          {
294             *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask;
295             deb++;
296          }
297       }
298       else
299       {
300          gdcmVerboseMacro("Weird image");
301          throw FormatError( "Weird image !?" );
302       }
303    }
304    return true;
305 }
306
307 /**
308  * \brief   Convert (cY plane, cB plane, cR plane) to RGB pixels
309  * \warning Works on all the frames at a time
310  */
311 void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels()
312 {
313    uint8_t *localRaw = Raw;
314    uint8_t *copyRaw = new uint8_t[ RawSize ];
315    memmove( copyRaw, localRaw, RawSize );
316
317    // to see the tricks about YBR_FULL, YBR_FULL_422,
318    // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
319    // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
320    // and be *very* affraid
321    //
322    int l        = XSize * YSize;
323    int nbFrames = ZSize;
324
325    uint8_t *a = copyRaw;
326    uint8_t *b = copyRaw + l;
327    uint8_t *c = copyRaw + l + l;
328    double R, G, B;
329
330    /// \todo : Replace by the 'well known' integer computation
331    ///         counterpart. Refer to
332    ///            http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
333    ///         for code optimisation.
334
335    for ( int i = 0; i < nbFrames; i++ )
336    {
337       for ( int j = 0; j < l; j++ )
338       {
339          R = 1.164 *(*a-16) + 1.596 *(*c -128) + 0.5;
340          G = 1.164 *(*a-16) - 0.813 *(*c -128) - 0.392 *(*b -128) + 0.5;
341          B = 1.164 *(*a-16) + 2.017 *(*b -128) + 0.5;
342
343          if (R < 0.0)   R = 0.0;
344          if (G < 0.0)   G = 0.0;
345          if (B < 0.0)   B = 0.0;
346          if (R > 255.0) R = 255.0;
347          if (G > 255.0) G = 255.0;
348          if (B > 255.0) B = 255.0;
349
350          *(localRaw++) = (uint8_t)R;
351          *(localRaw++) = (uint8_t)G;
352          *(localRaw++) = (uint8_t)B;
353          a++;
354          b++;
355          c++;
356       }
357    }
358    delete[] copyRaw;
359 }
360
361 /**
362  * \brief   Convert (Red plane, Green plane, Blue plane) to RGB pixels
363  * \warning Works on all the frames at a time
364  */
365 void PixelReadConvert::ConvertRGBPlanesToRGBPixels()
366 {
367    uint8_t *localRaw = Raw;
368    uint8_t *copyRaw = new uint8_t[ RawSize ];
369    memmove( copyRaw, localRaw, RawSize );
370
371    int l = XSize * YSize * ZSize;
372
373    uint8_t* a = copyRaw;
374    uint8_t* b = copyRaw + l;
375    uint8_t* c = copyRaw + l + l;
376
377    for (int j = 0; j < l; j++)
378    {
379       *(localRaw++) = *(a++);
380       *(localRaw++) = *(b++);
381       *(localRaw++) = *(c++);
382    }
383    delete[] copyRaw;
384 }
385
386 bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
387 {
388    // ComputeRawAndRGBSizes is already made by 
389    // ::GrabInformationsFromfile. So, the structure sizes are
390    // correct
391    Squeeze();
392
393    //////////////////////////////////////////////////
394    //// First stage: get our hands on the Pixel Data.
395    if ( !fp )
396    {
397       gdcmVerboseMacro( "Unavailable file pointer." );
398       return false;
399    }
400
401    fp->seekg( PixelOffset, std::ios::beg );
402    if( fp->fail() || fp->eof())
403    {
404       gdcmVerboseMacro( "Unable to find PixelOffset in file." );
405       return false;
406    }
407
408    AllocateRaw();
409
410    //////////////////////////////////////////////////
411    //// Second stage: read from disk dans decompress.
412    if ( BitsAllocated == 12 )
413    {
414       ReadAndDecompress12BitsTo16Bits( fp);
415    }
416    else if ( IsRaw )
417    {
418       // This problem can be found when some obvious informations are found
419       // after the field containing the image data. In this case, these
420       // bad data are added to the size of the image (in the PixelDataLength
421       // variable). But RawSize is the right size of the image !
422       if( PixelDataLength != RawSize)
423       {
424          gdcmVerboseMacro( "Mismatch between PixelReadConvert and RawSize." );
425       }
426       if( PixelDataLength > RawSize)
427       {
428          fp->read( (char*)Raw, RawSize);
429       }
430       else
431       {
432          fp->read( (char*)Raw, PixelDataLength);
433       }
434
435       if ( fp->fail() || fp->eof())
436       {
437          gdcmVerboseMacro( "Reading of Raw pixel data failed." );
438          return false;
439       }
440    } 
441    else if ( IsRLELossless )
442    {
443       if ( ! RLEInfo->ReadAndDecompressRLEFile( fp, Raw, XSize, YSize, ZSize, BitsAllocated ) )
444       {
445          gdcmVerboseMacro( "RLE decompressor failed." );
446          return false;
447       }
448    }
449    else
450    {
451       // Default case concerns JPEG family
452       if ( ! ReadAndDecompressJPEGFile( fp ) )
453       {
454          gdcmVerboseMacro( "JPEG decompressor failed." );
455          return false;
456       }
457    }
458
459    ////////////////////////////////////////////
460    //// Third stage: twigle the bytes and bits.
461    ConvertReorderEndianity();
462    ConvertReArrangeBits();
463    ConvertHandleColor();
464
465    return true;
466 }
467
468 void PixelReadConvert::ConvertHandleColor()
469 {
470    //////////////////////////////////
471    // Deal with the color decoding i.e. handle:
472    //   - R, G, B planes (as opposed to RGB pixels)
473    //   - YBR (various) encodings.
474    //   - LUT[s] (or "PALETTE COLOR").
475    //
476    // The classification in the color decoding schema is based on the blending
477    // of two Dicom tags values:
478    // * "Photometric Interpretation" for which we have the cases:
479    //  - [Photo A] MONOCHROME[1|2] pictures,
480    //  - [Photo B] RGB or YBR_FULL_422 (which acts as RGB),
481    //  - [Photo C] YBR_* (with the above exception of YBR_FULL_422)
482    //  - [Photo D] "PALETTE COLOR" which indicates the presence of LUT[s].
483    // * "Planar Configuration" for which we have the cases:
484    //  - [Planar 0] 0 then Pixels are already RGB
485    //  - [Planar 1] 1 then we have 3 planes : R, G, B,
486    //  - [Planar 2] 2 then we have 1 gray Plane and 3 LUTs
487    //
488    // Now in theory, one could expect some coherence when blending the above
489    // cases. For example we should not encounter files belonging at the
490    // time to case [Planar 0] and case [Photo D].
491    // Alas, this was only theory ! Because in practice some odd (read ill
492    // formated Dicom) files (e.g. gdcmData/US-PAL-8-10x-echo.dcm) we encounter:
493    //     - "Planar Configuration" = 0,
494    //     - "Photometric Interpretation" = "PALETTE COLOR".
495    // Hence gdcm will use the folowing "heuristic" in order to be tolerant
496    // towards Dicom-non-conformance files:
497    //   << whatever the "Planar Configuration" value might be, a
498    //      "Photometric Interpretation" set to "PALETTE COLOR" forces
499    //      a LUT intervention >>
500    //
501    // Now we are left with the following handling of the cases:
502    // - [Planar 0] OR  [Photo A] no color decoding (since respectively
503    //       Pixels are already RGB and monochrome pictures have no color :),
504    // - [Planar 1] AND [Photo B] handled with ConvertRGBPlanesToRGBPixels()
505    // - [Planar 1] AND [Photo C] handled with ConvertYcBcRPlanesToRGBPixels()
506    // - [Planar 2] OR  [Photo D] requires LUT intervention.
507
508    if ( ! IsRawRGB() )
509    {
510       // [Planar 2] OR  [Photo D]: LUT intervention done outside
511       return;
512    }
513                                                                                 
514    if ( PlanarConfiguration == 1 )
515    {
516       if ( IsYBRFull )
517       {
518          // [Planar 1] AND [Photo C] (remember YBR_FULL_422 acts as RGB)
519          ConvertYcBcRPlanesToRGBPixels();
520       }
521       else
522       {
523          // [Planar 1] AND [Photo C]
524          ConvertRGBPlanesToRGBPixels();
525       }
526       return;
527    }
528                                                                                 
529    // When planarConf is 0, and RLELossless (forbidden by Dicom norm)
530    // pixels need to be RGB-fied anyway
531    if (IsRLELossless)
532    {
533      ConvertRGBPlanesToRGBPixels();
534    }
535    // In *normal *case, when planarConf is 0, pixels are already in RGB
536 }
537
538 /**
539  * \brief Predicate to know wether the image[s] (once Raw) is RGB.
540  * \note See comments of \ref ConvertHandleColor
541  */
542 bool PixelReadConvert::IsRawRGB()
543 {
544    if (   IsMonochrome
545        || PlanarConfiguration == 2
546        || IsPaletteColor )
547    {
548       return false;
549    }
550    return true;
551 }
552
553 void PixelReadConvert::ComputeRawAndRGBSizes()
554 {
555    int bitsAllocated = BitsAllocated;
556    // Number of "Bits Allocated" is fixed to 16 when it's 12, since
557    // in this case we will expand the image to 16 bits (see
558    //    \ref ReadAndDecompress12BitsTo16Bits() )
559    if (  BitsAllocated == 12 )
560    {
561       bitsAllocated = 16;
562    }
563                                                                                 
564    RawSize =  XSize * YSize * ZSize
565                      * ( bitsAllocated / 8 )
566                      * SamplesPerPixel;
567    if ( HasLUT )
568    {
569       RGBSize = 3 * RawSize;
570    }
571    else
572    {
573       RGBSize = RawSize;
574    }
575 }
576
577 void PixelReadConvert::GrabInformationsFromFile( File *file )
578 {
579    // Number of Bits Allocated for storing a Pixel is defaulted to 16
580    // when absent from the file.
581    BitsAllocated = file->GetBitsAllocated();
582    if ( BitsAllocated == 0 )
583    {
584       BitsAllocated = 16;
585    }
586
587    // Number of "Bits Stored", defaulted to number of "Bits Allocated"
588    // when absent from the file.
589    BitsStored = file->GetBitsStored();
590    if ( BitsStored == 0 )
591    {
592       BitsStored = BitsAllocated;
593    }
594
595    // High Bit Position, defaulted to "Bits Allocated" - 1
596    HighBitPosition = file->GetHighBitPosition();
597    if ( HighBitPosition == 0 )
598    {
599       HighBitPosition = BitsAllocated - 1;
600    }
601
602    XSize = file->GetXSize();
603    YSize = file->GetYSize();
604    ZSize = file->GetZSize();
605    SamplesPerPixel = file->GetSamplesPerPixel();
606    PixelSize = file->GetPixelSize();
607    PixelSign = file->IsSignedPixelData();
608    SwapCode  = file->GetSwapCode();
609    std::string ts = file->GetTransferSyntax();
610    IsRaw =
611         ( ! file->IsDicomV3() )
612      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian
613      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndianDLXGE
614      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian
615      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian
616      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian;
617
618    IsJPEG2000      = Global::GetTS()->IsJPEG2000(ts);
619    IsJPEGLS        = Global::GetTS()->IsJPEGLS(ts);
620    IsJPEGLossy     = Global::GetTS()->IsJPEGLossy(ts);
621    IsJPEGLossless  = Global::GetTS()->IsJPEGLossless(ts);
622    IsRLELossless   = Global::GetTS()->IsRLELossless(ts);
623
624    PixelOffset     = file->GetPixelOffset();
625    PixelDataLength = file->GetPixelAreaLength();
626    RLEInfo  = file->GetRLEInfo();
627    JPEGInfo = file->GetJPEGInfo();
628
629    PlanarConfiguration = file->GetPlanarConfiguration();
630    IsMonochrome = file->IsMonochrome();
631    IsPaletteColor = file->IsPaletteColor();
632    IsYBRFull = file->IsYBRFull();
633
634    /////////////////////////////////////////////////////////////////
635    // LUT section:
636    HasLUT = file->HasLUT();
637    if ( HasLUT )
638    {
639       // Just in case some access to a File element requires disk access.
640       LutRedDescriptor   = file->GetEntryValue( 0x0028, 0x1101 );
641       LutGreenDescriptor = file->GetEntryValue( 0x0028, 0x1102 );
642       LutBlueDescriptor  = file->GetEntryValue( 0x0028, 0x1103 );
643    
644       // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
645       // [ refer to invocation of Document::SetMaxSizeLoadEntry() in
646       // Document::Document() ], the loading of the value (content) of a
647       // [Bin|Val]Entry occurence migth have been hindered (read simply NOT
648       // loaded). Hence, we first try to obtain the LUTs data from the file
649       // and when this fails we read the LUTs data directly from disk.
650       /// \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
651       ///       We should NOT bypass the [Bin|Val]Entry class. Instead
652       ///       an access to an UNLOADED content of a [Bin|Val]Entry occurence
653       ///       (e.g. BinEntry::GetBinArea()) should force disk access from
654       ///       within the [Bin|Val]Entry class itself. The only problem
655       ///       is that the [Bin|Val]Entry is unaware of the FILE* is was
656       ///       parsed from. Fix that. FIXME.
657    
658       ////// Red round
659       file->LoadEntryBinArea(0x0028, 0x1201);
660       LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
661       if ( ! LutRedData )
662       {
663          gdcmVerboseMacro( "Unable to read Red LUT data" );
664       }
665
666       ////// Green round:
667       file->LoadEntryBinArea(0x0028, 0x1202);
668       LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
669       if ( ! LutGreenData)
670       {
671          gdcmVerboseMacro( "Unable to read Green LUT data" );
672       }
673
674       ////// Blue round:
675       file->LoadEntryBinArea(0x0028, 0x1203);
676       LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
677       if ( ! LutBlueData )
678       {
679          gdcmVerboseMacro( "Unable to read Blue LUT data" );
680       }
681    }
682
683    ComputeRawAndRGBSizes();
684 }
685
686 /**
687  * \brief Build Red/Green/Blue/Alpha LUT from File
688  *         when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
689  *          and (0028,1101),(0028,1102),(0028,1102)
690  *            - xxx Palette Color Lookup Table Descriptor - are found
691  *          and (0028,1201),(0028,1202),(0028,1202)
692  *            - xxx Palette Color Lookup Table Data - are found
693  * \warning does NOT deal with :
694  *   0028 1100 Gray Lookup Table Descriptor (Retired)
695  *   0028 1221 Segmented Red Palette Color Lookup Table Data
696  *   0028 1222 Segmented Green Palette Color Lookup Table Data
697  *   0028 1223 Segmented Blue Palette Color Lookup Table Data
698  *   no known Dicom reader deals with them :-(
699  * @return a RGBA Lookup Table
700  */
701 void PixelReadConvert::BuildLUTRGBA()
702 {
703    if ( LutRGBA )
704    {
705       return;
706    }
707    // Not so easy : see
708    // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
709                                                                                 
710    if ( ! IsPaletteColor )
711    {
712       return;
713    }
714                                                                                 
715    if (   LutRedDescriptor   == GDCM_UNFOUND
716        || LutGreenDescriptor == GDCM_UNFOUND
717        || LutBlueDescriptor  == GDCM_UNFOUND )
718    {
719       return;
720    }
721
722    ////////////////////////////////////////////
723    // Extract the info from the LUT descriptors
724    int lengthR;   // Red LUT length in Bytes
725    int debR;      // Subscript of the first Lut Value
726    int nbitsR;    // Lut item size (in Bits)
727    int nbRead = sscanf( LutRedDescriptor.c_str(),
728                         "%d\\%d\\%d",
729                         &lengthR, &debR, &nbitsR );
730    if( nbRead != 3 )
731    {
732       gdcmVerboseMacro( "Wrong Red LUT descriptor" );
733    }
734                                                                                 
735    int lengthG;  // Green LUT length in Bytes
736    int debG;     // Subscript of the first Lut Value
737    int nbitsG;   // Lut item size (in Bits)
738    nbRead = sscanf( LutGreenDescriptor.c_str(),
739                     "%d\\%d\\%d",
740                     &lengthG, &debG, &nbitsG );
741    if( nbRead != 3 )
742    {
743       gdcmVerboseMacro( "Wrong Green LUT descriptor" );
744    }
745                                                                                 
746    int lengthB;  // Blue LUT length in Bytes
747    int debB;     // Subscript of the first Lut Value
748    int nbitsB;   // Lut item size (in Bits)
749    nbRead = sscanf( LutRedDescriptor.c_str(),
750                     "%d\\%d\\%d",
751                     &lengthB, &debB, &nbitsB );
752    if( nbRead != 3 )
753    {
754       gdcmVerboseMacro( "Wrong Blue LUT descriptor" );
755    }
756                                                                                 
757    ////////////////////////////////////////////////////////
758    if ( ( ! LutRedData ) || ( ! LutGreenData ) || ( ! LutBlueData ) )
759    {
760       return;
761    }
762
763    ////////////////////////////////////////////////
764    // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT
765    LutRGBA = new uint8_t[ 1024 ]; // 256 * 4 (R, G, B, Alpha)
766    if ( !LutRGBA )
767       return;
768
769    memset( LutRGBA, 0, 1024 );
770                                                                                 
771    int mult;
772    if ( ( nbitsR == 16 ) && ( BitsAllocated == 8 ) )
773    {
774       // when LUT item size is different than pixel size
775       mult = 2; // high byte must be = low byte
776    }
777    else
778    {
779       // See PS 3.3-2003 C.11.1.1.2 p 619
780       mult = 1;
781    }
782                                                                                 
783    // if we get a black image, let's just remove the '+1'
784    // from 'i*mult+1' and check again
785    // if it works, we shall have to check the 3 Palettes
786    // to see which byte is ==0 (first one, or second one)
787    // and fix the code
788    // We give up the checking to avoid some (useless ?) overhead
789    // (optimistic asumption)
790    int i;
791    uint8_t* a = LutRGBA + 0;
792    for( i=0; i < lengthR; ++i )
793    {
794       *a = LutRedData[i*mult+1];
795       a += 4;
796    }
797                                                                                 
798    a = LutRGBA + 1;
799    for( i=0; i < lengthG; ++i)
800    {
801       *a = LutGreenData[i*mult+1];
802       a += 4;
803    }
804                                                                                 
805    a = LutRGBA + 2;
806    for(i=0; i < lengthB; ++i)
807    {
808       *a = LutBlueData[i*mult+1];
809       a += 4;
810    }
811                                                                                 
812    a = LutRGBA + 3;
813    for(i=0; i < 256; ++i)
814    {
815       *a = 1; // Alpha component
816       a += 4;
817    }
818 }
819
820 /**
821  * \brief Build the RGB image from the Raw imagage and the LUTs.
822  */
823 bool PixelReadConvert::BuildRGBImage()
824 {
825    if ( RGB )
826    {
827       // The job is already done.
828       return true;
829    }
830
831    if ( ! Raw )
832    {
833       // The job can't be done
834       return false;
835    }
836
837    BuildLUTRGBA();
838    if ( ! LutRGBA )
839    {
840       // The job can't be done
841       return false;
842    }
843                                                                                 
844    // Build RGB Pixels
845    AllocateRGB();
846    uint8_t* localRGB = RGB;
847    for (size_t i = 0; i < RawSize; ++i )
848    {
849       int j  = Raw[i] * 4;
850       *localRGB++ = LutRGBA[j];
851       *localRGB++ = LutRGBA[j+1];
852       *localRGB++ = LutRGBA[j+2];
853    }
854    return true;
855 }
856
857 /**
858  * \brief        Print self.
859  * @param indent Indentation string to be prepended during printing.
860  * @param os     Stream to print to.
861  */
862 void PixelReadConvert::Print( std::ostream &os, std::string const & indent )
863 {
864    os << indent
865       << "--- Pixel information -------------------------"
866       << std::endl;
867    os << indent
868       << "Pixel Data: offset " << PixelOffset
869       << " x(" << std::hex << PixelOffset << std::dec
870       << ")   length " << PixelDataLength
871       << " x(" << std::hex << PixelDataLength << std::dec
872       << ")" << std::endl;
873
874    if ( IsRLELossless )
875    {
876       if ( RLEInfo )
877       {
878          RLEInfo->Print( os, indent );
879       }
880       else
881       {
882          gdcmVerboseMacro("Set as RLE file but NO RLEinfo present.");
883       }
884    }
885
886    if ( IsJPEG2000 || IsJPEGLossless || IsJPEGLossy || IsJPEGLS )
887    {
888       if ( JPEGInfo )
889       {
890          JPEGInfo->Print( os, indent );
891       }
892       else
893       {
894          gdcmVerboseMacro("Set as JPEG file but NO JPEGinfo present.");
895       }
896    }
897 }
898
899 } // end namespace gdcm
900
901 // NOTES on File internal calls
902 // User
903 // ---> GetImageData
904 //     ---> GetImageDataIntoVector
905 //        |---> GetImageDataIntoVectorRaw
906 //        | lut intervention
907 // User
908 // ---> GetImageDataRaw
909 //     ---> GetImageDataIntoVectorRaw
910