Program: gdcm
Module: $RCSfile: gdcmFile.cxx,v $
Language: C++
- Date: $Date: 2005/02/15 18:12:34 $
- Version: $Revision: 1.224 $
+ Date: $Date: 2005/02/17 11:02:47 $
+ Version: $Revision: 1.225 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
// Create a new BinEntry to change the the DictEntry
// The changed DictEntry will have
// - a correct PixelVR OB or OW)
- // - a VM to "PXL"
// - the name to "Pixel Data"
BinEntry *oldEntry = dynamic_cast<BinEntry *>(entry);
if(oldEntry)
*/
int File::GetImageNumber()
{
- // The function i atoi() takes the address of an area of memory as
- // parameter and converts the string stored at that location to an integer
- // using the external decimal to internal binary conversion rules. This may
- // be preferable to sscanf() since atoi() is a much smaller, simpler and
- // faster function. sscanf() can do all possible conversions whereas
- // atoi() can only do single decimal integer conversions.
- //0020 0013 IS REL Image Number
+ //0020 0013 : Image Number
std::string strImNumber = GetEntryValue(0x0020,0x0013);
if ( strImNumber != GDCM_UNFOUND )
{
*/
ModalityType File::GetModality()
{
- // 0008 0060 CS ID Modality
+ // 0008 0060 : Modality
std::string strModality = GetEntryValue(0x0008,0x0060);
if ( strModality != GDCM_UNFOUND )
{
if ( xspacing == 0.)
{
- gdcmWarningMacro("gdcmData/CT-MONO2-8-abdo.dcm problem");
+ gdcmWarningMacro("gdcmData/CT-MONO2-8-abdo.dcm-like problem");
// seems to be a bug in the header ...
nbValues = sscanf( strSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing);
gdcmAssertMacro( nbValues == 2 );
*/
float File::GetZSpacing()
{
- // Spacing Between Slices : distance entre le milieu de chaque coupe
- // Les coupes peuvent etre :
+ // Spacing Between Slices : distance between the middle of 2 slices
+ // Slices may be :
// jointives (Spacing between Slices = Slice Thickness)
- // chevauchantes (Spacing between Slices < Slice Thickness)
+ // overlapping (Spacing between Slices < Slice Thickness)
// disjointes (Spacing between Slices > Slice Thickness)
// Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
- // ca interesse le physicien de l'IRM, pas le visualisateur de volumes ...
- // Si le Spacing Between Slices est Missing,
- // on suppose que les coupes sont jointives
+ // It only concerns the MRI guys, not people wanting to visualize volmues
+ // If Spacing Between Slices is Missing,
+ // we suppose slices joint together
const std::string &strSpacingBSlices = GetEntryValue(0x0018,0x0088);
* - 32S signed 32 bit,
* - FD floating double 64 bits (Not kosher DICOM, but so usefull!)
* \warning 12 bit images appear as 16 bit.
- * 24 bit images appear as 8 bit
+ * 24 bit images appear as 8 bit + photochromatic interp ="RGB "
* @return 0S if nothing found. NOT USABLE file. The caller has to check
*/
std::string File::GetPixelType()
* (as opposed to 'DicomDir related') entries
* then writes in a file all the (Dicom Elements) included the Pixels
* @param fileName file name to write to
- * @param filetype Type of the File to be written
+ * @param writetype Type of the File to be written
* (ACR, ExplicitVR, ImplicitVR)
*/
-bool File::Write(std::string fileName, FileType filetype)
+bool File::Write(std::string fileName, FileType writetype)
{
std::ofstream *fp = new std::ofstream(fileName.c_str(),
std::ios::out | std::ios::binary);
}
// Entry : 0002|0000 = group length -> recalculated
- ValEntry *e0002 = GetValEntry(0x0002,0x0000);
- if( e0002 )
+ ValEntry*e0000 = GetValEntry(0x0002,0x0000);
+ if( e0000 )
{
std::ostringstream sLen;
- sLen << ComputeGroup0002Length(filetype);
- e0002->SetValue(sLen.str());
+ sLen << ComputeGroup0002Length(writetype);
+ e0000->SetValue(sLen.str());
}
// Bits Allocated
}
}
- Document::WriteContent(fp, filetype);
+ Document::WriteContent(fp, writetype);
fp->close();
delete fp;
* \brief Initialize a default DICOM File that should contain all the
* field require by other reader. DICOM standard does not
* explicitely defines those fields, heuristic has been choosen.
- * This is not perfect as we are writting a CT image...
+ * This is not perfect as we are writting a Secondary Capture image...
*/
void File::InitializeDefaultFile()
{
// Meta Element Group Length
InsertValEntry("146 ", 0x0002, 0x0000);
- // Media Storage SOP Class UID (CT Image Storage)
- InsertValEntry("1.2.840.10008.5.1.4.1.1.2", 0x0002, 0x0002);
+ // Media Storage SOP Class UID (Secondary Capture Image Storage)
+ InsertValEntry("1.2.840.10008.5.1.4.1.1.7", 0x0002, 0x0002);
// Media Storage SOP Instance UID
InsertValEntry(uidMedia.c_str(), 0x0002, 0x0003);
// Transfer Syntax UID (Explicit VR Little Endian)
Program: gdcm
Module: $RCSfile: gdcmFileHelper.cxx,v $
Language: C++
- Date: $Date: 2005/02/11 11:22:59 $
- Version: $Revision: 1.16 $
+ Date: $Date: 2005/02/17 11:00:33 $
+ Version: $Revision: 1.17 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
#include <fstream>
+
namespace gdcm
{
//-------------------------------------------------------------------------
* @param content new value (string) to substitute with
* @param group group number of the Dicom Element to modify
* @param elem element number of the Dicom Element to modify
+ * \return false if DocEntry not found
*/
bool FileHelper::SetValEntry(std::string const &content,
uint16_t group, uint16_t elem)
{
- return FileInternal->SetValEntry(content,group,elem);
+ return FileInternal->SetValEntry(content, group, elem);
}
* @param lgth new value length
* @param group group number of the Dicom Element to modify
* @param elem element number of the Dicom Element to modify
+ * \return false if DocEntry not found
*/
bool FileHelper::SetBinEntry(uint8_t *content, int lgth,
uint16_t group, uint16_t elem)
{
- return FileInternal->SetBinEntry(content,lgth,group,elem);
+ return FileInternal->SetBinEntry(content, lgth, group, elem);
}
/**
* \brief Modifies the value of a given DocEntry (Dicom entry)
- * when it exists. Create it with the given value when unexistant.
- * @param content (string) Value to be set
+ * when it exists. Creates it with the given value when unexistant.
+ * @param content (string)value to be set
* @param group Group number of the Entry
* @param elem Element number of the Entry
* \return pointer to the modified/created Dicom entry (NULL when creation
/**
* \brief Modifies the value of a given DocEntry (Dicom entry)
- * when it exists. Create it with the given value when unexistant.
+ * when it exists. Creates it with the given value when unexistant.
* A copy of the binArea is made to be kept in the Document.
- * @param binArea (binary) value to be set
+ * @param binArea (binary)value to be set
* @param lgth new value length
* @param group Group number of the Entry
* @param elem Element number of the Entry
BinEntry *FileHelper::InsertBinEntry(uint8_t *binArea, int lgth,
uint16_t group, uint16_t elem)
{
- return FileInternal->InsertBinEntry(binArea,lgth,group,elem);
+ return FileInternal->InsertBinEntry(binArea, lgth, group, elem);
}
/**
* \brief Modifies the value of a given DocEntry (Dicom entry)
- * when it exists. Create it with the given value when unexistant.
- * A copy of the binArea is made to be kept in the Document.
+ * when it exists. Creates it, empty (?!) when unexistant.
* @param group Group number of the Entry
* @param elem Element number of the Entry
* \return pointer to the modified/created Dicom entry (NULL when creation
*/
SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem)
{
- return FileInternal->InsertSeqEntry(group,elem);
+ return FileInternal->InsertSeqEntry(group, elem);
}
/**
* 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
+ * NULL if alloc fails
*/
uint8_t *FileHelper::GetImageDataRaw ()
{
* user is allowed to pass any kind of pixelsn since the size is
* given in bytes)
* @param expectedSize total image size, *in Bytes*
- *
- * @return boolean
*/
void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize)
{
- SetUserData(inData,expectedSize);
+ SetUserData(inData, expectedSize);
}
/**
* \brief Set the image data defined by the user
* \warning When writting the file, this data are get as default data to write
* @param inData user supplied pixel area (uint8_t* is just for the compiler.
- * user is allowed to pass any kind of pixelsn since the size is
+ * user is allowed to pass any kind of pixels since the size is
* given in bytes)
- * @param expectedSize total image size, *in Bytes*
-
+ * @param expectedSize total image size, *in Bytes*
*/
void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize)
{
- PixelWriteConverter->SetUserData(inData,expectedSize);
+ PixelWriteConverter->SetUserData(inData, expectedSize);
}
/**
/**
* \brief Get the image data from the file.
- * If a LUT is found, the data are not expanded !
+ * Even when a LUT is found, the data are not expanded to RGB!
*/
uint8_t *FileHelper::GetRawData()
{
/**
* \brief Get the image data size from the file.
- * If a LUT is found, the data are not expanded !
+ * Even when a LUT is found, the data are not expanded to RGB!
*/
size_t FileHelper::GetRawDataSize()
{
{
case ImplicitVR:
SetWriteFileTypeToImplicitVR();
+ CheckMetaElements();
break;
case ExplicitVR:
SetWriteFileTypeToExplicitVR();
+ CheckMetaElements();
break;
case ACR:
case ACR_LIBIDO:
break;
default:
SetWriteFileTypeToExplicitVR();
+ CheckMetaElements();
}
// --------------------------------------------------------------
switch(WriteMode)
{
case WMODE_RAW :
- SetWriteToRaw();
+ SetWriteToRaw(); // modifies and pushes to the archive, when necessary
break;
case WMODE_RGB :
- SetWriteToRGB();
+ SetWriteToRGB(); // modifies and pushes to the archive, when necessary
break;
}
- bool check = CheckWriteIntegrity();
+ bool check = CheckWriteIntegrity(); // verifies length
if(check)
{
check = FileInternal->Write(fileName,WriteType);
//-----------------------------------------------------------------------------
// Protected
/**
- * \brief Check the write integrity
+ * \brief Checks the write integrity
*
* The tests made are :
* - verify the size of the image to write with the possible write
}
/**
- * \brief Update the File to write RAW datas
+ * \brief Updates the File to write RAW data (as opposed to RGB data)
+ * (modifies, when necessary, photochromatic interpretation,
+ * bits allocated, Pixels element VR)
*/
void FileHelper::SetWriteToRaw()
{
}
/**
- * \brief Update the File to write RGB datas
+ * \brief Updates the File to write RGB data (as opposed to RAW data)
+ * (modifies, when necessary, photochromatic interpretation,
+ * samples per pixel, Planar configuration,
+ * bits allocated, bits stored, high bit -ACR 24 bits-
+ * Pixels element VR, pushes out the LUT, )
*/
void FileHelper::SetWriteToRGB()
{
Archive->Push(0x0028,0x1202);
Archive->Push(0x0028,0x1203);
- // For old ACR-NEMA
+ // For old '24 Bits' ACR-NEMA
// Thus, we have a RGB image and the bits allocated = 24 and
// samples per pixels = 1 (in the read file)
if(FileInternal->GetBitsAllocated()==24)
Archive->Restore(0x0028,0x1201);
Archive->Restore(0x0028,0x1202);
Archive->Restore(0x0028,0x1203);
+
+ // group 0002 may be pushed out for ACR-NEMA writting purposes
+ Archive->Restore(0x0002,0x0000);
+ Archive->Restore(0x0002,0x0001);
+ Archive->Restore(0x0002,0x0002);
+ Archive->Restore(0x0002,0x0003);
+ Archive->Restore(0x0002,0x0010);
+ Archive->Restore(0x0002,0x0012);
+ Archive->Restore(0x0002,0x0013);
+ Archive->Restore(0x0002,0x0016);
+ Archive->Restore(0x0002,0x0100);
+ Archive->Restore(0x0002,0x0102);
}
/**
- * \brief Set in the File the write type to ACR
+ * \brief Pushes out the whole group 0002
+ * FIXME : better, set a flag to tell the writer not to write it ...
+ * FIXME : method should probably have an other name !
+ * SetWriteFileTypeToACR is NOT opposed to
+ * SetWriteFileTypeToExplicitVR and SetWriteFileTypeToImplicitVR
*/
void FileHelper::SetWriteFileTypeToACR()
{
- Archive->Push(0x0002,0x0010);
+ Archive->Push(0x0002,0x0000);
+ Archive->Push(0x0002,0x0001);
+ Archive->Push(0x0002,0x0002);
+ Archive->Push(0x0002,0x0003);
+ Archive->Push(0x0002,0x0010);// Only TransferSyntax was pushed out !
+ Archive->Push(0x0002,0x0012);
+ Archive->Push(0x0002,0x0013);
+ Archive->Push(0x0002,0x0016);
+ Archive->Push(0x0002,0x0100);
+ Archive->Push(0x0002,0x0102);
}
/**
- * \brief Set in the File the write type to Explicit VR
+ * \brief Sets in the File the TransferSyntax to 'Explicit VR Little Endian"
*/
void FileHelper::SetWriteFileTypeToExplicitVR()
{
}
/**
- * \brief Set in the File the write type to Implicit VR
+ * \brief Sets in the File the TransferSyntax to 'Implicit VR Little Endian"
*/
void FileHelper::SetWriteFileTypeToImplicitVR()
{
/**
- * \brief Restore in the File the write type
+ * \brief Restore in the File the initial group 0002
*/
void FileHelper::RestoreWriteFileType()
{
- Archive->Restore(0x0002,0x0010);
+ // group 0002 may be pushed out for ACR-NEMA writting purposes
+ Archive->Restore(0x0002,0x0000);
+ Archive->Restore(0x0002,0x0001);
+ Archive->Restore(0x0002,0x0002);
+ Archive->Restore(0x0002,0x0003);
+ Archive->Restore(0x0002,0x0010);//only TransferSyntax was pushed out/restored
+ Archive->Restore(0x0002,0x0012);
+ Archive->Restore(0x0002,0x0013);
+ Archive->Restore(0x0002,0x0016);
+ Archive->Restore(0x0002,0x0100);
+ Archive->Restore(0x0002,0x0102);
}
/**
}
/**
- * \brief Copy a ValEntry content
+ * \brief Duplicates a ValEntry or creates it.
* @param group Group number of the Entry
* @param elem Element number of the Entry
- * \return pointer to the modified/created Val Entry (NULL when creation
+ * \return pointer to the new Val Entry (NULL when creation
* failed).
*/
-ValEntry *FileHelper::CopyValEntry(uint16_t group,uint16_t elem)
+ValEntry *FileHelper::CopyValEntry(uint16_t group, uint16_t elem)
{
DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
ValEntry *newE;
}
else
{
- newE = GetFile()->NewValEntry(group,elem);
+ newE = GetFile()->NewValEntry(group, elem);
}
return newE;
}
/**
- * \brief Modifies the value of a given Bin Entry (Dicom Element)
- * when it exists. Create it with the given value when unexistant.
+ * \brief Duplicates a BinEntry or creates it.
* @param group Group number of the Entry
* @param elem Element number of the Entry
* @param vr Value Representation of the Entry
- * \return pointer to the modified/created Bin Entry (NULL when creation
+ * FIXME : what is it used for?
+ * \return pointer to the new Bin Entry (NULL when creation
* failed).
*/
-BinEntry *FileHelper::CopyBinEntry(uint16_t group,uint16_t elem,
+BinEntry *FileHelper::CopyBinEntry(uint16_t group, uint16_t elem,
const std::string &vr)
{
DocEntry *oldE = FileInternal->GetDocEntry(group, elem);
}
else
{
- newE = GetFile()->NewBinEntry(group,elem,vr);
+ newE = GetFile()->NewBinEntry(group, elem, vr);
}
return newE;
}
+/**
+ * \brief Checks the MetaElements Group (0002).
+ * adds the mandatory Entries if not found
+ * (when user asks to write as a DICOM file, an ACR-NEMA file
+ * he read before)
+ */
+void FileHelper::CheckMetaElements()
+{
+ // just to remember : 'official' 0002 group
+
+ //0002 0000 UL 1 Meta Group Length
+ //0002 0001 OB 1 File Meta Information Version
+ //0002 0002 UI 1 Media Stored SOP Class UID
+ //0002 0003 UI 1 Media Stored SOP Instance UID
+ //0002 0010 UI 1 Transfer Syntax UID
+ //0002 0012 UI 1 Implementation Class UID
+ //0002 0013 SH 1 Implementation Version Name
+ //0002 0016 AE 1 Source Application Entity Title
+ //0002 0100 UI 1 Private Information Creator
+ //0002 0102 OB 1 Private Information
+
+ std::string uid = Util::CreateUniqueUID();
+ std::string uidMedia = uid;
+
+ // Create them if not found
+ ValEntry *e0000 = CopyValEntry(0x0002,0x0000);
+ e0000->SetValue("0"); // for the moment
+ Archive->Push(e0000);
+
+ BinEntry *e0001 = CopyBinEntry(0x0002,0x0001, "OB");
+ e0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(), false);
+ e0001->SetLength(2);
+
+ ValEntry *e0002 = CopyValEntry(0x0002,0x0002);
+ // [Secondary Capture Image Storage]
+ e0002->SetValue("1.2.840.10008.5.1.4.1.1.7");
+ Archive->Push(e0002);
+
+ ValEntry *e0003 = CopyValEntry(0x0002,0x0003);
+ e0003->SetValue(uidMedia.c_str());
+ Archive->Push(e0003);
+
+ ValEntry *e0010 = CopyValEntry(0x0002,0x0010);
+ //Explicit VR - Little Endian
+ e0010->SetValue("1.2.840.10008.1.2.1");
+ Archive->Push(e0010);
+
+ ValEntry *e0012 = CopyValEntry(0x0002,0x0012);
+ e0012->SetValue("Implementation.Class.UID");
+ Archive->Push(e0012);
+
+ ValEntry *e0013 = CopyValEntry(0x0002,0x0013);
+ e0013->SetValue("GDCM 1.0");
+ Archive->Push(e0013);
+
+ ValEntry *e0016 = CopyValEntry(0x0002,0x0016);
+ e0016->SetValue("1.2.840.10008.5.1.4.1.1.7");
+ Archive->Push(e0016);
+}
+
//-----------------------------------------------------------------------------
// Private
/**