/*
*
* Copyright (C) 2019-2020, Open Connections GmbH
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation are maintained by
*
* OFFIS e.V.
* R&D Division Health
* Escherweg 2
* D-26121 Oldenburg, Germany
*
*
* Module: dcmfg
*
* Author: Michael Onken
*
* Purpose: Class for loading Concatenations
*
*/
#ifndef CONCATENATIONLOADER_H
#define CONCATENATIONLOADER_H
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmfg/fgdefine.h"
#include "dcmtk/dcmiod/iodtypes.h"
#include "dcmtk/dcmiod/iodutil.h"
#include "dcmtk/ofstd/oflist.h"
#include "dcmtk/ofstd/ofmap.h"
class DcmDataset;
/** Class for scanning files for concatenations and if desired, load
* one of them. If successful, loading produces the merged SOP Instance
* as a single dataset plus its frames in a separate data structure. The following
* workflow must be used:
*
* - Call to one of the scan() methods.
* - If scanning was successful, call getInfo() to get information about the
* concatenations found by scan(). getFailedFiles() will return those files
* who could not be read, do not provide Concatenation information or had other errors.
* - Call to the load() method in order to load of the the Concatenations found
* during scan(). Selection is done via the Concatenations Concatenation UID.
* The result is made available as a single, merged dataset without Pixel Data attribute
* and a vector containing all frames of the merged instance.
*
*/
class DCMTK_DCMFG_EXPORT ConcatenationLoader
{
public:
/// Structure representing information about a Concatenation,
/// consisting of its instances and common data.
struct DCMTK_DCMFG_EXPORT Info
{
/// Struct representing single SOP Instance being part of a Concatenation.
struct DCMTK_DCMFG_EXPORT Instance
{
/// Filename of concatenation instance
OFFilename m_Filename;
/// SOP Instance UID of concatenation instance
OFString m_sopInstanceUID;
/// Number of Frames extracted from concatenation instance
Uint32 m_NumberOfFrames;
/// In-Concatenation Number extracted from concatenation instance
Uint16 m_InConcatenationNumber;
/** Virtual destructor, frees memory
*/
virtual ~Instance();
/** Default constructor
*/
Instance();
};
/** Default constructor */
Info();
/** Copy constructor
* @param rhs The Info to copy from
*/
Info(const Info& rhs);
/** Assignment operator
* @param rhs The Info to copy from
* @return Reference to "this" object
*/
Info& operator=(const Info& rhs);
/// List of instances that belong to this Concatenation
OFList m_Files;
/// File that contains the source of this Concatenation, i.e.
/// the SOP Instance UID of Concatenation Source tag points to.
/// Might be empty if such file is not found during scanning.
OFFilename m_FileConatenationSource;
/// Concatenation UID of this Concatenation, extracted from concatenation instances
OFString m_ConcatenationUID;
/// SOP Instance UID of Concatenation Source, extracted from concatenation instances
OFString m_SourceUID;
/// In-Concatenation Total Number, extracted from concatenation instances (optional in DICOM)
Uint16 m_inConcatTotalNumber;
/// Total number of frames, i.e. the number of frames that make up this concatenation instance.
/// The number is computed by summing up the number of frames in instances found during scanning.
size_t m_NumTotalFrames;
/// Patient ID extracted from concatenation instances
OFString m_PatientID;
/// Study Instance UID extracted from concatenation instances
OFString m_StudyInstanceUID;
/// Series Instance UID extracted from concatenation instances
OFString m_SeriesInstanceUID;
/// SOP Class UID extracted from concatenation instances
OFString m_SOPClassUID;
/// Bits Allocated extracted from concatenation instances
Uint16 m_BitsAlloc;
/// Rows extracted from concatenation instances
Uint16 m_Rows;
/// Columns extracted from concatenation instances
Uint16 m_Cols;
/** Print overview of this Concatenation
* @param out The stream to print to
*/
void print(OFStringStream& out);
/** Virtual destructor
*/
virtual ~Info();
};
/// structure representing error information about a failed file
struct DCMTK_DCMFG_EXPORT Failure
{
/// filename
OFFilename fname;
/// error text
OFString errorText;
/// SOP Instance UID
OFString sopInstance;
/** constructor.
* @param fn filename
* @param err error text
* @param uid SOP instance UID
*/
Failure(const OFFilename& fn, const OFString& err, const OFString& uid)
: fname(fn), errorText(err), sopInstance(uid) {}
};
/// Result type of scan()
typedef OFMap TScanResult;
/// Iterator type for iterating over scan() results
typedef OFMap::iterator ScanResultIt;
/// Result type for the failures reported by scan()
typedef OFList TScanFailures;
/// Result type for iterating the failures reported by scan()
typedef OFListIterator(Failure) TScanFailureIt;
/** Constructor
*/
ConcatenationLoader();
/** Virtual destructor
*/
virtual ~ConcatenationLoader();
/** Ignore missing SOP Instance UID of Concatenation Source
* @param ignore If OFTrue, missing or empty SOP Instance UID of Concatenation Source tag is
* ignored and operation continues.
*/
virtual void setIgnoreMissingSourceUID(const OFBool ignore);
/** Scan given list of files for Concatenations. If successful, a results
* can be accessed by calling getInfo() which contains an overview of the
* Concatenations found (and files that failed during reading).
* @param files The files to scan
* @return EC_Normal if scanning was successful, i.e. at least one Concatenation
* could be discovered successfully.
*/
virtual OFCondition scan(const OFList& files);
/** Scan given directory for Concatenations. If successful, a results
* can be accessed by calling getInfo() which contains an overview of the
* Concatenations found (and files that failed during reading).
* @param directory The directory to scan
* @param pattern The search pattern (* per default)
* @param recursive If OFTrue, sub directories are scanned, too (default: OFTrue)
* @return EC_Normal if scanning was successful, i.e. at least one Concatenation
* could be discovered successfully.
*/
virtual OFCondition scan(const OFFilename& directory, const OFFilename& pattern = "*", OFBool recursive = OFTrue);
/** Get successful results of scan() operation. Returns empty result set is scan() has
* not been called before.
* @return The results of the scan() operation
*/
virtual const TScanResult& getInfo();
/** Get failed files of scan() operation. Returns empty result set is scan() has
* not been called before (may be empty otherwise).
* @return The failed files of the scan() operation
*/
virtual const TScanFailures& getFailedFiles();
/** Load Concatenation and merge it into "original" source dataset.
* The Concatenation to be loaded is selected by its Concatenation UID.
* Frames are not written to the dataset's Pixel Data attribute but instead
* reside in a frame structure provided by the caller (since they could exceed
* the uncompressed maximum of 4 GB allowed in a single dataset).
* @param concatenationUID The Concatenation UID of the Concatenation
* to be loaded
* @param dataset The result dataset. The caller must hand in a pointer to
* a valid dataset, i.e. memory allocation must be done by the caller.
* During loading, the dataset must not be freed outside this class.
* However, the caller stays responsible to delete the dataset after usage.
* @param frames The resulting frames. Vector should provided empty by the user.
* The user is responsible for deleting frames after successful operation.
* If load() fails, this parameter should return an empty vector.
* @return EC_Normal if loading Concatenation worked, error otherwise.
*/
virtual OFCondition
load(const OFString& concatenationUID, DcmDataset* dataset, OFVector& frames);
protected:
/** Handles single file of a Concatenation and extracts structure for later
* access by the user.
* @param file The file to process
* @param info The concatenation information structure to store results to
*/
virtual void handleFile(const OFFilename& file, ConcatenationLoader::Info& info);
/** Checks an current file's information whether it fits to the rest of the
* Concatenation instances already read. If this is the case, the instance's
* information is added to the results.
* @param info Information for this Concatenation
* @param inst Instance information that should be added to the Concatenation
* @param error Error, if instance cannot be processed/added, otherwise empty.
*/
virtual void checkAndInsertInfo(const ConcatenationLoader::Info& info,
const ConcatenationLoader::Info::Instance& inst,
OFString& error);
/** Check whether two numbers equal to 0 or empty.
* @param num1 The first number
* @param num2 The second number
* @return OFTrue if both number are equal or one of them is 0, OFFalse otherwise.
*/
virtual OFBool zeroOrEqual(const size_t num1, const size_t num2);
/** Check whether two strings are equal or one of them is empty.
* @param str1 The first string
* @param str2 The second string
* @return OFTrue if both strings are equal or one of them is empty, OFFalse otherwise.
*/
virtual OFBool emptyOrEqual(const OFString& str1, const OFString& str2);
/** Get that number from both which is not 0.
* @param num1 The first number
* @param num2 The second number
* @return num1 if num 1 is not zero, num 2 otherwise.
*/
template
T getNotZero(const T num1, const T num2);
/** Perform consistency checks on the Concatenations found.
* @return EC_Normal if successful, failure otherwise
*/
virtual OFCondition doScanFinalChecks();
/** Prepare template (dataset) that is used to represent the final
* result dataset.
* @param firstInstance The first (or any instance) of the concatenation
* instances that will be used to create the result dataset.
* @return EC_Normal if successful, failure otherwise
*/
virtual OFCondition prepareTemplate(Info& firstInstance);
/** Extract frames from given item. Works for Bits Allocated = 8
* and Bits Allocated = 16. Resulting frames are stored
* in member variable.
* @param item The item to read Pixel Data attribute from
* @param info Concatenation information providing pixel meta data
* like Rows and Columns
* @param numFrames The number of frames to extract from item's
* Pixel Data attribute
* @return EC_Normal if extraction was successful, error otherwise.
*/
virtual OFCondition extractFrames(DcmItem& item, Info& info, Uint32 numFrames);
/** Extract binary frames (Bits Allocated = 1) from given item.
* The resulting frames are stored in member variable.
* @param item The item to read Pixel Data attribute from
* @param info Concatenation information providing pixel meta data
* like Rows and Columns
* @param numFrames The number of frames to extract from item's
* Pixel Data attribute
* @return EC_Normal if extraction was successful, error otherwise.
*/
virtual OFCondition extractBinaryFrames(DcmItem& item, Info& info, Uint32 numFrames);
/** Deletes those concatenation attributes from given item that are not
* used or get a different value in the resulting merged dataset.
* @param item The item to delete from
* @return EC_Normal if successful, error otherwise
*/
virtual OFCondition deleteConcatAttributes(DcmItem& item);
/** Moves all Per-Frame Functional Group items found in given item
* to result instance.
* @param item The item to delete from
* @return EC_Normal if deletion was successful, error otherwise
*/
virtual OFCondition movePerFrameItems(DcmItem& item);
/** Insert/adapt attributes that are required with the merged result
* instance.
* @return EC_Normal if successful, failure otherwise
*/
virtual OFCondition insertDestinationAttributes();
virtual OFCondition
computeBytesPerFrame(const Uint16 rows, const Uint16 cols, const Uint16 bitsAlloc, size_t& bytes_per_frame);
private:
/// Map with entries consisting each of ConcatenationUID and related
/// Concatenation information.
TScanResult m_Concats;
/// List with failed files, each entry consisting of filename, error text and
/// SOP Instance UID (latter might be empty).
TScanFailures m_FailedFiles;
/// If OFTrue, the missing of attribute SOP Instance UID of Concatenation
/// Source is ignored and will not lead to an error
OFBool m_ignoreMissingSourceUID;
/// The dataset that will contain the final merged SOP instance produced
/// by the load() method. Once a merged instance is provided to the caller,
/// as a result of load(), the caller is responsible for deleting the
/// related memory.
DcmDataset* m_Result;
/// The frames that will contain all the frames of the merged SOP instance
/// produced by the load() method. Once a merged instance is provided to
/// the caller, as a result of load(), the caller is responsible for
/// deleting the related memory.
OFVector m_Frames;
};
#endif // CONCATENATIONLOADER_H