X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmPixelReadConvert.cxx;h=07c2fd94c5e158a7869e73e544be8286484348c8;hb=03acf3c119c6657129b8aeae8cb2205e481a105b;hp=79ab4e446abfc883c590790671a5f60609c4c0ad;hpb=922095a0dd56f24d651b36f62256690020937d9a;p=gdcm.git diff --git a/src/gdcmPixelReadConvert.cxx b/src/gdcmPixelReadConvert.cxx index 79ab4e44..07c2fd94 100644 --- a/src/gdcmPixelReadConvert.cxx +++ b/src/gdcmPixelReadConvert.cxx @@ -1,10 +1,10 @@ /*========================================================================= - + Program: gdcm Module: $RCSfile: gdcmPixelReadConvert.cxx,v $ Language: C++ - Date: $Date: 2004/12/10 13:49:07 $ - Version: $Revision: 1.5 $ + Date: $Date: 2005/01/06 20:03:28 $ + Version: $Revision: 1.14 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -39,16 +39,26 @@ namespace gdcm // For JPEG 2000, body in file gdcmJpeg2000.cxx bool gdcm_read_JPEG2000_file (std::ifstream* fp, void* image_buffer); +#define JOCTET uint8_t // For JPEG 8 Bits, body in file gdcmJpeg8.cxx -bool gdcm_read_JPEG_file8 (std::ifstream* fp, void* image_buffer); - +bool gdcm_read_JPEG_file8 (std::ifstream *fp, void *image_buffer); +bool gdcm_read_JPEG_memory8 (const JOCTET *buffer, const size_t buflen, + void *image_buffer, + size_t *howManyRead, size_t *howManyWritten); +// // For JPEG 12 Bits, body in file gdcmJpeg12.cxx -bool gdcm_read_JPEG_file12 (std::ifstream* fp, void* image_buffer); +bool gdcm_read_JPEG_file12 (std::ifstream *fp, void *image_buffer); +bool gdcm_read_JPEG_memory12 (const JOCTET *buffer, const size_t buflen, + void *image_buffer, + size_t *howManyRead, size_t *howManyWritten); // For JPEG 16 Bits, body in file gdcmJpeg16.cxx // Beware this is misleading there is no 16bits DCT algorithm, only // jpeg lossless compression exist in 16bits. -bool gdcm_read_JPEG_file16 (std::ifstream* fp, void* image_buffer); +bool gdcm_read_JPEG_file16 (std::ifstream *fp, void *image_buffer); +bool gdcm_read_JPEG_memory16 (const JOCTET *buffer, const size_t buflen, + void* image_buffer, + size_t *howManyRead, size_t *howManyWritten); //----------------------------------------------------------------------------- @@ -111,7 +121,7 @@ void PixelReadConvert::AllocateRaw() * \brief Read from file a 12 bits per pixel image and decompress it * into a 16 bits per pixel image. */ -void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream* fp ) +void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream *fp ) throw ( FormatError ) { int nbPixels = XSize * YSize; @@ -165,24 +175,24 @@ void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream* fp ) */ bool PixelReadConvert::DecompressRLE16BitsFromRLE8Bits( int NumberOfFrames ) { - size_t PixelNumber = XSize * YSize; - size_t RawSize = XSize * YSize * NumberOfFrames; + size_t pixelNumber = XSize * YSize; + size_t rawSize = XSize * YSize * NumberOfFrames; // We assumed Raw contains the decoded RLE pixels but as // 8 bits per pixel. In order to convert those pixels to 16 bits // per pixel we cannot work in place within Raw and hence // we copy it in a safe place, say copyRaw. - uint8_t* copyRaw = new uint8_t[ RawSize * 2 ]; - memmove( copyRaw, Raw, RawSize * 2 ); + uint8_t* copyRaw = new uint8_t[ rawSize * 2 ]; + memmove( copyRaw, Raw, rawSize * 2 ); uint8_t* x = Raw; uint8_t* a = copyRaw; - uint8_t* b = a + PixelNumber; + uint8_t* b = a + pixelNumber; for ( int i = 0; i < NumberOfFrames; i++ ) { - for ( unsigned int j = 0; j < PixelNumber; j++ ) + for ( unsigned int j = 0; j < pixelNumber; j++ ) { *(x++) = *(b++); *(x++) = *(a++); @@ -206,10 +216,10 @@ bool PixelReadConvert::DecompressRLE16BitsFromRLE8Bits( int NumberOfFrames ) * @param fp File Pointer: on entry the position should be the one of * the fragment to be decoded. */ -bool PixelReadConvert::ReadAndDecompressRLEFragment( uint8_t* subRaw, +bool PixelReadConvert::ReadAndDecompressRLEFragment( uint8_t *subRaw, long fragmentSize, long RawSegmentSize, - std::ifstream* fp ) + std::ifstream *fp ) { int8_t count; long numberOfOutputBytes = 0; @@ -264,9 +274,9 @@ bool PixelReadConvert::ReadAndDecompressRLEFragment( uint8_t* subRaw, * at which the pixel data should be copied * @return Boolean */ -bool PixelReadConvert::ReadAndDecompressRLEFile( std::ifstream* fp ) +bool PixelReadConvert::ReadAndDecompressRLEFile( std::ifstream *fp ) { - uint8_t* subRaw = Raw; + uint8_t *subRaw = Raw; long RawSegmentSize = XSize * YSize; // Loop on the frame[s] @@ -305,7 +315,7 @@ void PixelReadConvert::ConvertSwapZone() if( BitsAllocated == 16 ) { - uint16_t* im16 = (uint16_t*)Raw; + uint16_t *im16 = (uint16_t*)Raw; switch( SwapCode ) { case 0: @@ -403,15 +413,17 @@ void PixelReadConvert::ConvertReorderEndianity() } } + /** * \brief Reads from disk the Pixel Data of JPEG Dicom encapsulated - & file and decompress it. + * file and decompress it. This funciton assumes that each + * jpeg fragment contains a whole frame (jpeg file). * @param fp File Pointer * @return Boolean */ -bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream* fp ) +bool PixelReadConvert::ReadAndDecompressJPEGFramesFromFile( std::ifstream *fp ) { - uint8_t* localRaw = Raw; + uint8_t *localRaw = Raw; // Loop on the fragment[s] for( JPEGFragmentsInfo::JPEGFragmentsList::iterator it = JPEGInfo->Fragments.begin(); @@ -420,14 +432,7 @@ bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream* fp ) { fp->seekg( (*it)->Offset, std::ios::beg); - if ( IsJPEG2000 ) - { - if ( ! gdcm_read_JPEG2000_file( fp,localRaw ) ) - { - return false; - } - } - else if ( BitsStored == 8) + if ( BitsStored == 8) { // JPEG Lossy : call to IJG 6b if ( ! gdcm_read_JPEG_file8( fp, localRaw ) ) @@ -470,6 +475,236 @@ bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream* fp ) return true; } +/** + * \brief Reads from disk the Pixel Data of JPEG Dicom encapsulated + * file and decompress it. This function assumes that the dicom + * image is a single frame split into several JPEG fragments. + * Those fragments will be glued together into a memory buffer + * before being read. + * @param fp File Pointer + * @return Boolean + */ +bool PixelReadConvert:: +ReadAndDecompressJPEGSingleFrameFragmentsFromFile( std::ifstream *fp ) +{ + // Loop on the fragment[s] to get total length + size_t totalLength = 0; + JPEGFragmentsInfo::JPEGFragmentsList::iterator it; + for( it = JPEGInfo->Fragments.begin(); + it != JPEGInfo->Fragments.end(); + ++it ) + { + totalLength += (*it)->Length; + } + + // Concatenate the jpeg fragments into a local buffer + JOCTET *buffer = new JOCTET [totalLength]; + JOCTET *p = buffer; + + // Loop on the fragment[s] + for( it = JPEGInfo->Fragments.begin(); + it != JPEGInfo->Fragments.end(); + ++it ) + { + fp->seekg( (*it)->Offset, std::ios::beg); + size_t len = (*it)->Length; + fp->read((char *)p,len); + p += len; + } + + size_t howManyRead = 0; + size_t howManyWritten = 0; + + if ( BitsStored == 8) + { + if ( ! gdcm_read_JPEG_memory8( buffer, totalLength, Raw, + &howManyRead, &howManyWritten ) ) + { + dbg.Error( + "PixelConvert::ReadAndDecompressJPEGFile: failed to read jpeg8 " + ); + delete [] buffer; + return false; + } + } + else if ( BitsStored <= 12) + { + if ( ! gdcm_read_JPEG_memory12( buffer, totalLength, Raw, + &howManyRead, &howManyWritten ) ) + { + dbg.Error( + "PixelConvert::ReadAndDecompressJPEGFile: failed to read jpeg12 " + ); + delete [] buffer; + return false; + } + } + else if ( BitsStored <= 16) + { + + if ( ! gdcm_read_JPEG_memory16( buffer, totalLength, Raw, + &howManyRead, &howManyWritten ) ) + { + dbg.Error( + "PixelConvert::ReadAndDecompressJPEGFile: failed to read jpeg16 " + ); + delete [] buffer; + return false; + } + } + else + { + // other JPEG lossy not supported + dbg.Error("PixelConvert::ReadAndDecompressJPEGFile: unknown " + "jpeg lossy compression "); + delete [] buffer; + return false; + } + + // free local buffer + delete [] buffer; + + return true; +} + +/** + * \brief Reads from disk the Pixel Data of JPEG Dicom encapsulated + * file and decompress it. This function handles the generic + * and complex case where the DICOM contains several frames, + * and some of the frames are possibly split into several JPEG + * fragments. + * @param fp File Pointer + * @return Boolean + */ +bool PixelReadConvert:: +ReadAndDecompressJPEGFragmentedFramesFromFile( std::ifstream *fp ) +{ + // Loop on the fragment[s] to get total length + size_t totalLength = 0; + JPEGFragmentsInfo::JPEGFragmentsList::iterator it; + for( it = JPEGInfo->Fragments.begin(); + it != JPEGInfo->Fragments.end(); + ++it ) + { + totalLength += (*it)->Length; + } + + // Concatenate the jpeg fragments into a local buffer + JOCTET *buffer = new JOCTET [totalLength]; + JOCTET *p = buffer; + + // Loop on the fragment[s] + for( it = JPEGInfo->Fragments.begin(); + it != JPEGInfo->Fragments.end(); + ++it ) + { + fp->seekg( (*it)->Offset, std::ios::beg); + size_t len = (*it)->Length; + fp->read((char *)p,len); + p+=len; + } + + size_t howManyRead = 0; + size_t howManyWritten = 0; + size_t fragmentLength = 0; + + for( it = JPEGInfo->Fragments.begin() ; + (it != JPEGInfo->Fragments.end()) && (howManyRead < totalLength); + ++it ) + { + fragmentLength += (*it)->Length; + + if (howManyRead > fragmentLength) continue; + + if ( BitsStored == 8) + { + if ( ! gdcm_read_JPEG_memory8( buffer+howManyRead, totalLength-howManyRead, + Raw+howManyWritten, + &howManyRead, &howManyWritten ) ) + { + dbg.Error("PixelConvert::ReadAndDecompressJPEGFile: failed to read jpeg8 "); + delete [] buffer; + return false; + } + } + else if ( BitsStored <= 12) + { + + if ( ! gdcm_read_JPEG_memory12( buffer+howManyRead, totalLength-howManyRead, + Raw+howManyWritten, + &howManyRead, &howManyWritten ) ) + { + dbg.Error("PixelConvert::ReadAndDecompressJPEGFile: failed to read jpeg12 "); + delete [] buffer; + return false; + } + } + else if ( BitsStored <= 16) + { + + if ( ! gdcm_read_JPEG_memory16( buffer+howManyRead, totalLength-howManyRead, + Raw+howManyWritten, + &howManyRead, &howManyWritten ) ) + { + dbg.Error("PixelConvert::ReadAndDecompressJPEGFile: failed to read jpeg16 "); + delete [] buffer; + return false; + } + } + else + { + // other JPEG lossy not supported + dbg.Error("PixelConvert::ReadAndDecompressJPEGFile: unknown " + "jpeg lossy compression "); + delete [] buffer; + return false; + } + + if (howManyRead < fragmentLength) + howManyRead = fragmentLength; + } + + // free local buffer + delete [] buffer; + + return true; +} + +/** + * \brief Reads from disk the Pixel Data of JPEG Dicom encapsulated + * file and decompress it. + * @param fp File Pointer + * @return Boolean + */ +bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp ) +{ + if ( IsJPEG2000 ) + { + fp->seekg( (*JPEGInfo->Fragments.begin())->Offset, std::ios::beg); + if ( ! gdcm_read_JPEG2000_file( fp,Raw ) ) + return false; + } + + if ( ( ZSize == 1 ) && ( JPEGInfo->Fragments.size() > 1 ) ) + { + // we have one frame split into several fragments + // we will pack those fragments into a single buffer and + // read from it + return ReadAndDecompressJPEGSingleFrameFragmentsFromFile( fp ); + } + else if (JPEGInfo->Fragments.size() == (size_t)ZSize) + { + // suppose each fragment is a frame + return ReadAndDecompressJPEGFramesFromFile( fp ); + } + else + { + // The dicom image contains frames containing fragments of images + // a more complex algorithm :-) + return ReadAndDecompressJPEGFragmentedFramesFromFile( fp ); + } +} + /** * \brief Re-arrange the bits within the bytes. * @return Boolean @@ -517,8 +752,8 @@ bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError ) */ void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels() { - uint8_t* localRaw = Raw; - uint8_t* copyRaw = new uint8_t[ RawSize ]; + uint8_t *localRaw = Raw; + uint8_t *copyRaw = new uint8_t[ RawSize ]; memmove( copyRaw, localRaw, RawSize ); // to see the tricks about YBR_FULL, YBR_FULL_422, @@ -529,9 +764,9 @@ void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels() int l = XSize * YSize; int nbFrames = ZSize; - uint8_t* a = copyRaw; - uint8_t* b = copyRaw + l; - uint8_t* c = copyRaw + l + l; + uint8_t *a = copyRaw; + uint8_t *b = copyRaw + l; + uint8_t *c = copyRaw + l + l; double R, G, B; /// \todo : Replace by the 'well known' integer computation @@ -571,8 +806,8 @@ void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels() */ void PixelReadConvert::ConvertRGBPlanesToRGBPixels() { - uint8_t* localRaw = Raw; - uint8_t* copyRaw = new uint8_t[ RawSize ]; + uint8_t *localRaw = Raw; + uint8_t *copyRaw = new uint8_t[ RawSize ]; memmove( copyRaw, localRaw, RawSize ); int l = XSize * YSize * ZSize; @@ -590,7 +825,7 @@ void PixelReadConvert::ConvertRGBPlanesToRGBPixels() delete[] copyRaw; } -bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream* fp ) +bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp ) { // ComputeRawAndRGBSizes is already made by // ::GrabInformationsFromHeader. So, the structure sizes are @@ -787,7 +1022,7 @@ void PixelReadConvert::ComputeRawAndRGBSizes() } } -void PixelReadConvert::GrabInformationsFromHeader( Header* header ) +void PixelReadConvert::GrabInformationsFromHeader( Header *header ) { // Number of Bits Allocated for storing a Pixel is defaulted to 16 // when absent from the header. @@ -846,7 +1081,6 @@ void PixelReadConvert::GrabInformationsFromHeader( Header* header ) if ( HasLUT ) { // Just in case some access to a Header element requires disk access. - // Note: gdcmDocument::Fp is leaved open after OpenFile. LutRedDescriptor = header->GetEntryByNumber( 0x0028, 0x1101 ); LutGreenDescriptor = header->GetEntryByNumber( 0x0028, 0x1102 ); LutBlueDescriptor = header->GetEntryByNumber( 0x0028, 0x1103 ); @@ -1068,6 +1302,15 @@ bool PixelReadConvert::BuildRGBImage() return true; } +/** + * \brief Print self. + * @param os Stream to print to. + */ +void PixelReadConvert::Print( std::ostream &os ) +{ + Print("",os); +} + /** * \brief Print self. * @param indent Indentation string to be prepended during printing. @@ -1080,10 +1323,10 @@ void PixelReadConvert::Print( std::string indent, std::ostream &os ) << std::endl; os << indent << "Pixel Data: offset " << PixelOffset - << " x" << std::hex << PixelOffset << std::dec - << " length " << PixelDataLength - << " x" << std::hex << PixelDataLength << std::dec - << std::endl; + << " x(" << std::hex << PixelOffset << std::dec + << ") length " << PixelDataLength + << " x(" << std::hex << PixelDataLength << std::dec + << ")" << std::endl; if ( IsRLELossless ) { @@ -1123,3 +1366,4 @@ void PixelReadConvert::Print( std::string indent, std::ostream &os ) // User // ---> GetImageDataRaw // ---> GetImageDataIntoVectorRaw +