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