From da6bc02a3bb5627685bd70f5503305a7f9b3d7cd Mon Sep 17 00:00:00 2001 From: frog Date: Sun, 10 Oct 2004 16:43:58 +0000 Subject: [PATCH] * 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. 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 and stores the result in a gdcmJPEGFragmentsInfo. - src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: all JPEG related code (among other stuff) moved away from gdcmFile:; to gdcmPixelConvert:: --- ChangeLog | 16 ++- Doc/Website/CodingStyle.html | 2 +- src/CMakeLists.txt | 1 + src/gdcmDocument.cxx | 162 +++++++++++++++++++-------- src/gdcmDocument.h | 13 ++- src/gdcmFile.cxx | 197 +++++---------------------------- src/gdcmFile.h | 15 +-- src/gdcmJPEGFragment.h | 51 +++++++++ src/gdcmJPEGFragmentsInfo.cxx | 30 +++++ src/gdcmJPEGFragmentsInfo.h | 49 +++++++++ src/gdcmJpeg12.cxx | 6 +- src/gdcmJpeg2000.cxx | 7 +- src/gdcmJpeg8.cxx | 7 +- src/gdcmPixelConvert.cxx | 201 +++++++++++++++++++++++++--------- src/gdcmPixelConvert.h | 36 ++++-- src/gdcmRLEFramesInfo.h | 7 +- 16 files changed, 486 insertions(+), 314 deletions(-) create mode 100644 src/gdcmJPEGFragment.h create mode 100644 src/gdcmJPEGFragmentsInfo.cxx create mode 100644 src/gdcmJPEGFragmentsInfo.h diff --git a/ChangeLog b/ChangeLog index 912b4b43..7b3e64d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +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 + (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 + and stores the result in a gdcmJPEGFragmentsInfo. + - src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: all JPEG related + code (among other stuff) moved away from gdcmFile:; to + gdcmPixelConvert:: + 2004-10-08 Eric Boix * src/gdcmCommon.h now declares int8_t for non stdint.h plateforms. * CLEANUP_ROUND (7) for gdcmPixelConvert (lost at sea) @@ -12,7 +27,6 @@ - src/gdcmFile.[cxx|h} gdcmPixelConvert.[cxx|h], SwapZone(), ConvertReorderEndianity(), ConvertDecmpres12BitsTo16Bits() moved away from gdcmFile:: to gdcmPixelConvert::. - 2004-10-07 Eric Boix * CLEANUP_ROUND (5) for gdcmPixelConvert (Upshit creek without a paddle) diff --git a/Doc/Website/CodingStyle.html b/Doc/Website/CodingStyle.html index d62d019f..53910bb9 100644 --- a/Doc/Website/CodingStyle.html +++ b/Doc/Website/CodingStyle.html @@ -279,7 +279,7 @@ long long -> int64_t; Hence do not use declarations like "unsigned int". With g++, accessing those typedef is achieved by the following - #include + #include < stdint.h > diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc7a730a..8a44a443 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,7 @@ SET(libgdcm_la_SOURCES gdcmGlobal.cxx gdcmHeader.cxx gdcmHeaderHelper.cxx + gdcmJPEGFragmentsInfo.cxx gdcmJpeg8.cxx gdcmJpeg12.cxx gdcmJpeg2000.cxx diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index c037ba6d..7b8af5e2 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2004/10/10 03:03:10 $ - Version: $Revision: 1.101 $ + Date: $Date: 2004/10/10 16:43:59 $ + Version: $Revision: 1.102 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -450,21 +450,32 @@ bool gdcmDocument::IsJPEG2000() } /** - * \brief Determines if the Transfer Syntax corresponds to encapsulated - * of encoded Pixel Data (as opposed to native). - * @return True when encapsulated. False when native. + * \brief Determines if the Transfer Syntax corresponds to any form + * of Jpeg encoded Pixel data. + * @return True when any form of JPEG found. False otherwise. */ -bool gdcmDocument::IsEncapsulateTransferSyntax() +bool gdcmDocument::IsJPEGTransferSyntax() { return ( IsJPEGBaseLineProcess1TransferSyntax() || IsJPEGExtendedProcess2_4TransferSyntax() || IsJPEGExtendedProcess3_5TransferSyntax() || IsJPEGSpectralSelectionProcess6_8TransferSyntax() - || IsRLELossLessTransferSyntax() || IsJPEGLossless() || IsJPEG2000() ); } + +/** + * \brief Determines if the Transfer Syntax corresponds to encapsulated + * of encoded Pixel Data (as opposed to native). + * @return True when encapsulated. False when native. + */ +bool gdcmDocument::IsEncapsulateTransferSyntax() +{ + return ( IsJPEGTransferSyntax() + || IsRLELossLessTransferSyntax() ); +} + /** * \brief Predicate for dicom version 3 file. * @return True when the file is a dicom version 3. @@ -981,12 +992,14 @@ bool gdcmDocument::SetEntryByNumber(std::string const& content, gdcmVRKey vr = valEntry->GetVR(); if( vr == "US" || vr == "SS" ) { - c = gdcmUtil::CountSubstring(content, "\\") + 1; // for multivaluated items + // for multivaluated items + c = gdcmUtil::CountSubstring(content, "\\") + 1; l = c*2; } else if( vr == "UL" || vr == "SL" ) { - c = gdcmUtil::CountSubstring(content, "\\") + 1; // for multivaluated items + // for multivaluated items + c = gdcmUtil::CountSubstring(content, "\\") + 1; l = c*4;; } } @@ -1468,26 +1481,28 @@ void gdcmDocument::ParseDES(gdcmDocEntrySet *set, LoadDocEntry( newBinEntry ); } - if (newDocEntry->GetGroup() == 0x7fe0 && - newDocEntry->GetElement() == 0x0010 ) + if ( ( newDocEntry->GetGroup() == 0x7fe0 ) + && ( newDocEntry->GetElement() == 0x0010 ) ) { if ( IsRLELossLessTransferSyntax() ) { long PositionOnEntry = ftell(Fp); - fseek(Fp, newDocEntry->GetOffset(), SEEK_SET); + fseek( Fp, newDocEntry->GetOffset(), SEEK_SET ); ComputeRLEInfo(); - fseek(Fp, PositionOnEntry, SEEK_SET); + fseek( Fp, PositionOnEntry, SEEK_SET ); } - else + else + if ( IsJPEGTransferSyntax() ) { - SkipToNextDocEntry(newDocEntry); + long PositionOnEntry = ftell(Fp); + fseek( Fp, newDocEntry->GetOffset(), SEEK_SET ); + ComputeJPEGFragmentInfo(); + fseek( Fp, PositionOnEntry, SEEK_SET ); } } - else - { - // to be sure we are at the beginning - SkipToNextDocEntry(newDocEntry); - } + + // Just to make sure we are at the beginning of next entry. + SkipToNextDocEntry(newDocEntry); } else { @@ -2828,30 +2843,11 @@ uint32_t gdcmDocument::ReadTagLength(uint16_t testGroup, uint16_t testElement) } /** - * \brief Parse pixel data from disk of [multi-]fragment RLE encoding. - * Compute the RLE extra information and store it in \ref RLEInfo - * for later pixel retrieval usage. + * \brief When parsing the Pixel Data of an encapsulated file, read + * the basic offset table (when present, and BTW dump it). */ -void gdcmDocument::ComputeRLEInfo() +void gdcmDocument::ReadAndSkipEncapsulatedBasicOffsetTable() { - if ( ! IsRLELossLessTransferSyntax() ) - { - return; - } - // Encoded pixel data: for the time being we are only concerned with - // Jpeg or RLE Pixel data encodings. - // As stated in PS 3.5-2003, section 8.2 p44: - // "If sent in Encapsulated Format (i.e. other than the Native Format) the - // value representation OB is used". - // Hence we expect an OB value representation. Concerning OB VR, - // the section PS 3.5-2003, section A.4.c p 58-59, states: - // "For the Value Representations OB and OW, the encoding shall meet the - // following specifications depending on the Data element tag:" - // [...snip...] - // - the first item in the sequence of items before the encoded pixel - // data stream shall be basic offset table item. The basic offset table - // item value, however, is not required to be present" - //// Read the Basic Offset Table Item Tag length... uint32_t itemLength = ReadTagLength(0xfffe, 0xe000); @@ -2866,6 +2862,7 @@ void gdcmDocument::ComputeRLEInfo() char* basicOffsetTableItemValue = new char[itemLength + 1]; fread(basicOffsetTableItemValue, itemLength, 1, Fp); +#ifdef GDCM_DEBUG for (unsigned int i=0; i < itemLength; i += 4 ) { uint32_t individualLength = str2num( &basicOffsetTableItemValue[i], @@ -2873,22 +2870,52 @@ void gdcmDocument::ComputeRLEInfo() std::ostringstream s; s << " Read one length: "; s << std::hex << individualLength << std::endl; - dbg.Verbose(0, "gdcmDocument::ComputeRLEInfo: ", s.str().c_str()); + dbg.Verbose(0, + "gdcmDocument::ReadAndSkipEncapsulatedBasicOffsetTable: ", + s.str().c_str()); } +#endif //GDCM_DEBUG + delete[] basicOffsetTableItemValue; } +} - // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G) - // Loop on the frame[s] and store the parsed information in a - // gdcmRLEFramesInfo. - long frameLength; +/** + * \brief Parse pixel data from disk of [multi-]fragment RLE encoding. + * Compute the RLE extra information and store it in \ref RLEInfo + * for later pixel retrieval usage. + */ +void gdcmDocument::ComputeRLEInfo() +{ + if ( ! IsRLELossLessTransferSyntax() ) + { + return; + } + + // Encoded pixel data: for the time being we are only concerned with + // Jpeg or RLE Pixel data encodings. + // As stated in PS 3.5-2003, section 8.2 p44: + // "If sent in Encapsulated Format (i.e. other than the Native Format) the + // value representation OB is used". + // Hence we expect an OB value representation. Concerning OB VR, + // the section PS 3.5-2003, section A.4.c p 58-59, states: + // "For the Value Representations OB and OW, the encoding shall meet the + // following specifications depending on the Data element tag:" + // [...snip...] + // - the first item in the sequence of items before the encoded pixel + // data stream shall be basic offset table item. The basic offset table + // item value, however, is not required to be present" + + ReadAndSkipEncapsulatedBasicOffsetTable(); + // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G) // Loop on the individual frame[s] and store the information // on the RLE fragments in a gdcmRLEFramesInfo. // Note: - when only a single frame is present, this is a // classical image. // - when more than one frame are present, then we are in // the case of a multi-frame image. + long frameLength; while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) ) { // Parse the RLE Header and store the corresponding RLE Segment @@ -2944,6 +2971,47 @@ void gdcmDocument::ComputeRLEInfo() } } +/** + * \brief Parse pixel data from disk of [multi-]fragment Jpeg encoding. + * Compute the jpeg extra information (fragment[s] offset[s] and + * length) and store it[them] in \ref JPEGInfo for later pixel + * retrieval usage. + */ +void gdcmDocument::ComputeJPEGFragmentInfo() +{ + // If you need to, look for comments of ComputeRLEInfo(). + if ( ! IsJPEGTransferSyntax() ) + { + return; + } + + ReadAndSkipEncapsulatedBasicOffsetTable(); + + // Loop on the fragments[s] and store the parsed information in a + // gdcmJPEGInfo. + long fragmentLength; + while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) ) + { + long fragmentOffset = ftell(Fp); + + // Store the collected info + gdcmJPEGFragment* newFragment = new gdcmJPEGFragment; + newFragment->Offset = fragmentOffset; + newFragment->Length = fragmentLength; + JPEGInfo.Fragments.push_back( newFragment ); + + SkipBytes( fragmentLength ); + } + + // Make sure that at the end of the item we encounter a 'Sequence + // Delimiter Item': + if ( !ReadTag(0xfffe, 0xe0dd) ) + { + dbg.Verbose(0, "gdcmDocument::ComputeRLEInfo: no sequence delimiter "); + dbg.Verbose(0, " item at end of JPEG item sequence"); + } +} + /** * \brief Walk recursively the given \ref gdcmDocEntrySet, and feed * the given hash table (\ref TagDocEntryHT) with all the diff --git a/src/gdcmDocument.h b/src/gdcmDocument.h index 86e86b26..80d3d3f6 100644 --- a/src/gdcmDocument.h +++ b/src/gdcmDocument.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.h,v $ Language: C++ - Date: $Date: 2004/10/09 03:36:57 $ - Version: $Revision: 1.48 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.49 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -26,6 +26,7 @@ #include "gdcmDictSet.h" #include "gdcmDocEntry.h" #include "gdcmRLEFramesInfo.h" +#include "gdcmJPEGFragmentsInfo.h" #include "gdcmDocEntrySet.h" #include "gdcmElementSet.h" @@ -94,6 +95,9 @@ protected: /// Store the RLE frames info obtained during parsing of pixels. gdcmRLEFramesInfo RLEInfo; + /// Store the JPEG fragments info obtained during parsing of pixels. + gdcmJPEGFragmentsInfo JPEGInfo; + /// \brief Amount of printed details for each Header Entry (Dicom Element): /// 0 : stands for the least detail level. int PrintLevel; @@ -116,13 +120,14 @@ public: bool IsExplicitVRLittleEndianTransferSyntax(); bool IsDeflatedExplicitVRLittleEndianTransferSyntax(); bool IsExplicitVRBigEndianTransferSyntax(); + bool IsRLELossLessTransferSyntax(); bool IsJPEGBaseLineProcess1TransferSyntax(); bool IsJPEGExtendedProcess2_4TransferSyntax(); bool IsJPEGExtendedProcess3_5TransferSyntax(); bool IsJPEGSpectralSelectionProcess6_8TransferSyntax(); - bool IsRLELossLessTransferSyntax(); bool IsJPEGLossless(); bool IsJPEG2000(); + bool IsJPEGTransferSyntax(); bool IsEncapsulateTransferSyntax(); bool IsDicomV3(); @@ -164,7 +169,9 @@ protected: gdcmDocument( std::string const & filename ); virtual ~gdcmDocument(); + void ReadAndSkipEncapsulatedBasicOffsetTable(); void ComputeRLEInfo(); + void ComputeJPEGFragmentInfo(); // Entry bool CheckIfEntryExistByNumber(uint16_t group, uint16_t elem ); public: diff --git a/src/gdcmFile.cxx b/src/gdcmFile.cxx index 2defabda..2cd11677 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/08 17:24:54 $ - Version: $Revision: 1.137 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.138 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -19,7 +19,6 @@ #include "gdcmFile.h" #include "gdcmDebug.h" #include "gdcmPixelConvert.h" -#include "jpeg/ljpg/jpegless.h" typedef std::pair IterHT; @@ -521,14 +520,15 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t maxSize) bool signedPixel = Header->IsSignedPixelData(); gdcmPixelConvert::ConvertReorderEndianity( - (uint8_t*) destination, - ImageDataSize, - numberBitsStored, - numberBitsAllocated, - Header->GetSwapCode(), - signedPixel ); - - ConvertReArrangeBits( (uint8_t*) destination, + (uint8_t*) destination, + ImageDataSize, + numberBitsStored, + numberBitsAllocated, + Header->GetSwapCode(), + signedPixel ); + + gdcmPixelConvert::ConvertReArrangeBits( + (uint8_t*) destination, ImageDataSize, numberBitsStored, numberBitsAllocated, @@ -614,50 +614,6 @@ size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t maxSize) return ImageDataSize; } -/** - * \brief Re-arrange the bits within the bytes. - */ -void gdcmFile::ConvertReArrangeBits( uint8_t* pixelZone, - size_t imageDataSize, - int numberBitsStored, - int numberBitsAllocated, - int highBitPosition) - throw ( gdcmFormatError ) -{ - if ( numberBitsStored != numberBitsAllocated ) - { - int l = (int)(imageDataSize / (numberBitsAllocated/8)); - if ( numberBitsAllocated == 16 ) - { - uint16_t mask = 0xffff; - mask = mask >> ( numberBitsAllocated - numberBitsStored ); - uint16_t* deb = (uint16_t*)pixelZone; - for(int i = 0; i> (numberBitsStored - highBitPosition - 1)) & mask; - deb++; - } - } - else if ( numberBitsAllocated == 32 ) - { - uint32_t mask = 0xffffffff; - mask = mask >> ( numberBitsAllocated - numberBitsStored ); - uint32_t* deb = (uint32_t*)pixelZone; - for(int i = 0; i> (numberBitsStored - highBitPosition - 1)) & mask; - deb++; - } - } - else - { - dbg.Verbose(0, "gdcmFile::ConvertReArrangeBits: weird image"); - throw gdcmFormatError( "gdcmFile::ConvertReArrangeBits()", - "weird image !?" ); - } - } -} - /** * \brief Convert (Y plane, cB plane, cR plane) to RGB pixels * \warning Works on all the frames at a time @@ -971,7 +927,8 @@ bool gdcmFile::ReadPixelData(void* destination) // ---------------------- Run Length Encoding if ( Header->IsRLELossLessTransferSyntax() ) { - bool res = gdcmPixelConvert::gdcm_read_RLE_file ( destination, + bool res = gdcmPixelConvert::ReadAndDecompressRLEFile( + destination, Header->GetXSize(), Header->GetYSize(), Header->GetZSize(), @@ -989,122 +946,18 @@ bool gdcmFile::ReadPixelData(void* destination) numberBitsAllocated = 16; } - int nBytes= numberBitsAllocated/8; - int taille = Header->GetXSize() * Header->GetYSize() - * Header->GetSamplesPerPixel(); - long fragmentBegining; // for ftell, fseek - - bool jpg2000 = Header->IsJPEG2000(); - bool jpgLossless = Header->IsJPEGLossless(); - - bool res = true; - uint16_t ItemTagGr, ItemTagEl; - int ln; - - // Position on begining of Jpeg Pixels - - fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr - fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El - if(Header->GetSwapCode()) - { - ItemTagGr = Header->SwapShort(ItemTagGr); - ItemTagEl = Header->SwapShort(ItemTagEl); - } - - fread(&ln,4,1,fp); - if( Header->GetSwapCode() ) - { - ln = Header->SwapLong( ln ); // Basic Offset Table Item length - } - - if ( ln != 0 ) - { - // What is it used for ?!? - uint8_t* BasicOffsetTableItemValue = new uint8_t[ln+1]; - fread(BasicOffsetTableItemValue,ln,1,fp); - //delete[] BasicOffsetTableItemValue; - } - - // first Fragment initialisation - fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr - fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El - if( Header->GetSwapCode() ) - { - ItemTagGr = Header->SwapShort( ItemTagGr ); - ItemTagEl = Header->SwapShort( ItemTagEl ); - } - - // parsing fragments until Sequence Delim. Tag found - while ( ItemTagGr == 0xfffe && ItemTagEl != 0xe0dd ) - { - // --- for each Fragment - fread(&ln,4,1,fp); - if( Header->GetSwapCode() ) - { - ln = Header->SwapLong(ln); // Fragment Item length - } - fragmentBegining = ftell( fp ); - - if ( jpg2000 ) - { - // JPEG 2000 : call to ??? - res = gdcm_read_JPEG2000_file (fp,destination); // Not Yet written - // ------------------------------------- endif (JPEG2000) - } - else if (jpgLossless) - { - // JPEG LossLess : call to xmedcom Lossless JPEG - // Reading Fragment pixels - JPEGLosslessDecodeImage (fp, (uint16_t*)destination, - Header->GetPixelSize() * 8 * Header->GetSamplesPerPixel(), ln); - res = 1; // in order not to break the loop - - } // ------------------------------------- endif (JPEGLossless) - else - { - // JPEG Lossy : call to IJG 6b - if ( Header->GetBitsStored() == 8) - { - // Reading Fragment pixels - res = gdcm_read_JPEG_file (fp,destination); - } - else if ( Header->GetBitsStored() == 12) - { - // Reading Fragment pixels - res = gdcm_read_JPEG_file12 (fp,destination); - } - else - { - // other JPEG lossy not supported - dbg.Error(" gdcmFile::ReadPixelData : unknown jpeg lossy compression"); - return 0; - } - // ------------------------------------- endif (JPEGLossy) - } - - if ( !res ) - { - break; - } - - // location in user's memory - // for next fragment (if any) - destination = (uint8_t*)destination + taille * nBytes; - - fseek(fp,fragmentBegining, SEEK_SET); // To be sure we start - fseek(fp,ln,SEEK_CUR); // at the begining of next fragment - - ItemTagGr = ItemTagEl = 0; - fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr - fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El - if( Header->GetSwapCode() ) - { - ItemTagGr = Header->SwapShort( ItemTagGr ); - ItemTagEl = Header->SwapShort( ItemTagEl ); - } - } - // endWhile parsing fragments until Sequence Delim. Tag found - + bool res = gdcmPixelConvert::ReadAndDecompressJPEGFile( + (uint8_t*)destination, + Header->GetXSize(), + Header->GetYSize(), + Header->GetBitsAllocated(), + Header->GetBitsStored(), + Header->GetSamplesPerPixel(), + Header->GetPixelSize(), + Header->IsJPEG2000(), + Header->IsJPEGLossless(), + &(Header->JPEGInfo), + fp ); Header->CloseFile(); return res; } diff --git a/src/gdcmFile.h b/src/gdcmFile.h index 057f02bd..7d153eff 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/08 17:02:53 $ - Version: $Revision: 1.58 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.59 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -43,12 +43,6 @@ public: void ConvertRGBPlanesToRGBPixels( uint8_t* source, uint8_t* destination ); void ConvertYcBcRPlanesToRGBPixels( uint8_t* source, uint8_t* destination ); - void ConvertReArrangeBits( - uint8_t* pixelZone, - size_t imageDataSize, - int numberBitsStored, - int numberBitsAllocated, - int highBitPosition ) throw ( gdcmFormatError ); /// Accessor to \ref ImageDataSize size_t GetImageDataSize(){ return ImageDataSize; }; @@ -95,20 +89,15 @@ private: bool ReadPixelData(void* destination); // For JPEG 8 Bits, body in file gdcmJpeg.cxx - bool gdcm_read_JPEG_file (FILE* fp, void* image_buffer); bool gdcm_write_JPEG_file (FILE* fp, void* image_buffer, int image_width, int image_heigh, int quality); // For JPEG 12 Bits, body in file gdcmJpeg12.cxx - bool gdcm_read_JPEG_file12 (FILE* fp, void* image_buffer); bool gdcm_write_JPEG_file12 (FILE* fp, void* image_buffer, int image_width, int image_height, int quality); - // For JPEG 2000, body in file gdcmJpeg2000.cxx - bool gdcm_read_JPEG2000_file (FILE* fp, void* image_buffer); - void SaveInitialValues(); // will belong to the future gdcmPixelData class void RestoreInitialValues(); // will belong to the future gdcmPixelData class void DeleteInitialValues(); // will belong to the future gdcmPixelData class diff --git a/src/gdcmJPEGFragment.h b/src/gdcmJPEGFragment.h new file mode 100644 index 00000000..7c515c14 --- /dev/null +++ b/src/gdcmJPEGFragment.h @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJPEGFragment.h,v $ + Language: C++ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef GDCMJPEGFRAGMENT_H +#define GDCMJPEGFRAGMENT_H + +#include "gdcmCommon.h" + +/** + * \brief Utility class for summerizing the informations of a JPEG + * fragment of an "Encapsulated JPEG Compressed Image". + * This information is a mix of: + * - the fragment offset + * - the fragment length + * + * Each instance of this class (they can be as many instances for + * a given gdcmDocument as they are JPEG fragments and they are + * collected in a \ref gdcmJPEGFragmentsInfo ) + */ +class GDCM_EXPORT gdcmJPEGFragment +{ +friend class gdcmDocument; +friend class gdcmFile; +friend class gdcmPixelConvert; + long Offset; + long Length; + gdcmJPEGFragment() + { + Offset = 0; + Length = 0; + } +}; + +//----------------------------------------------------------------------------- +#endif diff --git a/src/gdcmJPEGFragmentsInfo.cxx b/src/gdcmJPEGFragmentsInfo.cxx new file mode 100644 index 00000000..f981336b --- /dev/null +++ b/src/gdcmJPEGFragmentsInfo.cxx @@ -0,0 +1,30 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJPEGFragmentsInfo.cxx,v $ + Language: C++ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "gdcmJPEGFragmentsInfo.h" + +gdcmJPEGFragmentsInfo::~gdcmJPEGFragmentsInfo() +{ + for(JPEGFragmentsList::iterator it = Fragments.begin(); + it != Fragments.end(); + ++it ) + { + delete (*it); + } + Fragments.clear(); +} diff --git a/src/gdcmJPEGFragmentsInfo.h b/src/gdcmJPEGFragmentsInfo.h new file mode 100644 index 00000000..4db039cf --- /dev/null +++ b/src/gdcmJPEGFragmentsInfo.h @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJPEGFragmentsInfo.h,v $ + Language: C++ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#ifndef GDCMJPEGFRAGMENTSINFO_H +#define GDCMJPEGFRAGMENTSINFO_H + +#include "gdcmJPEGFragment.h" +#include + +/** + * \brief Utility class for gathering the informations of the collection + * of JPEG fragment[s] (see \ref gdcmJPEGFragment) when handling + * "Encapsulated JPEG Compressed Images". + * The informations on each frame are obtained during the parsing + * of a gdcmDocument (refer to + * \ref gdcmDocument::ComputeJPEGFragmentInfo() ). + * They shall be used when (if necessary) decoding the fragments. + * + * This class is simply a stl list<> of \ref gdcmJPEGFragment. + */ +class GDCM_EXPORT gdcmJPEGFragmentsInfo +{ + typedef std::list< gdcmJPEGFragment* > JPEGFragmentsList; +friend class gdcmDocument; +friend class gdcmFile; +friend class gdcmPixelConvert; + JPEGFragmentsList Fragments; +public: + ~gdcmJPEGFragmentsInfo(); +}; + +//----------------------------------------------------------------------------- +#endif diff --git a/src/gdcmJpeg12.cxx b/src/gdcmJpeg12.cxx index 056afa39..cf315656 100644 --- a/src/gdcmJpeg12.cxx +++ b/src/gdcmJpeg12.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmJpeg12.cxx,v $ Language: C++ - Date: $Date: 2004/10/10 00:42:55 $ - Version: $Revision: 1.19 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.20 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -134,7 +134,7 @@ METHODDEF(void) my_error_exit (j_common_ptr cinfo) * @return 1 on success, 0 on error */ -bool gdcmFile::gdcm_read_JPEG_file12 (FILE* fp,void* image_buffer) +bool gdcm_read_JPEG_file12 ( FILE* fp,void* image_buffer ) { char *pimage; diff --git a/src/gdcmJpeg2000.cxx b/src/gdcmJpeg2000.cxx index 3b0499be..65198a9a 100644 --- a/src/gdcmJpeg2000.cxx +++ b/src/gdcmJpeg2000.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmJpeg2000.cxx,v $ Language: C++ - Date: $Date: 2004/10/08 04:52:55 $ - Version: $Revision: 1.10 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.11 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -20,7 +20,6 @@ //----------------------------------------------------------------------------- /** - * \ingroup gdcmFile * \brief routine for JPEG decompression * @param fp pointer to an already open file descriptor * JPEG2000 encoded image @@ -29,7 +28,7 @@ * @warning : not yet made */ -bool gdcmFile::gdcm_read_JPEG2000_file (FILE* fp,void* image_buffer) { +bool gdcm_read_JPEG2000_file (FILE* fp,void* image_buffer) { (void)fp; //FIXME (void)image_buffer; //FIXME std::cout << "Sorry JPEG 2000 File not yet taken into account" << std::endl; diff --git a/src/gdcmJpeg8.cxx b/src/gdcmJpeg8.cxx index cf623c2c..d8d62229 100644 --- a/src/gdcmJpeg8.cxx +++ b/src/gdcmJpeg8.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmJpeg8.cxx,v $ Language: C++ - Date: $Date: 2004/10/10 00:42:55 $ - Version: $Revision: 1.4 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.5 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -359,7 +359,6 @@ METHODDEF(void) my_error_exit (j_common_ptr cinfo) { */ /** - * \ingroup gdcmFile * \brief routine for JPEG decompression * @param fp pointer to an already open file descriptor * 8 significant bits per pixel @@ -367,7 +366,7 @@ METHODDEF(void) my_error_exit (j_common_ptr cinfo) { * @return 1 on success, 0 on error */ -bool gdcmFile::gdcm_read_JPEG_file (FILE* fp, void* image_buffer) +bool gdcm_read_JPEG_file ( FILE* fp, void* image_buffer ) { char* pimage; diff --git a/src/gdcmPixelConvert.cxx b/src/gdcmPixelConvert.cxx index cf03ba7c..32c2d318 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/10 03:03:10 $ - Version: $Revision: 1.5 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.6 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -19,11 +19,30 @@ ////////////////// 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 +// +// grep PIXELCONVERT everywhere and clean up ! + + #define str2num(str, typeNum) *((typeNum *)(str)) #include "gdcmDebug.h" #include "gdcmPixelConvert.h" +// External JPEG decompression + +// for JPEGLosslessDecodeImage +#include "jpeg/ljpg/jpegless.h" + +// For JPEG 2000, body in file gdcmJpeg2000.cxx +bool gdcm_read_JPEG2000_file (FILE* fp, void* image_buffer); + +// For JPEG 8 Bits, body in file gdcmJpeg8.cxx +bool gdcm_read_JPEG_file (FILE* fp, void* image_buffer); + +// For JPEG 12 Bits, body in file gdcmJpeg12.cxx +bool gdcm_read_JPEG_file12 (FILE* fp, void* image_buffer); + + //----------------------------------------------------------------------------- // Constructor / Destructor @@ -119,55 +138,10 @@ void gdcmPixelConvert::ConvertDecompress12BitsTo16Bits( } } -/** - * \brief Read from file an uncompressed image. - */ -bool gdcmPixelConvert::ReadUncompressed( FILE* filePointer, - size_t uncompressedSize, - size_t expectedSize ) -{ - if ( expectedSize > uncompressedSize ) - { - dbg.Verbose(0, "gdcmPixelConvert::ReadUncompressed: expectedSize" - "is bigger than it should"); - return false; - } - SetUncompressedSize( uncompressedSize ); - AllocateUncompressed(); - size_t ItemRead = fread( (void*)Uncompressed, expectedSize, 1, filePointer); - if ( ItemRead != 1 ) - { - return false; - } - return true; -} - -/** - * \brief Convert a Gray plane and ( Lut R, Lut G, Lut B ) into an - * RGB plane. - * @return True on success. - */ -bool gdcmPixelConvert::ConvertGrayAndLutToRGB( uint8_t *lutRGBA ) - -{ - (void)lutRGBA; - /// We assume Uncompressed contains the decompressed gray plane - /// and build the RGB image. - SetRGBSize( UncompressedSize ); - AllocateRGB(); - -//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -//COPY HERE THE CODE OF GetImageDataIntoVector - - /// \todo check that operator new []didn't fail, and sometimes return false - return true; -} - /** * \brief Try to deal with RLE 16 Bits. * We assume the RLE has allready been parsed and loaded in - * Uncompressed (through \ref ReadAndUncompressRLE8Bits ). + * Uncompressed (through \ref ReadAndDecompressJPEGFile ). * We here need to make 16 Bits Pixels from Low Byte and * High Byte 'Planes'...(for what it may mean) * @return Boolean @@ -271,7 +245,7 @@ bool gdcmPixelConvert::ReadAndUncompressRLEFragment( uint8_t* decodedZone, * at which the pixel data should be copied * @return Boolean */ -bool gdcmPixelConvert::gdcm_read_RLE_file( void* image_buffer, +bool gdcmPixelConvert::ReadAndDecompressRLEFile( void* image_buffer, int XSize, int YSize, int ZSize, @@ -290,9 +264,9 @@ bool gdcmPixelConvert::gdcm_read_RLE_file( void* image_buffer, ++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); + fseek( fp, (*it)->Offset[k] ,SEEK_SET ); (void)gdcmPixelConvert::ReadAndUncompressRLEFragment( (uint8_t*) im, (*it)->Length[k], uncompressedSegmentSize, fp ); @@ -431,3 +405,128 @@ void gdcmPixelConvert::ConvertReorderEndianity( uint8_t* pixelZone, } } +/** + * \brief Reads from disk the Pixel Data of JPEG Dicom encapsulated + & file and uncompress it. + * @param fp already open File Pointer + * @param destination Where decompressed fragments should end up + * @return Boolean + */ +bool gdcmPixelConvert::ReadAndDecompressJPEGFile( uint8_t* destination, + int XSize, + int YSize, + int BitsAllocated, + int BitsStored, + int SamplesPerPixel, + int PixelSize, + bool isJPEG2000, + bool isJPEGLossless, + gdcmJPEGFragmentsInfo* JPEGInfo, + FILE* fp ) +{ + // Loop on the fragment[s] + for( gdcmJPEGFragmentsInfo::JPEGFragmentsList::iterator + it = JPEGInfo->Fragments.begin(); + it != JPEGInfo->Fragments.end(); + ++it ) + { + fseek( fp, (*it)->Offset, SEEK_SET ); + + if ( isJPEG2000 ) + { + if ( ! gdcm_read_JPEG2000_file( fp, destination ) ) + { + return false; + } + } + else if ( isJPEGLossless ) + { + // JPEG LossLess : call to xmedcom Lossless JPEG + JPEGLosslessDecodeImage( fp, + (uint16_t*)destination, + PixelSize * 8 * SamplesPerPixel, + (*it)->Length ); + } + else if ( BitsStored == 8) + { + // JPEG Lossy : call to IJG 6b + if ( ! gdcm_read_JPEG_file ( fp, destination ) ) + { + return false; + } + } + else if ( BitsStored == 12) + { + // Reading Fragment pixels + if ( ! gdcm_read_JPEG_file12 ( fp, destination ) ) + { + return false; + } + } + else + { + // other JPEG lossy not supported + dbg.Error(" gdcmFile::ReadPixelData : unknown jpeg lossy " + " compression "); + return false; + } + + // Advance to next free location in destination + // for next fragment decompression (if any) + int length = XSize * YSize * SamplesPerPixel; + int numberBytes = BitsAllocated / 8; + + destination = (uint8_t*)destination + length * numberBytes; + + } + return true; +} + +/** + * \brief Re-arrange the bits within the bytes. + * @param fp already open File Pointer + * @param destination Where decompressed fragments should end up + * @return Boolean + */ +bool gdcmPixelConvert::ConvertReArrangeBits( + uint8_t* pixelZone, + size_t imageDataSize, + int numberBitsStored, + int numberBitsAllocated, + int highBitPosition ) + throw ( gdcmFormatError ) +{ + if ( numberBitsStored != numberBitsAllocated ) + { + int l = (int)(imageDataSize / (numberBitsAllocated/8)); + if ( numberBitsAllocated == 16 ) + { + uint16_t mask = 0xffff; + mask = mask >> ( numberBitsAllocated - numberBitsStored ); + uint16_t* deb = (uint16_t*)pixelZone; + for(int i = 0; i> (numberBitsStored - highBitPosition - 1)) & mask; + deb++; + } + } + else if ( numberBitsAllocated == 32 ) + { + uint32_t mask = 0xffffffff; + mask = mask >> ( numberBitsAllocated - numberBitsStored ); + uint32_t* deb = (uint32_t*)pixelZone; + for(int i = 0; i> (numberBitsStored - highBitPosition - 1)) & mask; + deb++; + } + } + else + { + dbg.Verbose(0, "gdcmPixelConvert::ConvertReArrangeBits: weird image"); + throw gdcmFormatError( "gdcmFile::ConvertReArrangeBits()", + "weird image !?" ); + } + } +} + diff --git a/src/gdcmPixelConvert.h b/src/gdcmPixelConvert.h index 02f11f3b..8121f0b6 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/08 17:02:53 $ - Version: $Revision: 1.4 $ + Date: $Date: 2004/10/10 16:44:00 $ + Version: $Revision: 1.5 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -22,6 +22,7 @@ #include "gdcmCommon.h" #include "gdcmRLEFramesInfo.h" +#include "gdcmJPEGFragmentsInfo.h" #include "gdcmException.h" /* @@ -53,15 +54,6 @@ public: void Squeeze(); ////////////////////////////////////////////////////////// // In progress -bool ReadAndUncompress12Bits( FILE* filePointer, - size_t uncompressedSize, - size_t PixelNumber ); -bool ReadUncompressed( FILE* filePointer, - size_t uncompressedSize, - size_t expectedSize ); -bool ConvertGrayAndLutToRGB( uint8_t *lutRGBA ); -bool ReadAndUncompressRLE8Bits(FILE* fp, size_t uncompressedSize ); - static bool UncompressRLE16BitsFromRLE8Bits( int XSize, int YSize, @@ -72,7 +64,7 @@ bool ReadAndUncompressRLE8Bits(FILE* fp, size_t uncompressedSize ); long fragmentSize, long uncompressedSegmentSize, FILE* fp ); - static bool gdcm_read_RLE_file( + static bool ReadAndDecompressRLEFile( void* image_buffer, int XSize, int YSize, @@ -93,6 +85,26 @@ bool ReadAndUncompressRLE8Bits(FILE* fp, size_t uncompressedSize ); int numberBitsAllocated, int swapCode, bool signedPixel ); + static bool ReadAndDecompressJPEGFile( + uint8_t* destination, + int XSize, + int YSize, + int BitsAllocated, + int BitsStored, + int SamplesPerPixel, + int PixelSize, + bool isJPEG2000, + bool isJPEGLossless, + gdcmJPEGFragmentsInfo* JPEGInfo, + FILE* fp ); + static bool gdcmPixelConvert::ConvertReArrangeBits( + uint8_t* pixelZone, + size_t imageDataSize, + int numberBitsStored, + int numberBitsAllocated, + int highBitPosition ) throw ( gdcmFormatError ); + + }; //----------------------------------------------------------------------------- diff --git a/src/gdcmRLEFramesInfo.h b/src/gdcmRLEFramesInfo.h index 843ab0ed..8994ed8e 100644 --- a/src/gdcmRLEFramesInfo.h +++ b/src/gdcmRLEFramesInfo.h @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmRLEFramesInfo.h,v $ Language: C++ - Date: $Date: 2004/10/08 16:27:20 $ - Version: $Revision: 1.3 $ + Date: $Date: 2004/10/10 16:44:00 $ + 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 @@ -31,7 +31,8 @@ * of a multiframe image. In this case the collection is limited * to a single individual frame. * The informations on each frame are obtained during the parsing - * of a gdcmDocument (refer to \ref gdcmDocument::Parse7FE0() ). + * of a gdcmDocument (refer to + * \ref gdcmDocument::ComputeRLEInfo() ). * They shall be used when (if necessary) decoding the frames. * * This class is simply a stl list<> of \ref gdcmRLEFrame. -- 2.48.1