1 /*=========================================================================
4 Module: $RCSfile: gdcmPixelReadConvert.cxx,v $
6 Date: $Date: 2007/09/05 08:22:57 $
7 Version: $Revision: 1.122 $
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.
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.
17 =========================================================================*/
19 #include "gdcmPixelReadConvert.h"
20 #include "gdcmDebug.h"
22 #include "gdcmGlobal.h"
24 #include "gdcmDocEntry.h"
25 #include "gdcmRLEFramesInfo.h"
26 #include "gdcmJPEGFragmentsInfo.h"
29 #include <stdio.h> //for sscanf
31 #if defined(__BORLANDC__)
32 #include <mem.h> // for memset
35 namespace GDCM_NAME_SPACE
38 //bool ReadMPEGFile (std::ifstream *fp, char *inputdata, size_t lenght);
39 bool gdcm_read_JPEG2000_file (void* raw,
40 char *inputdata, size_t inputlength);
41 //-----------------------------------------------------------------------------
42 #define str2num(str, typeNum) *((typeNum *)(str))
44 //-----------------------------------------------------------------------------
45 // Constructor / Destructor
47 PixelReadConvert::PixelReadConvert()
63 /// Canonical Destructor
64 PixelReadConvert::~PixelReadConvert()
69 //-----------------------------------------------------------------------------
72 * \brief Predicate to know whether the image[s] (once Raw) is RGB.
73 * \note See comments of \ref ConvertHandleColor
75 bool PixelReadConvert::IsRawRGB()
78 || PlanarConfiguration == 2
86 * \brief Gets various usefull informations from the file header
87 * @param file gdcm::File pointer
88 * @param fileHelper gdcm::FileHelper pointer
90 void PixelReadConvert::GrabInformationsFromFile( File *file,
91 FileHelper *fileHelper )
93 // Number of Bits Allocated for storing a Pixel is defaulted to 16
94 // when absent from the file.
95 BitsAllocated = file->GetBitsAllocated();
96 if ( BitsAllocated == 0 )
100 else if ( BitsAllocated > 8 && BitsAllocated < 16 && BitsAllocated != 12 )
105 // Number of "Bits Stored", defaulted to number of "Bits Allocated"
106 // when absent from the file.
107 BitsStored = file->GetBitsStored();
108 if ( BitsStored == 0 )
110 BitsStored = BitsAllocated;
113 // High Bit Position, defaulted to "Bits Allocated" - 1
114 HighBitPosition = file->GetHighBitPosition();
115 if ( HighBitPosition == 0 )
117 HighBitPosition = BitsAllocated - 1;
120 XSize = file->GetXSize();
121 YSize = file->GetYSize();
122 ZSize = file->GetZSize();
123 TSize = file->GetTSize();
124 SamplesPerPixel = file->GetSamplesPerPixel();
125 //PixelSize = file->GetPixelSize(); Useless
126 PixelSign = file->IsSignedPixelData();
127 SwapCode = file->GetSwapCode();
129 IsPrivateGETransferSyntax = IsMPEG
130 = IsJPEG2000 = IsJPEGLS = IsJPEGLossy
131 = IsJPEGLossless = IsRLELossless
134 if (! file->IsDicomV3() ) // Should be ACR-NEMA file
140 std::string ts = file->GetTransferSyntax();
143 while (true) // shorter to write than 'if elseif elseif elseif' ...
145 // mind the order : check the most usual first.
146 if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian) break;
147 if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian ) break;
148 if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian) break;
149 if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE) break;
150 // DeflatedExplicitVRLittleEndian syntax means the whole Dataset (Header + Pixels) is compressed !
151 // Not dealt with ! (Parser hangs)
152 //if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian) break;
155 // cache whether this is a strange GE transfer syntax (which uses
156 // a little endian transfer syntax for the header and a big endian
157 // transfer syntax for the pixel data).
158 IsPrivateGETransferSyntax =
159 ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE );
161 IsMPEG = IsJPEG2000 = IsJPEGLS = IsJPEGLossy = IsJPEGLossless = IsRLELossless = false;
166 // mind the order : check the most usual first.
167 if( IsJPEGLossy = Global::GetTS()->IsJPEGLossy(ts) ) break;
168 if( IsJPEGLossless = Global::GetTS()->IsJPEGLossless(ts) ) break;
169 if( IsRLELossless = Global::GetTS()->IsRLELossless(ts) ) break;
170 if( IsJPEG2000 = Global::GetTS()->IsJPEG2000(ts) ) break;
171 if( IsMPEG = Global::GetTS()->IsMPEG(ts) ) break;
172 if( IsJPEGLS = Global::GetTS()->IsJPEGLS(ts) ) break;
173 // DeflatedExplicitVRLittleEndian is considered as 'Unexpected' (we don't know yet how to process !)
174 gdcmWarningMacro("Unexpected Transfer Syntax :[" << ts << "]");
180 PixelOffset = file->GetPixelOffset();
181 PixelDataLength = file->GetPixelAreaLength();
182 RLEInfo = file->GetRLEInfo();
183 JPEGInfo = file->GetJPEGInfo();
185 IsMonochrome = file->IsMonochrome();
186 IsMonochrome1 = file->IsMonochrome1();
187 IsPaletteColor = file->IsPaletteColor();
188 IsYBRFull = file->IsYBRFull();
190 PlanarConfiguration = file->GetPlanarConfiguration();
192 /////////////////////////////////////////////////////////////////
194 HasLUT = file->HasLUT();
197 // Just in case some access to a File element requires disk access.
198 LutRedDescriptor = file->GetEntryString( 0x0028, 0x1101 );
199 LutGreenDescriptor = file->GetEntryString( 0x0028, 0x1102 );
200 LutBlueDescriptor = file->GetEntryString( 0x0028, 0x1103 );
202 // FIXME : The following comment is probabely meaningless, since LUT are *always*
203 // loaded at parsing time, whatever their length is.
205 // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
206 // [ refer to invocation of Document::SetMaxSizeLoadEntry() in
207 // Document::Document() ], the loading of the value (content) of a
208 // [Bin|Val]Entry occurence migth have been hindered (read simply NOT
209 // loaded). Hence, we first try to obtain the LUTs data from the file
210 // and when this fails we read the LUTs data directly from disk.
211 // \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
212 // We should NOT bypass the [Bin|Val]Entry class. Instead
213 // an access to an UNLOADED content of a [Bin|Val]Entry occurence
214 // (e.g. DataEntry::GetBinArea()) should force disk access from
215 // within the [Bin|Val]Entry class itself. The only problem
216 // is that the [Bin|Val]Entry is unaware of the FILE* is was
217 // parsed from. Fix that. FIXME.
220 file->LoadEntryBinArea(0x0028, 0x1201);
221 LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
224 gdcmWarningMacro("Unable to read Red Palette Color Lookup Table data");
228 file->LoadEntryBinArea(0x0028, 0x1202);
229 LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
232 gdcmWarningMacro("Unable to read Green Palette Color Lookup Table data");
236 file->LoadEntryBinArea(0x0028, 0x1203);
237 LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
240 gdcmWarningMacro("Unable to read Blue Palette Color Lookup Table data");
245 ComputeRawAndRGBSizes();
248 /// \brief Reads from disk and decompresses Pixels
249 bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
251 // ComputeRawAndRGBSizes is already made by
252 // ::GrabInformationsFromfile. So, the structure sizes are
256 //////////////////////////////////////////////////
257 //// First stage: get our hands on the Pixel Data.
260 gdcmWarningMacro( "Unavailable file pointer." );
264 fp->seekg( PixelOffset, std::ios::beg );
265 if ( fp->fail() || fp->eof() )
267 gdcmWarningMacro( "Unable to find PixelOffset in file." );
273 //////////////////////////////////////////////////
275 CallStartMethod(); // for progress bar
276 unsigned int count = 0;
277 unsigned int frameSize;
278 unsigned int bitsAllocated = BitsAllocated;
279 //if(bitsAllocated == 12)
280 if(bitsAllocated > 8 && bitsAllocated < 16)
282 frameSize = XSize*YSize*SamplesPerPixel*bitsAllocated/8;
284 //// Second stage: read from disk and decompress.
286 if ( BitsAllocated == 12 ) // We suppose 'BitsAllocated' = 12 only exist for uncompressed files
288 ReadAndDecompress12BitsTo16Bits( fp);
292 // This problem can be found when some obvious informations are found
293 // after the field containing the image data. In this case, these
294 // bad data are added to the size of the image (in the PixelDataLength
295 // variable). But RawSize is the right size of the image !
296 if ( PixelDataLength != RawSize )
298 gdcmWarningMacro( "Mismatch between PixelReadConvert : "
299 << PixelDataLength << " and RawSize : " << RawSize );
302 //todo : is it the right patch?
303 char *raw = (char*)Raw;
304 uint32_t remainingLength;
306 unsigned int lengthToRead;
308 if ( PixelDataLength > RawSize )
309 lengthToRead = RawSize;
311 lengthToRead = PixelDataLength;
313 // perform a frame by frame reading
314 remainingLength = lengthToRead;
315 unsigned int nbFrames = lengthToRead / frameSize;
316 for (i=0;i<nbFrames; i++)
318 Progress = (float)(count+1)/(float)nbFrames;
319 fp->read( raw, frameSize);
321 remainingLength -= frameSize;
324 if (remainingLength !=0 )
325 fp->read( raw, remainingLength);
327 if ( fp->fail() || fp->eof())
329 gdcmWarningMacro( "Reading of Raw pixel data failed." );
333 else if ( IsRLELossless )
335 if ( ! RLEInfo->DecompressRLEFile
336 ( fp, Raw, XSize, YSize, ZSize, TSize, BitsAllocated ) )
338 gdcmWarningMacro( "RLE decompressor failed." );
344 //gdcmWarningMacro( "Sorry, MPEG not yet taken into account" );
346 // fp has already been seek to start of mpeg
347 //ReadMPEGFile(fp, (char*)Raw, PixelDataLength);
352 // Default case concerns JPEG family
353 if ( ! ReadAndDecompressJPEGFile( fp ) )
355 gdcmWarningMacro( "JPEG decompressor ( ReadAndDecompressJPEGFile()"
356 << " method ) failed." );
361 ////////////////////////////////////////////
362 //// Third stage: twigle the bytes and bits.
363 ConvertReorderEndianity();
364 ConvertReArrangeBits();
365 ConvertFixGreyLevels();
366 if (UserFunction) // user is allowed to Mirror, TopDown, Rotate,...the image
367 UserFunction( Raw, FileInternal);
368 ConvertHandleColor();
373 /// Deletes Pixels Area
374 void PixelReadConvert::Squeeze()
390 * \brief Build the RGB image from the Raw image and the LUTs.
392 bool PixelReadConvert::BuildRGBImage()
396 // The job is already done.
402 // The job can't be done
409 // The job can't be done
413 gdcmDebugMacro( "--> BuildRGBImage" );
419 if ( BitsAllocated <= 8 )
421 uint8_t *localRGB = RGB;
422 for (size_t i = 0; i < RawSize; ++i )
425 *localRGB++ = LutRGBA[j];
426 *localRGB++ = LutRGBA[j+1];
427 *localRGB++ = LutRGBA[j+2];
431 else // deal with 16 bits pixels and 16 bits Palette color
433 uint16_t *localRGB = (uint16_t *)RGB;
434 for (size_t i = 0; i < RawSize/2; ++i )
436 j = ((uint16_t *)Raw)[i] * 4;
437 *localRGB++ = ((uint16_t *)LutRGBA)[j];
438 *localRGB++ = ((uint16_t *)LutRGBA)[j+1];
439 *localRGB++ = ((uint16_t *)LutRGBA)[j+2];
446 //-----------------------------------------------------------------------------
449 //-----------------------------------------------------------------------------
452 * \brief Read from file a 12 bits per pixel image and decompress it
453 * into a 16 bits per pixel image.
455 void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream *fp )
456 throw ( FormatError )
458 /// \todo Fix the 3D, 4D pb
459 int nbPixels = XSize * YSize * TSize;
460 uint16_t *localDecompres = (uint16_t*)Raw;
462 for( int p = 0; p < nbPixels; p += 2 )
466 fp->read( (char*)&b0, 1);
467 if ( fp->fail() || fp->eof() )
469 throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
470 "Unfound first block" );
473 fp->read( (char*)&b1, 1 );
474 if ( fp->fail() || fp->eof())
476 throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
477 "Unfound second block" );
480 fp->read( (char*)&b2, 1 );
481 if ( fp->fail() || fp->eof())
483 throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()",
484 "Unfound second block" );
487 // Two steps are necessary to please VC++
489 // 2 pixels 12bit = [0xABCDEF]
490 // 2 pixels 16bit = [0x0ABD] + [0x0FCE]
492 *localDecompres++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
494 *localDecompres++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
496 /// \todo JPR Troubles expected on Big-Endian processors ?
501 * \brief Reads from disk the Pixel Data of JPEG Dicom encapsulated
502 * file and decompress it.
503 * @param fp File Pointer
506 bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp )
510 // make sure this is the right JPEG compression
511 assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEGLS );
512 // FIXME this is really ugly but it seems I have to load the complete
513 // jpeg2000 stream to use jasper:
514 // I don't think we'll ever be able to deal with multiple fragments properly
518 unsigned long inputlength = 0;
519 JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment();
522 inputlength += jpegfrag->GetLength();
523 jpegfrag = JPEGInfo->GetNextFragment();
525 gdcmAssertMacro( inputlength != 0);
526 uint8_t *inputdata = new uint8_t[inputlength];
527 char *pinputdata = (char*)inputdata;
528 jpegfrag = JPEGInfo->GetFirstFragment();
531 fp->seekg( jpegfrag->GetOffset(), std::ios::beg);
532 fp->read(pinputdata, jpegfrag->GetLength());
533 pinputdata += jpegfrag->GetLength();
534 jpegfrag = JPEGInfo->GetNextFragment();
536 // Warning the inputdata buffer is deleted in the function
537 if ( gdcm_read_JPEG2000_file( Raw,
538 (char*)inputdata, inputlength ) )
542 // wow what happen, must be an error
543 gdcmWarningMacro( "gdcm_read_JPEG2000_file() failed ");
548 if( (unsigned int)ZSize != JPEGInfo->GetFragmentCount() )
550 gdcmErrorMacro( "Sorry GDCM does not handle this type of fragments" );
553 // Hopefully every dicom fragment is *exactly* the j2k stream
554 JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment();
555 char *praw = (char*)Raw;
558 unsigned long inputlength = jpegfrag->GetLength();
559 char *inputdata = new char[inputlength];
560 fp->seekg( jpegfrag->GetOffset(), std::ios::beg);
561 fp->read(inputdata, jpegfrag->GetLength());
562 // Warning the inputdata buffer is deleted in the function
563 gdcm_read_JPEG2000_file( praw,
564 inputdata, inputlength) ;
565 praw += XSize*YSize*SamplesPerPixel*(BitsAllocated/8);
566 jpegfrag = JPEGInfo->GetNextFragment();
573 // make sure this is the right JPEG compression
574 assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEG2000 );
575 // WARNING : JPEG-LS is NOT the 'classical' Jpeg Lossless :
576 // [JPEG-LS is the basis for new lossless/near-lossless compression
577 // standard for continuous-tone images intended for JPEG2000. The standard
578 // is based on the LOCO-I algorithm (LOw COmplexity LOssless COmpression
579 // for Images) developed at Hewlett-Packard Laboratories]
581 // see http://datacompression.info/JPEGLS.shtml
584 std::cerr << "count:" << JPEGInfo->GetFragmentCount() << std::endl;
585 unsigned long inputlength = 0;
586 JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment();
589 inputlength += jpegfrag->GetLength();
590 jpegfrag = JPEGInfo->GetNextFragment();
592 gdcmAssertMacro( inputlength != 0);
593 uint8_t *inputdata = new uint8_t[inputlength];
594 char *pinputdata = (char*)inputdata;
595 jpegfrag = JPEGInfo->GetFirstFragment();
598 fp->seekg( jpegfrag->GetOffset(), std::ios::beg);
599 fp->read(pinputdata, jpegfrag->GetLength());
600 pinputdata += jpegfrag->GetLength();
601 jpegfrag = JPEGInfo->GetNextFragment();
604 //fp->read((char*)Raw, PixelDataLength);
606 std::ofstream out("/tmp/jpegls.jpg");
607 out.write((char*)inputdata, inputlength);
612 gdcmWarningMacro( "Sorry, JPEG-LS not yet taken into account" );
613 fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg);
614 // if ( ! gdcm_read_JPEGLS_file( fp,Raw ) )
619 // make sure this is the right JPEG compression
620 assert( !IsJPEGLS || !IsJPEG2000 );
621 // Precompute the offset localRaw will be shifted with
622 int length = XSize * YSize * ZSize * SamplesPerPixel;
623 int numberBytes = BitsAllocated / 8;
625 // to avoid major troubles when BitsStored == 8 && BitsAllocated==16 !
627 if (BitsStored == 8 && BitsAllocated==16)
631 JPEGInfo->DecompressFromFile(fp, Raw, dummy, numberBytes, length );
637 * \brief Build Red/Green/Blue/Alpha LUT from File when :
638 * - (0028,0004) : Photometric Interpretation == [PALETTE COLOR ]
640 * - (0028,1101),(0028,1102),(0028,1102)
641 * xxx Palette Color Lookup Table Descriptor are found
643 * - (0028,1201),(0028,1202),(0028,1202)
644 * xxx Palette Color Lookup Table Data - are found
645 * \warning does NOT deal with :
646 * - 0028 1100 Gray Lookup Table Descriptor (Retired)
647 * - 0028 1221 Segmented Red Palette Color Lookup Table Data
648 * - 0028 1222 Segmented Green Palette Color Lookup Table Data
649 * - 0028 1223 Segmented Blue Palette Color Lookup Table Data
650 * no known Dicom reader deals with them :-(
651 * @return a RGBA Lookup Table
653 void PixelReadConvert::BuildLUTRGBA()
656 // Note to code reviewers :
657 // The problem is *much more* complicated, since a lot of manufacturers
658 // Don't follow the norm :
659 // have a look at David Clunie's remark at the end of this .cxx file.
666 // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
668 if ( ! IsPaletteColor )
673 if ( LutRedDescriptor == GDCM_UNFOUND
674 || LutGreenDescriptor == GDCM_UNFOUND
675 || LutBlueDescriptor == GDCM_UNFOUND )
677 gdcmWarningMacro( "(At least) a LUT Descriptor is missing" );
681 ////////////////////////////////////////////
682 // Extract the info from the LUT descriptors
683 int lengthR; // Red LUT length in Bytes
684 int debR; // Subscript of the first Lut Value
685 int nbitsR; // Lut item size (in Bits)
686 int nbRead; // nb of items in LUT descriptor (must be = 3)
688 nbRead = sscanf( LutRedDescriptor.c_str(),
690 &lengthR, &debR, &nbitsR );
693 gdcmWarningMacro( "Wrong Red LUT descriptor" );
695 int lengthG; // Green LUT length in Bytes
696 int debG; // Subscript of the first Lut Value
697 int nbitsG; // Lut item size (in Bits)
699 nbRead = sscanf( LutGreenDescriptor.c_str(),
701 &lengthG, &debG, &nbitsG );
704 gdcmWarningMacro( "Wrong Green LUT descriptor" );
707 int lengthB; // Blue LUT length in Bytes
708 int debB; // Subscript of the first Lut Value
709 int nbitsB; // Lut item size (in Bits)
710 nbRead = sscanf( LutRedDescriptor.c_str(),
712 &lengthB, &debB, &nbitsB );
715 gdcmWarningMacro( "Wrong Blue LUT descriptor" );
718 gdcmDebugMacro(" lengthR " << lengthR << " debR "
719 << debR << " nbitsR " << nbitsR);
720 gdcmDebugMacro(" lengthG " << lengthG << " debG "
721 << debG << " nbitsG " << nbitsG);
722 gdcmDebugMacro(" lengthB " << lengthB << " debB "
723 << debB << " nbitsB " << nbitsB);
725 if ( !lengthR ) // if = 2^16, this shall be 0 see : CP-143
727 if ( !lengthG ) // if = 2^16, this shall be 0
729 if ( !lengthB ) // if = 2^16, this shall be 0
732 ////////////////////////////////////////////////////////
734 if ( ( ! LutRedData ) || ( ! LutGreenData ) || ( ! LutBlueData ) )
736 gdcmWarningMacro( "(At least) a LUT is missing" );
740 // -------------------------------------------------------------
742 if ( BitsAllocated <= 8 )
744 // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT
745 LutRGBA = new uint8_t[ 1024 ]; // 256 * 4 (R, G, B, Alpha)
750 memset( LutRGBA, 0, 1024 );
753 if ( ( nbitsR == 16 ) && ( BitsAllocated == 8 ) )
755 // when LUT item size is different than pixel size
756 mult = 2; // high byte must be = low byte
760 // See PS 3.3-2003 C.11.1.1.2 p 619
764 // if we get a black image, let's just remove the '+1'
765 // from 'i*mult+1' and check again
766 // if it works, we shall have to check the 3 Palettes
767 // to see which byte is ==0 (first one, or second one)
769 // We give up the checking to avoid some (useless ?) overhead
770 // (optimistic asumption)
774 //take "Subscript of the first Lut Value" (debR,debG,debB) into account!
776 //FIXME : +1 : to get 'low value' byte
777 // Trouble expected on Big Endian Processors ?
778 // 16 BIts Per Pixel Palette Color to be swapped?
780 a = LutRGBA + 0 + debR;
781 for( i=0; i < lengthR; ++i )
783 *a = LutRedData[i*mult+1];
787 a = LutRGBA + 1 + debG;
788 for( i=0; i < lengthG; ++i)
790 *a = LutGreenData[i*mult+1];
794 a = LutRGBA + 2 + debB;
795 for(i=0; i < lengthB; ++i)
797 *a = LutBlueData[i*mult+1];
802 for(i=0; i < 256; ++i)
804 *a = 1; // Alpha component
810 // Probabely the same stuff is to be done for 16 Bits Pixels
811 // with 65536 entries LUT ?!?
812 // Still looking for accurate info on the web :-(
814 gdcmWarningMacro( "Sorry Palette Color Lookup Tables not yet dealt with"
815 << " for 16 Bits Per Pixel images" );
817 // forge the 4 * 16 Bits Red/Green/Blue/Alpha LUT
819 LutRGBA = (uint8_t *)new uint16_t[ 65536*4 ]; // 2^16 * 4 (R, G, B, Alpha)
822 memset( LutRGBA, 0, 65536*4*2 ); // 16 bits = 2 bytes ;-)
824 LutItemNumber = 65536;
830 //take "Subscript of the first Lut Value" (debR,debG,debB) into account!
832 a16 = (uint16_t*)LutRGBA + 0 + debR;
833 for( i=0; i < lengthR; ++i )
835 *a16 = ((uint16_t*)LutRedData)[i];
839 a16 = (uint16_t*)LutRGBA + 1 + debG;
840 for( i=0; i < lengthG; ++i)
842 *a16 = ((uint16_t*)LutGreenData)[i];
846 a16 = (uint16_t*)LutRGBA + 2 + debB;
847 for(i=0; i < lengthB; ++i)
849 *a16 = ((uint16_t*)LutBlueData)[i];
853 a16 = (uint16_t*)LutRGBA + 3 ;
854 for(i=0; i < 65536; ++i)
856 *a16 = 1; // Alpha component
859 /* Just to 'see' the LUT, at debug time
860 // Don't remove this commented out code.
862 a16=(uint16_t*)LutRGBA;
863 for (int j=0;j<65536;j++)
865 std::cout << *a16 << " " << *(a16+1) << " "
866 << *(a16+2) << " " << *(a16+3) << std::endl;
874 * \brief Swap the bytes, according to \ref SwapCode.
876 void PixelReadConvert::ConvertSwapZone()
880 // If this file is 'ImplicitVR BigEndian PrivateGE Transfer Syntax',
881 // then the header is in little endian format and the pixel data is in
882 // big endian format. When reading the header, GDCM has already established
883 // a byte swapping code suitable for this machine to read the
884 // header. In TS::ImplicitVRBigEndianPrivateGE, this code will need
885 // to be switched in order to read the pixel data. This must be
886 // done REGARDLESS of the processor endianess!
888 // Example: Assume we are on a little endian machine. When
889 // GDCM reads the header, the header will match the machine
890 // endianess and the swap code will be established as a no-op.
891 // When GDCM reaches the pixel data, it will need to switch the
892 // swap code to do big endian to little endian conversion.
894 // Now, assume we are on a big endian machine. When GDCM reads the
895 // header, the header will be recognized as a different endianess
896 // than the machine endianess, and a swap code will be established
897 // to convert from little endian to big endian. When GDCM readers
898 // the pixel data, the pixel data endianess will now match the
899 // machine endianess. But we currently have a swap code that
900 // converts from little endian to big endian. In this case, we
901 // need to switch the swap code to a no-op.
903 // Therefore, in either case, if the file is in
904 // 'ImplicitVR BigEndian PrivateGE Transfer Syntax', then GDCM needs to switch
905 // the byte swapping code when entering the pixel data.
907 int tempSwapCode = SwapCode;
908 if ( IsPrivateGETransferSyntax )
910 gdcmWarningMacro(" IsPrivateGETransferSyntax found; turn the SwapCode");
911 // PrivateGETransferSyntax only exists for 'true' Dicom images
912 // we assume there is no 'exotic' 32 bits endianess!
913 if (SwapCode == 1234)
917 else if (SwapCode == 4321)
923 if ( BitsAllocated == 16 )
925 uint16_t *im16 = (uint16_t*)Raw;
926 switch( tempSwapCode )
933 for( i = 0; i < RawSize / 2; i++ )
935 im16[i]= (im16[i] >> 8) | (im16[i] << 8 );
939 gdcmWarningMacro("SwapCode value (16 bits) not allowed."
943 else if ( BitsAllocated == 32 )
948 uint32_t *im32 = (uint32_t*)Raw;
949 switch ( tempSwapCode )
954 for( i = 0; i < RawSize / 4; i++ )
956 low = im32[i] & 0x0000ffff; // 4321
957 high = im32[i] >> 16;
958 high = ( high >> 8 ) | ( high << 8 );
959 low = ( low >> 8 ) | ( low << 8 );
961 im32[i] = ( s32 << 16 ) | high;
965 for( i = 0; i < RawSize / 4; i++ )
967 low = im32[i] & 0x0000ffff; // 2143
968 high = im32[i] >> 16;
969 high = ( high >> 8 ) | ( high << 8 );
970 low = ( low >> 8 ) | ( low << 8 );
972 im32[i] = ( s32 << 16 ) | low;
976 for( i = 0; i < RawSize / 4; i++ )
978 low = im32[i] & 0x0000ffff; // 3412
979 high = im32[i] >> 16;
981 im32[i] = ( s32 << 16 ) | high;
985 gdcmWarningMacro("SwapCode value (32 bits) not allowed." << tempSwapCode );
991 * \brief Deal with endianness i.e. re-arange bytes inside the integer
993 void PixelReadConvert::ConvertReorderEndianity()
995 if ( BitsAllocated != 8 )
1000 // Special kludge in order to deal with xmedcon broken images:
1001 if ( BitsAllocated == 16
1002 && BitsStored < BitsAllocated
1005 int l = (int)( RawSize / ( BitsAllocated / 8 ) );
1006 uint16_t *deb = (uint16_t *)Raw;
1007 for(int i = 0; i<l; i++)
1009 if ( *deb == 0xffff )
1019 * \brief Deal with Grey levels i.e. re-arange them
1020 * to have low values = dark, high values = bright
1022 void PixelReadConvert::ConvertFixGreyLevels()
1027 uint32_t i; // to please M$VC6
1032 if ( BitsAllocated == 8 )
1034 uint8_t *deb = (uint8_t *)Raw;
1035 for (i=0; i<RawSize; i++)
1043 if ( BitsAllocated == 16 )
1046 for (j=0; j<BitsStored-1; j++)
1048 mask = (mask << 1) +1; // will be fff when BitsStored=12
1051 uint16_t *deb = (uint16_t *)Raw;
1052 for (i=0; i<RawSize/2; i++)
1062 if ( BitsAllocated == 8 )
1064 uint8_t smask8 = 255;
1065 uint8_t *deb = (uint8_t *)Raw;
1066 for (i=0; i<RawSize; i++)
1068 *deb = smask8 - *deb;
1073 if ( BitsAllocated == 16 )
1075 uint16_t smask16 = 65535;
1076 uint16_t *deb = (uint16_t *)Raw;
1077 for (i=0; i<RawSize/2; i++)
1079 *deb = smask16 - *deb;
1088 * \brief Re-arrange the bits within the bytes.
1089 * @return Boolean always true
1091 bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError )
1094 if ( BitsStored != BitsAllocated )
1096 int l = (int)( RawSize / ( BitsAllocated / 8 ) );
1097 if ( BitsAllocated == 16 )
1099 // pmask : to mask the 'unused bits' (may contain overlays)
1100 uint16_t pmask = 0xffff;
1102 // It's up to the user to decide if he wants to ignore overlays (if any),
1103 // not to gdcm, without asking.
1104 // default is NOT TO LOAD, in order not to confuse ITK users (and others!).
1106 if ( !FH->GetKeepOverlays() ) // mask spurious bits ! (overlay are NOT loaded!)
1108 pmask = pmask >> ( BitsAllocated - BitsStored );
1110 // else : it's up to the user to manage the 'pixels + overlays' he just loaded!
1112 uint16_t *deb = (uint16_t*)Raw;
1114 if ( !PixelSign ) // Pixels are unsigned
1116 for(int i = 0; i<l; i++)
1118 *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask;
1122 else // Pixels are signed
1124 // Hope there is never ACR-NEMA-like overlays within signed pixels (?!?)
1126 // smask : to check the 'sign' when BitsStored != BitsAllocated
1127 uint16_t smask = 0x0001;
1128 smask = smask << ( 16 - (BitsAllocated - BitsStored + 1) );
1129 // nmask : to propagate sign bit on negative values
1130 int16_t nmask = (int16_t)0x8000;
1131 nmask = nmask >> ( BitsAllocated - BitsStored - 1 );
1133 for(int i = 0; i<l; i++)
1135 *deb = *deb >> (BitsStored - HighBitPosition - 1);
1138 *deb = *deb | nmask;
1142 *deb = *deb & pmask;
1148 else if ( BitsAllocated == 32 )
1150 // pmask : to mask the 'unused bits' (may contain overlays)
1151 uint32_t pmask = 0xffffffff;
1152 pmask = pmask >> ( BitsAllocated - BitsStored );
1154 uint32_t *deb = (uint32_t*)Raw;
1158 for(int i = 0; i<l; i++)
1160 *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask;
1166 // smask : to check the 'sign' when BitsStored != BitsAllocated
1167 uint32_t smask = 0x00000001;
1168 smask = smask >> ( 32 - (BitsAllocated - BitsStored +1 ));
1169 // nmask : to propagate sign bit on negative values
1170 int32_t nmask = 0x80000000;
1171 nmask = nmask >> ( BitsAllocated - BitsStored -1 );
1173 for(int i = 0; i<l; i++)
1175 *deb = *deb >> (BitsStored - HighBitPosition - 1);
1177 *deb = *deb | nmask;
1179 *deb = *deb & pmask;
1186 gdcmWarningMacro("Weird image (BitsAllocated !=8, 12, 16, 32)");
1187 throw FormatError( "Weird image !?" );
1194 * \brief Convert (Red plane, Green plane, Blue plane) to RGB pixels
1195 * \warning Works on all the frames at a time
1197 void PixelReadConvert::ConvertRGBPlanesToRGBPixels()
1199 gdcmWarningMacro("--> ConvertRGBPlanesToRGBPixels");
1201 uint8_t *localRaw = Raw;
1202 uint8_t *copyRaw = new uint8_t[ RawSize ];
1203 memmove( copyRaw, localRaw, RawSize );
1205 int l = XSize * YSize * ZSize;
1207 uint8_t *a = copyRaw;
1208 uint8_t *b = copyRaw + l;
1209 uint8_t *c = copyRaw + l + l;
1211 for (int j = 0; j < l; j++)
1213 *(localRaw++) = *(a++);
1214 *(localRaw++) = *(b++);
1215 *(localRaw++) = *(c++);
1221 * \brief Convert (cY plane, cB plane, cR plane) to RGB pixels
1222 * \warning Works on all the frames at a time
1224 void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels()
1226 // Remarks for YBR newbees :
1227 // YBR_FULL works very much like RGB, i.e. three samples per pixel,
1228 // just the color space is YCbCr instead of RGB. This is particularly useful
1229 // for doppler ultrasound where most of the image is grayscale
1230 // (i.e. only populates the Y components) and Cb and Cr are mostly zero,
1231 // except for the few patches of color on the image.
1232 // On such images, RLE achieves a compression ratio that is much better
1233 // than the compression ratio on an equivalent RGB image.
1235 gdcmWarningMacro("--> ConvertYcBcRPlanesToRGBPixels");
1237 uint8_t *localRaw = Raw;
1238 uint8_t *copyRaw = new uint8_t[ RawSize ];
1239 memmove( copyRaw, localRaw, RawSize );
1241 // to see the tricks about YBR_FULL, YBR_FULL_422,
1242 // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
1243 // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
1244 // and be *very* affraid
1247 /// \todo : find an example to see how 3rd dim and 4th dim work together
1248 int l = XSize * YSize * TSize;
1249 int nbFrames = ZSize;
1251 uint8_t *a = copyRaw + 0;
1252 uint8_t *b = copyRaw + l;
1253 uint8_t *c = copyRaw + l+ l;
1256 /// We replaced easy to understand but time consuming floating point
1257 /// computations by the 'well known' integer computation counterpart
1259 /// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
1260 /// for code optimisation.
1262 for ( int i = 0; i < nbFrames; i++ )
1264 for ( int j = 0; j < l; j++ )
1266 R = 38142 *(*a-16) + 52298 *(*c -128);
1267 G = 38142 *(*a-16) - 26640 *(*c -128) - 12845 *(*b -128);
1268 B = 38142 *(*a-16) + 66093 *(*b -128);
1277 if (R > 255) R = 255;
1278 if (G > 255) G = 255;
1279 if (B > 255) B = 255;
1281 *(localRaw++) = (uint8_t)R;
1282 *(localRaw++) = (uint8_t)G;
1283 *(localRaw++) = (uint8_t)B;
1292 /// \brief Deals with the color decoding i.e. handle:
1293 /// - R, G, B planes (as opposed to RGB pixels)
1294 /// - YBR (various) encodings.
1295 /// - LUT[s] (or "PALETTE COLOR").
1297 void PixelReadConvert::ConvertHandleColor()
1299 //////////////////////////////////
1300 // Deal with the color decoding i.e. handle:
1301 // - R, G, B planes (as opposed to RGB pixels)
1302 // - YBR (various) encodings.
1303 // - LUT[s] (or "PALETTE COLOR").
1305 // The classification in the color decoding schema is based on the blending
1306 // of two Dicom tags values:
1307 // * "Photometric Interpretation" for which we have the cases:
1308 // - [Photo A] MONOCHROME[1|2] pictures,
1309 // - [Photo B] RGB or YBR_FULL_422 (which acts as RGB),
1310 // - [Photo C] YBR_* (with the above exception of YBR_FULL_422)
1311 // - [Photo D] "PALETTE COLOR" which indicates the presence of LUT[s].
1312 // * "Planar Configuration" for which we have the cases:
1313 // - [Planar 0] 0 then Pixels are already RGB
1314 // - [Planar 1] 1 then we have 3 planes : R, G, B,
1315 // - [Planar 2] 2 then we have 1 gray Plane and 3 LUTs
1317 // Now in theory, one could expect some coherence when blending the above
1318 // cases. For example we should not encounter files belonging at the
1319 // time to case [Planar 0] and case [Photo D].
1320 // Alas, this was only theory ! Because in practice some odd (read ill
1321 // formated Dicom) files (e.g. gdcmData/US-PAL-8-10x-echo.dcm) we encounter:
1322 // - "Planar Configuration" = 0,
1323 // - "Photometric Interpretation" = "PALETTE COLOR".
1324 // Hence gdcm will use the folowing "heuristic" in order to be tolerant
1325 // towards Dicom-non-conformant files:
1326 // << whatever the "Planar Configuration" value might be, a
1327 // "Photometric Interpretation" set to "PALETTE COLOR" forces
1328 // a LUT intervention >>
1330 // Now we are left with the following handling of the cases:
1331 // - [Planar 0] OR [Photo A] no color decoding (since respectively
1332 // Pixels are already RGB and monochrome pictures have no color :),
1333 // - [Planar 1] AND [Photo B] handled with ConvertRGBPlanesToRGBPixels()
1334 // - [Planar 1] AND [Photo C] handled with ConvertYcBcRPlanesToRGBPixels()
1335 // - [Planar 2] OR [Photo D] requires LUT intervention.
1337 gdcmDebugMacro("--> ConvertHandleColor "
1338 << "Planar Configuration " << PlanarConfiguration );
1342 // [Planar 2] OR [Photo D]: LUT intervention done outside
1343 gdcmDebugMacro("--> RawRGB : LUT intervention done outside");
1347 if ( PlanarConfiguration == 1 )
1351 // [Planar 1] AND [Photo C] (remember YBR_FULL_422 acts as RGB)
1352 gdcmDebugMacro("--> YBRFull");
1353 ConvertYcBcRPlanesToRGBPixels();
1357 // [Planar 1] AND [Photo C]
1358 gdcmDebugMacro("--> YBRFull");
1359 ConvertRGBPlanesToRGBPixels();
1364 // When planarConf is 0, and RLELossless (forbidden by Dicom norm)
1365 // pixels need to be RGB-fyied anyway
1369 gdcmDebugMacro("--> RLE Lossless");
1370 ConvertRGBPlanesToRGBPixels();
1373 // In *normal *case, when planarConf is 0, pixels are already in RGB
1376 /// Computes the Pixels Size
1377 void PixelReadConvert::ComputeRawAndRGBSizes()
1379 int bitsAllocated = BitsAllocated;
1380 // Number of "Bits Allocated" is fixed to 16 when it's 12, since
1381 // in this case we will expand the image to 16 bits (see
1382 // \ref ReadAndDecompress12BitsTo16Bits() )
1383 if ( BitsAllocated == 12 )
1388 RawSize = XSize * YSize * ZSize * TSize
1389 * ( bitsAllocated / 8 )
1393 RGBSize = 3 * RawSize; // works for 8 and 16 bits per Pixel
1399 RawSize += RawSize%2;
1400 RGBSize += RGBSize%2;
1403 /// Allocates room for RGB Pixels
1404 void PixelReadConvert::AllocateRGB()
1408 RGB = new uint8_t[RGBSize];
1411 /// Allocates room for RAW Pixels
1412 void PixelReadConvert::AllocateRaw()
1416 Raw = new uint8_t[RawSize];
1419 //-----------------------------------------------------------------------------
1422 * \brief Print self.
1423 * @param indent Indentation string to be prepended during printing.
1424 * @param os Stream to print to.
1426 void PixelReadConvert::Print( std::ostream &os, std::string const &indent )
1429 << "--- Pixel information -------------------------"
1432 << "Pixel Data: offset " << PixelOffset
1433 << " x(" << std::hex << PixelOffset << std::dec
1434 << ") length " << PixelDataLength
1435 << " x(" << std::hex << PixelDataLength << std::dec
1436 << ")" << std::endl;
1438 if ( IsRLELossless )
1442 RLEInfo->Print( os, indent );
1446 gdcmWarningMacro("Set as RLE file but NO RLEinfo present.");
1450 if ( IsJPEG2000 || IsJPEGLossless || IsJPEGLossy || IsJPEGLS )
1454 JPEGInfo->Print( os, indent );
1458 gdcmWarningMacro("Set as JPEG file but NO JPEGinfo present.");
1464 * \brief CallStartMethod
1466 void PixelReadConvert::CallStartMethod()
1470 CommandManager::ExecuteCommand(FH,CMD_STARTPROGRESS);
1474 * \brief CallProgressMethod
1476 void PixelReadConvert::CallProgressMethod()
1478 CommandManager::ExecuteCommand(FH,CMD_PROGRESS);
1482 * \brief CallEndMethod
1484 void PixelReadConvert::CallEndMethod()
1487 CommandManager::ExecuteCommand(FH,CMD_ENDPROGRESS);
1490 //-----------------------------------------------------------------------------
1491 } // end namespace gdcm
1493 // Note to developpers :
1494 // Here is a very detailled post from David Clunie, on the troubles caused
1495 // 'non standard' LUT and LUT description
1496 // We shall have to take it into accound in our code.
1501 Subject: Problem with VOI LUTs in Agfa and Fuji CR and GE DX images, was Re: VOI LUT issues
1502 Date: Sun, 06 Feb 2005 17:13:40 GMT
1503 From: David Clunie <dclunie@dclunie.com>
1504 Reply-To: dclunie@dclunie.com
1505 Newsgroups: comp.protocols.dicom
1506 References: <1107553502.040221.189550@o13g2000cwo.googlegroups.com>
1508 > THE LUT that comes with [my] image claims to be 16-bit, but none of the
1509 > values goes higher than 4095. That being said, though, none of my
1510 > original pixel values goes higher than that, either. I have read
1511 > elsewhere on this group that when that happens you are supposed to
1512 > adjust the LUT. Can someone be more specific? There was a thread from
1513 > 2002 where Marco and David were mentioning doing precisely that.
1520 You have encountered the well known "we know what the standard says but
1521 we are going to ignore it and do what we have been doing for almost
1522 a decade regardless" CR vendor bug. Agfa started this, but they are not
1523 the only vendor doing this now; GE and Fuji may have joined the club.
1525 Sadly, one needs to look at the LUT Data, figure out what the maximum
1526 value actually encoded is, and find the next highest power of 2 (e.g.
1527 212 in this case), to figure out what the range of the data is
1528 supposed to be. I have assumed that if the maximum value in the LUT
1529 data is less than a power of 2 minus 1 (e.g. 0xebc) then the intent
1530 of the vendor was not to use the maximum available grayscale range
1531 of the display (e.g. the maximum is 0xfff in this case). An alternative
1532 would be to scale to the actual maximum rather than a power of two.
1534 Very irritating, and in theory not totally reliable if one really
1535 intended the full 16 bits and only used, say 15, but that is extremely
1536 unlikely since everything would be too dark, and this heuristic
1539 There has never been anything in the standard that describes having
1540 to go through these convolutions. Since the only value in the
1541 standard that describes the bit depth of the LUT values is LUT
1542 Descriptor value 3 and that is (usually) always required to be
1543 either 8 or 16, it mystifies me how the creators' of these images
1544 imagine that the receiver is going to divine the range that is intended. Further, the standard is quite explicit that this 3rd
1545 value defines the range of LUT values, but as far as I am aware, all
1546 the vendors are ignoring the standard and indeed sending a third value
1549 This problem is not confined to CR, and is also seen with DX products.
1551 Typically I have seen:
1553 - Agfa CR, which usually (always ?) sends LUTs, values up to 0x0fff
1554 - Fuji CR, which occasionally send LUTs, values up to 0x03ff
1555 - GE DX, for presentation, which always have LUTs, up to 0x3fff
1557 Swissray, Siemens, Philips, Canon and Kodak never seem to send VOI LUTs
1558 at this point (which is a whole other problem). Note that the presence
1559 or absence of a VOI LUT as opposed to window values may be configurable
1560 on the modality in some cases, and I have just looked at what I happen
1561 to have received from a myriad of sites over whose configuration I have
1562 no control. This may be why the majority of Fuji images have no VOI LUTs,
1563 but a few do (or it may be the Siemens system that these Fuji images went
1564 through that perhaps added it). I do have some test Hologic DX images that
1565 are not from a clinical site that do actually get this right (a value
1566 of 12 for the third value and a max of 0xfff).
1568 Since almost every vendor that I have encountered that encodes LUTs
1569 makes this mistake, perhaps it is time to amend the standard to warn
1570 implementor's of receivers and/or sanction this bad behavior. We have
1571 talked about this in the past in WG 6 but so far everyone has been
1572 reluctant to write into the standard such a comment. Maybe it is time
1573 to try again, since if one is not aware of this problem, one cannot
1574 effectively implement display using VOI LUTs, and there is a vast
1575 installed base to contend with.
1577 I did not check presentation states, in which VOI LUTs could also be
1578 encountered, for the prevalence of this mistake, nor did I look at the
1579 encoding of Modality LUT's, which are unusual. Nor did I check digital
1580 mammography images. I would be interested to hear from anyone who has.
1584 PS. The following older thread in this newsgroup discusses this:
1586 "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"
1588 PPS. From a historical perspective, the following may be of interest.
1590 In the original standard in 1993, all that was said about this was a
1591 reference to the corresponding such where Modality LUTs are described
1594 "The third value specifies the number of bits for each entry in the
1595 LUT Data. It shall take the value 8 or 16. The LUT Data shall be stored
1596 in a format equivalent to 8 or 16 bits allocated and high bit equal
1599 Since the high bit hint was not apparently explicit enough, a very
1600 early CP, CP 15 (submitted by Agfa as it happens), replaced this with:
1602 "The third value conveys the range of LUT entry values. It shall take
1603 the value 8 or 16, corresponding with the LUT entry value range of
1606 Note: The third value is not required for describing the
1607 LUT data and is only included for informational usage
1608 and for maintaining compatibility with ACRNEMA 2.0.
1610 The LUT Data contains the LUT entry values."
1612 That is how it read in the 1996, 1998 and 1999 editions.
1614 By the 2000 edition, Supplement 33 that introduced presentation states
1615 extensively reworked this entire section and tried to explain this in
1618 "The output range is from 0 to 2^n-1 where n is the third value of LUT
1619 Descriptor. This range is always unsigned."
1621 and also added a note to spell out what the output range meant in the
1624 "9. The output of the Window Center/Width or VOI LUT transformation
1625 is either implicitly scaled to the full range of the display device
1626 if there is no succeeding transformation defined, or implicitly scaled
1627 to the full input range of the succeeding transformation step (such as
1628 the Presentation LUT), if present. See C.11.6.1."
1630 It still reads this way in the 2004 edition.
1632 Note that LUTs in other applications than the general VOI LUT allow for
1633 values other than 8 or 16 in the third value of LUT descriptor to permit
1634 ranges other than 0 to 255 or 65535.
1636 In addition, the DX Image Module specializes the VOI LUT
1637 attributes as follows, in PS 3.3 section C.8.11.3.1.5 (added in Sup 32):
1639 "The third value specifies the number of bits for each entry in the LUT
1640 Data (analogous to ìbits storedî). It shall be between 10-16. The LUT
1641 Data shall be stored in a format equivalent to 16 ìbits allocatedî and
1642 ìhigh bitî equal to ìbits storedî - 1. The third value conveys the range
1643 of LUT entry values. These unsigned LUT entry values shall range between
1644 0 and 2^n-1, where n is the third value of the LUT Descriptor."
1646 So in the case of the GE DX for presentation images, the third value of
1647 LUT descriptor is allowed to be and probably should be 14 rather than 16.