]> Creatis software - gdcm.git/blob - src/gdcmPixelReadConvert.cxx
STYLE: remove GetNextttttt + minor Doc
[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 04:15:33 $
7   Version:   $Revision: 1.40 $
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  * \brief     Try to deal with RLE 16 Bits. 
134  *            We assume the RLE has already been parsed and loaded in
135  *            Raw (through \ref ReadAndDecompressJPEGFile ).
136  *            We here need to make 16 Bits Pixels from Low Byte and
137  *            High Byte 'Planes'...(for what it may mean)
138  * @return    Boolean
139  */
140 bool PixelReadConvert::DecompressRLE16BitsFromRLE8Bits( int NumberOfFrames )
141 {
142    size_t pixelNumber = XSize * YSize;
143    size_t rawSize = XSize * YSize * NumberOfFrames;
144
145    // We assumed Raw contains the decoded RLE pixels but as
146    // 8 bits per pixel. In order to convert those pixels to 16 bits
147    // per pixel we cannot work in place within Raw and hence
148    // we copy it in a safe place, say copyRaw.
149
150    uint8_t* copyRaw = new uint8_t[rawSize * 2];
151    memmove( copyRaw, Raw, rawSize * 2 );
152
153    uint8_t* x = Raw;
154    uint8_t* a = copyRaw;
155    uint8_t* b = a + pixelNumber;
156
157    for ( int i = 0; i < NumberOfFrames; i++ )
158    {
159       for ( unsigned int j = 0; j < pixelNumber; j++ )
160       {
161          *(x++) = *(b++);
162          *(x++) = *(a++);
163       }
164    }
165
166    delete[] copyRaw;
167       
168    /// \todo check that operator new []didn't fail, and sometimes return false
169    return true;
170 }
171
172 /**
173  * \brief Implementation of the RLE decoding algorithm for decompressing
174  *        a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86]
175  * @param subRaw Sub region of \ref Raw where the decoded fragment
176  *        should be placed.
177  * @param fragmentSize The length of the binary fragment as found on the disk.
178  * @param RawSegmentSize The expected length of the fragment ONCE
179  *        Raw.
180  * @param fp File Pointer: on entry the position should be the one of
181  *        the fragment to be decoded.
182  */
183 bool PixelReadConvert::ReadAndDecompressRLEFragment( uint8_t *subRaw,
184                                                  long fragmentSize,
185                                                  long RawSegmentSize,
186                                                  std::ifstream *fp )
187 {
188    int8_t count;
189    long numberOfOutputBytes = 0;
190    long numberOfReadBytes = 0;
191
192    while( numberOfOutputBytes < RawSegmentSize )
193    {
194       fp->read( (char*)&count, 1 );
195       numberOfReadBytes += 1;
196       if ( count >= 0 )
197       // Note: count <= 127 comparison is always true due to limited range
198       //       of data type int8_t [since the maximum of an exact width
199       //       signed integer of width N is 2^(N-1) - 1, which for int8_t
200       //       is 127].
201       {
202          fp->read( (char*)subRaw, count + 1);
203          numberOfReadBytes   += count + 1;
204          subRaw     += count + 1;
205          numberOfOutputBytes += count + 1;
206       }
207       else
208       {
209          if ( ( count <= -1 ) && ( count >= -127 ) )
210          {
211             int8_t newByte;
212             fp->read( (char*)&newByte, 1);
213             numberOfReadBytes += 1;
214             for( int i = 0; i < -count + 1; i++ )
215             {
216                subRaw[i] = newByte;
217             }
218             subRaw     += -count + 1;
219             numberOfOutputBytes += -count + 1;
220          }
221       }
222       // if count = 128 output nothing
223                                                                                 
224       if ( numberOfReadBytes > fragmentSize )
225       {
226          gdcmVerboseMacro( "Read more bytes than the segment size.");
227          return false;
228       }
229    }
230    return true;
231 }
232
233 /**
234  * \brief     Reads from disk the Pixel Data of 'Run Length Encoded'
235  *            Dicom encapsulated file and decompress it.
236  * @param     fp already open File Pointer
237  *            at which the pixel data should be copied
238  * @return    Boolean
239  */
240 bool PixelReadConvert::ReadAndDecompressRLEFile( std::ifstream *fp )
241 {
242    uint8_t *subRaw = Raw;
243    long RawSegmentSize = XSize * YSize;
244
245    // Loop on the frame[s]
246    RLEFrame *frame = RLEInfo->GetFirstFrame();
247    while( frame )
248    {
249       // Loop on the fragments
250       for( unsigned int k = 1; k <= frame->GetNumberOfFragments(); k++ )
251       {
252          fp->seekg(frame->GetOffset(k),std::ios::beg);
253          ReadAndDecompressRLEFragment(subRaw,
254                                       frame->GetLength(k),
255                                       RawSegmentSize, 
256                                       fp);
257          subRaw += RawSegmentSize;
258       }
259       frame = RLEInfo->GetNextFrame();
260    }
261
262    if ( BitsAllocated == 16 )
263    {
264       // Try to deal with RLE 16 Bits
265       (void)DecompressRLE16BitsFromRLE8Bits( ZSize );
266    }
267
268    return true;
269 }
270
271 /**
272  * \brief Swap the bytes, according to \ref SwapCode.
273  */
274 void PixelReadConvert::ConvertSwapZone()
275 {
276    unsigned int i;
277
278    if( BitsAllocated == 16 )
279    {
280       uint16_t *im16 = (uint16_t*)Raw;
281       switch( SwapCode )
282       {
283          case 1234:
284             break;
285          case 3412:
286          case 2143:
287          case 4321:
288             for( i = 0; i < RawSize / 2; i++ )
289             {
290                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
291             }
292             break;
293          default:
294             gdcmVerboseMacro("SwapCode value (16 bits) not allowed.");
295       }
296    }
297    else if( BitsAllocated == 32 )
298    {
299       uint32_t s32;
300       uint16_t high;
301       uint16_t low;
302       uint32_t* im32 = (uint32_t*)Raw;
303       switch ( SwapCode )
304       {
305          case 1234:
306             break;
307          case 4321:
308             for( i = 0; i < RawSize / 4; i++ )
309             {
310                low     = im32[i] & 0x0000ffff;  // 4321
311                high    = im32[i] >> 16;
312                high    = ( high >> 8 ) | ( high << 8 );
313                low     = ( low  >> 8 ) | ( low  << 8 );
314                s32     = low;
315                im32[i] = ( s32 << 16 ) | high;
316             }
317             break;
318          case 2143:
319             for( i = 0; i < RawSize / 4; i++ )
320             {
321                low     = im32[i] & 0x0000ffff;   // 2143
322                high    = im32[i] >> 16;
323                high    = ( high >> 8 ) | ( high << 8 );
324                low     = ( low  >> 8 ) | ( low  << 8 );
325                s32     = high;
326                im32[i] = ( s32 << 16 ) | low;
327             }
328             break;
329          case 3412:
330             for( i = 0; i < RawSize / 4; i++ )
331             {
332                low     = im32[i] & 0x0000ffff; // 3412
333                high    = im32[i] >> 16;
334                s32     = low;
335                im32[i] = ( s32 << 16 ) | high;
336             }
337             break;
338          default:
339             gdcmVerboseMacro("SwapCode value (32 bits) not allowed." );
340       }
341    }
342 }
343
344 /**
345  * \brief Deal with endianness i.e. re-arange bytes inside the integer
346  */
347 void PixelReadConvert::ConvertReorderEndianity()
348 {
349    if ( BitsAllocated != 8 )
350    {
351       ConvertSwapZone();
352    }
353
354    // Special kludge in order to deal with xmedcon broken images:
355    if ( BitsAllocated == 16
356      && BitsStored < BitsAllocated
357      && !PixelSign )
358    {
359       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
360       uint16_t *deb = (uint16_t *)Raw;
361       for(int i = 0; i<l; i++)
362       {
363          if( *deb == 0xffff )
364          {
365            *deb = 0;
366          }
367          deb++;
368       }
369    }
370 }
371
372 /**
373  * \brief     Reads from disk the Pixel Data of JPEG Dicom encapsulated
374  *            file and decompress it.
375  * @param     fp File Pointer
376  * @return    Boolean
377  */
378 bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp )
379 {
380    if ( IsJPEG2000 )
381    {
382       gdcmVerboseMacro( "Sorry, JPEG2000 not yet taken into account" );
383       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
384 //    if ( ! gdcm_read_JPEG2000_file( fp,Raw ) )
385           return false;
386    }
387
388    if ( IsJPEGLS )
389    {
390       gdcmVerboseMacro( "Sorry, JPEG-LS not yet taken into account" );
391       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
392 //    if ( ! gdcm_read_JPEGLS_file( fp,Raw ) )
393          return false;
394    }
395
396    // else ??
397    // Precompute the offset localRaw will be shifted with
398    int length = XSize * YSize * SamplesPerPixel;
399    int numberBytes = BitsAllocated / 8;
400
401    JPEGInfo->DecompressJPEGFramesFromFile(fp, Raw, BitsStored, numberBytes, length );
402    return true;
403 }
404
405 /**
406  * \brief  Re-arrange the bits within the bytes.
407  * @return Boolean
408  */
409 bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError )
410 {
411    if ( BitsStored != BitsAllocated )
412    {
413       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
414       if ( BitsAllocated == 16 )
415       {
416          uint16_t mask = 0xffff;
417          mask = mask >> ( BitsAllocated - BitsStored );
418          uint16_t* deb = (uint16_t*)Raw;
419          for(int i = 0; i<l; i++)
420          {
421             *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask;
422             deb++;
423          }
424       }
425       else if ( BitsAllocated == 32 )
426       {
427          uint32_t mask = 0xffffffff;
428          mask = mask >> ( BitsAllocated - BitsStored );
429          uint32_t* deb = (uint32_t*)Raw;
430          for(int i = 0; i<l; i++)
431          {
432             *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask;
433             deb++;
434          }
435       }
436       else
437       {
438          gdcmVerboseMacro("Weird image");
439          throw FormatError( "Weird image !?" );
440       }
441    }
442    return true;
443 }
444
445 /**
446  * \brief   Convert (cY plane, cB plane, cR plane) to RGB pixels
447  * \warning Works on all the frames at a time
448  */
449 void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels()
450 {
451    uint8_t *localRaw = Raw;
452    uint8_t *copyRaw = new uint8_t[ RawSize ];
453    memmove( copyRaw, localRaw, RawSize );
454
455    // to see the tricks about YBR_FULL, YBR_FULL_422,
456    // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
457    // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
458    // and be *very* affraid
459    //
460    int l        = XSize * YSize;
461    int nbFrames = ZSize;
462
463    uint8_t *a = copyRaw;
464    uint8_t *b = copyRaw + l;
465    uint8_t *c = copyRaw + l + l;
466    double R, G, B;
467
468    /// \todo : Replace by the 'well known' integer computation
469    ///         counterpart. Refer to
470    ///            http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
471    ///         for code optimisation.
472
473    for ( int i = 0; i < nbFrames; i++ )
474    {
475       for ( int j = 0; j < l; j++ )
476       {
477          R = 1.164 *(*a-16) + 1.596 *(*c -128) + 0.5;
478          G = 1.164 *(*a-16) - 0.813 *(*c -128) - 0.392 *(*b -128) + 0.5;
479          B = 1.164 *(*a-16) + 2.017 *(*b -128) + 0.5;
480
481          if (R < 0.0)   R = 0.0;
482          if (G < 0.0)   G = 0.0;
483          if (B < 0.0)   B = 0.0;
484          if (R > 255.0) R = 255.0;
485          if (G > 255.0) G = 255.0;
486          if (B > 255.0) B = 255.0;
487
488          *(localRaw++) = (uint8_t)R;
489          *(localRaw++) = (uint8_t)G;
490          *(localRaw++) = (uint8_t)B;
491          a++;
492          b++;
493          c++;
494       }
495    }
496    delete[] copyRaw;
497 }
498
499 /**
500  * \brief   Convert (Red plane, Green plane, Blue plane) to RGB pixels
501  * \warning Works on all the frames at a time
502  */
503 void PixelReadConvert::ConvertRGBPlanesToRGBPixels()
504 {
505    uint8_t *localRaw = Raw;
506    uint8_t *copyRaw = new uint8_t[ RawSize ];
507    memmove( copyRaw, localRaw, RawSize );
508
509    int l = XSize * YSize * ZSize;
510
511    uint8_t* a = copyRaw;
512    uint8_t* b = copyRaw + l;
513    uint8_t* c = copyRaw + l + l;
514
515    for (int j = 0; j < l; j++)
516    {
517       *(localRaw++) = *(a++);
518       *(localRaw++) = *(b++);
519       *(localRaw++) = *(c++);
520    }
521    delete[] copyRaw;
522 }
523
524 bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
525 {
526    // ComputeRawAndRGBSizes is already made by 
527    // ::GrabInformationsFromfile. So, the structure sizes are
528    // correct
529    Squeeze();
530
531    //////////////////////////////////////////////////
532    //// First stage: get our hands on the Pixel Data.
533    if ( !fp )
534    {
535       gdcmVerboseMacro( "Unavailable file pointer." );
536       return false;
537    }
538
539    fp->seekg( PixelOffset, std::ios::beg );
540    if( fp->fail() || fp->eof())
541    {
542       gdcmVerboseMacro( "Unable to find PixelOffset in file." );
543       return false;
544    }
545
546    AllocateRaw();
547
548    //////////////////////////////////////////////////
549    //// Second stage: read from disk dans decompress.
550    if ( BitsAllocated == 12 )
551    {
552       ReadAndDecompress12BitsTo16Bits( fp);
553    }
554    else if ( IsRaw )
555    {
556       // This problem can be found when some obvious informations are found
557       // after the field containing the image data. In this case, these
558       // bad data are added to the size of the image (in the PixelDataLength
559       // variable). But RawSize is the right size of the image !
560       if( PixelDataLength != RawSize)
561       {
562          gdcmVerboseMacro( "Mismatch between PixelReadConvert and RawSize." );
563       }
564       if( PixelDataLength > RawSize)
565       {
566          fp->read( (char*)Raw, RawSize);
567       }
568       else
569       {
570          fp->read( (char*)Raw, PixelDataLength);
571       }
572
573       if ( fp->fail() || fp->eof())
574       {
575          gdcmVerboseMacro( "Reading of Raw pixel data failed." );
576          return false;
577       }
578    } 
579    else if ( IsRLELossless )
580    {
581       if ( ! ReadAndDecompressRLEFile( fp ) )
582       {
583          gdcmVerboseMacro( "RLE decompressor failed." );
584          return false;
585       }
586    }
587    else
588    {
589       // Default case concerns JPEG family
590       if ( ! ReadAndDecompressJPEGFile( fp ) )
591       {
592          gdcmVerboseMacro( "JPEG decompressor failed." );
593          return false;
594       }
595    }
596
597    ////////////////////////////////////////////
598    //// Third stage: twigle the bytes and bits.
599    ConvertReorderEndianity();
600    ConvertReArrangeBits();
601    ConvertHandleColor();
602
603    return true;
604 }
605
606 void PixelReadConvert::ConvertHandleColor()
607 {
608    //////////////////////////////////
609    // Deal with the color decoding i.e. handle:
610    //   - R, G, B planes (as opposed to RGB pixels)
611    //   - YBR (various) encodings.
612    //   - LUT[s] (or "PALETTE COLOR").
613    //
614    // The classification in the color decoding schema is based on the blending
615    // of two Dicom tags values:
616    // * "Photometric Interpretation" for which we have the cases:
617    //  - [Photo A] MONOCHROME[1|2] pictures,
618    //  - [Photo B] RGB or YBR_FULL_422 (which acts as RGB),
619    //  - [Photo C] YBR_* (with the above exception of YBR_FULL_422)
620    //  - [Photo D] "PALETTE COLOR" which indicates the presence of LUT[s].
621    // * "Planar Configuration" for which we have the cases:
622    //  - [Planar 0] 0 then Pixels are already RGB
623    //  - [Planar 1] 1 then we have 3 planes : R, G, B,
624    //  - [Planar 2] 2 then we have 1 gray Plane and 3 LUTs
625    //
626    // Now in theory, one could expect some coherence when blending the above
627    // cases. For example we should not encounter files belonging at the
628    // time to case [Planar 0] and case [Photo D].
629    // Alas, this was only theory ! Because in practice some odd (read ill
630    // formated Dicom) files (e.g. gdcmData/US-PAL-8-10x-echo.dcm) we encounter:
631    //     - "Planar Configuration" = 0,
632    //     - "Photometric Interpretation" = "PALETTE COLOR".
633    // Hence gdcm will use the folowing "heuristic" in order to be tolerant
634    // towards Dicom-non-conformance files:
635    //   << whatever the "Planar Configuration" value might be, a
636    //      "Photometric Interpretation" set to "PALETTE COLOR" forces
637    //      a LUT intervention >>
638    //
639    // Now we are left with the following handling of the cases:
640    // - [Planar 0] OR  [Photo A] no color decoding (since respectively
641    //       Pixels are already RGB and monochrome pictures have no color :),
642    // - [Planar 1] AND [Photo B] handled with ConvertRGBPlanesToRGBPixels()
643    // - [Planar 1] AND [Photo C] handled with ConvertYcBcRPlanesToRGBPixels()
644    // - [Planar 2] OR  [Photo D] requires LUT intervention.
645
646    if ( ! IsRawRGB() )
647    {
648       // [Planar 2] OR  [Photo D]: LUT intervention done outside
649       return;
650    }
651                                                                                 
652    if ( PlanarConfiguration == 1 )
653    {
654       if ( IsYBRFull )
655       {
656          // [Planar 1] AND [Photo C] (remember YBR_FULL_422 acts as RGB)
657          ConvertYcBcRPlanesToRGBPixels();
658       }
659       else
660       {
661          // [Planar 1] AND [Photo C]
662          ConvertRGBPlanesToRGBPixels();
663       }
664       return;
665    }
666                                                                                 
667    // When planarConf is 0, and RLELossless (forbidden by Dicom norm)
668    // pixels need to be RGB-fied anyway
669    if (IsRLELossless)
670    {
671      ConvertRGBPlanesToRGBPixels();
672    }
673    // In *normal *case, when planarConf is 0, pixels are already in RGB
674 }
675
676 /**
677  * \brief Predicate to know wether the image[s] (once Raw) is RGB.
678  * \note See comments of \ref ConvertHandleColor
679  */
680 bool PixelReadConvert::IsRawRGB()
681 {
682    if (   IsMonochrome
683        || PlanarConfiguration == 2
684        || IsPaletteColor )
685    {
686       return false;
687    }
688    return true;
689 }
690
691 void PixelReadConvert::ComputeRawAndRGBSizes()
692 {
693    int bitsAllocated = BitsAllocated;
694    // Number of "Bits Allocated" is fixed to 16 when it's 12, since
695    // in this case we will expand the image to 16 bits (see
696    //    \ref ReadAndDecompress12BitsTo16Bits() )
697    if (  BitsAllocated == 12 )
698    {
699       bitsAllocated = 16;
700    }
701                                                                                 
702    RawSize =  XSize * YSize * ZSize
703                      * ( bitsAllocated / 8 )
704                      * SamplesPerPixel;
705    if ( HasLUT )
706    {
707       RGBSize = 3 * RawSize;
708    }
709    else
710    {
711       RGBSize = RawSize;
712    }
713 }
714
715 void PixelReadConvert::GrabInformationsFromFile( File *file )
716 {
717    // Number of Bits Allocated for storing a Pixel is defaulted to 16
718    // when absent from the file.
719    BitsAllocated = file->GetBitsAllocated();
720    if ( BitsAllocated == 0 )
721    {
722       BitsAllocated = 16;
723    }
724
725    // Number of "Bits Stored", defaulted to number of "Bits Allocated"
726    // when absent from the file.
727    BitsStored = file->GetBitsStored();
728    if ( BitsStored == 0 )
729    {
730       BitsStored = BitsAllocated;
731    }
732
733    // High Bit Position, defaulted to "Bits Allocated" - 1
734    HighBitPosition = file->GetHighBitPosition();
735    if ( HighBitPosition == 0 )
736    {
737       HighBitPosition = BitsAllocated - 1;
738    }
739
740    XSize = file->GetXSize();
741    YSize = file->GetYSize();
742    ZSize = file->GetZSize();
743    SamplesPerPixel = file->GetSamplesPerPixel();
744    PixelSize = file->GetPixelSize();
745    PixelSign = file->IsSignedPixelData();
746    SwapCode  = file->GetSwapCode();
747    std::string ts = file->GetTransferSyntax();
748    IsRaw =
749         ( ! file->IsDicomV3() )
750      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian
751      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndianDLXGE
752      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian
753      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian
754      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian;
755
756    IsJPEG2000      = Global::GetTS()->IsJPEG2000(ts);
757    IsJPEGLS        = Global::GetTS()->IsJPEGLS(ts);
758    IsJPEGLossy     = Global::GetTS()->IsJPEGLossy(ts);
759    IsJPEGLossless  = Global::GetTS()->IsJPEGLossless(ts);
760    IsRLELossless   = Global::GetTS()->IsRLELossless(ts);
761
762    PixelOffset     = file->GetPixelOffset();
763    PixelDataLength = file->GetPixelAreaLength();
764    RLEInfo  = file->GetRLEInfo();
765    JPEGInfo = file->GetJPEGInfo();
766
767    PlanarConfiguration = file->GetPlanarConfiguration();
768    IsMonochrome = file->IsMonochrome();
769    IsPaletteColor = file->IsPaletteColor();
770    IsYBRFull = file->IsYBRFull();
771
772    /////////////////////////////////////////////////////////////////
773    // LUT section:
774    HasLUT = file->HasLUT();
775    if ( HasLUT )
776    {
777       // Just in case some access to a File element requires disk access.
778       LutRedDescriptor   = file->GetEntryValue( 0x0028, 0x1101 );
779       LutGreenDescriptor = file->GetEntryValue( 0x0028, 0x1102 );
780       LutBlueDescriptor  = file->GetEntryValue( 0x0028, 0x1103 );
781    
782       // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
783       // [ refer to invocation of Document::SetMaxSizeLoadEntry() in
784       // Document::Document() ], the loading of the value (content) of a
785       // [Bin|Val]Entry occurence migth have been hindered (read simply NOT
786       // loaded). Hence, we first try to obtain the LUTs data from the file
787       // and when this fails we read the LUTs data directly from disk.
788       /// \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
789       ///       We should NOT bypass the [Bin|Val]Entry class. Instead
790       ///       an access to an UNLOADED content of a [Bin|Val]Entry occurence
791       ///       (e.g. BinEntry::GetBinArea()) should force disk access from
792       ///       within the [Bin|Val]Entry class itself. The only problem
793       ///       is that the [Bin|Val]Entry is unaware of the FILE* is was
794       ///       parsed from. Fix that. FIXME.
795    
796       ////// Red round
797       file->LoadEntryBinArea(0x0028, 0x1201);
798       LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
799       if ( ! LutRedData )
800       {
801          gdcmVerboseMacro( "Unable to read Red LUT data" );
802       }
803
804       ////// Green round:
805       file->LoadEntryBinArea(0x0028, 0x1202);
806       LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
807       if ( ! LutGreenData)
808       {
809          gdcmVerboseMacro( "Unable to read Green LUT data" );
810       }
811
812       ////// Blue round:
813       file->LoadEntryBinArea(0x0028, 0x1203);
814       LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
815       if ( ! LutBlueData )
816       {
817          gdcmVerboseMacro( "Unable to read Blue LUT data" );
818       }
819    }
820
821    ComputeRawAndRGBSizes();
822 }
823
824 /**
825  * \brief Build Red/Green/Blue/Alpha LUT from File
826  *         when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
827  *          and (0028,1101),(0028,1102),(0028,1102)
828  *            - xxx Palette Color Lookup Table Descriptor - are found
829  *          and (0028,1201),(0028,1202),(0028,1202)
830  *            - xxx Palette Color Lookup Table Data - are found
831  * \warning does NOT deal with :
832  *   0028 1100 Gray Lookup Table Descriptor (Retired)
833  *   0028 1221 Segmented Red Palette Color Lookup Table Data
834  *   0028 1222 Segmented Green Palette Color Lookup Table Data
835  *   0028 1223 Segmented Blue Palette Color Lookup Table Data
836  *   no known Dicom reader deals with them :-(
837  * @return a RGBA Lookup Table
838  */
839 void PixelReadConvert::BuildLUTRGBA()
840 {
841    if ( LutRGBA )
842    {
843       return;
844    }
845    // Not so easy : see
846    // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
847                                                                                 
848    if ( ! IsPaletteColor )
849    {
850       return;
851    }
852                                                                                 
853    if (   LutRedDescriptor   == GDCM_UNFOUND
854        || LutGreenDescriptor == GDCM_UNFOUND
855        || LutBlueDescriptor  == GDCM_UNFOUND )
856    {
857       return;
858    }
859
860    ////////////////////////////////////////////
861    // Extract the info from the LUT descriptors
862    int lengthR;   // Red LUT length in Bytes
863    int debR;      // Subscript of the first Lut Value
864    int nbitsR;    // Lut item size (in Bits)
865    int nbRead = sscanf( LutRedDescriptor.c_str(),
866                         "%d\\%d\\%d",
867                         &lengthR, &debR, &nbitsR );
868    if( nbRead != 3 )
869    {
870       gdcmVerboseMacro( "Wrong Red LUT descriptor" );
871    }
872                                                                                 
873    int lengthG;  // Green LUT length in Bytes
874    int debG;     // Subscript of the first Lut Value
875    int nbitsG;   // Lut item size (in Bits)
876    nbRead = sscanf( LutGreenDescriptor.c_str(),
877                     "%d\\%d\\%d",
878                     &lengthG, &debG, &nbitsG );
879    if( nbRead != 3 )
880    {
881       gdcmVerboseMacro( "Wrong Green LUT descriptor" );
882    }
883                                                                                 
884    int lengthB;  // Blue LUT length in Bytes
885    int debB;     // Subscript of the first Lut Value
886    int nbitsB;   // Lut item size (in Bits)
887    nbRead = sscanf( LutRedDescriptor.c_str(),
888                     "%d\\%d\\%d",
889                     &lengthB, &debB, &nbitsB );
890    if( nbRead != 3 )
891    {
892       gdcmVerboseMacro( "Wrong Blue LUT descriptor" );
893    }
894                                                                                 
895    ////////////////////////////////////////////////////////
896    if ( ( ! LutRedData ) || ( ! LutGreenData ) || ( ! LutBlueData ) )
897    {
898       return;
899    }
900
901    ////////////////////////////////////////////////
902    // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT
903    LutRGBA = new uint8_t[ 1024 ]; // 256 * 4 (R, G, B, Alpha)
904    if ( !LutRGBA )
905       return;
906
907    memset( LutRGBA, 0, 1024 );
908                                                                                 
909    int mult;
910    if ( ( nbitsR == 16 ) && ( BitsAllocated == 8 ) )
911    {
912       // when LUT item size is different than pixel size
913       mult = 2; // high byte must be = low byte
914    }
915    else
916    {
917       // See PS 3.3-2003 C.11.1.1.2 p 619
918       mult = 1;
919    }
920                                                                                 
921    // if we get a black image, let's just remove the '+1'
922    // from 'i*mult+1' and check again
923    // if it works, we shall have to check the 3 Palettes
924    // to see which byte is ==0 (first one, or second one)
925    // and fix the code
926    // We give up the checking to avoid some (useless ?) overhead
927    // (optimistic asumption)
928    int i;
929    uint8_t* a = LutRGBA + 0;
930    for( i=0; i < lengthR; ++i )
931    {
932       *a = LutRedData[i*mult+1];
933       a += 4;
934    }
935                                                                                 
936    a = LutRGBA + 1;
937    for( i=0; i < lengthG; ++i)
938    {
939       *a = LutGreenData[i*mult+1];
940       a += 4;
941    }
942                                                                                 
943    a = LutRGBA + 2;
944    for(i=0; i < lengthB; ++i)
945    {
946       *a = LutBlueData[i*mult+1];
947       a += 4;
948    }
949                                                                                 
950    a = LutRGBA + 3;
951    for(i=0; i < 256; ++i)
952    {
953       *a = 1; // Alpha component
954       a += 4;
955    }
956 }
957
958 /**
959  * \brief Build the RGB image from the Raw imagage and the LUTs.
960  */
961 bool PixelReadConvert::BuildRGBImage()
962 {
963    if ( RGB )
964    {
965       // The job is already done.
966       return true;
967    }
968
969    if ( ! Raw )
970    {
971       // The job can't be done
972       return false;
973    }
974
975    BuildLUTRGBA();
976    if ( ! LutRGBA )
977    {
978       // The job can't be done
979       return false;
980    }
981                                                                                 
982    // Build RGB Pixels
983    AllocateRGB();
984    uint8_t* localRGB = RGB;
985    for (size_t i = 0; i < RawSize; ++i )
986    {
987       int j  = Raw[i] * 4;
988       *localRGB++ = LutRGBA[j];
989       *localRGB++ = LutRGBA[j+1];
990       *localRGB++ = LutRGBA[j+2];
991    }
992    return true;
993 }
994
995 /**
996  * \brief        Print self.
997  * @param indent Indentation string to be prepended during printing.
998  * @param os     Stream to print to.
999  */
1000 void PixelReadConvert::Print( std::ostream &os, std::string const & indent )
1001 {
1002    os << indent
1003       << "--- Pixel information -------------------------"
1004       << std::endl;
1005    os << indent
1006       << "Pixel Data: offset " << PixelOffset
1007       << " x(" << std::hex << PixelOffset << std::dec
1008       << ")   length " << PixelDataLength
1009       << " x(" << std::hex << PixelDataLength << std::dec
1010       << ")" << std::endl;
1011
1012    if ( IsRLELossless )
1013    {
1014       if ( RLEInfo )
1015       {
1016          RLEInfo->Print( os, indent );
1017       }
1018       else
1019       {
1020          gdcmVerboseMacro("Set as RLE file but NO RLEinfo present.");
1021       }
1022    }
1023
1024    if ( IsJPEG2000 || IsJPEGLossless || IsJPEGLossy || IsJPEGLS )
1025    {
1026       if ( JPEGInfo )
1027       {
1028          JPEGInfo->Print( os, indent );
1029       }
1030       else
1031       {
1032          gdcmVerboseMacro("Set as JPEG file but NO JPEGinfo present.");
1033       }
1034    }
1035 }
1036
1037 } // end namespace gdcm
1038
1039 // NOTES on File internal calls
1040 // User
1041 // ---> GetImageData
1042 //     ---> GetImageDataIntoVector
1043 //        |---> GetImageDataIntoVectorRaw
1044 //        | lut intervention
1045 // User
1046 // ---> GetImageDataRaw
1047 //     ---> GetImageDataIntoVectorRaw
1048