diff --git a/Modules/Multilabel/mitkLabelSetIOHelper.cpp b/Modules/Multilabel/mitkLabelSetIOHelper.cpp index bd17069ae7..70d5e47426 100644 --- a/Modules/Multilabel/mitkLabelSetIOHelper.cpp +++ b/Modules/Multilabel/mitkLabelSetIOHelper.cpp @@ -1,271 +1,271 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkLabelSetIOHelper.h" #include "mitkLabelSetImage.h" #include #include namespace { std::string EnsureExtension(const std::string& filename) { const std::string extension = ".lsetp"; if (filename.size() < extension.size() || std::string::npos == filename.find(extension, filename.size() - extension.size())) return filename + extension; return filename; } } bool mitk::LabelSetIOHelper::SaveLabelSetImagePreset(const std::string &presetFilename, mitk::LabelSetImage::Pointer &inputImage) { const auto filename = EnsureExtension(presetFilename); tinyxml2::XMLDocument xmlDocument; xmlDocument.InsertEndChild(xmlDocument.NewDeclaration()); auto *rootElement = xmlDocument.NewElement("LabelSetImagePreset"); rootElement->SetAttribute("layers", inputImage->GetNumberOfLayers()); xmlDocument.InsertEndChild(rootElement); for (unsigned int layerIndex = 0; layerIndex < inputImage->GetNumberOfLayers(); layerIndex++) { auto *layerElement = xmlDocument.NewElement("Layer"); layerElement->SetAttribute("index", layerIndex); layerElement->SetAttribute("labels", inputImage->GetNumberOfLabels(layerIndex)); rootElement->InsertEndChild(layerElement); for (unsigned int labelIndex = 0; labelIndex < inputImage->GetNumberOfLabels(layerIndex); labelIndex++) layerElement->InsertEndChild(LabelSetIOHelper::GetLabelAsXMLElement(xmlDocument, inputImage->GetLabel(labelIndex, layerIndex))); } - return xmlDocument.SaveFile(filename.c_str()); + return tinyxml2::XML_SUCCESS == xmlDocument.SaveFile(filename.c_str()); } void mitk::LabelSetIOHelper::LoadLabelSetImagePreset(const std::string &presetFilename, mitk::LabelSetImage::Pointer &inputImage) { if (inputImage.IsNull()) return; const auto filename = EnsureExtension(presetFilename); tinyxml2::XMLDocument xmlDocument; if(tinyxml2::XML_SUCCESS != xmlDocument.LoadFile(filename.c_str())) return; auto *rootElement = xmlDocument.FirstChildElement("LabelSetImagePreset"); if (nullptr == rootElement) { MITK_WARN << "Not a valid LabelSet preset"; return; } auto activeLayerBackup = inputImage->GetActiveLayer(); int numberOfLayers = 0; rootElement->QueryIntAttribute("layers", &numberOfLayers); auto* layerElement = rootElement->FirstChildElement("Layer"); if (nullptr == layerElement) { MITK_WARN << "LabelSet preset does not contain any layers"; return; } for (int layerIndex = 0; layerIndex < numberOfLayers; layerIndex++) { int numberOfLabels = 0; layerElement->QueryIntAttribute("labels", &numberOfLabels); if (nullptr == inputImage->GetLabelSet(layerIndex)) { inputImage->AddLayer(); } else { inputImage->SetActiveLayer(layerIndex); } auto *labelElement = layerElement->FirstChildElement("Label"); if (nullptr == labelElement) continue; for (int labelIndex = 0; labelIndex < numberOfLabels; labelIndex++) { auto label = mitk::LabelSetIOHelper::LoadLabelFromXMLDocument(labelElement); const auto labelValue = label->GetValue(); if (0 != labelValue) { auto* labelSet = inputImage->GetLabelSet(layerIndex); auto* alreadyExistingLabel = labelSet->GetLabel(labelValue); if (nullptr != alreadyExistingLabel) { // Override existing label with label from preset alreadyExistingLabel->ConcatenatePropertyList(label); labelSet->UpdateLookupTable(labelValue); } else { labelSet->AddLabel(label); } } labelElement = labelElement->NextSiblingElement("Label"); if (nullptr == labelElement) continue; } layerElement = layerElement->NextSiblingElement("Layer"); if (nullptr == layerElement) continue; } inputImage->SetActiveLayer(activeLayerBackup); } tinyxml2::XMLElement *mitk::LabelSetIOHelper::GetLabelAsXMLElement(tinyxml2::XMLDocument &doc, Label *label) { auto *labelElem = doc.NewElement("Label"); // add XML contents const PropertyList::PropertyMap *propmap = label->GetMap(); for (auto iter = propmap->begin(); iter != propmap->end(); ++iter) { std::string key = iter->first; const BaseProperty *property = iter->second; auto *element = PropertyToXMLElement(doc, key, property); if (element) labelElem->InsertEndChild(element); } return labelElem; } mitk::Label::Pointer mitk::LabelSetIOHelper::LoadLabelFromXMLDocument(const tinyxml2::XMLElement *labelElem) { // reread auto *propElem = labelElem->FirstChildElement("property"); std::string name; mitk::BaseProperty::Pointer prop; mitk::Label::Pointer label = mitk::Label::New(); while (propElem) { LabelSetIOHelper::PropertyFromXMLElement(name, prop, propElem); label->SetProperty(name, prop); propElem = propElem->NextSiblingElement("property"); } return label.GetPointer(); } tinyxml2::XMLElement *mitk::LabelSetIOHelper::PropertyToXMLElement(tinyxml2::XMLDocument &doc, const std::string &key, const BaseProperty *property) { auto *keyelement = doc.NewElement("property"); keyelement->SetAttribute("key", key.c_str()); keyelement->SetAttribute("type", property->GetNameOfClass()); // construct name of serializer class std::string serializername(property->GetNameOfClass()); serializername += "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (allSerializers.size() < 1) MITK_ERROR << "No serializer found for " << property->GetNameOfClass() << ". Skipping object"; if (allSerializers.size() > 1) MITK_WARN << "Multiple serializers found for " << property->GetNameOfClass() << "Using arbitrarily the first one."; for (auto iter = allSerializers.begin(); iter != allSerializers.end(); ++iter) { if (auto *serializer = dynamic_cast(iter->GetPointer())) { serializer->SetProperty(property); try { auto *valueelement = serializer->Serialize(doc); if (valueelement) keyelement->InsertEndChild(valueelement); } catch (std::exception &e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } break; } } return keyelement; } bool mitk::LabelSetIOHelper::PropertyFromXMLElement(std::string &key, mitk::BaseProperty::Pointer &prop, const tinyxml2::XMLElement *elem) { const char* typeC = elem->Attribute("type"); std::string type = nullptr != typeC ? typeC : ""; const char* keyC = elem->Attribute("key"); key = nullptr != keyC ? keyC : ""; // construct name of serializer class std::string serializername(type); serializername += "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (allSerializers.size() < 1) MITK_ERROR << "No serializer found for " << type << ". Skipping object"; if (allSerializers.size() > 1) MITK_WARN << "Multiple deserializers found for " << type << "Using arbitrarily the first one."; for (auto iter = allSerializers.begin(); iter != allSerializers.end(); ++iter) { if (auto *serializer = dynamic_cast(iter->GetPointer())) { try { prop = serializer->Deserialize(elem->FirstChildElement()); } catch (std::exception &e) { MITK_ERROR << "Deserializer " << serializer->GetNameOfClass() << " failed: " << e.what(); return false; } break; } } if (prop.IsNull()) return false; return true; } diff --git a/Modules/Persistence/mitkPropertyListsXmlFileReaderAndWriter.cpp b/Modules/Persistence/mitkPropertyListsXmlFileReaderAndWriter.cpp index 6802822eae..213e8b4fc7 100644 --- a/Modules/Persistence/mitkPropertyListsXmlFileReaderAndWriter.cpp +++ b/Modules/Persistence/mitkPropertyListsXmlFileReaderAndWriter.cpp @@ -1,261 +1,263 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPropertyListsXmlFileReaderAndWriter.h" #include "mitkProperties.h" #include "mitkStandaloneDataStorage.h" #include #include namespace { std::string ReadStringAttribute(const tinyxml2::XMLElement* elem, const char *name) { const char* attrib = elem->Attribute(name); return attrib != nullptr ? attrib : ""; } } namespace mitk { bool PropertyListsXmlFileReaderAndWriter::PropertyFromXmlElem(std::string &name, mitk::BaseProperty::Pointer &prop, const tinyxml2::XMLElement *elem) const { if (nullptr == elem) return false; std::string type = ReadStringAttribute(elem, "type"); if (type.empty()) { MITK_WARN << "type attribute not found in property"; return false; } name = ReadStringAttribute(elem, "name"); if (name.empty()) { MITK_WARN << "name attribute not found in property"; return false; } tinyxml2::XMLError err = tinyxml2::XML_SUCCESS; if (type == "BoolProperty") { int val = 0; err = elem->QueryIntAttribute("value", &val); if (tinyxml2::XML_SUCCESS == err) { prop = mitk::BoolProperty::New(val == 1 ? true : false); } } else if (type == "StringProperty") { const auto* attrib = elem->FindAttribute("value"); if (nullptr == attrib) { err = tinyxml2::XML_NO_ATTRIBUTE; } else { auto val = ReadStringAttribute(elem, "value"); prop = mitk::StringProperty::New(val); } } else if (type == "IntProperty") { int val = 0; err = elem->QueryIntAttribute("value", &val); if (tinyxml2::XML_SUCCESS == err) { prop = mitk::IntProperty::New(val); } } else if (type == "DoubleProperty") { double val = 0; err = elem->QueryDoubleAttribute("value", &val); if (tinyxml2::XML_SUCCESS == err) { prop = mitk::DoubleProperty::New(val); } } else if (type == "FloatProperty") { float val = 0; err = elem->QueryFloatAttribute("value", &val); if (tinyxml2::XML_SUCCESS == err) { prop = mitk::FloatProperty::New(val); } } else { err = tinyxml2::XML_WRONG_ATTRIBUTE_TYPE; MITK_WARN << "type attribute unknown. Only BoolProperty, StringProperty, IntProperty, DoubleProperty or FloatProperty allowed."; } return tinyxml2::XML_SUCCESS == err; } bool PropertyListsXmlFileReaderAndWriter::PropertyToXmlElem(const std::string &name, const mitk::BaseProperty *prop, tinyxml2::XMLElement *elem) const { if (nullptr == prop || nullptr == elem) return false; const mitk::IntProperty *intProp = nullptr; const mitk::FloatProperty *floatProp = nullptr; const mitk::DoubleProperty *doubleProp = nullptr; const mitk::BoolProperty *boolProp = nullptr; const mitk::StringProperty *stringProp = nullptr; bool writeOp = true; if (nullptr != (boolProp = dynamic_cast(prop))) { elem->SetAttribute(GetPropertyListIdElementName(), name.c_str()); elem->SetAttribute("value", boolProp->GetValue() ? 1 : 0); elem->SetAttribute("type", "BoolProperty"); } else if (nullptr != (stringProp = dynamic_cast(prop))) { elem->SetAttribute(GetPropertyListIdElementName(), name.c_str()); elem->SetAttribute("value", stringProp->GetValue()); elem->SetAttribute("type", "StringProperty"); } else if (nullptr != (intProp = dynamic_cast(prop))) { elem->SetAttribute(GetPropertyListIdElementName(), name.c_str()); elem->SetAttribute("value", intProp->GetValue()); elem->SetAttribute("type", "IntProperty"); } else if (nullptr != (doubleProp = dynamic_cast(prop))) { elem->SetAttribute(GetPropertyListIdElementName(), name.c_str()); elem->SetAttribute("value", doubleProp->GetValue()); elem->SetAttribute("type", "DoubleProperty"); } else if (nullptr != (floatProp = dynamic_cast(prop))) { elem->SetAttribute(GetPropertyListIdElementName(), name.c_str()); elem->SetAttribute("value", floatProp->GetValue()); elem->SetAttribute("type", "FloatProperty"); } else { MITK_WARN("PropertyListImportFromXmlFile") << "Base property " << name << " is unknown"; writeOp = false; } return writeOp; } bool PropertyListsXmlFileReaderAndWriter::WriteLists(const std::string &fileName, const std::map &_PropertyLists) const { tinyxml2::XMLDocument doc; doc.InsertEndChild(doc.NewDeclaration()); // create root auto *propertyListsElem = doc.NewElement("PropertyLists"); bool allPropsConverted = true; auto it = _PropertyLists.begin(); while (it != _PropertyLists.end()) { const std::string &id = (*it).first; const PropertyList *propList = (*it).second; auto *propertyListElem = doc.NewElement("PropertyList"); propertyListElem->SetAttribute(GetPropertyListIdElementName(), id.c_str()); const std::map *propMap = propList->GetMap(); auto propMapIt = propMap->begin(); while (propMapIt != propMap->end()) { const std::string &propName = (*propMapIt).first; const BaseProperty *prop = (*propMapIt).second; auto *propertyElem = doc.NewElement("Property"); if (!this->PropertyToXmlElem(propName, prop, propertyElem)) allPropsConverted = false; propertyListElem->InsertEndChild(propertyElem); ++propMapIt; } propertyListsElem->InsertEndChild(propertyListElem); ++it; } doc.InsertEndChild(propertyListsElem); - return (allPropsConverted && doc.SaveFile(fileName.c_str())); + return (allPropsConverted && tinyxml2::XML_SUCCESS == doc.SaveFile(fileName.c_str())); } bool PropertyListsXmlFileReaderAndWriter::ReadLists(const std::string &fileName, std::map &_PropertyLists) const { // reread tinyxml2::XMLDocument doc; doc.LoadFile(fileName.c_str()); tinyxml2::XMLHandle docHandle(&doc); auto *elem = docHandle.FirstChildElement("PropertyLists").FirstChildElement("PropertyList").ToElement(); if (nullptr == elem) { MITK_WARN("PropertyListFromXml") << "Cannot find a PropertyList element (inside a PropertyLists element)"; return false; } bool opRead = false; while (nullptr != elem) { std::string propListId = ReadStringAttribute(elem, GetPropertyListIdElementName()); if (propListId.empty()) break; + opRead = true; + auto propList = mitk::PropertyList::New(); auto *propElem = elem->FirstChildElement("Property"); while (nullptr != propElem) { std::string name; mitk::BaseProperty::Pointer prop; opRead = this->PropertyFromXmlElem(name, prop, propElem); if (!opRead) break; propList->SetProperty(name, prop); propElem = propElem->NextSiblingElement("Property"); } if (!opRead) break; _PropertyLists[propListId] = propList; elem = elem->NextSiblingElement("PropertyList"); } return opRead; } PropertyListsXmlFileReaderAndWriter::PropertyListsXmlFileReaderAndWriter() {} PropertyListsXmlFileReaderAndWriter::~PropertyListsXmlFileReaderAndWriter() {} const char *PropertyListsXmlFileReaderAndWriter::GetPropertyListIdElementName() { return "name"; } }