X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmPixelConvert.cxx;h=9a8afcd3ed7afdb18f9559b42b7885a6db2a9faf;hb=4dd42f8153a4d5ea8d2524b3c6670e80232f73b4;hp=5923d8de31d535448b7c05389080cfaf8cb55327;hpb=689f929ff0f35aabd30d81ffa75eb66fdf1a3c16;p=gdcm.git diff --git a/src/gdcmPixelConvert.cxx b/src/gdcmPixelConvert.cxx index 5923d8de..9a8afcd3 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/09/29 17:33:17 $ - Version: $Revision: 1.1 $ + Date: $Date: 2004/10/08 17:02:53 $ + Version: $Revision: 1.4 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -16,7 +16,9 @@ =========================================================================*/ -////// #include +////////////////// TEMPORARY NOT +// look for "fixMem" and convert that to a member of this class +// Removing the prefix fixMem and dealing with allocations should do the trick #define str2num(str, typeNum) *((typeNum *)(str)) #include "gdcmDebug.h" @@ -68,46 +70,53 @@ void gdcmPixelConvert::AllocateUncompressed() * \brief Read from file a 12 bits per pixel image and uncompress it * into a 16 bits per pixel image. */ -bool gdcmPixelConvert::ReadAndUncompress12Bits( FILE* filePointer, - size_t uncompressedSize, - size_t PixelNumber ) +void gdcmPixelConvert::ConvertDecompress12BitsTo16Bits( + uint8_t* pixelZone, + int sizeX, + int sizeY, + FILE* filePtr) + throw ( gdcmFormatError ) { - SetUncompressedSize( uncompressedSize ); - AllocateUncompressed(); - - uint16_t* pdestination = (uint16_t*)Uncompressed; + int nbPixels = sizeX * sizeY; + uint16_t* destination = (uint16_t*)pixelZone; - for(int p = 0; p < PixelNumber; p += 2 ) + for( int p = 0; p < nbPixels; p += 2 ) { - // 2 pixels 12bit = [0xABCDEF] - // 2 pixels 16bit = [0x0ABD] + [0x0FCE] uint8_t b0, b1, b2; size_t ItemRead; - ItemRead = fread( &b0, 1, 1, filePointer); + + ItemRead = fread( &b0, 1, 1, filePtr); if ( ItemRead != 1 ) { - return false; + throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()", + "Unfound first block" ); } - ItemRead = fread( &b1, 1, 1, filePointer); + + ItemRead = fread( &b1, 1, 1, filePtr); if ( ItemRead != 1 ) { - return false; + throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()", + "Unfound second block" ); } - ItemRead = fread( &b2, 1, 1, filePointer); + + ItemRead = fread( &b2, 1, 1, filePtr); if ( ItemRead != 1 ) { - return false; + throw gdcmFormatError( "gdcmFile::ConvertDecompress12BitsTo16Bits()", + "Unfound second block" ); } - //Two steps are necessary to please VC++ - *pdestination++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f); + // Two steps are necessary to please VC++ + // + // 2 pixels 12bit = [0xABCDEF] + // 2 pixels 16bit = [0x0ABD] + [0x0FCE] // A B D - *pdestination++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4); + *destination++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f); // F C E + *destination++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4); /// \todo JPR Troubles expected on Big-Endian processors ? } - return true; } /** @@ -163,29 +172,23 @@ bool gdcmPixelConvert::ConvertGrayAndLutToRGB( uint8_t *lutRGBA ) * @return Boolean */ bool gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits( - size_t PixelNumber, - int NumberOfFrames ) - + int XSize, + int YSize, + int NumberOfFrames, + uint8_t* fixMemUncompressed ) { - /// We assumed Uncompressed contains the decoded RLE pixels but as - /// 8 bits per pixel. In order to convert those pixels to 16 bits - /// per pixel we need to double the space. Hence we cannot work in - /// place within Uncompressed. So, here is how we handle things: - /// - First stage: copy Uncompressed in a safe place, say OldUncompressed - /// - Second stage: reallocate Uncompressed with the needed space - /// - Third stage: expand from OldUncompressed to Uncompressed - /// - Fourth stage: clean up OldUncompressed - - /// First stage: - uint8_t* OldUncompressed = new uint8_t[UncompressedSize * 2]; - memmove( OldUncompressed, Uncompressed, UncompressedSize); - - /// Second stage: - SetUncompressedSize( 2 * UncompressedSize ); - AllocateUncompressed(); + size_t PixelNumber = XSize * YSize; + size_t fixMemUncompressedSize = XSize * YSize * NumberOfFrames; - /// Third stage: - uint8_t* x = Uncompressed; + // We assumed Uncompressed 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 Uncompressed and hence + // we copy Uncompressed in a safe place, say OldUncompressed. + + uint8_t* OldUncompressed = new uint8_t[ fixMemUncompressedSize * 2 ]; + memmove( OldUncompressed, fixMemUncompressed, fixMemUncompressedSize * 2); + + uint8_t* x = fixMemUncompressed; uint8_t* a = OldUncompressed; uint8_t* b = a + PixelNumber; @@ -198,9 +201,232 @@ bool gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits( } } - // Fourth stage: delete[] OldUncompressed; /// \todo check that operator new []didn't fail, and sometimes return false return true; } + +/** + * \brief Implementation of the RLE decoding algorithm for uncompressing + * a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86] + */ +bool gdcmPixelConvert::ReadAndUncompressRLEFragment( uint8_t* decodedZone, + long fragmentSize, + long uncompressedSegmentSize, + FILE* fp ) +{ + int8_t count; + long numberOfOutputBytes = 0; + long numberOfReadBytes = 0; + + while( numberOfOutputBytes < uncompressedSegmentSize ) + { + fread( &count, 1, 1, fp ); + numberOfReadBytes += 1; + if ( count >= 0 ) + // Note: count <= 127 comparison is always true due to limited range + // of data type int8_t [since the maximum of an exact width + // signed integer of width N is 2^(N-1) - 1, which for int8_t + // is 127]. + { + fread( decodedZone, count + 1, 1, fp); + numberOfReadBytes += count + 1; + decodedZone += count + 1; + numberOfOutputBytes += count + 1; + } + else + { + if ( ( count <= -1 ) && ( count >= -127 ) ) + { + int8_t newByte; + fread( &newByte, 1, 1, fp); + numberOfReadBytes += 1; + for( int i = 0; i < -count + 1; i++ ) + { + decodedZone[i] = newByte; + } + decodedZone += -count + 1; + numberOfOutputBytes += -count + 1; + } + } + // if count = 128 output nothing + + if ( numberOfReadBytes > fragmentSize ) + { + dbg.Verbose(0, "gdcmFile::gdcm_read_RLE_fragment: we read more " + "bytes than the segment size."); + return false; + } + } + return true; +} + +/** + * \brief Reads from disk the Pixel Data of 'Run Length Encoded' + * Dicom encapsulated file and uncompress it. + * @param fp already open File Pointer + * @param image_buffer destination Address (in caller's memory space) + * at which the pixel data should be copied + * @return Boolean + */ +bool gdcmPixelConvert::gdcm_read_RLE_file( void* image_buffer, + int XSize, + int YSize, + int ZSize, + int BitsAllocated, + gdcmRLEFramesInfo* RLEInfo, + FILE* fp ) +{ + uint8_t* im = (uint8_t*)image_buffer; + long uncompressedSegmentSize = XSize * YSize; + + + // Loop on the frame[s] + for( gdcmRLEFramesInfo::RLEFrameList::iterator + it = RLEInfo->Frames.begin(); + it != RLEInfo->Frames.end(); + ++it ) + { + // Loop on the fragments + for( unsigned int k = 1; k <= (*it)->NumberFragments; k++ ) + { + fseek( fp, (*it)->Offset[k] ,SEEK_SET); + (void)gdcmPixelConvert::ReadAndUncompressRLEFragment( + (uint8_t*) im, (*it)->Length[k], + uncompressedSegmentSize, fp ); + im += uncompressedSegmentSize; + } + } + + if ( BitsAllocated == 16 ) + { + // Try to deal with RLE 16 Bits + (void)gdcmPixelConvert::UncompressRLE16BitsFromRLE8Bits( + XSize, + YSize, + ZSize, + (uint8_t*) image_buffer); + } + + return true; +} + +/** + * \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 gdcmPixelConvert::SwapZone(void* im, int swap, int lgr, int nb) +{ + int i; + + if( nb == 16 ) + { + uint16_t* im16 = (uint16_t*)im; + switch( swap ) + { + case 0: + case 12: + case 1234: + break; + case 21: + case 3412: + case 2143: + case 4321: + for(i=0; i < lgr/2; i++) + { + im16[i]= (im16[i] >> 8) | (im16[i] << 8 ); + } + break; + default: + std::cout << "SWAP value (16 bits) not allowed :i" << swap << + std::endl; + } + } + else if( nb == 32 ) + { + uint32_t s32; + uint16_t fort, faible; + uint32_t* im32 = (uint32_t*)im; + switch ( swap ) + { + case 0: + case 1234: + break; + case 4321: + for(i = 0; i < lgr/4; i++) + { + faible = im32[i] & 0x0000ffff; // 4321 + fort = im32[i] >> 16; + fort = ( fort >> 8 ) | ( fort << 8 ); + faible = ( faible >> 8 ) | ( faible << 8); + s32 = faible; + im32[i] = ( s32 << 16 ) | fort; + } + break; + case 2143: + for(i = 0; i < lgr/4; i++) + { + faible = im32[i] & 0x0000ffff; // 2143 + fort = im32[i] >> 16; + fort = ( fort >> 8 ) | ( fort << 8 ); + faible = ( faible >> 8) | ( faible << 8); + s32 = fort; + im32[i] = ( s32 << 16 ) | faible; + } + break; + case 3412: + for(i = 0; i < lgr/4; i++) + { + faible = im32[i] & 0x0000ffff; // 3412 + fort = im32[i] >> 16; + s32 = faible; + im32[i] = ( s32 << 16 ) | fort; + } + break; + default: + std::cout << "SWAP value (32 bits) not allowed : " << swap << + std::endl; + } + } +} + + + +/** + * \brief Deal with endianity i.e. re-arange bytes inside the integer + */ +void gdcmPixelConvert::ConvertReorderEndianity( uint8_t* pixelZone, + size_t imageDataSize, + int numberBitsStored, + int numberBitsAllocated, + int swapCode, + bool signedPixel) +{ + if ( numberBitsAllocated != 8 ) + { + SwapZone( pixelZone, swapCode, imageDataSize, numberBitsAllocated ); + } + + // Special kludge in order to deal with xmedcon broken images: + if ( ( numberBitsAllocated == 16 ) + && ( numberBitsStored < numberBitsAllocated ) + && ( ! signedPixel ) ) + { + int l = (int)(imageDataSize / (numberBitsAllocated/8)); + uint16_t *deb = (uint16_t *)pixelZone; + for(int i = 0; i