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