📄 gdcmpixelreadconvert.cxx
字号:
/*=========================================================================
Program: gdcm
Module: $RCSfile: gdcmPixelReadConvert.cxx,v $
Language: C++
Date: $Date: 2008-05-28 11:26:41 $
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
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 "gdcmPixelReadConvert.h"
#include "gdcmDebug.h"
#include "gdcmFile.h"
#include "gdcmGlobal.h"
#include "gdcmTS.h"
#include "gdcmDocEntry.h"
#include "gdcmRLEFramesInfo.h"
#include "gdcmJPEGFragmentsInfo.h"
#include <fstream>
#include <stdio.h> //for sscanf
#if defined(__BORLANDC__)
#include <mem.h> // for memset
#endif
namespace gdcm
{
//bool ReadMPEGFile (std::ifstream *fp, void *image_buffer, size_t lenght);
bool gdcm_read_JPEG2000_file (void* raw,
char *inputdata, size_t inputlength);
//-----------------------------------------------------------------------------
#define str2num(str, typeNum) *((typeNum *)(str))
//-----------------------------------------------------------------------------
// Constructor / Destructor
/// Constructor
PixelReadConvert::PixelReadConvert()
{
RGB = 0;
RGBSize = 0;
Raw = 0;
RawSize = 0;
LutRGBA = 0;
LutRedData = 0;
LutGreenData = 0;
LutBlueData = 0;
RLEInfo = 0;
JPEGInfo = 0;
UserFunction = 0;
FileInternal = 0;
}
/// Canonical Destructor
PixelReadConvert::~PixelReadConvert()
{
Squeeze();
}
//-----------------------------------------------------------------------------
// Public
/**
* \brief Predicate to know whether the image[s] (once Raw) is RGB.
* \note See comments of \ref ConvertHandleColor
*/
bool PixelReadConvert::IsRawRGB()
{
if ( IsMonochrome
|| PlanarConfiguration == 2
|| IsPaletteColor )
{
return false;
}
return true;
}
/**
* \brief Gets various usefull informations from the file header
* @param file gdcm::File pointer
*/
void PixelReadConvert::GrabInformationsFromFile( File *file )
{
// Number of Bits Allocated for storing a Pixel is defaulted to 16
// when absent from the file.
BitsAllocated = file->GetBitsAllocated();
if ( BitsAllocated == 0 )
{
BitsAllocated = 16;
}
else if ( BitsAllocated > 8 && BitsAllocated < 16 && BitsAllocated != 12 )
{
BitsAllocated = 16;
}
// Number of "Bits Stored", defaulted to number of "Bits Allocated"
// when absent from the file.
BitsStored = file->GetBitsStored();
if ( BitsStored == 0 )
{
BitsStored = BitsAllocated;
}
// High Bit Position, defaulted to "Bits Allocated" - 1
HighBitPosition = file->GetHighBitPosition();
if ( HighBitPosition == 0 )
{
HighBitPosition = BitsAllocated - 1;
}
XSize = file->GetXSize();
YSize = file->GetYSize();
ZSize = file->GetZSize();
SamplesPerPixel = file->GetSamplesPerPixel();
//PixelSize = file->GetPixelSize(); Useless
PixelSign = file->IsSignedPixelData();
SwapCode = file->GetSwapCode();
IsPrivateGETransferSyntax = IsMPEG
= IsJPEG2000 = IsJPEGLS = IsJPEGLossy
= IsJPEGLossless = IsRLELossless
= false;
std::string ts = file->GetTransferSyntax();
IsRaw =
( ! file->IsDicomV3() )
|| Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian
|| Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE
|| Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian
|| Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian
|| Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian;
IsMPEG = Global::GetTS()->IsMPEG(ts);
IsJPEG2000 = Global::GetTS()->IsJPEG2000(ts);
IsJPEGLS = Global::GetTS()->IsJPEGLS(ts);
IsJPEGLossy = Global::GetTS()->IsJPEGLossy(ts);
IsJPEGLossless = Global::GetTS()->IsJPEGLossless(ts);
IsRLELossless = Global::GetTS()->IsRLELossless(ts);
IsPrivateGETransferSyntax =
( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE );
PixelOffset = file->GetPixelOffset();
PixelDataLength = file->GetPixelAreaLength();
RLEInfo = file->GetRLEInfo();
JPEGInfo = file->GetJPEGInfo();
IsMonochrome = file->IsMonochrome();
IsMonochrome1 = file->IsMonochrome1();
IsPaletteColor = file->IsPaletteColor();
IsYBRFull = file->IsYBRFull();
PlanarConfiguration = file->GetPlanarConfiguration();
/////////////////////////////////////////////////////////////////
// LUT section:
HasLUT = file->HasLUT();
if ( HasLUT )
{
// Just in case some access to a File element requires disk access.
LutRedDescriptor = file->GetEntryValue( 0x0028, 0x1101 );
LutGreenDescriptor = file->GetEntryValue( 0x0028, 0x1102 );
LutBlueDescriptor = file->GetEntryValue( 0x0028, 0x1103 );
// FIXME : The following comment is probabely meaningless, since LUT are *always*
// loaded at parsing time, whatever their length is.
// Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE
// [ refer to invocation of Document::SetMaxSizeLoadEntry() in
// Document::Document() ], the loading of the value (content) of a
// [Bin|Val]Entry occurence migth have been hindered (read simply NOT
// loaded). Hence, we first try to obtain the LUTs data from the file
// and when this fails we read the LUTs data directly from disk.
// \TODO Reading a [Bin|Val]Entry directly from disk is a kludge.
// We should NOT bypass the [Bin|Val]Entry class. Instead
// an access to an UNLOADED content of a [Bin|Val]Entry occurence
// (e.g. BinEntry::GetBinArea()) should force disk access from
// within the [Bin|Val]Entry class itself. The only problem
// is that the [Bin|Val]Entry is unaware of the FILE* is was
// parsed from. Fix that. FIXME.
// //// Red round
file->LoadEntryBinArea(0x0028, 0x1201);
LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 );
if ( ! LutRedData )
{
gdcmWarningMacro("Unable to read Red Palette Color Lookup Table data");
}
// //// Green round:
file->LoadEntryBinArea(0x0028, 0x1202);
LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 );
if ( ! LutGreenData)
{
gdcmWarningMacro("Unable to read Green Palette Color Lookup Table data");
}
// //// Blue round:
file->LoadEntryBinArea(0x0028, 0x1203);
LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 );
if ( ! LutBlueData )
{
gdcmWarningMacro("Unable to read Blue Palette Color Lookup Table data");
}
}
FileInternal = file;
ComputeRawAndRGBSizes();
}
/// \brief Reads from disk and decompresses Pixels
bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp )
{
// ComputeRawAndRGBSizes is already made by
// ::GrabInformationsFromfile. So, the structure sizes are
// correct
Squeeze();
//////////////////////////////////////////////////
//// First stage: get our hands on the Pixel Data.
if ( !fp )
{
gdcmWarningMacro( "Unavailable file pointer." );
return false;
}
fp->seekg( PixelOffset, std::ios::beg );
if ( fp->fail() || fp->eof() )
{
gdcmWarningMacro( "Unable to find PixelOffset in file." );
return false;
}
AllocateRaw();
//////////////////////////////////////////////////
//// Second stage: read from disk and decompress.
if ( BitsAllocated == 12 ) // We suppose 'BitsAllocated' = 12 only exist for uncompressed files
{
ReadAndDecompress12BitsTo16Bits( fp);
}
else if ( IsRaw )
{
// This problem can be found when some obvious informations are found
// after the field containing the image data. In this case, these
// bad data are added to the size of the image (in the PixelDataLength
// variable). But RawSize is the right size of the image !
if ( PixelDataLength != RawSize )
{
gdcmWarningMacro( "Mismatch between PixelReadConvert : "
<< PixelDataLength << " and RawSize : " << RawSize );
}
if ( PixelDataLength > RawSize )
{
fp->read( (char*)Raw, RawSize);
}
else
{
fp->read( (char*)Raw, RawSize);
}
if ( fp->fail() || fp->eof())
{
gdcmWarningMacro( "Reading of Raw pixel data failed." );
return false;
}
}
else if ( IsRLELossless )
{
if ( ! RLEInfo->DecompressRLEFile
( fp, Raw, XSize, YSize, ZSize, BitsAllocated ) )
{
gdcmWarningMacro( "RLE decompressor failed." );
return false;
}
}
else if ( IsMPEG )
{
//gdcmWarningMacro( "Sorry, MPEG not yet taken into account" );
//return false;
// fp has already been seek to start of mpeg
//ReadMPEGFile(fp, (char*)Raw, PixelDataLength);
return true;
}
else
{
// Default case concerns JPEG family
if ( ! ReadAndDecompressJPEGFile( fp ) )
{
gdcmWarningMacro( "JPEG decompressor ( ReadAndDecompressJPEGFile()"
<< " method ) failed." );
return false;
}
}
////////////////////////////////////////////
//// Third stage: twigle the bytes and bits.
ConvertReorderEndianity();
ConvertReArrangeBits();
ConvertFixGreyLevels();
if (UserFunction) // user is allowed to Mirror, TopDown, Rotate,...the image
UserFunction( Raw, FileInternal);
ConvertHandleColor();
return true;
}
/// Deletes Pixels Area
void PixelReadConvert::Squeeze()
{
if ( RGB )
delete [] RGB;
RGB = 0;
if ( Raw )
delete [] Raw;
Raw = 0;
if ( LutRGBA )
delete [] LutRGBA;
LutRGBA = 0;
}
/**
* \brief Build the RGB image from the Raw image and the LUTs.
*/
bool PixelReadConvert::BuildRGBImage()
{
if ( RGB )
{
// The job is already done.
return true;
}
if ( ! Raw )
{
// The job can't be done
return false;
}
BuildLUTRGBA();
if ( ! LutRGBA )
{
// The job can't be done
return false;
}
gdcmDebugMacro( "--> BuildRGBImage" );
// Build RGB Pixels
AllocateRGB();
int j;
if ( BitsAllocated <= 8 )
{
uint8_t *localRGB = RGB;
for (size_t i = 0; i < RawSize; ++i )
{
j = Raw[i] * 4;
*localRGB++ = LutRGBA[j];
*localRGB++ = LutRGBA[j+1];
*localRGB++ = LutRGBA[j+2];
}
}
else // deal with 16 bits pixels and 16 bits Palette color
{
uint16_t *localRGB = (uint16_t *)RGB;
for (size_t i = 0; i < RawSize/2; ++i )
{
j = ((uint16_t *)Raw)[i] * 4;
*localRGB++ = ((uint16_t *)LutRGBA)[j];
*localRGB++ = ((uint16_t *)LutRGBA)[j+1];
*localRGB++ = ((uint16_t *)LutRGBA)[j+2];
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -