X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmFile.cxx;h=b3eb62e680299e2f8d0ba6a44de98e652057a7ed;hb=152194ed48de20a5189b610bd8d3d26fea95c2ce;hp=975b0a4f7ac07d1c1faf0b47bccfc5e9290e2e90;hpb=e6671b4378ba33a2cdf7c711e4e45250af74dbbc;p=gdcm.git diff --git a/src/gdcmFile.cxx b/src/gdcmFile.cxx index 975b0a4f..b3eb62e6 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/07/31 23:30:04 $ - Version: $Revision: 1.119 $ + Date: $Date: 2004/09/10 18:54:38 $ + Version: $Revision: 1.124 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -22,74 +22,145 @@ typedef std::pair IterHT; -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------- // Constructor / Destructor /** * \ingroup gdcmFile - * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant - * file (see SetFileName, SetDcmTag and Write) + * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3 + * file (gdcmHeader only deals with the ... header) * Opens (in read only and when possible) an existing file and checks * for DICOM compliance. Returns NULL on failure. + * It will be up to the user to load the pixels into memory + * (see GetImageData, GetImageDataRaw) * \note the in-memory representation of all available tags found in * the DICOM header is post-poned to first header information access. * This avoid a double parsing of public part of the header when - * one sets an a posteriori shadow dictionary (efficiency can be + * user sets an a posteriori shadow dictionary (efficiency can be * seen as a side effect). - * @param header file to be opened for reading datas - * @return + * @param header already built gdcmHeader */ gdcmFile::gdcmFile(gdcmHeader *header) { Header = header; SelfHeader = false; - PixelRead = -1; // no ImageData read yet. - - if (Header->IsReadable()) - { - SetPixelDataSizeFromHeader(); - } + SetInitialValues(); } /** * \ingroup gdcmFile - * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant - * file (see SetFileName, SetDcmTag and Write) + * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3 + * file (gdcmHeader only deals with the ... header) * Opens (in read only and when possible) an existing file and checks * for DICOM compliance. Returns NULL on failure. + * It will be up to the user to load the pixels into memory + * (see GetImageData, GetImageDataRaw) * \note the in-memory representation of all available tags found in * the DICOM header is post-poned to first header information access. * This avoid a double parsing of public part of the header when * one sets an a posteriori shadow dictionary (efficiency can be * seen as a side effect). * @param filename file to be opened for parsing - * @param exception_on_error whether we throw an exception or not */ -gdcmFile::gdcmFile(std::string const & filename, - bool exception_on_error ) +gdcmFile::gdcmFile(std::string const & filename ) { - Header = new gdcmHeader( filename, exception_on_error ); + Header = new gdcmHeader( filename ); SelfHeader = true; + SetInitialValues(); +} + +/** + * \ingroup gdcmFile + * \brief Sets some initial for the Constructor + */ +void gdcmFile::SetInitialValues() +{ PixelRead = -1; // no ImageData read yet. + LastAllocatedPixelDataLength = 0; + Pixel_Data = 0; + InitialSpp = ""; + InitialPhotInt = ""; + InitialPlanConfig = ""; + InitialBitsAllocated = ""; + + InitialRedLUTDescr = 0; + InitialGreenLUTDescr = 0; + InitialBlueLUTDescr = 0; + InitialRedLUTData = 0; + InitialGreenLUTData = 0; + InitialBlueLUTData = 0; + if ( Header->IsReadable() ) { SetPixelDataSizeFromHeader(); + + // the following values *may* be modified + // by gdcmFile::GetImageDataIntoVectorRaw + // we save their initial value. + InitialSpp = Header->GetEntryByNumber(0x0028,0x0002); + InitialPhotInt = Header->GetEntryByNumber(0x0028,0x0004); + InitialPlanConfig = Header->GetEntryByNumber(0x0028,0x0006); + InitialBitsAllocated = Header->GetEntryByNumber(0x0028,0x0100); + + // the following entries *may* be removed + // by gdcmFile::GetImageDataIntoVectorRaw + // we save them. + + // we SHALL save them ! + // (some troubles, now) + /* + InitialRedLUTDescr = Header->GetDocEntryByNumber(0x0028,0x1101); + InitialGreenLUTDescr = Header->GetDocEntryByNumber(0x0028,0x1102); + InitialBlueLUTDescr = Header->GetDocEntryByNumber(0x0028,0x1103); + InitialRedLUTData = Header->GetDocEntryByNumber(0x0028,0x1201); + InitialGreenLUTData = Header->GetDocEntryByNumber(0x0028,0x1202); + InitialBlueLUTData = Header->GetDocEntryByNumber(0x0028,0x1203); + + if (InitialRedLUTData == NULL) + std::cout << "echec InitialRedLUTData " << std::endl; + else + { + printf("%p\n",InitialRedLUTData); + InitialRedLUTData->Print(); std::cout <GetXSize() * Header->GetYSize() + ImageDataSize = + ImageDataSizeRaw = Header->GetXSize() * Header->GetYSize() * Header->GetZSize() * (nb/8) * Header->GetSamplesPerPixel(); std::string str_PhotometricInterpretation = Header->GetEntryByNumber(0x0028,0x0004); - // if ( str_PhotometricInterpretation == "PALETTE COLOR " ) + // if ( str_PhotometricInterpretation == "PALETTE COLOR " ), // pb when undealt Segmented Palette Color if ( Header->HasLUT() ) @@ -164,63 +236,59 @@ void gdcmFile::SetPixelDataSizeFromHeader() } } -/** - * \ingroup gdcmFile - * \brief Returns the size (in bytes) of required memory to hold - * the pixel data represented in this file. - * @return The size of pixel data in bytes. - */ -size_t gdcmFile::GetImageDataSize() -{ - return ImageDataSize; -} - -/** - * \ingroup gdcmFile - * \brief Returns the size (in bytes) of required memory to hold - * the pixel data represented in this file, when user DOESN'T want - * to get RGB pixels image when it's stored as a PALETTE COLOR image - * -the (vtk) user is supposed to know how deal with LUTs- - * \warning to be used with GetImagePixelsRaw() - * @return The size of pixel data in bytes. - */ -size_t gdcmFile::GetImageDataSizeRaw() -{ - return ImageDataSizeRaw; -} - /** * \ingroup gdcmFile - * \brief Allocates necessary memory, copies the pixel data - * (image[s]/volume[s]) to newly allocated zone. - * Transforms YBR pixels into RGB pixels if any - * Transforms 3 planes R, G, B into a single RGB Plane - * Transforms single Grey plane + 3 Palettes into a RGB Plane + * \brief - Allocates necessary memory, + * - Reads the pixels from disk (uncompress if necessary), + * - Transforms YBR pixels, if any, into RGB pixels + * - Transforms 3 planes R, G, B, if any, into a single RGB Plane + * - Transforms single Grey plane + 3 Palettes into a RGB Plane + * - Copies the pixel data (image[s]/volume[s]) to newly allocated zone. * @return Pointer to newly allocated pixel data. * NULL if alloc fails */ void *gdcmFile::GetImageData() { - // FIXME - // I need to deallocate PixelData before doing any allocation: - PixelData = new uint8_t[ImageDataSize]; - if ( PixelData ) + // FIXME (Mathieu) + // I need to deallocate Pixel_Data before doing any allocation: + + if ( Pixel_Data ) + if ( LastAllocatedPixelDataLength != ImageDataSize ) + free(Pixel_Data); + if ( !Pixel_Data ) + Pixel_Data = new uint8_t[ImageDataSize]; + + if ( Pixel_Data ) { - GetImageDataIntoVector(PixelData, ImageDataSize); - GetHeader()->SetEntryVoidAreaByNumber( PixelData, + LastAllocatedPixelDataLength = ImageDataSize; + + // we load the pixels (and transform grey level + LUT into RGB) + GetImageDataIntoVector(Pixel_Data, ImageDataSize); + + // We say the value *is* loaded. + GetHeader()->SetEntryByNumber( GDCM_BINLOADED, + GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel()); + + // Will be 7fe0, 0010 in standard case + GetHeader()->SetEntryVoidAreaByNumber( Pixel_Data, GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel()); } PixelRead = 0; // no PixelRaw - return PixelData; + return Pixel_Data; } /** * \ingroup gdcmFile - * \brief Copies at most MaxSize bytes of pixel data to caller's + * \brief + * Read the pixels from disk (uncompress if necessary), + * Transforms YBR pixels, if any, into RGB pixels + * Transforms 3 planes R, G, B, if any, into a single RGB Plane + * Transforms single Grey plane + 3 Palettes into a RGB Plane + * Copies at most MaxSize bytes of pixel data to caller allocated * memory space. - * \warning This function was designed to avoid people that want to build - * a volume from an image stack to need first to get the image pixels + * \warning This function allows people that want to build a volume + * from an image stack *not to* have, first to get the image pixels, * and then move them to the volume area. * It's absolutely useless for any VTK user since vtk chooses * to invert the lines of an image, that is the last line comes first @@ -238,9 +306,8 @@ void *gdcmFile::GetImageData() */ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t maxSize) { - //size_t l = GetImageDataIntoVectorRaw (destination, maxSize); GetImageDataIntoVectorRaw (destination, maxSize); - PixelRead = 0 ; // no PixelRaw + PixelRead = 0 ; // =0 : no ImageDataRaw if ( !Header->HasLUT() ) { return ImageDataSize; @@ -254,7 +321,6 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t maxSize) if ( lutRGBA ) { int j; - //int l = ImageDataSizeRaw; //loss of precision // move Gray pixels to temp area memmove(newDest, destination, ImageDataSizeRaw); for (size_t i=0; iSetEntryByNumber(spp,0x0028,0x0002); - std::string rgb = "RGB "; // Photometric Interpretation + std::string rgb = "RGB "; // Photometric Interpretation Header->SetEntryByNumber(rgb,0x0028,0x0004); std::string planConfig = "0"; // Planar Configuration Header->SetEntryByNumber(planConfig,0x0028,0x0006); } - else //why is there a 'else' when an allocation failed ? - { - // need to make RGB Pixels (?) - // from grey Pixels (?!) - // and Gray Lut (!?!) - // or Segmented xxx Palette Color Lookup Table Data and so on - - // Oops! I get one (gdcm-US-ALOKA-16.dcm) - // No idea how to manage such an image + else // GetLUTRGBA() failed + { + // (gdcm-US-ALOKA-16.dcm), contains Segmented xxx Palette Color + // that are *more* than 65535 long ?!? + // No idea how to manage such an image ! + // Need to make RGB Pixels (?) from grey Pixels (?!) and Gray Lut (!?!) // It seems that *no Dicom Viewer* has any idea :-( - // Segmented xxx Palette Color are *more* than 65535 long ?!? - - std::string rgb = "MONOCHROME1 "; // Photometric Interpretation - Header->SetEntryByNumber(rgb,0x0028,0x0004); + + std::string photomInterp = "MONOCHROME1 "; // Photometric Interpretation + Header->SetEntryByNumber(photomInterp,0x0028,0x0004); } /// \todo Drop Palette Color out of the Header? @@ -302,35 +364,50 @@ size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t maxSize) /** * \ingroup gdcmFile - * \brief Allocates necessary memory, copies the pixel data - * (image[s]/volume[s]) to newly allocated zone. - * Transforms YBR pixels into RGB pixels if any - * Transforms 3 planes R, G, B into a single RGB Plane + * \brief Allocates necessary memory, + * Transforms YBR pixels (if any) into RGB pixels + * Transforms 3 planes R, G, B (if any) into a single RGB Plane + * Copies the pixel data (image[s]/volume[s]) to newly allocated zone. * DOES NOT transform Grey plane + 3 Palettes into a RGB Plane * @return Pointer to newly allocated pixel data. * \ NULL if alloc fails */ void * gdcmFile::GetImageDataRaw () { - size_t imgDataSize = ImageDataSize; + size_t imgDataSize; if ( Header->HasLUT() ) - { /// \todo Let gdcmHeader user a chance to get the right value imgDataSize = ImageDataSizeRaw; - } + else + imgDataSize = ImageDataSize; + + // FIXME (Mathieu) + // I need to deallocate Pixel_Data before doing any allocation: + + if ( Pixel_Data ) + if ( LastAllocatedPixelDataLength != imgDataSize ) + free(Pixel_Data); + if ( !Pixel_Data ) + Pixel_Data = new uint8_t[imgDataSize]; - // FIXME - // I need to deallocate PixelData before doing any allocation: - PixelData = new uint8_t[imgDataSize]; - if ( PixelData ) + if ( Pixel_Data ) { - GetImageDataIntoVectorRaw(PixelData, ImageDataSize); - GetHeader()->SetEntryVoidAreaByNumber(PixelData, - GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel()); + LastAllocatedPixelDataLength = imgDataSize; + + // we load the pixels ( grey level or RGB, but NO transformation) + GetImageDataIntoVectorRaw(Pixel_Data, imgDataSize); + + // We say the value *is* loaded. + GetHeader()->SetEntryByNumber( GDCM_BINLOADED, + GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel()); + + // will be 7fe0, 0010 in standard cases + GetHeader()->SetEntryVoidAreaByNumber(Pixel_Data, + GetHeader()->GetGrPixel(), GetHeader()->GetNumPixel()); } PixelRead = 1; // PixelRaw - return PixelData; + return Pixel_Data; } /** @@ -360,8 +437,30 @@ void * gdcmFile::GetImageDataRaw () size_t gdcmFile::GetImageDataIntoVectorRaw (void *destination, size_t maxSize) { int nb, nbu, highBit, sign; + + // we save the initial values of the following + // in order to be able to restore the header in a disk-consistent state + // (if user asks twice to get the pixels from disk) + + if ( PixelRead == -1 ) // File was never "read" before + { + InitialSpp = Header->GetEntryByNumber(0x0028,0x0002); + InitialPhotInt = Header->GetEntryByNumber(0x0028,0x0004); + InitialPlanConfig = Header->GetEntryByNumber(0x0028,0x0006); + InitialBitsAllocated = Header->GetEntryByNumber(0x0028,0x0100); + } + else // File was already "read", the following *may* have been modified + // we restore them to be in a disk-consistent state + { + // FIXME : What happened with the LUTs ? + Header->SetEntryByNumber(InitialSpp,0x0028,0x0002); + Header->SetEntryByNumber(InitialPhotInt,0x0028,0x0004); + Header->SetEntryByNumber(InitialPlanConfig,0x0028,0x0006); + Header->SetEntryByNumber(InitialBitsAllocated,0x0028,0x0100); + } + PixelRead = 1 ; // PixelRaw - + if ( ImageDataSize > maxSize ) { dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: pixel data bigger" @@ -600,12 +699,14 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void *destination, size_t maxSize) // CreateOrReplaceIfExist ? - std::string spp = "3"; // Samples Per Pixel - std::string rgb = "RGB "; // Photometric Interpretation - std::string planConfig = "0"; // Planar Configuration + std::string spp = "3"; // Samples Per Pixel + std::string photInt = "RGB "; // Photometric Interpretation + std::string planConfig = "0"; // Planar Configuration + + Header->SetEntryByNumber(spp,0x0028,0x0002); - Header->SetEntryByNumber(rgb,0x0028,0x0004); + Header->SetEntryByNumber(photInt,0x0028,0x0004); Header->SetEntryByNumber(planConfig,0x0028,0x0006); /// \todo Drop Palette Color out of the Header? @@ -617,7 +718,7 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void *destination, size_t maxSize) * \brief performs a shalow copy (not a deep copy) of the user given * pixel area. * 'image' Pixels are presented as C-like 2D arrays : line per line. - * 'volume'Pixels are presented as C-like 3D arrays : lane per plane + * 'volume'Pixels are presented as C-like 3D arrays : plane per plane * \warning user is kindly requested NOT TO 'free' the Pixel area * @param inData user supplied pixel area * @param expectedSize total image size, in Bytes @@ -627,10 +728,11 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void *destination, size_t maxSize) bool gdcmFile::SetImageData(void *inData, size_t expectedSize) { Header->SetImageDataSize( expectedSize ); - PixelData = inData; - ImageDataSize = expectedSize; +// FIXME : if already allocated, memory leak ! + Pixel_Data = inData; + ImageDataSize = ImageDataSizeRaw = expectedSize; PixelRead = 1; - +// FIXME : 7fe0, 0010 IS NOT set ... return true; } @@ -652,7 +754,7 @@ bool gdcmFile::WriteRawData(std::string const & fileName) printf("Fail to open (write) file [%s] \n", fileName.c_str()); return false; } - fwrite (PixelData, ImageDataSize, 1, fp1); + fwrite (Pixel_Data, ImageDataSize, 1, fp1); fclose (fp1); return true; @@ -796,7 +898,7 @@ bool gdcmFile::WriteBase (std::string const & fileName, FileType type) } // ----------------- End of Special Patch ---------------- - // fwrite(PixelData, ImageDataSize, 1, fp1); // should be useless, now + // fwrite(Pixel_Data, ImageDataSize, 1, fp1); // should be useless, now fclose (fp1); return true;