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