X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmPixelConvert.cxx;h=d3d6b7aa980d70c5d77f1e980cacd173415f7171;hb=e5e7b1bd7ee84e8f9dc7da5d1d42b598fac68399;hp=d89550502970ec5c0faebed340ccac6438943020;hpb=f5028f34faa657dc1722331963f97c7734ee2d2a;p=gdcm.git diff --git a/src/gdcmPixelConvert.cxx b/src/gdcmPixelConvert.cxx index d8955050..d3d6b7aa 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/20 22:31:52 $ - Version: $Revision: 1.17 $ + Date: $Date: 2004/11/25 10:24:34 $ + Version: $Revision: 1.33 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -24,25 +24,26 @@ #include "gdcmDebug.h" #include "gdcmPixelConvert.h" +#include +#include namespace gdcm { - #define str2num(str, typeNum) *((typeNum *)(str)) // For JPEG 2000, body in file gdcmJpeg2000.cxx -bool gdcm_read_JPEG2000_file (FILE* fp, void* image_buffer); +bool gdcm_read_JPEG2000_file (std::ifstream* fp, void* image_buffer); // For JPEG 8 Bits, body in file gdcmJpeg8.cxx -bool gdcm_read_JPEG_file8 (FILE* fp, void* image_buffer); +bool gdcm_read_JPEG_file8 (std::ifstream* fp, void* image_buffer); // For JPEG 12 Bits, body in file gdcmJpeg12.cxx -bool gdcm_read_JPEG_file12 (FILE* fp, void* image_buffer); +bool gdcm_read_JPEG_file12 (std::ifstream* fp, void* image_buffer); // 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 (FILE* fp, void* image_buffer); +bool gdcm_read_JPEG_file16 (std::ifstream* fp, void* image_buffer); //----------------------------------------------------------------------------- @@ -65,14 +66,19 @@ void PixelConvert::Squeeze() { delete [] RGB; } + RGB = 0; + if ( Decompressed ) { delete [] Decompressed; } + Decompressed = 0; + if ( LutRGBA ) { delete [] LutRGBA; } + LutRGBA = 0; } PixelConvert::~PixelConvert() @@ -100,38 +106,37 @@ void PixelConvert::AllocateDecompressed() * \brief Read from file a 12 bits per pixel image and decompress it * into a 16 bits per pixel image. */ -void PixelConvert::ReadAndDecompress12BitsTo16Bits( FILE* fp ) +void PixelConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream* fp ) throw ( FormatError ) { int nbPixels = XSize * YSize; uint16_t* localDecompres = (uint16_t*)Decompressed; - + for( int p = 0; p < nbPixels; p += 2 ) { uint8_t b0, b1, b2; - size_t ItemRead; - - ItemRead = fread( &b0, 1, 1, fp ); - if ( ItemRead != 1 ) + + fp->read( (char*)&b0, 1); + if ( fp->fail() || fp->eof() )//Fp->gcount() == 1 { throw FormatError( "PixelConvert::ReadAndDecompress12BitsTo16Bits()", "Unfound first block" ); } - - ItemRead = fread( &b1, 1, 1, fp ); - if ( ItemRead != 1 ) + + fp->read( (char*)&b1, 1 ); + if ( fp->fail() || fp->eof())//Fp->gcount() == 1 { throw FormatError( "PixelConvert::ReadAndDecompress12BitsTo16Bits()", "Unfound second block" ); } - - ItemRead = fread( &b2, 1, 1, fp ); - if ( ItemRead != 1 ) + + fp->read( (char*)&b2, 1 ); + if ( fp->fail() || fp->eof())//Fp->gcount() == 1 { throw FormatError( "PixelConvert::ReadAndDecompress12BitsTo16Bits()", "Unfound second block" ); } - + // Two steps are necessary to please VC++ // // 2 pixels 12bit = [0xABCDEF] @@ -140,7 +145,7 @@ void PixelConvert::ReadAndDecompress12BitsTo16Bits( FILE* fp ) *localDecompres++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f); // F C E *localDecompres++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4); - + /// \todo JPR Troubles expected on Big-Endian processors ? } } @@ -174,8 +179,8 @@ bool PixelConvert::DecompressRLE16BitsFromRLE8Bits( int NumberOfFrames ) { for ( unsigned int j = 0; j < PixelNumber; j++ ) { - *(x++) = *(a++); *(x++) = *(b++); + *(x++) = *(a++); } } @@ -199,15 +204,15 @@ bool PixelConvert::DecompressRLE16BitsFromRLE8Bits( int NumberOfFrames ) bool PixelConvert::ReadAndDecompressRLEFragment( uint8_t* subDecompressed, long fragmentSize, long decompressedSegmentSize, - FILE* fp ) + std::ifstream* fp ) { int8_t count; long numberOfOutputBytes = 0; long numberOfReadBytes = 0; - + while( numberOfOutputBytes < decompressedSegmentSize ) { - fread( &count, 1, 1, fp ); + fp->read( (char*)&count, 1 ); numberOfReadBytes += 1; if ( count >= 0 ) // Note: count <= 127 comparison is always true due to limited range @@ -215,7 +220,7 @@ bool PixelConvert::ReadAndDecompressRLEFragment( uint8_t* subDecompressed, // signed integer of width N is 2^(N-1) - 1, which for int8_t // is 127]. { - fread( subDecompressed, count + 1, 1, fp); + fp->read( (char*)subDecompressed, count + 1); numberOfReadBytes += count + 1; subDecompressed += count + 1; numberOfOutputBytes += count + 1; @@ -225,7 +230,7 @@ bool PixelConvert::ReadAndDecompressRLEFragment( uint8_t* subDecompressed, if ( ( count <= -1 ) && ( count >= -127 ) ) { int8_t newByte; - fread( &newByte, 1, 1, fp); + fp->read( (char*)&newByte, 1); numberOfReadBytes += 1; for( int i = 0; i < -count + 1; i++ ) { @@ -254,7 +259,7 @@ bool PixelConvert::ReadAndDecompressRLEFragment( uint8_t* subDecompressed, * at which the pixel data should be copied * @return Boolean */ -bool PixelConvert::ReadAndDecompressRLEFile( FILE* fp ) +bool PixelConvert::ReadAndDecompressRLEFile( std::ifstream* fp ) { uint8_t* subDecompressed = Decompressed; long decompressedSegmentSize = XSize * YSize; @@ -266,9 +271,9 @@ bool PixelConvert::ReadAndDecompressRLEFile( FILE* fp ) ++it ) { // Loop on the fragments - for( int k = 1; k <= (*it)->NumberFragments; k++ ) + for( unsigned int k = 1; k <= (*it)->NumberFragments; k++ ) { - fseek( fp, (*it)->Offset[k] ,SEEK_SET ); + fp->seekg( (*it)->Offset[k] , std::ios_base::beg ); (void)ReadAndDecompressRLEFragment( subDecompressed, (*it)->Length[k], decompressedSegmentSize, @@ -276,13 +281,13 @@ bool PixelConvert::ReadAndDecompressRLEFile( FILE* fp ) subDecompressed += decompressedSegmentSize; } } - + if ( BitsAllocated == 16 ) { // Try to deal with RLE 16 Bits (void)DecompressRLE16BitsFromRLE8Bits( ZSize ); } - + return true; } @@ -292,7 +297,7 @@ bool PixelConvert::ReadAndDecompressRLEFile( FILE* fp ) void PixelConvert::ConvertSwapZone() { unsigned int i; - + if( BitsAllocated == 16 ) { uint16_t* im16 = (uint16_t*)Decompressed; @@ -399,7 +404,7 @@ void PixelConvert::ConvertReorderEndianity() * @param fp File Pointer * @return Boolean */ -bool PixelConvert::ReadAndDecompressJPEGFile( FILE* fp ) +bool PixelConvert::ReadAndDecompressJPEGFile( std::ifstream* fp ) { uint8_t* localDecompressed = Decompressed; // Loop on the fragment[s] @@ -408,7 +413,7 @@ bool PixelConvert::ReadAndDecompressJPEGFile( FILE* fp ) it != JPEGInfo->Fragments.end(); ++it ) { - fseek( fp, (*it)->Offset, SEEK_SET ); + fp->seekg( (*it)->Offset, std::ios_base::beg); if ( IsJPEG2000 ) { @@ -425,7 +430,7 @@ bool PixelConvert::ReadAndDecompressJPEGFile( FILE* fp ) return false; } } - else if ( BitsStored == 12) + else if ( BitsStored <= 12) { // Reading Fragment pixels if ( ! gdcm_read_JPEG_file12 ( fp, localDecompressed ) ) @@ -433,7 +438,7 @@ bool PixelConvert::ReadAndDecompressJPEGFile( FILE* fp ) return false; } } - else if ( BitsStored == 16) + else if ( BitsStored <= 16) { // Reading Fragment pixels if ( ! gdcm_read_JPEG_file16 ( fp, localDecompressed ) ) @@ -449,12 +454,12 @@ bool PixelConvert::ReadAndDecompressJPEGFile( FILE* fp ) "jpeg lossy compression "); return false; } - + // Advance to next free location in Decompressed // for next fragment decompression (if any) int length = XSize * YSize * SamplesPerPixel; int numberBytes = BitsAllocated / 8; - + localDecompressed += length * numberBytes; } return true; @@ -510,7 +515,7 @@ void PixelConvert::ConvertYcBcRPlanesToRGBPixels() uint8_t* localDecompressed = Decompressed; uint8_t* copyDecompressed = new uint8_t[ DecompressedSize ]; memmove( copyDecompressed, localDecompressed, DecompressedSize ); - + // 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 @@ -518,17 +523,17 @@ void PixelConvert::ConvertYcBcRPlanesToRGBPixels() // int l = XSize * YSize; int nbFrames = ZSize; - + uint8_t* a = copyDecompressed; uint8_t* b = copyDecompressed + l; uint8_t* c = copyDecompressed + 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++ ) @@ -536,14 +541,14 @@ void PixelConvert::ConvertYcBcRPlanesToRGBPixels() 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; - + *(localDecompressed++) = (uint8_t)R; *(localDecompressed++) = (uint8_t)G; *(localDecompressed++) = (uint8_t)B; @@ -564,13 +569,13 @@ void PixelConvert::ConvertRGBPlanesToRGBPixels() uint8_t* localDecompressed = Decompressed; uint8_t* copyDecompressed = new uint8_t[ DecompressedSize ]; memmove( copyDecompressed, localDecompressed, DecompressedSize ); - + int l = XSize * YSize * ZSize; - + uint8_t* a = copyDecompressed; uint8_t* b = copyDecompressed + l; uint8_t* c = copyDecompressed + l + l; - + for (int j = 0; j < l; j++) { *(localDecompressed++) = *(a++); @@ -580,26 +585,32 @@ void PixelConvert::ConvertRGBPlanesToRGBPixels() delete[] copyDecompressed; } -bool PixelConvert::ReadAndDecompressPixelData( FILE* fp ) +bool PixelConvert::ReadAndDecompressPixelData( std::ifstream* fp ) { - ComputeDecompressedAndRGBSizes(); - AllocateDecompressed(); + // ComputeDecompressedAndRGBSizes is already made by + // ::GrabInformationsFromHeader. So, the structure sizes are + // correct + Squeeze(); + ////////////////////////////////////////////////// //// First stage: get our hands on the Pixel Data. if ( !fp ) { - dbg.Verbose( 0, "PixelConvert::ReadAndDecompressPixelData: " - "unavailable file pointer." ); + dbg.Verbose( 0, "PixelConvert::ReadAndDecompressPixelData: " + "unavailable file pointer." ); return false; } - - if ( fseek( fp, PixelOffset, SEEK_SET ) == -1 ) + + fp->seekg( PixelOffset, std::ios_base::beg ); + if( fp->fail() || fp->eof()) //Fp->gcount() == 1 { - dbg.Verbose( 0, "PixelConvert::ReadAndDecompressPixelData: " - "unable to find PixelOffset in file." ); + dbg.Verbose( 0, "PixelConvert::ReadAndDecompressPixelData: " + "unable to find PixelOffset in file." ); return false; } - + + AllocateDecompressed(); + ////////////////////////////////////////////////// //// Second stage: read from disk dans decompress. if ( BitsAllocated == 12 ) @@ -608,8 +619,25 @@ bool PixelConvert::ReadAndDecompressPixelData( FILE* fp ) } else if ( IsDecompressed ) { - size_t ItemRead = fread( Decompressed, PixelDataLength, 1, fp ); - if ( ItemRead != 1 ) + // This problem can be found when some obvious informations are found + // after the field containing the image datas. In this case, these + // bad datas are added to the size of the image (in the PixelDataLength + // variable). But DecompressedSize is the right size of the image ! + if( PixelDataLength != DecompressedSize) + { + dbg.Verbose( 0, "PixelConvert::ReadAndDecompressPixelData: " + "Mismatch between PixelConvert and DecompressedSize." ); + } + if( PixelDataLength > DecompressedSize) + { + fp->read( (char*)Decompressed, DecompressedSize); + } + else + { + fp->read( (char*)Decompressed, PixelDataLength); + } + + if ( fp->fail() || fp->eof())//Fp->gcount() == 1 { dbg.Verbose( 0, "PixelConvert::ReadAndDecompressPixelData: " "reading of decompressed pixel data failed." ); @@ -703,9 +731,16 @@ void PixelConvert::ConvertHandleColor() // [Planar 1] AND [Photo C] ConvertRGBPlanesToRGBPixels(); } + return; } - // When planarConf is 0, pixels are allready in RGB + // When planarConf is 0, and RLELossless (forbidden by Dicom norm) + // pixels need to be RGB-fied anyway + if (IsRLELossless) + { + ConvertRGBPlanesToRGBPixels(); + } + // In *normal *case, when planarConf is 0, pixels are already in RGB } /** @@ -715,7 +750,7 @@ void PixelConvert::ConvertHandleColor() bool PixelConvert::IsDecompressedRGB() { if ( IsMonochrome - || ( PlanarConfiguration == 2 ) + || PlanarConfiguration == 2 || IsPaletteColor ) { return false; @@ -741,14 +776,17 @@ void PixelConvert::ComputeDecompressedAndRGBSizes() { RGBSize = 3 * DecompressedSize; } - + else + { + RGBSize = DecompressedSize; + } } void PixelConvert::GrabInformationsFromHeader( Header* header ) { // Just in case some access to a Header element requires disk access. // Note: gdcmDocument::Fp is leaved open after OpenFile. - FILE* fp = header->OpenFile(); + std::ifstream* fp = header->OpenFile(); // Number of Bits Allocated for storing a Pixel is defaulted to 16 // when absent from the header. BitsAllocated = header->GetBitsAllocated(); @@ -779,15 +817,17 @@ void PixelConvert::GrabInformationsFromHeader( Header* header ) PixelSize = header->GetPixelSize(); PixelSign = header->IsSignedPixelData(); SwapCode = header->GetSwapCode(); + TransferSyntaxType ts = header->GetTransferSyntax(); IsDecompressed = ( ! header->IsDicomV3() ) - || header->IsImplicitVRLittleEndianTransferSyntax() - || header->IsExplicitVRLittleEndianTransferSyntax() - || header->IsExplicitVRBigEndianTransferSyntax() - || header->IsDeflatedExplicitVRLittleEndianTransferSyntax(); + || ts == ImplicitVRLittleEndian + || ts == ImplicitVRLittleEndianDLXGE + || ts == ExplicitVRLittleEndian + || ts == ExplicitVRBigEndian + || ts == DeflatedExplicitVRLittleEndian; IsJPEG2000 = header->IsJPEG2000(); IsJPEGLossless = header->IsJPEGLossless(); - IsRLELossless = header->IsRLELossLessTransferSyntax(); + IsRLELossless = ( ts == RLELossless ); PixelOffset = header->GetPixelOffset(); PixelDataLength = header->GetPixelAreaLength(); RLEInfo = header->GetRLEInfo(); @@ -829,18 +869,15 @@ void PixelConvert::GrabInformationsFromHeader( Header* header ) DocEntry* lutRedDataEntry = header->GetDocEntryByNumber( 0x0028, 0x1201 ); LutRedData = new uint8_t[ lutRedDataEntry->GetLength() ]; - fseek( fp, lutRedDataEntry->GetOffset() ,SEEK_SET ); - int numberItem = fread( LutRedData, - (size_t)lutRedDataEntry->GetLength(), - 1, fp ); - if ( numberItem != 1 ) + fp->seekg( lutRedDataEntry->GetOffset() ,std::ios_base::beg ); + fp->read( (char*)LutRedData, (size_t)lutRedDataEntry->GetLength()); + if ( fp->fail() || fp->eof())//Fp->gcount() == 1 { dbg.Verbose(0, "PixelConvert::GrabInformationsFromHeader: " "unable to read red LUT data" ); - return; } } - + ////// Green round: LutGreenData = (uint8_t*)header->GetEntryBinAreaByNumber(0x0028, 0x1202 ); if ( ! LutGreenData) @@ -849,18 +886,15 @@ void PixelConvert::GrabInformationsFromHeader( Header* header ) DocEntry* lutGreenDataEntry = header->GetDocEntryByNumber( 0x0028, 0x1202 ); LutGreenData = new uint8_t[ lutGreenDataEntry->GetLength() ]; - fseek( fp, lutGreenDataEntry->GetOffset() ,SEEK_SET ); - int numberItem = fread( LutGreenData, - (size_t)lutGreenDataEntry->GetLength(), - 1, fp ); - if ( numberItem != 1 ) + fp->seekg( lutGreenDataEntry->GetOffset() , std::ios_base::beg ); + fp->read( (char*)LutGreenData, (size_t)lutGreenDataEntry->GetLength() ); + if ( fp->fail() || fp->eof())//Fp->gcount() == 1 { dbg.Verbose(0, "PixelConvert::GrabInformationsFromHeader: " "unable to read green LUT data" ); - return; } } - + ////// Blue round: LutBlueData = (uint8_t*)header->GetEntryBinAreaByNumber( 0x0028, 0x1203 ); if ( ! LutBlueData ) @@ -869,20 +903,22 @@ void PixelConvert::GrabInformationsFromHeader( Header* header ) DocEntry* lutBlueDataEntry = header->GetDocEntryByNumber( 0x0028, 0x1203 ); LutBlueData = new uint8_t[ lutBlueDataEntry->GetLength() ]; - fseek( fp, lutBlueDataEntry->GetOffset() ,SEEK_SET ); - int numberItem = fread( LutBlueData, - (size_t)lutBlueDataEntry->GetLength(), - 1, fp ); - if ( numberItem != 1 ) + fp->seekg( lutBlueDataEntry->GetOffset() , std::ios_base::beg ); + fp->read( (char*)LutBlueData, (size_t)lutBlueDataEntry->GetLength() ); + if ( fp->fail() || fp->eof())//Fp->gcount() == 1 { dbg.Verbose(0, "PixelConvert::GrabInformationsFromHeader: " "unable to read blue LUT data" ); - return; } } } - - header->CloseFile(); + + ComputeDecompressedAndRGBSizes(); + + if(fp) + { + header->CloseFile(); + } } /** @@ -914,9 +950,9 @@ void PixelConvert::BuildLUTRGBA() return; } - if ( ( LutRedDescriptor == GDCM_UNFOUND ) - || ( LutGreenDescriptor == GDCM_UNFOUND ) - || ( LutBlueDescriptor == GDCM_UNFOUND ) ) + if ( LutRedDescriptor == GDCM_UNFOUND + || LutGreenDescriptor == GDCM_UNFOUND + || LutBlueDescriptor == GDCM_UNFOUND ) { return; } @@ -1025,10 +1061,23 @@ void PixelConvert::BuildLUTRGBA() */ bool PixelConvert::BuildRGBImage() { + if ( RGB ) + { + // The job is already done. + return true; + } + + if ( ! Decompressed ) + { + // The job can't be done + return false; + } + BuildLUTRGBA(); - if ( ( ! LutRGBA ) || ( ! Decompressed ) ) + if ( ! LutRGBA ) { - return false; + // The job can't be done + return false; } // Build RGB Pixels @@ -1036,7 +1085,7 @@ bool PixelConvert::BuildRGBImage() uint8_t* localRGB = RGB; for (size_t i = 0; i < DecompressedSize; ++i ) { - int j = Decompressed[i] * 4; // \todo I don't get this 4 coefficient ! + int j = Decompressed[i] * 4; *localRGB++ = LutRGBA[j]; *localRGB++ = LutRGBA[j+1]; *localRGB++ = LutRGBA[j+2];