X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmPixelReadConvert.cxx;h=5b1ffc4b033d382d1ce9e8294409d68f1ac42ef7;hb=e7768bbebdc9a5972e396d71a3e848f5674ee378;hp=2a80ca647492d89ea74a77ab3fb9b68cc1f522aa;hpb=8fd45dc6d321d1419854dc0e4fa6a37d6826b655;p=gdcm.git diff --git a/src/gdcmPixelReadConvert.cxx b/src/gdcmPixelReadConvert.cxx index 2a80ca64..5b1ffc4b 100644 --- a/src/gdcmPixelReadConvert.cxx +++ b/src/gdcmPixelReadConvert.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmPixelReadConvert.cxx,v $ Language: C++ - Date: $Date: 2007/05/23 14:18:11 $ - Version: $Revision: 1.115 $ + Date: $Date: 2007/10/16 10:11:06 $ + Version: $Revision: 1.126 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -24,6 +24,7 @@ #include "gdcmDocEntry.h" #include "gdcmRLEFramesInfo.h" #include "gdcmJPEGFragmentsInfo.h" +#include "gdcmSegmentedPalette.h" #include #include //for sscanf @@ -35,7 +36,7 @@ namespace GDCM_NAME_SPACE { -//bool ReadMPEGFile (std::ifstream *fp, char *inputdata, size_t lenght); +//bool ReadMPEGFile (std::ifstream *fp, char *inputdata, size_t lenght); bool gdcm_read_JPEG2000_file (void* raw, char *inputdata, size_t inputlength); //----------------------------------------------------------------------------- @@ -44,7 +45,7 @@ bool gdcm_read_JPEG2000_file (void* raw, //----------------------------------------------------------------------------- // Constructor / Destructor /// Constructor -PixelReadConvert::PixelReadConvert() +PixelReadConvert::PixelReadConvert() { RGB = 0; RGBSize = 0; @@ -70,7 +71,7 @@ PixelReadConvert::~PixelReadConvert() // Public /** * \brief Predicate to know whether the image[s] (once Raw) is RGB. - * \note See comments of \ref ConvertHandleColor + * \note See comments of ConvertHandleColor */ bool PixelReadConvert::IsRawRGB() { @@ -97,11 +98,11 @@ void PixelReadConvert::GrabInformationsFromFile( File *file, { BitsAllocated = 16; } - - else if (BitsAllocated > 8 && BitsAllocated < 16 && BitsAllocated != 12) + 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(); @@ -154,13 +155,13 @@ void PixelReadConvert::GrabInformationsFromFile( File *file, } // 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). + // transfer syntax for the pixel data). IsPrivateGETransferSyntax = ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE ); - IsMPEG = IsJPEG2000 = IsJPEGLS = IsJPEGLossy = IsJPEGLossless = IsRLELossless = false; + IsMPEG = IsJPEG2000 = IsJPEGLS = IsJPEGLossy = IsJPEGLossless = IsRLELossless = false; if (!IsRaw) - { + { while(true) { // mind the order : check the most usual first. @@ -170,7 +171,8 @@ void PixelReadConvert::GrabInformationsFromFile( File *file, 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 !) + // DeflatedExplicitVRLittleEndian is considered as 'Unexpected' + // (we don't know yet how to process !) gdcmWarningMacro("Unexpected Transfer Syntax :[" << ts << "]"); break; } @@ -194,51 +196,114 @@ void PixelReadConvert::GrabInformationsFromFile( File *file, HasLUT = file->HasLUT(); if ( HasLUT ) { - // Just in case some access to a File element requires disk access. +/* + 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 ); - - // 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"); - } + // 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; @@ -323,7 +388,7 @@ bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp ) } if (remainingLength !=0 ) fp->read( raw, remainingLength); - + if ( fp->fail() || fp->eof()) { gdcmWarningMacro( "Reading of Raw pixel data failed." ); @@ -381,9 +446,9 @@ void PixelReadConvert::Squeeze() delete [] Raw; Raw = 0; - if ( LutRGBA ) - delete [] LutRGBA; - LutRGBA = 0; + //if ( LutRGBA ) + // delete [] LutRGBA; + //LutRGBA = 0; } /** @@ -513,33 +578,60 @@ bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp ) // jpeg2000 stream to use jasper: // I don't think we'll ever be able to deal with multiple fragments properly - unsigned long inputlength = 0; - JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment(); - while( jpegfrag ) - { + if( ZSize == 1 ) + { + unsigned long inputlength = 0; + JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment(); + while( jpegfrag ) + { inputlength += jpegfrag->GetLength(); jpegfrag = JPEGInfo->GetNextFragment(); - } - gdcmAssertMacro( inputlength != 0); - uint8_t *inputdata = new uint8_t[inputlength]; - char *pinputdata = (char*)inputdata; - jpegfrag = JPEGInfo->GetFirstFragment(); - while( jpegfrag ) - { + } + gdcmAssertMacro( inputlength != 0); + uint8_t *inputdata = new uint8_t[inputlength]; + char *pinputdata = (char*)inputdata; + jpegfrag = JPEGInfo->GetFirstFragment(); + while( jpegfrag ) + { fp->seekg( jpegfrag->GetOffset(), std::ios::beg); fp->read(pinputdata, jpegfrag->GetLength()); pinputdata += jpegfrag->GetLength(); jpegfrag = JPEGInfo->GetNextFragment(); - } - // Warning the inputdata buffer is delete in the function - if ( ! gdcm_read_JPEG2000_file( Raw, - (char*)inputdata, inputlength ) ) - { + } + // Warning the inputdata buffer is deleted in the function + if ( gdcm_read_JPEG2000_file( Raw, + (char*)inputdata, inputlength ) ) + { return true; - } - // wow what happen, must be an error - gdcmWarningMacro( "gdcm_read_JPEG2000_file() failed "); - return false; + } + // wow what happen, must be an error + gdcmWarningMacro( "gdcm_read_JPEG2000_file() failed "); + return false; + } + else + { + if( (unsigned int)ZSize != JPEGInfo->GetFragmentCount() ) + { + gdcmErrorMacro( "Sorry GDCM does not handle this type of fragments" ); + return false; + } + // Hopefully every dicom fragment is *exactly* the j2k stream + JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment(); + char *praw = (char*)Raw; + while( jpegfrag ) + { + unsigned long inputlength = jpegfrag->GetLength(); + char *inputdata = new char[inputlength]; + fp->seekg( jpegfrag->GetOffset(), std::ios::beg); + fp->read(inputdata, jpegfrag->GetLength()); + // Warning the inputdata buffer is deleted in the function + gdcm_read_JPEG2000_file( praw, + inputdata, inputlength) ; + praw += XSize*YSize*SamplesPerPixel*(BitsAllocated/8); + jpegfrag = JPEGInfo->GetNextFragment(); + } + return true; + } } else if ( IsJPEGLS ) { @@ -595,7 +687,13 @@ bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp ) int length = XSize * YSize * ZSize * SamplesPerPixel; int numberBytes = BitsAllocated / 8; - JPEGInfo->DecompressFromFile(fp, Raw, BitsStored, numberBytes, length ); + // to avoid major troubles when BitsStored == 8 && BitsAllocated==16 ! + int dummy; + if (BitsStored == 8 && BitsAllocated==16) + dummy = 16; + else + dummy = BitsStored; + JPEGInfo->DecompressFromFile(fp, Raw, dummy, numberBytes, length ); return true; } } @@ -838,7 +936,7 @@ void PixelReadConvert::BuildLUTRGBA() } /** - * \brief Swap the bytes, according to \ref SwapCode. + * \brief Swap the bytes, according to SwapCode. */ void PixelReadConvert::ConvertSwapZone() { @@ -1065,27 +1163,38 @@ bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError ) { // pmask : to mask the 'unused bits' (may contain overlays) uint16_t pmask = 0xffff; - pmask = pmask >> ( BitsAllocated - BitsStored ); + + // It's up to the user to decide if he wants to ignore overlays (if any), + // not to gdcm, without asking. + // default is NOT TO LOAD, in order not to confuse ITK users (and others!). + + if ( !FH->GetKeepOverlays() ) // mask spurious bits ! (overlay are NOT loaded!) + { + pmask = pmask >> ( BitsAllocated - BitsStored ); + } + // else : it's up to the user to manage the 'pixels + overlays' he just loaded! uint16_t *deb = (uint16_t*)Raw; if ( !PixelSign ) // Pixels are unsigned { for(int i = 0; i> (BitsStored - HighBitPosition - 1)) & pmask; deb++; } } else // Pixels are signed { + // Hope there is never ACR-NEMA-like overlays within signed pixels (?!?) + // smask : to check the 'sign' when BitsStored != BitsAllocated uint16_t smask = 0x0001; smask = smask << ( 16 - (BitsAllocated - BitsStored + 1) ); // nmask : to propagate sign bit on negative values int16_t nmask = (int16_t)0x8000; nmask = nmask >> ( BitsAllocated - BitsStored - 1 ); - + for(int i = 0; i> (BitsStored - HighBitPosition - 1); @@ -1187,9 +1296,9 @@ void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels() // except for the few patches of color on the image. // On such images, RLE achieves a compression ratio that is much better // than the compression ratio on an equivalent RGB image. - + gdcmWarningMacro("--> ConvertYcBcRPlanesToRGBPixels"); - + uint8_t *localRaw = Raw; uint8_t *copyRaw = new uint8_t[ RawSize ]; memmove( copyRaw, localRaw, RawSize ); @@ -1199,7 +1308,7 @@ void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels() // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf // and be *very* affraid // - + /// \todo : find an example to see how 3rd dim and 4th dim work together int l = XSize * YSize * TSize; int nbFrames = ZSize; @@ -1335,7 +1444,7 @@ void PixelReadConvert::ComputeRawAndRGBSizes() int bitsAllocated = BitsAllocated; // Number of "Bits Allocated" is fixed to 16 when it's 12, since // in this case we will expand the image to 16 bits (see - // \ref ReadAndDecompress12BitsTo16Bits() ) + // ReadAndDecompress12BitsTo16Bits() ) if ( BitsAllocated == 12 ) { bitsAllocated = 16; @@ -1352,6 +1461,8 @@ void PixelReadConvert::ComputeRawAndRGBSizes() { RGBSize = RawSize; } + RawSize += RawSize%2; + RGBSize += RGBSize%2; } /// Allocates room for RGB Pixels @@ -1441,7 +1552,6 @@ void PixelReadConvert::CallEndMethod() CommandManager::ExecuteCommand(FH,CMD_ENDPROGRESS); } - //----------------------------------------------------------------------------- } // end namespace gdcm