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