From eafd36f8a658f5d3b29e733bf87540150feaddf6 Mon Sep 17 00:00:00 2001 From: frog Date: Tue, 12 Oct 2004 09:59:44 +0000 Subject: [PATCH] * CLEANUP_ROUND (11) for gdcmPixelConvert (cafeine is my friend stage) src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: - more code moved away from File:: to PixelConvert:: - fat setup of PixelConverter set in place in File::Initialise. --- ChangeLog | 8 +- src/gdcmFile.cxx | 287 ++++++++++--------------------------- src/gdcmFile.h | 14 +- src/gdcmPixelConvert.cxx | 301 ++++++++++++++++++++++++++------------- src/gdcmPixelConvert.h | 139 ++++++++++-------- 5 files changed, 376 insertions(+), 373 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7b3e64d3..e9dc5656 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,16 @@ +2004-10-12 Eric Boix + * CLEANUP_ROUND (11) for gdcmPixelConvert (cafeine is my friend stage) + src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: + - more code moved away from File:: to PixelConvert:: + - fat setup of PixelConverter set in place in File::Initialise. + 2004-10-10 Eric Boix * CLEANUP_ROUND (10) for gdcmPixelConvert (Xanax is my friend stage) The JPEG fragments are now parsed at the same stage than the RLE information. All code related to JPEG is now in gdcmPixelConvert: - src/gdcmJPEGFragment.h and gdcmJPEGFragmentsInfo.[h|cxx] added - src/gdcmJpeg12.cxx, gdcmJpeg2000.cxx and gdcmJpeg8.cxx no longer - export a gdcmFile:: method. This are simply global functions + export a gdcmFile:: method. Those are simply global functions (for the time being this is better than having them attach to either gdcmFile:: or gdcmPixelConvert::). - src/gdcmDocument.[cxx|h], gdcmDocument:: now parser the JPEG fragments diff --git a/src/gdcmFile.cxx b/src/gdcmFile.cxx index 3484aecf..9a9dc3ae 100644 --- a/src/gdcmFile.cxx +++ b/src/gdcmFile.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmFile.cxx,v $ Language: C++ - Date: $Date: 2004/10/12 04:35:46 $ - Version: $Revision: 1.139 $ + Date: $Date: 2004/10/12 09:59:45 $ + Version: $Revision: 1.140 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -18,7 +18,6 @@ #include "gdcmFile.h" #include "gdcmDebug.h" -#include "gdcmPixelConvert.h" namespace gdcm { @@ -84,6 +83,64 @@ void File::Initialise() { ImageDataSize = ImageDataSizeRaw; } + + + + + // Just in case some access to a Header element requires disk access: + FILE* fp = HeaderInternal->OpenFile(); + // Number of Bits Allocated for storing a Pixel is defaulted to 16 + // when absent from the header. + int numberBitsAllocated = HeaderInternal->GetBitsAllocated(); + if ( numberBitsAllocated == 0 ) + { + numberBitsAllocated = 16; + } + PixelConverter.SetBitsAllocated( numberBitsAllocated ); + + // Number of "Bits Stored" defaulted to number of "Bits Allocated" + // when absent from the header. + int numberBitsStored = HeaderInternal->GetBitsStored(); + if ( numberBitsStored == 0 ) + { + numberBitsStored = numberBitsAllocated; + } + PixelConverter.SetBitsStored( numberBitsStored ); + + // High Bit Position + int highBitPosition = HeaderInternal->GetHighBitPosition(); + if ( highBitPosition == 0 ) + { + highBitPosition = numberBitsAllocated - 1; + } + PixelConverter.SetHighBitPosition( highBitPosition ); + + + PixelConverter.SetXSize( HeaderInternal->GetXSize() ); + PixelConverter.SetYSize( HeaderInternal->GetYSize() ); + PixelConverter.SetZSize( HeaderInternal->GetZSize() ); + PixelConverter.SetSamplesPerPixel( HeaderInternal->GetSamplesPerPixel() ); + PixelConverter.SetPixelSize( HeaderInternal->GetPixelSize() ); + PixelConverter.SetPixelSign( HeaderInternal->IsSignedPixelData() ); + PixelConverter.SetSwapCode( HeaderInternal->GetSwapCode() ); + PixelConverter.SetIsUncompressed( + ! HeaderInternal->IsDicomV3() + || HeaderInternal->IsImplicitVRLittleEndianTransferSyntax() + || HeaderInternal->IsExplicitVRLittleEndianTransferSyntax() + || HeaderInternal->IsExplicitVRBigEndianTransferSyntax() + || HeaderInternal->IsDeflatedExplicitVRLittleEndianTransferSyntax() ); + PixelConverter.SetIsJPEG2000( HeaderInternal->IsJPEG2000() ); + PixelConverter.SetIsJPEGLossless( HeaderInternal->IsJPEGLossless() ); + PixelConverter.SetIsRLELossless( + HeaderInternal->IsRLELossLessTransferSyntax() ); + PixelConverter.SetPixelOffset( HeaderInternal->GetPixelOffset() ); + PixelConverter.SetPixelDataLength( HeaderInternal->GetPixelAreaLength() ); + PixelConverter.SetRLEInfo( &(HeaderInternal->RLEInfo) ); + PixelConverter.SetJPEGInfo( &(HeaderInternal->JPEGInfo) ); + PixelConverter.SetDecompressedSize( ImageDataSize ); + + HeaderInternal->CloseFile(); + } SaveInitialValues(); } @@ -266,8 +323,11 @@ int File::ComputeDecompressedPixelDataSizeFromHeader() // 0028|1202 [US] [Green Palette Color Lookup Table Data] // 0028|1203 [US] [Blue Palette Color Lookup Table Data] - // Number of "Bits Allocated" int numberBitsAllocated = HeaderInternal->GetBitsAllocated(); + // Number of "Bits Allocated" is fixed to 16 when: + // - it is not defined (i.e. it's value is 0) + // - it's 12, since we will expand the image to 16 bits (see + // PixelConvert::ConvertDecompress12BitsTo16Bits() ) if ( ( numberBitsAllocated == 0 ) || ( numberBitsAllocated == 12 ) ) { numberBitsAllocated = 16; @@ -496,45 +556,13 @@ size_t File::GetImageDataIntoVectorRaw (void* destination, size_t maxSize) return (size_t)0; } - ReadPixelData( destination ); - - // Number of Bits Allocated for storing a Pixel - int numberBitsAllocated = HeaderInternal->GetBitsAllocated(); - if ( numberBitsAllocated == 0 ) - { - numberBitsAllocated = 16; - } - - // Number of Bits actually used - int numberBitsStored = HeaderInternal->GetBitsStored(); - if ( numberBitsStored == 0 ) - { - numberBitsStored = numberBitsAllocated; - } - - // High Bit Position - int highBitPosition = HeaderInternal->GetHighBitPosition(); - if ( highBitPosition == 0 ) - { - highBitPosition = numberBitsAllocated - 1; - } - - bool signedPixel = HeaderInternal->IsSignedPixelData(); - - PixelConvert::ConvertReorderEndianity( - (uint8_t*) destination, - ImageDataSize, - numberBitsStored, - numberBitsAllocated, - HeaderInternal->GetSwapCode(), - signedPixel ); - - PixelConvert::ConvertReArrangeBits( - (uint8_t*) destination, - ImageDataSize, - numberBitsStored, - numberBitsAllocated, - highBitPosition ); + FILE* fp = HeaderInternal->OpenFile(); + PixelConverter.ReadAndDecompressPixelData( destination, fp ); + HeaderInternal->CloseFile(); + + PixelConverter.ReorderEndianity( (uint8_t*) destination ); + + PixelConverter.ReArrangeBits( (uint8_t*) destination ); #ifdef GDCM_DEBUG FILE* DebugFile; @@ -579,18 +607,20 @@ size_t File::GetImageDataIntoVectorRaw (void* destination, size_t maxSize) if ( planConf == 1 ) { - uint8_t* newDest = new uint8_t[ImageDataSize]; // Warning : YBR_FULL_422 acts as RGB if ( HeaderInternal->IsYBRFull() ) { - ConvertYcBcRPlanesToRGBPixels((uint8_t*)destination, newDest); + PixelConverter.ConvertYcBcRPlanesToRGBPixels( + (uint8_t*)destination, + ImageDataSize ); } else { - ConvertRGBPlanesToRGBPixels((uint8_t*)destination, newDest); + PixelConverter.ConvertRGBPlanesToRGBPixels( + (uint8_t*)destination, + ImageDataSize ); } - memmove(destination, newDest, ImageDataSize); - delete[] newDest; + } /////////////////////////////////////////////////// @@ -616,77 +646,6 @@ size_t File::GetImageDataIntoVectorRaw (void* destination, size_t maxSize) return ImageDataSize; } -/** - * \brief Convert (Y plane, cB plane, cR plane) to RGB pixels - * \warning Works on all the frames at a time - */ -void File::ConvertYcBcRPlanesToRGBPixels(uint8_t* source, - uint8_t* destination) -{ - // to see the tricks about YBR_FULL, YBR_FULL_422, - // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at : - // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf - // and be *very* affraid - // - int l = HeaderInternal->GetXSize() * HeaderInternal->GetYSize(); - int nbFrames = HeaderInternal->GetZSize(); - - uint8_t* a = source; - uint8_t* b = source + l; - uint8_t* c = source + l + l; - double R, G, B; - - /// \todo : Replace by the 'well known' integer computation - /// counterpart. Refer to - /// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf - /// for code optimisation. - - for (int i = 0; i < nbFrames; i++) - { - for (int j = 0; j < l; j++) - { - R = 1.164 *(*a-16) + 1.596 *(*c -128) + 0.5; - G = 1.164 *(*a-16) - 0.813 *(*c -128) - 0.392 *(*b -128) + 0.5; - B = 1.164 *(*a-16) + 2.017 *(*b -128) + 0.5; - - if (R < 0.0) R = 0.0; - if (G < 0.0) G = 0.0; - if (B < 0.0) B = 0.0; - if (R > 255.0) R = 255.0; - if (G > 255.0) G = 255.0; - if (B > 255.0) B = 255.0; - - *(destination++) = (uint8_t)R; - *(destination++) = (uint8_t)G; - *(destination++) = (uint8_t)B; - a++; - b++; - c++; - } - } -} - -/** - * \brief Convert (Red plane, Green plane, Blue plane) to RGB pixels - * \warning Works on all the frames at a time - */ -void File::ConvertRGBPlanesToRGBPixels(uint8_t* source, - uint8_t* destination) -{ - int l = HeaderInternal->GetXSize() * HeaderInternal->GetYSize() * HeaderInternal->GetZSize(); - - uint8_t* a = source; - uint8_t* b = source + l; - uint8_t* c = source + l + l; - - for (int j = 0; j < l; j++) - { - *(destination++) = *(a++); - *(destination++) = *(b++); - *(destination++) = *(c++); - } -} - /** * \brief Points the internal Pixel_Data pointer to the callers inData * image representation, BUT WITHOUT COPYING THE DATA. @@ -874,95 +833,5 @@ bool File::WriteBase (std::string const & fileName, FileType type) return true; } -//----------------------------------------------------------------------------- -// Private -/** - * \brief Read pixel data from disk (optionaly decompressing) into the - * caller specified memory location. - * @param destination where the pixel data should be stored. - * - */ -bool File::ReadPixelData(void* destination) -{ - FILE* fp = HeaderInternal->OpenFile(); - - if ( !fp ) - { - return false; - } - if ( fseek(fp, HeaderInternal->GetPixelOffset(), SEEK_SET) == -1 ) - { - HeaderInternal->CloseFile(); - return false; - } - - if ( HeaderInternal->GetBitsAllocated() == 12 ) - { - PixelConvert::ConvertDecompress12BitsTo16Bits( - (uint8_t*)destination, - HeaderInternal->GetXSize(), - HeaderInternal->GetYSize(), - fp); - HeaderInternal->CloseFile(); - return true; - } - - // ---------------------- Uncompressed File - if ( !HeaderInternal->IsDicomV3() || - HeaderInternal->IsImplicitVRLittleEndianTransferSyntax() || - HeaderInternal->IsExplicitVRLittleEndianTransferSyntax() || - HeaderInternal->IsExplicitVRBigEndianTransferSyntax() || - HeaderInternal->IsDeflatedExplicitVRLittleEndianTransferSyntax() ) - { - size_t ItemRead = fread(destination, HeaderInternal->GetPixelAreaLength(), 1, fp); - HeaderInternal->CloseFile(); - if ( ItemRead != 1 ) - { - return false; - } - else - { - return true; - } - } - - // ---------------------- Run Length Encoding - if ( HeaderInternal->IsRLELossLessTransferSyntax() ) - { - bool res = PixelConvert::ReadAndDecompressRLEFile( - destination, - HeaderInternal->GetXSize(), - HeaderInternal->GetYSize(), - HeaderInternal->GetZSize(), - HeaderInternal->GetBitsAllocated(), - &(HeaderInternal->RLEInfo), - fp ); - HeaderInternal->CloseFile(); - return res; - } - - // --------------- SingleFrame/Multiframe JPEG Lossless/Lossy/2000 - int numberBitsAllocated = HeaderInternal->GetBitsAllocated(); - if ( ( numberBitsAllocated == 0 ) || ( numberBitsAllocated == 12 ) ) - { - numberBitsAllocated = 16; - } - - bool res = PixelConvert::ReadAndDecompressJPEGFile( - (uint8_t*)destination, - HeaderInternal->GetXSize(), - HeaderInternal->GetYSize(), - HeaderInternal->GetBitsAllocated(), - HeaderInternal->GetBitsStored(), - HeaderInternal->GetSamplesPerPixel(), - HeaderInternal->GetPixelSize(), - HeaderInternal->IsJPEG2000(), - HeaderInternal->IsJPEGLossless(), - &(HeaderInternal->JPEGInfo), - fp ); - HeaderInternal->CloseFile(); - return res; -} - } // end namespace gdcm diff --git a/src/gdcmFile.h b/src/gdcmFile.h index 5ef9efea..31c51a35 100644 --- a/src/gdcmFile.h +++ b/src/gdcmFile.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmFile.h,v $ Language: C++ - Date: $Date: 2004/10/12 04:35:46 $ - Version: $Revision: 1.60 $ + Date: $Date: 2004/10/12 09:59:45 $ + Version: $Revision: 1.61 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -21,6 +21,7 @@ #include "gdcmCommon.h" #include "gdcmHeader.h" +#include "gdcmPixelConvert.h" namespace gdcm { @@ -44,9 +45,6 @@ public: int ComputeDecompressedPixelDataSizeFromHeader(); - void ConvertRGBPlanesToRGBPixels( uint8_t* source, uint8_t* destination ); - void ConvertYcBcRPlanesToRGBPixels( uint8_t* source, uint8_t* destination ); - /// Accessor to \ref ImageDataSize size_t GetImageDataSize(){ return ImageDataSize; }; @@ -89,8 +87,6 @@ protected: private: void Initialise(); - bool ReadPixelData(void* destination); - // For JPEG 8 Bits, body in file gdcmJpeg.cxx bool gdcm_write_JPEG_file (FILE* fp, void* image_buffer, int image_width, int image_heigh, @@ -107,7 +103,7 @@ private: // members variables: - /// \brief Header to use to load the file + /// Header to use to load the file Header *HeaderInternal; /// \brief Whether the underlying \ref Header was loaded by @@ -118,6 +114,8 @@ private: /// wether already parsed bool Parsed; + /// FIXME + PixelConvert PixelConverter; // // --------------- Will be moved to a PixelData class // diff --git a/src/gdcmPixelConvert.cxx b/src/gdcmPixelConvert.cxx index 74f305ac..d3a0d896 100644 --- a/src/gdcmPixelConvert.cxx +++ b/src/gdcmPixelConvert.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmPixelConvert.cxx,v $ Language: C++ - Date: $Date: 2004/10/12 04:35:47 $ - Version: $Revision: 1.8 $ + Date: $Date: 2004/10/12 09:59:45 $ + Version: $Revision: 1.9 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -16,11 +16,12 @@ =========================================================================*/ -////////////////// TEMPORARY NOT +////////////////// TEMPORARY NOTE // look for "fixMem" and convert that to a member of this class // Removing the prefix fixMem and dealing with allocations should do the trick // // grep PIXELCONVERT everywhere and clean up ! + #include "gdcmDebug.h" #include "gdcmPixelConvert.h" @@ -29,10 +30,9 @@ // for JPEGLosslessDecodeImage #include "jpeg/ljpg/jpegless.h" - -namespace gdcm +namespace gdcm { - + #define str2num(str, typeNum) *((typeNum *)(str)) // For JPEG 2000, body in file gdcmJpeg2000.cxx @@ -52,8 +52,8 @@ PixelConvert::PixelConvert() { RGB = 0; RGBSize = 0; - Uncompressed = 0; - UncompressedSize = 0; + Decompressed = 0; + DecompressedSize = 0; } void PixelConvert::Squeeze() @@ -61,8 +61,8 @@ void PixelConvert::Squeeze() if ( RGB ) { delete [] RGB; } - if ( Uncompressed ) { - delete [] Uncompressed; + if ( Decompressed ) { + delete [] Decompressed; } } @@ -79,26 +79,24 @@ void PixelConvert::AllocateRGB() RGB = new uint8_t[RGBSize]; } -void PixelConvert::AllocateUncompressed() +void PixelConvert::AllocateDecompressed() { - if ( Uncompressed ) { - delete [] Uncompressed; + if ( Decompressed ) { + delete [] Decompressed; } - Uncompressed = new uint8_t[ UncompressedSize ]; + Decompressed = new uint8_t[ DecompressedSize ]; } /** * \brief Read from file a 12 bits per pixel image and uncompress it * into a 16 bits per pixel image. */ -void PixelConvert::ConvertDecompress12BitsTo16Bits( +void PixelConvert::Decompress12BitsTo16Bits( uint8_t* pixelZone, - int sizeX, - int sizeY, FILE* filePtr) throw ( FormatError ) { - int nbPixels = sizeX * sizeY; + int nbPixels = XSize * YSize; uint16_t* destination = (uint16_t*)pixelZone; for( int p = 0; p < nbPixels; p += 2 ) @@ -109,22 +107,22 @@ void PixelConvert::ConvertDecompress12BitsTo16Bits( ItemRead = fread( &b0, 1, 1, filePtr); if ( ItemRead != 1 ) { - throw FormatError( "File::ConvertDecompress12BitsTo16Bits()", - "Unfound first block" ); + throw FormatError( "File::Decompress12BitsTo16Bits()", + "Unfound first block" ); } ItemRead = fread( &b1, 1, 1, filePtr); if ( ItemRead != 1 ) { - throw FormatError( "File::ConvertDecompress12BitsTo16Bits()", - "Unfound second block" ); + throw FormatError( "File::Decompress12BitsTo16Bits()", + "Unfound second block" ); } ItemRead = fread( &b2, 1, 1, filePtr); if ( ItemRead != 1 ) { - throw FormatError( "File::ConvertDecompress12BitsTo16Bits()", - "Unfound second block" ); + throw FormatError( "File::Decompress12BitsTo16Bits()", + "Unfound second block" ); } // Two steps are necessary to please VC++ @@ -149,8 +147,6 @@ void PixelConvert::ConvertDecompress12BitsTo16Bits( * @return Boolean */ bool PixelConvert::UncompressRLE16BitsFromRLE8Bits( - int XSize, - int YSize, int NumberOfFrames, uint8_t* fixMemUncompressed ) { @@ -247,13 +243,9 @@ bool PixelConvert::ReadAndUncompressRLEFragment( uint8_t* decodedZone, * at which the pixel data should be copied * @return Boolean */ -bool PixelConvert::ReadAndDecompressRLEFile( void* image_buffer, - int XSize, - int YSize, - int ZSize, - int BitsAllocated, - RLEFramesInfo* RLEInfo, - FILE* fp ) +bool PixelConvert::ReadAndDecompressRLEFile( + void* image_buffer, + FILE* fp ) { uint8_t* im = (uint8_t*)image_buffer; long uncompressedSegmentSize = XSize * YSize; @@ -279,10 +271,7 @@ bool PixelConvert::ReadAndDecompressRLEFile( void* image_buffer, if ( BitsAllocated == 16 ) { // Try to deal with RLE 16 Bits - (void)PixelConvert::UncompressRLE16BitsFromRLE8Bits( - XSize, - YSize, - ZSize, + (void)UncompressRLE16BitsFromRLE8Bits( ZSize, (uint8_t*) image_buffer); } @@ -293,18 +282,15 @@ bool PixelConvert::ReadAndDecompressRLEFile( void* image_buffer, * \brief Swap the bytes, according to swap code. * \warning not end user intended * @param im area to deal with - * @param swap swap code - * @param lgr Area Length - * @param nb Pixels Bit number */ -void PixelConvert::SwapZone(void* im, int swap, int lgr, int nb) +void PixelConvert::SwapZone( uint8_t* im ) { int i; - if( nb == 16 ) + if( BitsAllocated == 16 ) { uint16_t* im16 = (uint16_t*)im; - switch( swap ) + switch( SwapCode ) { case 0: case 12: @@ -314,28 +300,28 @@ void PixelConvert::SwapZone(void* im, int swap, int lgr, int nb) case 3412: case 2143: case 4321: - for(i=0; i < lgr/2; i++) + for( i = 0; i < DecompressedSize / 2; i++ ) { im16[i]= (im16[i] >> 8) | (im16[i] << 8 ); } break; default: - std::cout << "SWAP value (16 bits) not allowed :i" << swap << - std::endl; + dbg.Verbose( 0, "PixelConvert::SwapZone: SwapCode value " + "(16 bits) not allowed." ); } } - else if( nb == 32 ) + else if( BitsAllocated == 32 ) { uint32_t s32; uint16_t fort, faible; uint32_t* im32 = (uint32_t*)im; - switch ( swap ) + switch ( SwapCode ) { case 0: case 1234: break; case 4321: - for(i = 0; i < lgr/4; i++) + for( i = 0; i < DecompressedSize / 4; i++ ) { faible = im32[i] & 0x0000ffff; // 4321 fort = im32[i] >> 16; @@ -346,7 +332,7 @@ void PixelConvert::SwapZone(void* im, int swap, int lgr, int nb) } break; case 2143: - for(i = 0; i < lgr/4; i++) + for( i = 0; i < DecompressedSize / 4; i++ ) { faible = im32[i] & 0x0000ffff; // 2143 fort = im32[i] >> 16; @@ -357,7 +343,7 @@ void PixelConvert::SwapZone(void* im, int swap, int lgr, int nb) } break; case 3412: - for(i = 0; i < lgr/4; i++) + for( i = 0; i < DecompressedSize / 4; i++ ) { faible = im32[i] & 0x0000ffff; // 3412 fort = im32[i] >> 16; @@ -366,35 +352,28 @@ void PixelConvert::SwapZone(void* im, int swap, int lgr, int nb) } break; default: - std::cout << "SWAP value (32 bits) not allowed : " << swap << - std::endl; + dbg.Verbose( 0, "PixelConvert::SwapZone: SwapCode value " + "(32 bits) not allowed." ); } } } - - /** * \brief Deal with endianity i.e. re-arange bytes inside the integer */ -void PixelConvert::ConvertReorderEndianity( uint8_t* pixelZone, - size_t imageDataSize, - int numberBitsStored, - int numberBitsAllocated, - int swapCode, - bool signedPixel) +void PixelConvert::ReorderEndianity( uint8_t* pixelZone ) { - if ( numberBitsAllocated != 8 ) + if ( BitsAllocated != 8 ) { - SwapZone( pixelZone, swapCode, imageDataSize, numberBitsAllocated ); + SwapZone( pixelZone ); } // Special kludge in order to deal with xmedcon broken images: - if ( ( numberBitsAllocated == 16 ) - && ( numberBitsStored < numberBitsAllocated ) - && ( ! signedPixel ) ) + if ( ( BitsAllocated == 16 ) + && ( BitsStored < BitsAllocated ) + && ( ! PixelSign ) ) { - int l = (int)(imageDataSize / (numberBitsAllocated/8)); + int l = (int)( DecompressedSize / ( BitsAllocated / 8 ) ); uint16_t *deb = (uint16_t *)pixelZone; for(int i = 0; iOffset, SEEK_SET ); - if ( isJPEG2000 ) + if ( IsJPEG2000 ) { if ( ! gdcm_read_JPEG2000_file( fp, destination ) ) { return false; } } - else if ( isJPEGLossless ) + else if ( IsJPEGLossless ) { // JPEG LossLess : call to xmedcom Lossless JPEG JPEGLosslessDecodeImage( fp, @@ -468,7 +439,7 @@ bool PixelConvert::ReadAndDecompressJPEGFile( uint8_t* destination, else { // other JPEG lossy not supported - dbg.Error(" File::ReadPixelData : unknown jpeg lossy " + dbg.Error(" File::ReadAndDecompressJPEGFile: unknown jpeg lossy " " compression "); return false; } @@ -490,46 +461,180 @@ bool PixelConvert::ReadAndDecompressJPEGFile( uint8_t* destination, * @param destination Where decompressed fragments should end up * @return Boolean */ -bool PixelConvert::ConvertReArrangeBits( - uint8_t* pixelZone, - size_t imageDataSize, - int numberBitsStored, - int numberBitsAllocated, - int highBitPosition ) +bool PixelConvert::ReArrangeBits( uint8_t* pixelZone ) throw ( FormatError ) { - if ( numberBitsStored != numberBitsAllocated ) + if ( BitsStored != BitsAllocated ) { - int l = (int)(imageDataSize / (numberBitsAllocated/8)); - if ( numberBitsAllocated == 16 ) + int l = (int)( DecompressedSize / ( BitsAllocated / 8 ) ); + if ( BitsAllocated == 16 ) { uint16_t mask = 0xffff; - mask = mask >> ( numberBitsAllocated - numberBitsStored ); + mask = mask >> ( BitsAllocated - BitsStored ); uint16_t* deb = (uint16_t*)pixelZone; for(int i = 0; i> (numberBitsStored - highBitPosition - 1)) & mask; + *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask; deb++; } } - else if ( numberBitsAllocated == 32 ) + else if ( BitsAllocated == 32 ) { uint32_t mask = 0xffffffff; - mask = mask >> ( numberBitsAllocated - numberBitsStored ); + mask = mask >> ( BitsAllocated - BitsStored ); uint32_t* deb = (uint32_t*)pixelZone; for(int i = 0; i> (numberBitsStored - highBitPosition - 1)) & mask; + *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & mask; deb++; } } else { - dbg.Verbose(0, "PixelConvert::ConvertReArrangeBits: weird image"); - throw FormatError( "File::ConvertReArrangeBits()", + dbg.Verbose(0, "PixelConvert::ReArrangeBits: weird image"); + throw FormatError( "File::ReArrangeBits()", "weird image !?" ); } } - return true; //??? } + +/** + * \brief Convert (Y plane, cB plane, cR plane) to RGB pixels + * \warning Works on all the frames at a time + */ +void PixelConvert::ConvertYcBcRPlanesToRGBPixels( + uint8_t* destination, + size_t imageDataSize ) +{ + uint8_t* oldPixelZone = new uint8_t[ imageDataSize ]; + memmove( oldPixelZone, destination, imageDataSize ); + + // to see the tricks about YBR_FULL, YBR_FULL_422, + // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at : + // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf + // and be *very* affraid + // + int l = XSize * YSize; + int nbFrames = ZSize; + + uint8_t* a = oldPixelZone; + uint8_t* b = oldPixelZone + l; + uint8_t* c = oldPixelZone + l + l; + double R, G, B; + + /// \todo : Replace by the 'well known' integer computation + /// counterpart. Refer to + /// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf + /// for code optimisation. + + for ( int i = 0; i < nbFrames; i++ ) + { + for ( int j = 0; j < l; j++ ) + { + R = 1.164 *(*a-16) + 1.596 *(*c -128) + 0.5; + G = 1.164 *(*a-16) - 0.813 *(*c -128) - 0.392 *(*b -128) + 0.5; + B = 1.164 *(*a-16) + 2.017 *(*b -128) + 0.5; + + if (R < 0.0) R = 0.0; + if (G < 0.0) G = 0.0; + if (B < 0.0) B = 0.0; + if (R > 255.0) R = 255.0; + if (G > 255.0) G = 255.0; + if (B > 255.0) B = 255.0; + + *(destination++) = (uint8_t)R; + *(destination++) = (uint8_t)G; + *(destination++) = (uint8_t)B; + a++; + b++; + c++; + } + } + delete[] oldPixelZone; +} + +/** + * \brief Convert (Red plane, Green plane, Blue plane) to RGB pixels + * \warning Works on all the frames at a time + */ +void PixelConvert::ConvertRGBPlanesToRGBPixels( + uint8_t* destination, + size_t imageDataSize ) +{ + uint8_t* oldPixelZone = new uint8_t[ imageDataSize ]; + memmove( oldPixelZone, destination, imageDataSize ); + + int l = XSize * YSize * ZSize; + + uint8_t* a = oldPixelZone; + uint8_t* b = oldPixelZone + l; + uint8_t* c = oldPixelZone + l + l; + + for (int j = 0; j < l; j++) + { + *(destination++) = *(a++); + *(destination++) = *(b++); + *(destination++) = *(c++); + } + delete[] oldPixelZone; +} + +bool PixelConvert::ReadAndDecompressPixelData( void* destination, FILE* fp ) +{ + if ( !fp ) + { + return false; + } + + if ( fseek(fp, PixelOffset, SEEK_SET) == -1 ) + { + return false; + } + + if ( BitsAllocated == 12 ) + { + Decompress12BitsTo16Bits( (uint8_t*)destination, fp); + return true; + } + + //////////// Decompressed File + if ( IsUncompressed ) + { + size_t ItemRead = fread( destination, PixelDataLength, 1, fp); + if ( ItemRead != 1 ) + { + return false; + } + else + { + return true; + } + } + + ///////////// Run Length Encoding + if ( IsRLELossless ) + { + return ReadAndDecompressRLEFile( destination, fp ); + } + + ///////////// SingleFrame/Multiframe JPEG Lossless/Lossy/2000 + return ReadAndDecompressJPEGFile( (uint8_t*)destination, fp ); +} + +void PixelConvert::ComputeDecompressedImageDataSize() +{ + int 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 Decompress12BitsTo16Bits() ) + if ( BitsAllocated == 12 ) + { + bitsAllocated = 16; + } + + DecompressedSize = XSize * YSize * ZSize + * ( bitsAllocated / 8 ) + * SamplesPerPixel; +} + } // end namespace gdcm diff --git a/src/gdcmPixelConvert.h b/src/gdcmPixelConvert.h index 0ac94ca4..e0e2b818 100644 --- a/src/gdcmPixelConvert.h +++ b/src/gdcmPixelConvert.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmPixelConvert.h,v $ Language: C++ - Date: $Date: 2004/10/12 04:35:47 $ - Version: $Revision: 1.6 $ + Date: $Date: 2004/10/12 09:59:45 $ + Version: $Revision: 1.7 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -25,9 +25,9 @@ #include "gdcmJPEGFragmentsInfo.h" #include "gdcmException.h" -namespace gdcm +namespace gdcm { - + /* * \brief Utility container for gathering the various forms the pixel data * migth take during the user demanded processes. @@ -38,77 +38,102 @@ friend class File; uint8_t* RGB; size_t RGBSize; //aka ImageDataSize /// Pixel data after decompression and bit/byte rearrangement. - uint8_t* Uncompressed; - size_t UncompressedSize; + uint8_t* Decompressed; + size_t DecompressedSize; + + // Set by the accessors: + size_t PixelOffset; + size_t PixelDataLength; + int XSize; + int YSize; + int ZSize; + int BitsAllocated; + int BitsStored; + int HighBitPosition; + int SamplesPerPixel; + int PixelSize; + bool PixelSign; + int SwapCode; + bool IsUncompressed; + bool IsJPEG2000; + bool IsJPEGLossless; + bool IsRLELossless; + RLEFramesInfo* RLEInfo; + JPEGFragmentsInfo* JPEGInfo; + +private: + bool ReadAndUncompressRLEFragment( + uint8_t* decodedZone, + long fragmentSize, + long uncompressedSegmentSize, + FILE* fp ); public: PixelConvert(); ~PixelConvert(); + void SetXSize( int xSize ) { XSize = xSize; } + void SetYSize( int ySize ) { YSize = ySize; } + void SetZSize( int zSize ) { ZSize = zSize; } + void SetBitsAllocated( int bitsAllocated ) { BitsAllocated = bitsAllocated; } + void SetBitsStored( int bitsStored ) { BitsStored = bitsStored; } + void SetHighBitPosition( int highBitPosition ) + { HighBitPosition = highBitPosition; } + void SetSamplesPerPixel( int samplesPerPixel ) + { SamplesPerPixel = samplesPerPixel; } + void SetPixelSize( int pixelSize ) { PixelSize = pixelSize; } + void SetPixelSign( int pixelSign ) { PixelSign = pixelSign; } + void SetSwapCode( int swapCode ) { SwapCode = swapCode; } + void SetIsUncompressed( bool isUncompressed ) + { IsUncompressed = isUncompressed; } + void SetIsJPEG2000( bool isJPEG2000 ) { IsJPEG2000 = isJPEG2000; } + void SetIsJPEGLossless( bool isJPEGLossless ) + { IsJPEGLossless = isJPEGLossless; } + void SetIsRLELossless( bool isRLELossless ) + { IsRLELossless = isRLELossless; } + void SetPixelOffset( size_t pixelOffset ) { PixelOffset = pixelOffset; } + void SetPixelDataLength( size_t pixelDataLength ) + { PixelDataLength = pixelDataLength; } + void SetRLEInfo( RLEFramesInfo* inRLEFramesInfo ) + { RLEInfo = inRLEFramesInfo; } + void SetJPEGInfo( JPEGFragmentsInfo* inJPEGFragmentsInfo ) + { JPEGInfo = inJPEGFragmentsInfo; } + uint8_t* GetRGB() { return RGB; } void SetRGBSize( size_t size ) { RGBSize = size; } size_t GetRGBSize() { return RGBSize; } void AllocateRGB(); - uint8_t* GetUncompressed() { return Uncompressed; } - void SetUncompressedSize( size_t size ) { UncompressedSize = size; } - size_t GetUncompressedSize() { return UncompressedSize; } - void AllocateUncompressed(); + uint8_t* GetDecompressed() { return Decompressed; } + void SetDecompressedSize( size_t size ) { DecompressedSize = size; } + size_t GetDecompressedSize() { return DecompressedSize; } + void AllocateDecompressed(); - void Squeeze(); ////////////////////////////////////////////////////////// // In progress - static bool UncompressRLE16BitsFromRLE8Bits( - int XSize, - int YSize, +private: + bool UncompressRLE16BitsFromRLE8Bits( int NumberOfFrames, uint8_t* fixMemUncompressed ); - static bool ReadAndUncompressRLEFragment( - uint8_t* decodedZone, - long fragmentSize, - long uncompressedSegmentSize, - FILE* fp ); - static bool ReadAndDecompressRLEFile( - void* image_buffer, - int XSize, - int YSize, - int ZSize, - int BitsAllocated, - RLEFramesInfo* RLEInfo, - FILE* fp ); - static void ConvertDecompress12BitsTo16Bits( + void ComputeDecompressedImageDataSize(); + void Decompress12BitsTo16Bits( uint8_t* pixelZone, - int sizeX, - int sizeY, FILE* filePtr) throw ( FormatError ); - static void SwapZone(void* im, int swap, int lgr, int nb); - static void ConvertReorderEndianity( - uint8_t* pixelZone, - size_t imageDataSize, - int numberBitsStored, - int numberBitsAllocated, - int swapCode, - bool signedPixel ); - static bool ReadAndDecompressJPEGFile( + bool ReadAndDecompressRLEFile( void* image_buffer, FILE* fp ); + bool ReadAndDecompressJPEGFile( uint8_t* destination, FILE* fp ); + void SwapZone( uint8_t* im ); +public: + void ReorderEndianity( uint8_t* pixelZone ); + bool ReArrangeBits( uint8_t* pixelZone ) throw ( FormatError ); + void ConvertRGBPlanesToRGBPixels( uint8_t* destination, - int XSize, - int YSize, - int BitsAllocated, - int BitsStored, - int SamplesPerPixel, - int PixelSize, - bool isJPEG2000, - bool isJPEGLossless, - JPEGFragmentsInfo* JPEGInfo, - FILE* fp ); - static bool PixelConvert::ConvertReArrangeBits( - uint8_t* pixelZone, - size_t imageDataSize, - int numberBitsStored, - int numberBitsAllocated, - int highBitPosition ) throw ( FormatError ); - - + size_t imageDataSize ); + void ConvertYcBcRPlanesToRGBPixels( + uint8_t* destination, + size_t imageDataSize ); + bool ReadAndDecompressPixelData( void* destination, FILE* fp ); + void Squeeze(); }; } // end namespace gdcm + //----------------------------------------------------------------------------- #endif -- 2.48.1