]> Creatis software - gdcm.git/blob - src/gdcmPixelReadConvert.cxx
BUG: Ok I dont understand gdcm internals anymore. Whoever broke the writting process...
[gdcm.git] / src / gdcmPixelReadConvert.cxx
1 /*=========================================================================
2  
3   Program:   gdcm
4   Module:    $RCSfile: gdcmPixelReadConvert.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/10/25 18:14:49 $
7   Version:   $Revision: 1.88 $
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    RLEInfo      = 0;
54    JPEGInfo     = 0;
55    UserFunction = 0;
56    FileInternal = 0;
57 }
58
59 /// Canonical Destructor
60 PixelReadConvert::~PixelReadConvert() 
61 {
62    Squeeze();
63 }
64
65 //-----------------------------------------------------------------------------
66 // Public
67 /**
68  * \brief Predicate to know whether the image[s] (once Raw) is RGB.
69  * \note See comments of \ref ConvertHandleColor
70  */
71 bool PixelReadConvert::IsRawRGB()
72 {
73    if (   IsMonochrome
74        || PlanarConfiguration == 2
75        || IsPaletteColor )
76    {
77       return false;
78    }
79    return true;
80 }
81 /**
82  * \brief Gets various usefull informations from the file header
83  * @param file gdcm::File pointer
84  */
85 void PixelReadConvert::GrabInformationsFromFile( File *file )
86 {
87    // Number of Bits Allocated for storing a Pixel is defaulted to 16
88    // when absent from the file.
89    BitsAllocated = file->GetBitsAllocated();
90    if ( BitsAllocated == 0 )
91    {
92       BitsAllocated = 16;
93    }
94
95    // Number of "Bits Stored", defaulted to number of "Bits Allocated"
96    // when absent from the file.
97    BitsStored = file->GetBitsStored();
98    if ( BitsStored == 0 )
99    {
100       BitsStored = BitsAllocated;
101    }
102
103    // High Bit Position, defaulted to "Bits Allocated" - 1
104    HighBitPosition = file->GetHighBitPosition();
105    if ( HighBitPosition == 0 )
106    {
107       HighBitPosition = BitsAllocated - 1;
108    }
109
110    XSize           = file->GetXSize();
111    YSize           = file->GetYSize();
112    ZSize           = file->GetZSize();
113    SamplesPerPixel = file->GetSamplesPerPixel();
114    //PixelSize       = file->GetPixelSize();  Useless
115    PixelSign       = file->IsSignedPixelData();
116    SwapCode        = file->GetSwapCode();
117    std::string ts  = file->GetTransferSyntax();
118    if ( ts == GDCM_UNKNOWN )
119      {
120      gdcmErrorMacro( "Could someone tell me how in the world could this happen !" );
121      abort(); // DO NOT REMOVE.  WE SHOULD NEVER READ SUCH IMAGE EVER (only gdcm can write such broekn dicom file)
122      }
123    IsRaw =
124         ( ! file->IsDicomV3() )
125      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian
126      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE
127      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian
128      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian
129      || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian;
130      
131    IsPrivateGETransferSyntax = 
132                 ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE );
133
134    IsMPEG          = Global::GetTS()->IsMPEG(ts);
135    IsJPEG2000      = Global::GetTS()->IsJPEG2000(ts);
136    IsJPEGLS        = Global::GetTS()->IsJPEGLS(ts);
137    IsJPEGLossy     = Global::GetTS()->IsJPEGLossy(ts);
138    IsJPEGLossless  = Global::GetTS()->IsJPEGLossless(ts);
139    IsRLELossless   = Global::GetTS()->IsRLELossless(ts);
140
141    PixelOffset     = file->GetPixelOffset();
142    PixelDataLength = file->GetPixelAreaLength();
143    RLEInfo         = file->GetRLEInfo();
144    JPEGInfo        = file->GetJPEGInfo();
145
146    IsMonochrome    = file->IsMonochrome();
147    IsMonochrome1   = file->IsMonochrome1();
148    IsPaletteColor  = file->IsPaletteColor();
149    IsYBRFull       = file->IsYBRFull();
150
151    PlanarConfiguration = file->GetPlanarConfiguration();
152
153    /////////////////////////////////////////////////////////////////
154    // LUT section:
155    HasLUT = file->HasLUT();
156    if ( HasLUT )
157    {
158       // Just in case some access to a File element requires disk access.
159       LutRedDescriptor   = file->GetEntryString( 0x0028, 0x1101 );
160       LutGreenDescriptor = file->GetEntryString( 0x0028, 0x1102 );
161       LutBlueDescriptor  = file->GetEntryString( 0x0028, 0x1103 );
162    
163       // The following comment is probabely meaningless, since LUT are *always*
164       // loaded at parsing time, whatever their length is.
165          
166       // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
167       // [ refer to invocation of Document::SetMaxSizeLoadEntry() in
168       // Document::Document() ], the loading of the value (content) of a
169       // [Bin|Val]Entry occurence migth have been hindered (read simply NOT
170       // loaded). Hence, we first try to obtain the LUTs data from the file
171       // and when this fails we read the LUTs data directly from disk.
172       // \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
173       //       We should NOT bypass the [Bin|Val]Entry class. Instead
174       //       an access to an UNLOADED content of a [Bin|Val]Entry occurence
175       //       (e.g. DataEntry::GetBinArea()) should force disk access from
176       //       within the [Bin|Val]Entry class itself. The only problem
177       //       is that the [Bin|Val]Entry is unaware of the FILE* is was
178       //       parsed from. Fix that. FIXME.
179    
180       // //// Red round
181       file->LoadEntryBinArea(0x0028, 0x1201);
182       LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
183       if ( ! LutRedData )
184       {
185          gdcmWarningMacro("Unable to read Red Palette Color Lookup Table data");
186       }
187
188       // //// Green round:
189       file->LoadEntryBinArea(0x0028, 0x1202);
190       LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
191       if ( ! LutGreenData)
192       {
193          gdcmWarningMacro("Unable to read Green Palette Color Lookup Table data");
194       }
195
196       // //// Blue round:
197       file->LoadEntryBinArea(0x0028, 0x1203);
198       LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
199       if ( ! LutBlueData )
200       {
201          gdcmWarningMacro("Unable to read Blue Palette Color Lookup Table data");
202       }
203    }
204    FileInternal = file;   
205
206    ComputeRawAndRGBSizes();
207 }
208
209 /// \brief Reads from disk and decompresses Pixels
210 bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
211 {
212    // ComputeRawAndRGBSizes is already made by 
213    // ::GrabInformationsFromfile. So, the structure sizes are
214    // correct
215    Squeeze();
216
217    //////////////////////////////////////////////////
218    //// First stage: get our hands on the Pixel Data.
219    if ( !fp )
220    {
221       gdcmWarningMacro( "Unavailable file pointer." );
222       return false;
223    }
224
225    fp->seekg( PixelOffset, std::ios::beg );
226    if ( fp->fail() || fp->eof() )
227    {
228       gdcmWarningMacro( "Unable to find PixelOffset in file." );
229       return false;
230    }
231
232    AllocateRaw();
233
234    //////////////////////////////////////////////////
235    //// Second stage: read from disk and decompress.
236    if ( BitsAllocated == 12 )
237    {
238       ReadAndDecompress12BitsTo16Bits( fp);
239    }
240    else if ( IsRaw )
241    {
242       // This problem can be found when some obvious informations are found
243       // after the field containing the image data. In this case, these
244       // bad data are added to the size of the image (in the PixelDataLength
245       // variable). But RawSize is the right size of the image !
246       if ( PixelDataLength != RawSize )
247       {
248          gdcmWarningMacro( "Mismatch between PixelReadConvert : "
249                           << PixelDataLength << " and RawSize : " << RawSize );
250       }
251       if ( PixelDataLength > RawSize )
252       {
253          fp->read( (char*)Raw, RawSize);
254       }
255       else
256       {
257          fp->read( (char*)Raw, PixelDataLength);
258       }
259
260       if ( fp->fail() || fp->eof())
261       {
262          gdcmWarningMacro( "Reading of Raw pixel data failed." );
263          return false;
264       }
265    } 
266    else if ( IsRLELossless )
267    {
268       if ( ! RLEInfo->DecompressRLEFile
269                                ( fp, Raw, XSize, YSize, ZSize, BitsAllocated ) )
270       {
271          gdcmWarningMacro( "RLE decompressor failed." );
272          return false;
273       }
274    }
275    else if ( IsMPEG )
276    {
277       //gdcmWarningMacro( "Sorry, MPEG not yet taken into account" );
278       //return false;
279       // fp has already been seek to start of mpeg
280       //ReadMPEGFile(fp, Raw, PixelDataLength); 
281       return true;
282    }
283    else
284    {
285       // Default case concerns JPEG family
286       if ( ! ReadAndDecompressJPEGFile( fp ) )
287       {
288          gdcmWarningMacro( "JPEG decompressor failed." );
289          return false;
290       }
291    }
292
293    ////////////////////////////////////////////
294    //// Third stage: twigle the bytes and bits.
295    ConvertReorderEndianity();
296    ConvertReArrangeBits();
297    ConvertFixGreyLevels();
298    if (UserFunction) // user is allowed to Mirror, TopDown, Rotate,...the image
299       UserFunction( Raw, FileInternal);
300    ConvertHandleColor();
301
302    return true;
303 }
304
305 /// Deletes Pixels Area
306 void PixelReadConvert::Squeeze() 
307 {
308    if ( RGB )
309       delete [] RGB;
310    RGB = 0;
311
312    if ( Raw )
313       delete [] Raw;
314    Raw = 0;
315
316    if ( LutRGBA )
317       delete [] LutRGBA;
318    LutRGBA = 0;
319 }
320
321 /**
322  * \brief Build the RGB image from the Raw image and the LUTs.
323  */
324 bool PixelReadConvert::BuildRGBImage()
325 {
326    if ( RGB )
327    {
328       // The job is already done.
329       return true;
330    }
331
332    if ( ! Raw )
333    {
334       // The job can't be done
335       return false;
336    }
337
338    BuildLUTRGBA();
339    if ( ! LutRGBA )
340    {
341       // The job can't be done
342       return false;
343    }
344
345    gdcmWarningMacro( "--> BuildRGBImage" );
346                                                                                 
347    // Build RGB Pixels
348    AllocateRGB();
349    
350    int j;
351    if ( BitsAllocated <= 8 )
352    {
353       uint8_t *localRGB = RGB;
354       for (size_t i = 0; i < RawSize; ++i )
355       {
356          j  = Raw[i] * 4;
357          *localRGB++ = LutRGBA[j];
358          *localRGB++ = LutRGBA[j+1];
359          *localRGB++ = LutRGBA[j+2];
360       }
361     }
362  
363     else  // deal with 16 bits pixels and 16 bits Palette color
364     {
365       uint16_t *localRGB = (uint16_t *)RGB;
366       for (size_t i = 0; i < RawSize/2; ++i )
367       {
368          j  = ((uint16_t *)Raw)[i] * 4;
369          *localRGB++ = ((uint16_t *)LutRGBA)[j];
370          *localRGB++ = ((uint16_t *)LutRGBA)[j+1];
371          *localRGB++ = ((uint16_t *)LutRGBA)[j+2];
372       } 
373     }
374  
375    return true;
376 }
377
378 //-----------------------------------------------------------------------------
379 // Protected
380
381 //-----------------------------------------------------------------------------
382 // Private
383 /**
384  * \brief Read from file a 12 bits per pixel image and decompress it
385  *        into a 16 bits per pixel image.
386  */
387 void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream *fp )
388                throw ( FormatError )
389 {
390    int nbPixels = XSize * YSize;
391    uint16_t *localDecompres = (uint16_t*)Raw;
392
393    for( int p = 0; p < nbPixels; p += 2 )
394    {
395       uint8_t b0, b1, b2;
396
397       fp->read( (char*)&b0, 1);
398       if ( fp->fail() || fp->eof() )
399       {
400          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
401                                 "Unfound first block" );
402       }
403
404       fp->read( (char*)&b1, 1 );
405       if ( fp->fail() || fp->eof())
406       {
407          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
408                                 "Unfound second block" );
409       }
410
411       fp->read( (char*)&b2, 1 );
412       if ( fp->fail() || fp->eof())
413       {
414          throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
415                                 "Unfound second block" );
416       }
417
418       // Two steps are necessary to please VC++
419       //
420       // 2 pixels 12bit =     [0xABCDEF]
421       // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
422       //                        A                     B                 D
423       *localDecompres++ =  ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
424       //                        F                     C                 E
425       *localDecompres++ =  ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
426
427       /// \todo JPR Troubles expected on Big-Endian processors ?
428    }
429 }
430
431 /**
432  * \brief     Reads from disk the Pixel Data of JPEG Dicom encapsulated
433  *            file and decompress it.
434  * @param     fp File Pointer
435  * @return    Boolean
436  */
437 bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp )
438 {
439    if ( IsJPEG2000 )
440    {
441      // make sure this is the right JPEG compression
442      assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEGLS );
443      // FIXME this is really ugly but it seems I have to load the complete
444      // jpeg2000 stream to use jasper:
445      // I don't think we'll ever be able to deal with multiple fragments properly
446
447       unsigned long inputlength = 0;
448       JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment();
449       while( jpegfrag )
450       {
451          inputlength += jpegfrag->GetLength();
452          jpegfrag = JPEGInfo->GetNextFragment();
453       }
454       gdcmAssertMacro( inputlength != 0);
455       uint8_t *inputdata = new uint8_t[inputlength];
456       char *pinputdata = (char*)inputdata;
457       jpegfrag = JPEGInfo->GetFirstFragment();
458       while( jpegfrag )
459       {
460          fp->seekg( jpegfrag->GetOffset(), std::ios::beg);
461          fp->read(pinputdata, jpegfrag->GetLength());
462          pinputdata += jpegfrag->GetLength();
463          jpegfrag = JPEGInfo->GetNextFragment();
464       }
465       // Warning the inputdata buffer is delete in the function
466       if ( ! gdcm_read_JPEG2000_file( Raw, 
467           (char*)inputdata, inputlength ) )
468       {
469          return true;
470       }
471       // wow what happen, must be an error
472       return false;
473    }
474    else if ( IsJPEGLS )
475    {
476      // make sure this is the right JPEG compression
477      assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEG2000 );
478    // WARNING : JPEG-LS is NOT the 'classical' Jpeg Lossless : 
479    // [JPEG-LS is the basis for new lossless/near-lossless compression
480    // standard for continuous-tone images intended for JPEG2000. The standard
481    // is based on the LOCO-I algorithm (LOw COmplexity LOssless COmpression
482    // for Images) developed at Hewlett-Packard Laboratories]
483    //
484    // see http://datacompression.info/JPEGLS.shtml
485    //
486 #if 0
487    std::cerr << "count:" << JPEGInfo->GetFragmentCount() << std::endl;
488       unsigned long inputlength = 0;
489       JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment();
490       while( jpegfrag )
491       {
492          inputlength += jpegfrag->GetLength();
493          jpegfrag = JPEGInfo->GetNextFragment();
494       }
495       gdcmAssertMacro( inputlength != 0);
496       uint8_t *inputdata = new uint8_t[inputlength];
497       char *pinputdata = (char*)inputdata;
498       jpegfrag = JPEGInfo->GetFirstFragment();
499       while( jpegfrag )
500       {
501          fp->seekg( jpegfrag->GetOffset(), std::ios::beg);
502          fp->read(pinputdata, jpegfrag->GetLength());
503          pinputdata += jpegfrag->GetLength();
504          jpegfrag = JPEGInfo->GetNextFragment();
505       }  
506       
507   //fp->read((char*)Raw, PixelDataLength);
508
509   std::ofstream out("/tmp/jpegls.jpg");
510   out.write((char*)inputdata, inputlength);
511   out.close();
512   delete[] inputdata;
513 #endif
514
515       gdcmWarningMacro( "Sorry, JPEG-LS not yet taken into account" );
516       fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
517 //    if ( ! gdcm_read_JPEGLS_file( fp,Raw ) )
518          return false;
519    }
520    else
521    {
522      // make sure this is the right JPEG compression
523      assert( !IsJPEGLS || !IsJPEG2000 );
524      // Precompute the offset localRaw will be shifted with
525      int length = XSize * YSize * SamplesPerPixel;
526      int numberBytes = BitsAllocated / 8;
527
528      JPEGInfo->DecompressFromFile(fp, Raw, BitsStored, numberBytes, length );
529      return true;
530    }
531 }
532
533 /**
534  * \brief Build Red/Green/Blue/Alpha LUT from File when :
535  *         - (0028,0004) : Photometric Interpretation == [PALETTE COLOR ]
536  *         and
537  *         - (0028,1101),(0028,1102),(0028,1102)
538  *            xxx Palette Color Lookup Table Descriptor are found
539  *          and 
540  *         - (0028,1201),(0028,1202),(0028,1202)
541  *           xxx Palette Color Lookup Table Data - are found
542  * \warning does NOT deal with :
543  *   - 0028 1100 Gray Lookup Table Descriptor (Retired)
544  *   - 0028 1221 Segmented Red Palette Color Lookup Table Data
545  *   - 0028 1222 Segmented Green Palette Color Lookup Table Data
546  *   - 0028 1223 Segmented Blue Palette Color Lookup Table Data
547  *   no known Dicom reader deals with them :-(
548  * @return a RGBA Lookup Table
549  */
550 void PixelReadConvert::BuildLUTRGBA()
551 {
552
553    // Note to code reviewers :
554    // The problem is *much more* complicated, since a lot of manufacturers
555    // Don't follow the norm :
556    // have a look at David Clunie's remark at the end of this .cxx file.
557    if ( LutRGBA )
558    
559    {
560       return;
561    }
562    // Not so easy : see
563    // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
564                                                                                 
565    if ( ! IsPaletteColor )
566    {
567       return;
568    }
569                                                                                 
570    if (   LutRedDescriptor   == GDCM_UNFOUND
571        || LutGreenDescriptor == GDCM_UNFOUND
572        || LutBlueDescriptor  == GDCM_UNFOUND )
573    {
574       gdcmWarningMacro( "(At least) a LUT Descriptor is missing" );
575       return;
576    }
577
578    ////////////////////////////////////////////
579    // Extract the info from the LUT descriptors
580    int lengthR;   // Red LUT length in Bytes
581    int debR;      // Subscript of the first Lut Value
582    int nbitsR;    // Lut item size (in Bits)
583    int nbRead;    // nb of items in LUT descriptor (must be = 3)
584
585    nbRead = sscanf( LutRedDescriptor.c_str(),
586                         "%d\\%d\\%d",
587                         &lengthR, &debR, &nbitsR );
588    if ( nbRead != 3 )
589    {
590       gdcmWarningMacro( "Wrong Red LUT descriptor" );
591    }                                                                                
592    int lengthG;  // Green LUT length in Bytes
593    int debG;     // Subscript of the first Lut Value
594    int nbitsG;   // Lut item size (in Bits)
595
596    nbRead = sscanf( LutGreenDescriptor.c_str(),
597                     "%d\\%d\\%d",
598                     &lengthG, &debG, &nbitsG );  
599    if ( nbRead != 3 )
600    {
601       gdcmWarningMacro( "Wrong Green LUT descriptor" );
602    }
603                                                                                 
604    int lengthB;  // Blue LUT length in Bytes
605    int debB;     // Subscript of the first Lut Value
606    int nbitsB;   // Lut item size (in Bits)
607    nbRead = sscanf( LutRedDescriptor.c_str(),
608                     "%d\\%d\\%d",
609                     &lengthB, &debB, &nbitsB );
610    if ( nbRead != 3 )
611    {
612       gdcmWarningMacro( "Wrong Blue LUT descriptor" );
613    }
614  
615    gdcmWarningMacro(" lengthR " << lengthR << " debR " 
616                  << debR << " nbitsR " << nbitsR);
617    gdcmWarningMacro(" lengthG " << lengthG << " debG " 
618                  << debG << " nbitsG " << nbitsG);
619    gdcmWarningMacro(" lengthB " << lengthB << " debB " 
620                  << debB << " nbitsB " << nbitsB);
621
622    if ( !lengthR ) // if = 2^16, this shall be 0 see : CP-143
623       lengthR=65536;
624    if ( !lengthG ) // if = 2^16, this shall be 0
625       lengthG=65536;
626    if ( !lengthB ) // if = 2^16, this shall be 0
627       lengthB=65536; 
628                                                                                 
629    ////////////////////////////////////////////////////////
630
631    if ( ( ! LutRedData ) || ( ! LutGreenData ) || ( ! LutBlueData ) )
632    {
633       gdcmWarningMacro( "(At least) a LUT is missing" );
634       return;
635    }
636
637    // -------------------------------------------------------------
638    
639    if ( BitsAllocated <= 8 )
640    {
641       // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT
642       LutRGBA = new uint8_t[ 1024 ]; // 256 * 4 (R, G, B, Alpha)
643       if ( !LutRGBA )
644          return;
645       LutItemNumber = 256;
646       LutItemSize   = 8;
647       memset( LutRGBA, 0, 1024 );
648                                                                                 
649       int mult;
650       if ( ( nbitsR == 16 ) && ( BitsAllocated == 8 ) )
651       {
652          // when LUT item size is different than pixel size
653          mult = 2; // high byte must be = low byte
654       }
655       else
656       {
657          // See PS 3.3-2003 C.11.1.1.2 p 619
658          mult = 1;
659       }
660                                                                                 
661       // if we get a black image, let's just remove the '+1'
662       // from 'i*mult+1' and check again
663       // if it works, we shall have to check the 3 Palettes
664       // to see which byte is ==0 (first one, or second one)
665       // and fix the code
666       // We give up the checking to avoid some (useless ?) overhead
667       // (optimistic asumption)
668       int i;
669       uint8_t *a;
670
671       //take "Subscript of the first Lut Value" (debR,debG,debB) into account!
672
673       //FIXME :  +1 : to get 'low value' byte
674       //         Trouble expected on Big Endian Processors ?
675       //         16 BIts Per Pixel Palette Color to be swapped?
676
677       a = LutRGBA + 0 + debR;
678       for( i=0; i < lengthR; ++i )
679       {
680          *a = LutRedData[i*mult+1]; 
681          a += 4;
682       }
683                                                                                 
684       a = LutRGBA + 1 + debG;
685       for( i=0; i < lengthG; ++i)
686       {
687          *a = LutGreenData[i*mult+1];
688          a += 4;
689       }
690                                                                                 
691       a = LutRGBA + 2 + debB;
692       for(i=0; i < lengthB; ++i)
693       {
694          *a = LutBlueData[i*mult+1];
695          a += 4;
696       }
697                                     
698       a = LutRGBA + 3 ;
699       for(i=0; i < 256; ++i)
700       {
701          *a = 1; // Alpha component
702          a += 4;
703       }
704    }
705    else
706    {
707       // Probabely the same stuff is to be done for 16 Bits Pixels
708       // with 65536 entries LUT ?!?
709       // Still looking for accurate info on the web :-(
710
711       gdcmWarningMacro( "Sorry Palette Color Lookup Tables not yet dealt with"
712                          << " for 16 Bits Per Pixel images" );
713
714       // forge the 4 * 16 Bits Red/Green/Blue/Alpha LUT
715
716       LutRGBA = (uint8_t *)new uint16_t[ 65536*4 ]; // 2^16 * 4 (R, G, B, Alpha)
717       if ( !LutRGBA )
718          return;
719       memset( LutRGBA, 0, 65536*4*2 );  // 16 bits = 2 bytes ;-)
720
721       LutItemNumber = 65536;
722       LutItemSize   = 16;
723
724       int i;
725       uint16_t *a16;
726
727       //take "Subscript of the first Lut Value" (debR,debG,debB) into account!
728
729       a16 = (uint16_t*)LutRGBA + 0 + debR;
730       for( i=0; i < lengthR; ++i )
731       {
732          *a16 = ((uint16_t*)LutRedData)[i];
733          a16 += 4;
734       }
735                                                                               
736       a16 = (uint16_t*)LutRGBA + 1 + debG;
737       for( i=0; i < lengthG; ++i)
738       {
739          *a16 = ((uint16_t*)LutGreenData)[i];
740          a16 += 4;
741       }
742                                                                                 
743       a16 = (uint16_t*)LutRGBA + 2 + debB;
744       for(i=0; i < lengthB; ++i)
745       {
746          *a16 = ((uint16_t*)LutBlueData)[i];
747          a16 += 4;
748       }
749                                                                              
750       a16 = (uint16_t*)LutRGBA + 3 ;
751       for(i=0; i < 65536; ++i)
752       {
753          *a16 = 1; // Alpha component
754          a16 += 4;
755       }
756 /* Just to 'see' the LUT, at debug time
757 // Don't remove this commented out code.
758
759       a16=(uint16_t*)LutRGBA;
760       for (int j=0;j<65536;j++)
761       {
762          std::cout << *a16     << " " << *(a16+1) << " "
763                    << *(a16+2) << " " << *(a16+3) << std::endl;
764          a16+=4;
765       }
766 */
767    }
768 }
769
770 /**
771  * \brief Swap the bytes, according to \ref SwapCode.
772  */
773 void PixelReadConvert::ConvertSwapZone()
774 {
775    unsigned int i;
776    uint16_t localSwapCode = SwapCode;
777    
778    // If this file is 'ImplicitVR BigEndian PrivateGE Transfer Syntax', 
779    // then the header is in little endian format and the pixel data is in 
780    // big endian format.  When reading the header, GDCM has already established
781    // a byte swapping code suitable for this machine to read the
782    // header. In TS::ImplicitVRBigEndianPrivateGE, this code will need
783    // to be switched in order to read the pixel data.  This must be
784    // done REGARDLESS of the processor endianess!
785    //
786    // Example:  Assume we are on a little endian machine.  When
787    // GDCM reads the header, the header will match the machine
788    // endianess and the swap code will be established as a no-op.
789    // When GDCM reaches the pixel data, it will need to switch the
790    // swap code to do big endian to little endian conversion.
791    //
792    // Now, assume we are on a big endian machine.  When GDCM reads the
793    // header, the header will be recognized as a different endianess
794    // than the machine endianess, and a swap code will be established
795    // to convert from little endian to big endian.  When GDCM readers
796    // the pixel data, the pixel data endianess will now match the
797    // machine endianess.  But we currently have a swap code that
798    // converts from little endian to big endian.  In this case, we
799    // need to switch the swap code to a no-op.
800    //
801    // Therefore, in either case, if the file is in
802    // 'ImplicitVR BigEndian PrivateGE Transfer Syntax', then GDCM needs to switch
803    // the byte swapping code when entering the pixel data.
804
805 /* //Let me check something.
806    //I wait for the Dashboard !   
807    if ( IsPrivateGETransferSyntax )
808    {
809       // PrivateGETransferSyntax only exists for 'true' Dicom images
810       // we assume there is no 'exotic' 32 bits endianess!
811       switch (localSwapCode)
812       {
813          case 1234:
814             localSwapCode = 4321;
815             break;
816          case 4321:
817             localSwapCode = 1234;
818             break;
819       }  
820    }
821 */   
822    if ( BitsAllocated == 16 )
823    {
824       uint16_t *im16 = (uint16_t*)Raw;
825       switch( localSwapCode )
826       {
827          case 1234:
828             break;
829          case 3412:
830          case 2143:
831          case 4321:
832             for( i = 0; i < RawSize / 2; i++ )
833             {
834                im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
835             }
836             break;
837          default:
838             gdcmWarningMacro("SwapCode value (16 bits) not allowed.");
839       }
840    }
841    else if ( BitsAllocated == 32 )
842    {
843       uint32_t s32;
844       uint16_t high;
845       uint16_t low;
846       uint32_t *im32 = (uint32_t*)Raw;
847       switch ( localSwapCode )
848       {
849          case 1234:
850             break;
851          case 4321:
852             for( i = 0; i < RawSize / 4; i++ )
853             {
854                low     = im32[i] & 0x0000ffff;  // 4321
855                high    = im32[i] >> 16;
856                high    = ( high >> 8 ) | ( high << 8 );
857                low     = ( low  >> 8 ) | ( low  << 8 );
858                s32     = low;
859                im32[i] = ( s32 << 16 ) | high;
860             }
861             break;
862          case 2143:
863             for( i = 0; i < RawSize / 4; i++ )
864             {
865                low     = im32[i] & 0x0000ffff;   // 2143
866                high    = im32[i] >> 16;
867                high    = ( high >> 8 ) | ( high << 8 );
868                low     = ( low  >> 8 ) | ( low  << 8 );
869                s32     = high;
870                im32[i] = ( s32 << 16 ) | low;
871             }
872             break;
873          case 3412:
874             for( i = 0; i < RawSize / 4; i++ )
875             {
876                low     = im32[i] & 0x0000ffff; // 3412
877                high    = im32[i] >> 16;
878                s32     = low;
879                im32[i] = ( s32 << 16 ) | high;
880             }
881             break;
882          default:
883             gdcmWarningMacro("SwapCode value (32 bits) not allowed." );
884       }
885    }
886 }
887
888 /**
889  * \brief Deal with endianness i.e. re-arange bytes inside the integer
890  */
891 void PixelReadConvert::ConvertReorderEndianity()
892 {
893    if ( BitsAllocated != 8 )
894    {
895       ConvertSwapZone();
896    }
897
898    // Special kludge in order to deal with xmedcon broken images:
899    if ( BitsAllocated == 16
900      && BitsStored < BitsAllocated
901      && !PixelSign )
902    {
903       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
904       uint16_t *deb = (uint16_t *)Raw;
905       for(int i = 0; i<l; i++)
906       {
907          if ( *deb == 0xffff )
908          {
909            *deb = 0;
910          }
911          deb++;
912       }
913    }
914 }
915
916 /**
917  * \brief Deal with Grey levels i.e. re-arange them
918  *        to have low values = dark, high values = bright
919  */
920 void PixelReadConvert::ConvertFixGreyLevels()
921 {
922    if (!IsMonochrome1)
923       return;
924
925    uint32_t i; // to please M$VC6
926    int16_t j;
927
928    if (!PixelSign)
929    {
930       if ( BitsAllocated == 8 )
931       {
932          uint8_t *deb = (uint8_t *)Raw;
933          for (i=0; i<RawSize; i++)      
934          {
935             *deb = 255 - *deb;
936             deb++;
937          }
938          return;
939       }
940
941       if ( BitsAllocated == 16 )
942       {
943          uint16_t mask =1;
944          for (j=0; j<BitsStored-1; j++)
945          {
946             mask = (mask << 1) +1; // will be fff when BitsStored=12
947          }
948
949          uint16_t *deb = (uint16_t *)Raw;
950          for (i=0; i<RawSize/2; i++)      
951          {
952             *deb = mask - *deb;
953             deb++;
954          }
955          return;
956        }
957    }
958    else
959    {
960       if ( BitsAllocated == 8 )
961       {
962          uint8_t smask8 = 255;
963          uint8_t *deb = (uint8_t *)Raw;
964          for (i=0; i<RawSize; i++)      
965          {
966             *deb = smask8 - *deb;
967             deb++;
968          }
969          return;
970       }
971       if ( BitsAllocated == 16 )
972       {
973          uint16_t smask16 = 65535;
974          uint16_t *deb = (uint16_t *)Raw;
975          for (i=0; i<RawSize/2; i++)      
976          {
977             *deb = smask16 - *deb;
978             deb++;
979          }
980          return;
981       }
982    }
983 }
984
985 /**
986  * \brief  Re-arrange the bits within the bytes.
987  * @return Boolean always true
988  */
989 bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError )
990 {
991
992    if ( BitsStored != BitsAllocated )
993    {
994       int l = (int)( RawSize / ( BitsAllocated / 8 ) );
995       if ( BitsAllocated == 16 )
996       {
997          // pmask : to mask the 'unused bits' (may contain overlays)
998          uint16_t pmask = 0xffff;
999          pmask = pmask >> ( BitsAllocated - BitsStored );
1000
1001          uint16_t *deb = (uint16_t*)Raw;
1002
1003          if ( !PixelSign )  // Pixels are unsigned
1004          {
1005             for(int i = 0; i<l; i++)
1006             {   
1007                *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask;
1008                deb++;
1009             }
1010          }
1011          else // Pixels are signed
1012          {
1013             // smask : to check the 'sign' when BitsStored != BitsAllocated
1014             uint16_t smask = 0x0001;
1015             smask = smask << ( 16 - (BitsAllocated - BitsStored + 1) );
1016             // nmask : to propagate sign bit on negative values
1017             int16_t nmask = (int16_t)0x8000;  
1018             nmask = nmask >> ( BitsAllocated - BitsStored - 1 );
1019  
1020             for(int i = 0; i<l; i++)
1021             {
1022                *deb = *deb >> (BitsStored - HighBitPosition - 1);
1023                if ( *deb & smask )
1024                {
1025                   *deb = *deb | nmask;
1026                }
1027                else
1028                {
1029                   *deb = *deb & pmask;
1030                }
1031                deb++;
1032             }
1033          }
1034       }
1035       else if ( BitsAllocated == 32 )
1036       {
1037          // pmask : to mask the 'unused bits' (may contain overlays)
1038          uint32_t pmask = 0xffffffff;
1039          pmask = pmask >> ( BitsAllocated - BitsStored );
1040
1041          uint32_t *deb = (uint32_t*)Raw;
1042
1043          if ( !PixelSign )
1044          {
1045             for(int i = 0; i<l; i++)
1046             {             
1047                *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask;
1048                deb++;
1049             }
1050          }
1051          else
1052          {
1053             // smask : to check the 'sign' when BitsStored != BitsAllocated
1054             uint32_t smask = 0x00000001;
1055             smask = smask >> ( 32 - (BitsAllocated - BitsStored +1 ));
1056             // nmask : to propagate sign bit on negative values
1057             int32_t nmask = 0x80000000;   
1058             nmask = nmask >> ( BitsAllocated - BitsStored -1 );
1059
1060             for(int i = 0; i<l; i++)
1061             {
1062                *deb = *deb >> (BitsStored - HighBitPosition - 1);
1063                if ( *deb & smask )
1064                   *deb = *deb | nmask;
1065                else
1066                   *deb = *deb & pmask;
1067                deb++;
1068             }
1069          }
1070       }
1071       else
1072       {
1073          gdcmWarningMacro("Weird image (BitsAllocated !=8, 12, 16, 32)");
1074          throw FormatError( "Weird image !?" );
1075       }
1076    }
1077    return true;
1078 }
1079
1080 /**
1081  * \brief   Convert (Red plane, Green plane, Blue plane) to RGB pixels
1082  * \warning Works on all the frames at a time
1083  */
1084 void PixelReadConvert::ConvertRGBPlanesToRGBPixels()
1085 {
1086    gdcmWarningMacro("--> ConvertRGBPlanesToRGBPixels");
1087
1088    uint8_t *localRaw = Raw;
1089    uint8_t *copyRaw = new uint8_t[ RawSize ];
1090    memmove( copyRaw, localRaw, RawSize );
1091
1092    int l = XSize * YSize * ZSize;
1093
1094    uint8_t *a = copyRaw;
1095    uint8_t *b = copyRaw + l;
1096    uint8_t *c = copyRaw + l + l;
1097
1098    for (int j = 0; j < l; j++)
1099    {
1100       *(localRaw++) = *(a++);
1101       *(localRaw++) = *(b++);
1102       *(localRaw++) = *(c++);
1103    }
1104    delete[] copyRaw;
1105 }
1106
1107 /**
1108  * \brief   Convert (cY plane, cB plane, cR plane) to RGB pixels
1109  * \warning Works on all the frames at a time
1110  */
1111 void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels()
1112 {
1113   // Remarks for YBR newbees :
1114   // YBR_FULL works very much like RGB, i.e. three samples per pixel, 
1115   // just the color space is YCbCr instead of RGB. This is particularly useful
1116   // for doppler ultrasound where most of the image is grayscale 
1117   // (i.e. only populates the Y components) and Cb and Cr are mostly zero,
1118   // except for the few patches of color on the image.
1119   // On such images, RLE achieves a compression ratio that is much better 
1120   // than the compression ratio on an equivalent RGB image. 
1121  
1122    gdcmWarningMacro("--> ConvertYcBcRPlanesToRGBPixels");
1123    
1124    uint8_t *localRaw = Raw;
1125    uint8_t *copyRaw = new uint8_t[ RawSize ];
1126    memmove( copyRaw, localRaw, RawSize );
1127
1128    // to see the tricks about YBR_FULL, YBR_FULL_422,
1129    // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
1130    // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
1131    // and be *very* affraid
1132    //
1133    int l        = XSize * YSize;
1134    int nbFrames = ZSize;
1135
1136    uint8_t *a = copyRaw + 0;
1137    uint8_t *b = copyRaw + l;
1138    uint8_t *c = copyRaw + l+ l;
1139    int32_t R, G, B;
1140
1141    ///  We replaced easy to understand but time consuming floating point
1142    ///  computations by the 'well known' integer computation counterpart
1143    ///  Refer to :
1144    ///            http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
1145    ///  for code optimisation.
1146
1147    for ( int i = 0; i < nbFrames; i++ )
1148    {
1149       for ( int j = 0; j < l; j++ )
1150       {
1151          R = 38142 *(*a-16) + 52298 *(*c -128);
1152          G = 38142 *(*a-16) - 26640 *(*c -128) - 12845 *(*b -128);
1153          B = 38142 *(*a-16) + 66093 *(*b -128);
1154
1155          R = (R+16384)>>15;
1156          G = (G+16384)>>15;
1157          B = (B+16384)>>15;
1158
1159          if (R < 0)   R = 0;
1160          if (G < 0)   G = 0;
1161          if (B < 0)   B = 0;
1162          if (R > 255) R = 255;
1163          if (G > 255) G = 255;
1164          if (B > 255) B = 255;
1165
1166          *(localRaw++) = (uint8_t)R;
1167          *(localRaw++) = (uint8_t)G;
1168          *(localRaw++) = (uint8_t)B;
1169          a++;
1170          b++;
1171          c++;
1172       }
1173    }
1174    delete[] copyRaw;
1175 }
1176
1177 /// \brief Deals with the color decoding i.e. handle:
1178 ///   - R, G, B planes (as opposed to RGB pixels)
1179 ///   - YBR (various) encodings.
1180 ///   - LUT[s] (or "PALETTE COLOR").
1181
1182 void PixelReadConvert::ConvertHandleColor()
1183 {
1184    //////////////////////////////////
1185    // Deal with the color decoding i.e. handle:
1186    //   - R, G, B planes (as opposed to RGB pixels)
1187    //   - YBR (various) encodings.
1188    //   - LUT[s] (or "PALETTE COLOR").
1189    //
1190    // The classification in the color decoding schema is based on the blending
1191    // of two Dicom tags values:
1192    // * "Photometric Interpretation" for which we have the cases:
1193    //  - [Photo A] MONOCHROME[1|2] pictures,
1194    //  - [Photo B] RGB or YBR_FULL_422 (which acts as RGB),
1195    //  - [Photo C] YBR_* (with the above exception of YBR_FULL_422)
1196    //  - [Photo D] "PALETTE COLOR" which indicates the presence of LUT[s].
1197    // * "Planar Configuration" for which we have the cases:
1198    //  - [Planar 0] 0 then Pixels are already RGB
1199    //  - [Planar 1] 1 then we have 3 planes : R, G, B,
1200    //  - [Planar 2] 2 then we have 1 gray Plane and 3 LUTs
1201    //
1202    // Now in theory, one could expect some coherence when blending the above
1203    // cases. For example we should not encounter files belonging at the
1204    // time to case [Planar 0] and case [Photo D].
1205    // Alas, this was only theory ! Because in practice some odd (read ill
1206    // formated Dicom) files (e.g. gdcmData/US-PAL-8-10x-echo.dcm) we encounter:
1207    //     - "Planar Configuration" = 0,
1208    //     - "Photometric Interpretation" = "PALETTE COLOR".
1209    // Hence gdcm will use the folowing "heuristic" in order to be tolerant
1210    // towards Dicom-non-conformant files:
1211    //   << whatever the "Planar Configuration" value might be, a
1212    //      "Photometric Interpretation" set to "PALETTE COLOR" forces
1213    //      a LUT intervention >>
1214    //
1215    // Now we are left with the following handling of the cases:
1216    // - [Planar 0] OR  [Photo A] no color decoding (since respectively
1217    //       Pixels are already RGB and monochrome pictures have no color :),
1218    // - [Planar 1] AND [Photo B] handled with ConvertRGBPlanesToRGBPixels()
1219    // - [Planar 1] AND [Photo C] handled with ConvertYcBcRPlanesToRGBPixels()
1220    // - [Planar 2] OR  [Photo D] requires LUT intervention.
1221
1222    gdcmWarningMacro("--> ConvertHandleColor"
1223                     << "Planar Configuration " << PlanarConfiguration );
1224
1225    if ( ! IsRawRGB() )
1226    {
1227       // [Planar 2] OR  [Photo D]: LUT intervention done outside
1228       gdcmWarningMacro("--> RawRGB : LUT intervention done outside");
1229       return;
1230    }
1231                                                                                 
1232    if ( PlanarConfiguration == 1 )
1233    {
1234       if ( IsYBRFull )
1235       {
1236          // [Planar 1] AND [Photo C] (remember YBR_FULL_422 acts as RGB)
1237          gdcmWarningMacro("--> YBRFull");
1238          ConvertYcBcRPlanesToRGBPixels();
1239       }
1240       else
1241       {
1242          // [Planar 1] AND [Photo C]
1243          gdcmWarningMacro("--> YBRFull");
1244          ConvertRGBPlanesToRGBPixels();
1245       }
1246       return;
1247    }
1248                                                                                 
1249    // When planarConf is 0, and RLELossless (forbidden by Dicom norm)
1250    // pixels need to be RGB-fyied anyway
1251
1252    if (IsRLELossless)
1253    { 
1254      gdcmWarningMacro("--> RLE Lossless");
1255      ConvertRGBPlanesToRGBPixels();
1256    }
1257
1258    // In *normal *case, when planarConf is 0, pixels are already in RGB
1259 }
1260
1261 /// Computes the Pixels Size
1262 void PixelReadConvert::ComputeRawAndRGBSizes()
1263 {
1264    int bitsAllocated = BitsAllocated;
1265    // Number of "Bits Allocated" is fixed to 16 when it's 12, since
1266    // in this case we will expand the image to 16 bits (see
1267    //    \ref ReadAndDecompress12BitsTo16Bits() )
1268    if (  BitsAllocated == 12 )
1269    {
1270       bitsAllocated = 16;
1271    }
1272                                                                                 
1273    RawSize =  XSize * YSize * ZSize
1274                      * ( bitsAllocated / 8 )
1275                      * SamplesPerPixel;
1276    if ( HasLUT )
1277    {
1278       RGBSize = 3 * RawSize; // works for 8 and 16 bits per Pixel
1279    }
1280    else
1281    {
1282       RGBSize = RawSize;
1283    }
1284 }
1285
1286 /// Allocates room for RGB Pixels
1287 void PixelReadConvert::AllocateRGB()
1288 {
1289   if ( RGB )
1290      delete [] RGB;
1291   RGB = new uint8_t[RGBSize];
1292 }
1293
1294 /// Allocates room for RAW Pixels
1295 void PixelReadConvert::AllocateRaw()
1296 {
1297   if ( Raw )
1298      delete [] Raw;
1299   Raw = new uint8_t[RawSize];
1300 }
1301
1302 //-----------------------------------------------------------------------------
1303 // Print
1304 /**
1305  * \brief        Print self.
1306  * @param indent Indentation string to be prepended during printing.
1307  * @param os     Stream to print to.
1308  */
1309 void PixelReadConvert::Print( std::ostream &os, std::string const &indent )
1310 {
1311    os << indent
1312       << "--- Pixel information -------------------------"
1313       << std::endl;
1314    os << indent
1315       << "Pixel Data: offset " << PixelOffset
1316       << " x(" << std::hex << PixelOffset << std::dec
1317       << ")   length " << PixelDataLength
1318       << " x(" << std::hex << PixelDataLength << std::dec
1319       << ")" << std::endl;
1320
1321    if ( IsRLELossless )
1322    {
1323       if ( RLEInfo )
1324       {
1325          RLEInfo->Print( os, indent );
1326       }
1327       else
1328       {
1329          gdcmWarningMacro("Set as RLE file but NO RLEinfo present.");
1330       }
1331    }
1332
1333    if ( IsJPEG2000 || IsJPEGLossless || IsJPEGLossy || IsJPEGLS )
1334    {
1335       if ( JPEGInfo )
1336       {
1337          JPEGInfo->Print( os, indent );
1338       }
1339       else
1340       {
1341          gdcmWarningMacro("Set as JPEG file but NO JPEGinfo present.");
1342       }
1343    }
1344 }
1345
1346 //-----------------------------------------------------------------------------
1347 } // end namespace gdcm
1348
1349 // Note to developpers :
1350 // Here is a very detailled post from David Clunie, on the troubles caused 
1351 // 'non standard' LUT and LUT description
1352 // We shall have to take it into accound in our code.
1353 // Some day ...
1354
1355
1356 /*
1357 Subject: Problem with VOI LUTs in Agfa and Fuji CR and GE DX images, was Re: VOI LUT issues
1358 Date: Sun, 06 Feb 2005 17:13:40 GMT
1359 From: David Clunie <dclunie@dclunie.com>
1360 Reply-To: dclunie@dclunie.com
1361 Newsgroups: comp.protocols.dicom
1362 References: <1107553502.040221.189550@o13g2000cwo.googlegroups.com>
1363
1364 > THE LUT that comes with [my] image claims to be 16-bit, but none of the
1365 > values goes higher than 4095.  That being said, though, none of my
1366 > original pixel values goes higher than that, either.  I have read
1367 > elsewhere on this group that when that happens you are supposed to
1368 > adjust the LUT.  Can someone be more specific?  There was a thread from
1369 > 2002 where Marco and David were mentioning doing precisely that.
1370 >
1371 > Thanks
1372 >
1373 > -carlos rodriguez
1374
1375
1376 You have encountered the well known "we know what the standard says but
1377 we are going to ignore it and do what we have been doing for almost
1378 a decade regardless" CR vendor bug. Agfa started this, but they are not
1379 the only vendor doing this now; GE and Fuji may have joined the club.
1380
1381 Sadly, one needs to look at the LUT Data, figure out what the maximum
1382 value actually encoded is, and find the next highest power of 2 (e.g.
1383 212 in this case), to figure out what the range of the data is
1384 supposed to be. I have assumed that if the maximum value in the LUT
1385 data is less than a power of 2 minus 1 (e.g. 0xebc) then the intent
1386 of the vendor was not to use the maximum available grayscale range
1387 of the display (e.g. the maximum is 0xfff in this case). An alternative
1388 would be to scale to the actual maximum rather than a power of two.
1389
1390 Very irritating, and in theory not totally reliable if one really
1391 intended the full 16 bits and only used, say 15, but that is extremely
1392 unlikely since everything would be too dark, and this heuristic
1393 seems to work OK.
1394
1395 There has never been anything in the standard that describes having
1396 to go through these convolutions. Since the only value in the
1397 standard that describes the bit depth of the LUT values is LUT
1398 Descriptor value 3 and that is (usually) always required to be
1399 either 8 or 16, it mystifies me how the creators' of these images
1400 imagine that the receiver is going to divine the range that is intended. Further, the standard is quite explicit that this 3rd
1401 value defines the range of LUT values, but as far as I am aware, all
1402 the vendors are ignoring the standard and indeed sending a third value
1403 of 16 in all cases.
1404
1405 This problem is not confined to CR, and is also seen with DX products.
1406
1407 Typically I have seen:
1408
1409 - Agfa CR, which usually (always ?) sends LUTs, values up to 0x0fff
1410 - Fuji CR, which occasionally send LUTs, values up to 0x03ff
1411 - GE DX, for presentation, which always have LUTs, up to 0x3fff
1412
1413 Swissray, Siemens, Philips, Canon and Kodak never seem to send VOI LUTs
1414 at this point (which is a whole other problem). Note that the presence
1415 or absence of a VOI LUT as opposed to window values may be configurable
1416 on the modality in some cases, and I have just looked at what I happen
1417 to have received from a myriad of sites over whose configuration I have
1418 no control. This may be why the majority of Fuji images have no VOI LUTs,
1419 but a few do (or it may be the Siemens system that these Fuji images went
1420 through that perhaps added it). I do have some test Hologic DX images that
1421 are not from a clinical site that do actually get this right (a value
1422 of 12 for the third value and a max of 0xfff).
1423
1424 Since almost every vendor that I have encountered that encodes LUTs
1425 makes this mistake, perhaps it is time to amend the standard to warn
1426 implementor's of receivers and/or sanction this bad behavior. We have
1427 talked about this in the past in WG 6 but so far everyone has been
1428 reluctant to write into the standard such a comment. Maybe it is time
1429 to try again, since if one is not aware of this problem, one cannot
1430 effectively implement display using VOI LUTs, and there is a vast
1431 installed base to contend with.
1432
1433 I did not check presentation states, in which VOI LUTs could also be
1434 encountered, for the prevalence of this mistake, nor did I look at the
1435 encoding of Modality LUT's, which are unusual. Nor did I check digital
1436 mammography images. I would be interested to hear from anyone who has.
1437
1438 David
1439
1440 PS. The following older thread in this newsgroup discusses this:
1441
1442 "http://groups-beta.google.com/group/comp.protocols.dicom/browse_frm/t hread/6a033444802a35fc/0f0a9a1e35c1468e?q=voi+lut&_done=%2Fgroup%2Fcom p.protocols.dicom%2Fsearch%3Fgroup%3Dcomp.protocols.dicom%26q%3Dvoi+lu t%26qt_g%3D1%26searchnow%3DSearch+this+group%26&_doneTitle=Back+to+Sea rch&&d#0f0a9a1e35c1468e"
1443
1444 PPS. From a historical perspective, the following may be of interest.
1445
1446 In the original standard in 1993, all that was said about this was a
1447 reference to the corresponding such where Modality LUTs are described
1448 that said:
1449
1450 "The third value specifies the number of bits for each entry in the
1451 LUT Data. It shall take the value 8 or 16. The LUT Data shall be stored
1452 in a format equivalent to 8 or 16 bits allocated and high bit equal
1453 1-bits allocated."
1454
1455 Since the high bit hint was not apparently explicit enough, a very
1456 early CP, CP 15 (submitted by Agfa as it happens), replaced this with:
1457
1458 "The third value conveys the range of LUT entry values. It shall take
1459 the value 8 or 16, corresponding with the LUT entry value range of
1460 256 or 65536.
1461
1462 Note:    The third value is not required for describing the
1463     LUT data and is only included for informational usage
1464     and for maintaining compatibility with ACRNEMA 2.0.
1465
1466 The LUT Data contains the LUT entry values."
1467
1468 That is how it read in the 1996, 1998 and 1999 editions.
1469
1470 By the 2000 edition, Supplement 33 that introduced presentation states
1471 extensively reworked this entire section and tried to explain this in
1472 different words:
1473
1474 "The output range is from 0 to 2^n-1 where n is the third value of LUT
1475 Descriptor. This range is always unsigned."
1476
1477 and also added a note to spell out what the output range meant in the
1478 VOI LUT section:
1479
1480 "9. The output of the Window Center/Width or VOI LUT transformation
1481 is either implicitly scaled to the full range of the display device
1482 if there is no succeeding transformation defined, or implicitly scaled
1483 to the full input range of the succeeding transformation step (such as
1484 the Presentation LUT), if present. See C.11.6.1."
1485
1486 It still reads this way in the 2004 edition.
1487
1488 Note that LUTs in other applications than the general VOI LUT allow for
1489 values other than 8 or 16 in the third value of LUT descriptor to permit
1490 ranges other than 0 to 255 or 65535.
1491
1492 In addition, the DX Image Module specializes the VOI LUT
1493 attributes as follows, in PS 3.3 section C.8.11.3.1.5 (added in Sup 32):
1494
1495 "The third value specifies the number of bits for each entry in the LUT
1496 Data (analogous to ìbits storedî). It shall be between 10-16. The LUT
1497 Data shall be stored in a format equivalent to 16 ìbits allocatedî and
1498 ìhigh bitî equal to ìbits storedî - 1. The third value conveys the range
1499 of LUT entry values. These unsigned LUT entry values shall range between
1500 0 and 2^n-1, where n is the third value of the LUT Descriptor."
1501
1502 So in the case of the GE DX for presentation images, the third value of
1503 LUT descriptor is allowed to be and probably should be 14 rather than 16.
1504
1505 */