+/**
+ * \brief Predicate to know whether the image[s] (once Raw) is RGB.
+ * \note See comments of ConvertHandleColor
+ */
+bool PixelReadConvert::IsRawRGB()
+{
+ if ( IsMonochrome
+ || PlanarConfiguration == 2
+ || IsPaletteColor )
+ {
+ return false;
+ }
+ return true;
+}
+/**
+ * \brief Gets various usefull informations from the file header
+ * @param file gdcm::File pointer
+ * @param fileHelper gdcm::FileHelper pointer
+ */
+void PixelReadConvert::GrabInformationsFromFile( File *file,
+ FileHelper *fileHelper )
+{
+ // Number of Bits Allocated for storing a Pixel is defaulted to 16
+ // when absent from the file.
+ BitsAllocated = file->GetBitsAllocated();
+ if ( BitsAllocated == 0 )
+ {
+ BitsAllocated = 16;
+ }
+ else if ( BitsAllocated > 8 && BitsAllocated < 16 && BitsAllocated != 12 )
+ {
+ BitsAllocated = 16;
+ }
+
+ // Number of "Bits Stored", defaulted to number of "Bits Allocated"
+ // when absent from the file.
+ BitsStored = file->GetBitsStored();
+ if ( BitsStored == 0 )
+ {
+ BitsStored = BitsAllocated;
+ }
+
+ // High Bit Position, defaulted to "Bits Allocated" - 1
+ HighBitPosition = file->GetHighBitPosition();
+ if ( HighBitPosition == 0 )
+ {
+ HighBitPosition = BitsAllocated - 1;
+ }
+
+ XSize = file->GetXSize();
+ YSize = file->GetYSize();
+ ZSize = file->GetZSize();
+ TSize = file->GetTSize();
+ SamplesPerPixel = file->GetSamplesPerPixel();
+ //PixelSize = file->GetPixelSize(); Useless
+ PixelSign = file->IsSignedPixelData();
+ SwapCode = file->GetSwapCode();
+
+ IsPrivateGETransferSyntax = IsMPEG
+ = IsJPEG2000 = IsJPEGLS = IsJPEGLossy
+ = IsJPEGLossless = IsRLELossless
+ = false;
+
+ if (! file->IsDicomV3() ) // Should be ACR-NEMA file
+ {
+ IsRaw = true;
+ }
+ else
+ {
+ std::string ts = file->GetTransferSyntax();
+
+ IsRaw = false;
+ while (true) // shorter to write than 'if elseif elseif elseif' ...
+ {
+ // mind the order : check the most usual first.
+ if( IsRaw = (Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian)) break;
+ if( IsRaw = (Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian)) break;
+ if( IsRaw = (Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian)) break;
+ if( IsRaw = (Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE)) break;
+ // DeflatedExplicitVRLittleEndian syntax means the whole Dataset (Header + Pixels) is compressed !
+ // Not dealt with ! (Parser hangs)
+ //if( IsRaw = Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian) break;
+ break;
+ }
+ // cache whether this is a strange GE transfer syntax (which uses
+ // a little endian transfer syntax for the header and a big endian
+ // transfer syntax for the pixel data).
+ IsPrivateGETransferSyntax =
+ ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE );
+
+ IsMPEG = IsJPEG2000 = IsJPEGLS = IsJPEGLossy = IsJPEGLossless = IsRLELossless = false;
+ if (!IsRaw)
+ {
+ while(true)
+ {
+ // mind the order : check the most usual first.
+ if( IsJPEGLossy = (Global::GetTS()->IsJPEGLossy(ts))) break;
+ if( IsJPEGLossless = (Global::GetTS()->IsJPEGLossless(ts))) break;
+ if( IsRLELossless = (Global::GetTS()->IsRLELossless(ts))) break;
+ if( IsJPEG2000 = (Global::GetTS()->IsJPEG2000(ts))) break;
+ if( IsMPEG = (Global::GetTS()->IsMPEG(ts))) break;
+ if( IsJPEGLS = (Global::GetTS()->IsJPEGLS(ts))) break;
+ // DeflatedExplicitVRLittleEndian is considered as 'Unexpected'
+ // (we don't know yet how to process !)
+ gdcmWarningMacro("Unexpected Transfer Syntax :[" << ts << "]");
+ break;
+ }
+ }
+ }
+
+ PixelOffset = file->GetPixelOffset();
+ PixelDataLength = file->GetPixelAreaLength();
+ RLEInfo = file->GetRLEInfo();
+ JPEGInfo = file->GetJPEGInfo();
+
+ IsMonochrome = file->IsMonochrome();
+ IsMonochrome1 = file->IsMonochrome1();
+ IsPaletteColor = file->IsPaletteColor();
+ IsYBRFull = file->IsYBRFull();
+
+ PlanarConfiguration = file->GetPlanarConfiguration();
+
+ /////////////////////////////////////////////////////////////////
+ // LUT section:
+ HasLUT = file->HasLUT();
+ if ( HasLUT )
+ {
+/*
+ C.7.6.3.1.5
+ The three values of Palette Color Lookup Table Descriptor (0028,1101-1103)
+ describe the format of the Lookup Table Data in the corresponding
+ Data Element (0028,1201-1203) or (0028,1221-1223).
+
+ The first value is the number of entries in the lookup table.
+ When the number of table entries is equal to 2**16 then this value shall be 0.
+
+ The second value is the first stored pixel value mapped.
+ This pixel value is mapped to the first entry in the Lookup Table Data.
+ All image pixel values less than the first entry value mapped are also
+ mapped to the first entry in the Lookup Table Data.
+ An image pixel value one greater than the first entry value mapped is
+ mapped to the second entry in the Lookup Table Data.
+ Subsequent image pixel values are mapped to the subsequent entries in
+ the Lookup Table Data up to an image pixel value equal to number of
+ entries + first entry value mapped - 1 which is mapped to the last entry
+ in the Lookup Table Data.
+ Image pixel values greater than or equal to number of entries + first entry
+ value mapped are also mapped to the last entry in the Lookup Table Data.
+
+ The third value specifies the number of bits for each entry in the Lookup
+ Table Data. It shall take the value of 8 or 16.
+ The LUT Data shall be stored in a format equivalent to 8 or 16 bits
+ allocated where the high bit is equal to bits allocated-1.
+
+ When the Palette Color Lookup Table Descriptor (0028,1101-1103) are used as
+ part of the Palette Color Lookup Table Module, the third value shall be
+ equal to 16.
+
+ Note: A value of 16 indicates the Lookup Table Data will range from (0,0,0)
+ minimum intensity to (65535,65535,65535) maximum intensity.
+
+*/
+
+ // Just in case some access to a File element requires disk access.
+ LutRedDescriptor = file->GetEntryString( 0x0028, 0x1101 );
+ LutGreenDescriptor = file->GetEntryString( 0x0028, 0x1102 );
+ LutBlueDescriptor = file->GetEntryString( 0x0028, 0x1103 );
+ // Is it a Segmented Palette ? Check if we find the red one:
+ if( file->GetDocEntry(0x0028,0x1221) ) // no need to check for blue & green
+ {
+ GDCM_NAME_SPACE::TagKey DCM_RedPaletteColorLookupTableDescriptor (0x0028, 0x1101);
+ GDCM_NAME_SPACE::TagKey DCM_GreenPaletteColorLookupTableDescriptor (0x0028, 0x1102);
+ GDCM_NAME_SPACE::TagKey DCM_BluePaletteColorLookupTableDescriptor (0x0028, 0x1103);
+
+ GDCM_NAME_SPACE::TagKey DCM_SegmentedRedPaletteColorLookupTableData (0x0028, 0x1221);
+ GDCM_NAME_SPACE::TagKey DCM_SegmentedGreenPaletteColorLookupTableData (0x0028, 0x1222);
+ GDCM_NAME_SPACE::TagKey DCM_SegmentedBluePaletteColorLookupTableData (0x0028, 0x1223);
+
+
+ LutRedData = new uint8_t[65535*2]; // FIXME: leak
+ LutGreenData = new uint8_t[65535*2];
+ LutBlueData = new uint8_t[65535*2];
+ // TODO need to check file is indeed PALETTE COLOR:
+ ReadPaletteInto(file, DCM_RedPaletteColorLookupTableDescriptor,
+ DCM_SegmentedRedPaletteColorLookupTableData,LutRedData);
+ ReadPaletteInto(file, DCM_GreenPaletteColorLookupTableDescriptor,
+ DCM_SegmentedGreenPaletteColorLookupTableData,LutGreenData);
+ ReadPaletteInto(file, DCM_BluePaletteColorLookupTableDescriptor,
+ DCM_SegmentedBluePaletteColorLookupTableData,LutBlueData);
+
+ }
+ else
+ {
+
+ // FIXME : The following comment is probabely meaningless, since LUT are *always*
+ // loaded at parsing time, whatever their length is.
+
+ // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
+ // [ refer to invocation of Document::SetMaxSizeLoadEntry() in
+ // Document::Document() ], the loading of the value (content) of a
+ // [Bin|Val]Entry occurence migth have been hindered (read simply NOT
+ // loaded). Hence, we first try to obtain the LUTs data from the file
+ // and when this fails we read the LUTs data directly from disk.
+ // \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
+ // We should NOT bypass the [Bin|Val]Entry class. Instead
+ // an access to an UNLOADED content of a [Bin|Val]Entry occurence
+ // (e.g. DataEntry::GetBinArea()) should force disk access from
+ // within the [Bin|Val]Entry class itself. The only problem
+ // is that the [Bin|Val]Entry is unaware of the FILE* is was
+ // parsed from. Fix that. FIXME.
+
+ // //// Red round
+ file->LoadEntryBinArea(0x0028, 0x1201);
+ LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
+ if ( ! LutRedData )
+ {
+ gdcmWarningMacro("Unable to read Red Palette Color Lookup Table data");
+ }
+
+ // //// Green round:
+ file->LoadEntryBinArea(0x0028, 0x1202);
+ LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
+ if ( ! LutGreenData)
+ {
+ gdcmWarningMacro("Unable to read Green Palette Color Lookup Table data");
+ }
+
+ // //// Blue round:
+ file->LoadEntryBinArea(0x0028, 0x1203);
+ LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
+ if ( ! LutBlueData )
+ {
+ gdcmWarningMacro("Unable to read Blue Palette Color Lookup Table data");
+ }
+ }
+ }
+ FileInternal = file;
+ FH = fileHelper;
+ ComputeRawAndRGBSizes();
+}
+
+/// \brief Reads from disk and decompresses Pixels
+bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
+{
+ // ComputeRawAndRGBSizes is already made by
+ // ::GrabInformationsFromfile. So, the structure sizes are
+ // correct
+ Squeeze();
+
+ //////////////////////////////////////////////////
+ //// First stage: get our hands on the Pixel Data.
+ if ( !fp )
+ {
+ gdcmWarningMacro( "Unavailable file pointer." );
+ return false;
+ }
+
+ fp->seekg( PixelOffset, std::ios::beg );
+ if ( fp->fail() || fp->eof() )
+ {
+ gdcmWarningMacro( "Unable to find PixelOffset in file." );
+ return false;
+ }
+
+ AllocateRaw();
+
+ //////////////////////////////////////////////////
+
+ CallStartMethod(); // for progress bar
+ unsigned int count = 0;
+ unsigned int frameSize;
+ unsigned int bitsAllocated = BitsAllocated;
+ //if(bitsAllocated == 12)
+ if(bitsAllocated > 8 && bitsAllocated < 16)
+ bitsAllocated = 16;
+ frameSize = XSize*YSize*SamplesPerPixel*bitsAllocated/8;
+
+ //// Second stage: read from disk and decompress.
+
+ if ( BitsAllocated == 12 ) // We suppose 'BitsAllocated' = 12 only exist for uncompressed files
+ {
+ ReadAndDecompress12BitsTo16Bits( fp);
+ }
+ else if ( IsRaw )
+ {
+ // This problem can be found when some obvious informations are found
+ // after the field containing the image data. In this case, these
+ // bad data are added to the size of the image (in the PixelDataLength
+ // variable). But RawSize is the right size of the image !
+ if ( PixelDataLength != RawSize )
+ {
+ gdcmWarningMacro( "Mismatch between PixelReadConvert : "
+ << PixelDataLength << " and RawSize : " << RawSize );
+ }
+
+ //todo : is it the right patch?
+ char *raw = (char*)Raw;
+ uint32_t remainingLength;
+ unsigned int i;
+ unsigned int lengthToRead;
+
+ if ( PixelDataLength > RawSize )
+ lengthToRead = RawSize;
+ else
+ lengthToRead = PixelDataLength;
+
+ // perform a frame by frame reading
+ remainingLength = lengthToRead;
+ unsigned int nbFrames = lengthToRead / frameSize;
+ for (i=0;i<nbFrames; i++)
+ {
+ Progress = (float)(count+1)/(float)nbFrames;
+ fp->read( raw, frameSize);
+ raw += frameSize;
+ remainingLength -= frameSize;
+ count++;
+ }
+ if (remainingLength !=0 )
+ fp->read( raw, remainingLength);
+
+ if ( fp->fail() || fp->eof())
+ {
+ gdcmWarningMacro( "Reading of Raw pixel data failed." );
+ return false;
+ }
+ }
+ else if ( IsRLELossless )
+ {
+ if ( ! RLEInfo->DecompressRLEFile
+ ( fp, Raw, XSize, YSize, ZSize, TSize, BitsAllocated ) )
+ {
+ gdcmWarningMacro( "RLE decompressor failed." );
+ return false;
+ }
+ }
+ else if ( IsMPEG )
+ {
+ //gdcmWarningMacro( "Sorry, MPEG not yet taken into account" );
+ //return false;
+ // fp has already been seek to start of mpeg
+ //ReadMPEGFile(fp, (char*)Raw, PixelDataLength);
+ return true;
+ }
+ else
+ {
+ // Default case concerns JPEG family
+ if ( ! ReadAndDecompressJPEGFile( fp ) )
+ {
+ gdcmWarningMacro( "JPEG decompressor ( ReadAndDecompressJPEGFile()"
+ << " method ) failed." );
+ return false;
+ }
+ }
+
+ ////////////////////////////////////////////
+ //// Third stage: twigle the bytes and bits.
+ ConvertReorderEndianity();
+ ConvertReArrangeBits();
+ ConvertFixGreyLevels();
+ if (UserFunction) // user is allowed to Mirror, TopDown, Rotate,...the image
+ UserFunction( Raw, FileInternal);
+ ConvertHandleColor();
+
+ return true;
+}
+
+/// Deletes Pixels Area