1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
/*
*
* Copyright (C) 2015-2021, 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 reading, accessing and writing stacks
*
*/
#include "dcmtk/dcmfg/stackinterface.h"
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmfg/fgfracon.h"
#include "dcmtk/dcmiod/iodutil.h"
FGStackInterface::FGStackInterface()
: m_Stacks()
{
}
FGStackInterface::~FGStackInterface()
{
while (m_Stacks.size() != 0)
{
OFMap<OFString, FGStack*>::iterator it = m_Stacks.begin();
FGStack* toDelete = (*it).second;
m_Stacks.erase(it);
delete toDelete;
}
}
void FGStackInterface::clear()
{
size_t stackSize = m_Stacks.size();
OFMap<OFString, FGStack*>::iterator it;
for (size_t count = 0; count < stackSize; count++)
{
it = m_Stacks.begin();
m_Stacks.erase(it);
}
}
OFCondition FGStackInterface::read(FGInterface& fgSource)
{
clear();
size_t numFrames = fgSource.getNumberOfFrames();
for (size_t count = 0; count < numFrames; count++)
{
// Get frame content FG if existing
FGFrameContent* fracon
= OFstatic_cast(FGFrameContent*, fgSource.get(OFstatic_cast(Uint32, count), DcmFGTypes::EFG_FRAMECONTENT));
if (fracon != NULL)
{
OFString stackID;
Uint32 inStackPos = 0;
// Check whether stack ID is actually present and get value
if ((fracon->getStackID(stackID).good()) && (fracon->getInStackPositionNumber(inStackPos).good()))
{
// Check whether this is a stack ID we do not know yet
OFMap<OFString, FGStack*>::iterator it = m_Stacks.begin();
while (it != m_Stacks.end())
{
// If this is an old stack, add frame to it
if ((*it).second->getStackID() == stackID)
{
// Add frame to stack if it is not in yet
if ((*it).second->getInStackPos(OFstatic_cast(Uint32, count)) == 0)
{
(*it).second->addFrame(OFstatic_cast(Uint32, count), inStackPos);
}
}
it++;
}
// If this is a new stack, add it to the list
if (it == m_Stacks.end())
{
FGStack* stack = new FGStack(stackID);
if (stack == NULL)
{
return EC_MemoryExhausted;
}
stack->addFrame(OFstatic_cast(Uint32, count), inStackPos);
if (!m_Stacks.insert(OFMake_pair(stack->getStackID(), stack)).second)
{
delete stack;
DCMFG_ERROR("Could not add stack to internal list (internal error, ignored)");
}
}
}
else
{
DCMFG_WARN("Reading stacks but Frame " << count << " does not provide Stack ID or In-Stack Position");
}
}
else
{
DCMFG_WARN("Reading stacks but Frame " << count << " does not provide a Frame Content functional group");
}
}
if (m_Stacks.size() == 0)
{
return FG_EC_NoStacksFound;
}
return EC_Normal;
}
OFCondition FGStackInterface::write(FGInterface& fgDestination)
{
size_t numFrames = fgDestination.getNumberOfFrames();
if (numFrames == 0)
{
return FG_EC_NotEnoughFrames;
}
// Check whether maximum in-stack position does not exceed number of frames in image
if (!checkConsistency(&fgDestination))
{
return FG_EC_InvalidData;
}
// Walk through stacks, and for each, add/overwrite stack information to
// the respective Frame Content functional groups
OFCondition result;
OFMap<OFString, FGStack*>::iterator stack = m_Stacks.begin();
while (result.good() && (stack != m_Stacks.end()))
{
OFString stackID = (*stack).second->getStackID();
// Walk over all referenced frames and add Stack information
OFMap<Uint32, Uint32>::const_iterator stackEntry = (*stack).second->begin();
while (stackEntry != (*stack).second->end())
{
Uint32 frameNo = (*stackEntry).first;
Uint32 inStackPos = (*stackEntry).second;
FGFrameContent* fg = ensureFrameContentFG(frameNo, fgDestination);
// Create functional group if not already existing
if (fg == NULL)
{
result = FG_EC_CouldNotAddFG;
}
if (result.good())
result = fg->setStackID(stackID);
if (result.good())
result = fg->setInStackPositionNumber(inStackPos
+ 1 /* vector counts from 0, position in DICOM starts with 1 */);
if (result.bad())
{
DCMFG_ERROR("Could not create or add stack with ID " << stackID << " to frame " << frameNo << ": "
<< result.text());
}
stackEntry++;
}
stack++;
}
return result;
}
FGFrameContent* FGStackInterface::ensureFrameContentFG(const Uint32 frameNo, FGInterface& fg)
{
FGFrameContent* content = OFstatic_cast(FGFrameContent*, fg.get(frameNo, DcmFGTypes::EFG_FRAMECONTENT));
if (!content)
{
FGFrameContent newContent;
OFCondition result = fg.addPerFrame(frameNo, newContent);
if (result.bad())
{
DCMFG_ERROR("Could not add Frame Content FG for frame " << frameNo);
}
else
{
content = OFstatic_cast(FGFrameContent*, fg.get(frameNo, DcmFGTypes::EFG_FRAMECONTENT));
}
}
return content;
}
OFBool FGStackInterface::addStack(FGStack* stack)
{
if (stack == NULL)
return OFFalse;
if (stack->getStackID().empty())
{
DCMFG_ERROR("Stack ID cannot be empty");
return OFFalse;
}
return m_Stacks.insert(OFMake_pair(stack->getStackID(), stack)).second;
}
size_t FGStackInterface::numStacks() const
{
return m_Stacks.size();
}
OFBool FGStackInterface::checkConsistency(FGInterface* fgContext)
{
size_t errors = 0;
size_t count = 0;
// Run over stacks and check whether each has a Stack ID.
// Also check whether stacks can be valid in the context
// of the given functional groups (e.g. frame range ok)
OFMap<OFString, FGStack*>::iterator it = m_Stacks.begin();
while (it != m_Stacks.end())
{
if ((*it).second->getStackID().empty())
{
errors++;
DCMFG_ERROR("Stack ID for stack #" << count << " is empty");
}
if (fgContext)
{
errors += checkContext((*it).second, fgContext);
}
it++;
count++;
}
return (errors == 0);
}
size_t FGStackInterface::checkContext(FGStack* stack, FGInterface* context)
{
// Must be non-empty
if (!stack || !context)
return 1;
// Check whether we have any frames
size_t numFrames = context->getNumberOfFrames();
if (numFrames == 0)
{
DCMFG_ERROR("Cannot have stacks without frames");
return 1;
}
// Walk over frames in stack and check that frame number and
// in-stack position is in range with the number of available frames
size_t errors = 0;
const OFMap<Uint32, Uint32>& frames = stack->m_FrameNumbers;
FGStack::const_iterator it = frames.begin();
for (size_t count = 0; count < numFrames; count++)
{
// Frame number must be in range
if ((*it).first > numFrames)
{
DCMFG_ERROR("Stack references frame #" << (*it).first << " but only #" << numFrames << " frames exist");
errors++;
}
if ((*it).second > numFrames)
{
DCMFG_ERROR("Stack references in-stack position #" << (*it).first << " but only #" << numFrames
<< " frames exist");
errors++;
}
}
return errors;
}
|