Mercurial > hg > orthanc-stone
changeset 65:885932a893de wasm
OrthancFrameLayerSource
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 16 May 2017 22:12:41 +0200 |
parents | 394e63010e02 |
children | 298f375dcb68 |
files | Framework/Layers/ILayerSource.h Framework/Layers/LayerSourceBase.cpp Framework/Layers/LayerSourceBase.h Framework/Layers/OrthancFrameLayerSource.cpp Framework/Layers/OrthancFrameLayerSource.h Framework/Toolbox/GeometryToolbox.h Framework/Widgets/IWidget.h Resources/CMake/OrthancStone.cmake Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp Resources/Orthanc/Resources/EmbedResources.py UnitTestsSources/UnitTestsMain.cpp |
diffstat | 10 files changed, 553 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Layers/ILayerSource.h Tue May 16 22:12:41 2017 +0200 @@ -0,0 +1,71 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "ILayerRenderer.h" +#include "../Toolbox/SliceGeometry.h" + +namespace OrthancStone +{ + class ILayerSource : public boost::noncopyable + { + public: + class IObserver : public boost::noncopyable + { + public: + virtual ~IObserver() + { + } + + // Triggered if the extent or the content of the volume has changed + virtual void NotifySourceChange(ILayerSource& source) = 0; + + // Triggered if some slice in the source volume has changed + virtual void NotifySliceChange(ILayerSource& source, + const SliceGeometry& slice) = 0; + + // The layer must be deleted by the observer. "layer" will never + // be "NULL", otherwise "NotifyLayerError()" would have been + // called. + virtual void NotifyLayerReady(ILayerRenderer *layer, + ILayerSource& source, + const SliceGeometry& viewportSlice) = 0; + + virtual void NotifyLayerError(ILayerSource& source, + const SliceGeometry& viewportSlice) = 0; + }; + + virtual ~ILayerSource() + { + } + + virtual void SetObserver(IObserver& observer) = 0; + + virtual bool GetExtent(double& x1, + double& y1, + double& x2, + double& y2, + const SliceGeometry& viewportSlice) = 0; + + virtual void ScheduleLayerCreation(const SliceGeometry& viewportSlice) = 0; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Layers/LayerSourceBase.cpp Tue May 16 22:12:41 2017 +0200 @@ -0,0 +1,76 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "LayerSourceBase.h" + +#include "../../Resources/Orthanc/Core/OrthancException.h" + +namespace OrthancStone +{ + void LayerSourceBase::NotifySourceChange() + { + if (observer_ != NULL) + { + observer_->NotifySourceChange(*this); + } + } + + void LayerSourceBase::NotifySliceChange(const SliceGeometry& slice) + { + if (observer_ != NULL) + { + observer_->NotifySliceChange(*this, slice); + } + } + + void LayerSourceBase::NotifyLayerReady(ILayerRenderer* layer, + ILayerSource& source, + const SliceGeometry& viewportSlice) + { + if (layer == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + if (observer_ != NULL) + { + observer_->NotifyLayerReady(layer, *this, viewportSlice); + } + else + { + delete layer; + } + } + + void LayerSourceBase::NotifyLayerError(ILayerSource& source, + const SliceGeometry& viewportSlice) + { + if (observer_ != NULL) + { + observer_->NotifyLayerError(*this, viewportSlice); + } + } + + void LayerSourceBase::SetObserver(IObserver& observer) + { + observer_ = &observer; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Layers/LayerSourceBase.h Tue May 16 22:12:41 2017 +0200 @@ -0,0 +1,53 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "ILayerSource.h" + +namespace OrthancStone +{ + class LayerSourceBase : public ILayerSource + { + private: + IObserver* observer_; + + protected: + void NotifySourceChange(); + + void NotifySliceChange(const SliceGeometry& slice); + + // Takes ownership of "layer" (that cannot be "NULL") + void NotifyLayerReady(ILayerRenderer* layer, + ILayerSource& source, + const SliceGeometry& viewportSlice); + + void NotifyLayerError(ILayerSource& source, + const SliceGeometry& viewportSlice); + + public: + LayerSourceBase() : observer_(NULL) + { + } + + virtual void SetObserver(IObserver& observer); + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Layers/OrthancFrameLayerSource.cpp Tue May 16 22:12:41 2017 +0200 @@ -0,0 +1,213 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "OrthancFrameLayerSource.h" + +#include "FrameRenderer.h" +#include "../../Resources/Orthanc/Core/Images/PngReader.h" +#include "../../Resources/Orthanc/Core/Logging.h" +#include "../../Resources/Orthanc/Core/OrthancException.h" +#include "../Toolbox/DicomFrameConverter.h" + +#include <boost/lexical_cast.hpp> + + +namespace OrthancStone +{ + class OrthancFrameLayerSource::Operation : public Orthanc::IDynamicObject + { + private: + Content content_; + SliceGeometry viewportSlice_; + + public: + Operation(Content content) : content_(content) + { + } + + void SetViewportSlice(const SliceGeometry& slice) + { + viewportSlice_ = slice; + } + + const SliceGeometry& GetViewportSlice() const + { + return viewportSlice_; + } + + Content GetContent() const + { + return content_; + } + }; + + + OrthancFrameLayerSource::OrthancFrameLayerSource(IWebService& orthanc, + const std::string& instanceId, + unsigned int frame) : + orthanc_(orthanc), + instanceId_(instanceId), + frame_(frame) + { + orthanc_.ScheduleGetRequest(*this, + "/instances/" + instanceId + "/tags", + new Operation(Content_Tags)); + } + + + void OrthancFrameLayerSource::SetObserver(IObserver& observer) + { + LayerSourceBase::SetObserver(observer); + + if (dataset_.get() != NULL) + { + NotifySourceChange(); + } + } + + void OrthancFrameLayerSource::NotifyError(const std::string& uri, + Orthanc::IDynamicObject* payload) + { + LOG(ERROR) << "Cannot download " << uri; + } + + void OrthancFrameLayerSource::NotifySuccess(const std::string& uri, + const void* answer, + size_t answerSize, + Orthanc::IDynamicObject* payload) + { + std::auto_ptr<Operation> operation(reinterpret_cast<Operation*>(payload)); + + if (operation.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else if (operation->GetContent() == Content_Tags) + { + dataset_.reset(new OrthancPlugins::FullOrthancDataset(answer, answerSize)); + + DicomFrameConverter converter; + converter.ReadParameters(*dataset_); + format_ = converter.GetExpectedPixelFormat(); + + NotifySourceChange(); + } + else if (operation->GetContent() == Content_Frame) + { + std::auto_ptr<Orthanc::PngReader> image(new Orthanc::PngReader); + image->ReadFromMemory(answer, answerSize); + + if (format_ == Orthanc::PixelFormat_SignedGrayscale16) + { + if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16) + { + image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); + } + else + { + NotifyLayerReady(NULL, *this, operation->GetViewportSlice()); + } + } + + SliceGeometry frameSlice(*dataset_); + NotifyLayerReady(FrameRenderer::CreateRenderer(image.release(), + operation->GetViewportSlice(), + frameSlice, *dataset_, 1, 1, true), + *this, operation->GetViewportSlice()); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + bool OrthancFrameLayerSource::GetExtent(double& x1, + double& y1, + double& x2, + double& y2, + const SliceGeometry& viewportSlice /* ignored */) + { + if (dataset_.get() == NULL) + { + return false; + } + else + { + // Assume that PixelSpacingX == PixelSpacingY == 1 + + OrthancPlugins::DicomDatasetReader reader(*dataset_); + + unsigned int width, height; + + if (!reader.GetUnsignedIntegerValue(width, OrthancPlugins::DICOM_TAG_COLUMNS) || + !reader.GetUnsignedIntegerValue(height, OrthancPlugins::DICOM_TAG_ROWS)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + x1 = 0; + y1 = 0; + x2 = static_cast<double>(width); + y2 = static_cast<double>(height); + + return true; + } + } + + + void OrthancFrameLayerSource::ScheduleLayerCreation(const SliceGeometry& viewportSlice) + { + if (dataset_.get() == NULL) + { + NotifyLayerReady(NULL, *this, viewportSlice); + } + else + { + std::string uri = ("/instances/" + instanceId_ + "/frames/" + + boost::lexical_cast<std::string>(frame_)); + + std::string compressed; + + switch (format_) + { + case Orthanc::PixelFormat_RGB24: + uri += "/preview"; + break; + + case Orthanc::PixelFormat_Grayscale16: + uri += "/image-uint16"; + break; + + case Orthanc::PixelFormat_SignedGrayscale16: + uri += "/image-int16"; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + std::auto_ptr<Operation> operation(new Operation(Content_Frame)); + operation->SetViewportSlice(viewportSlice); + orthanc_.ScheduleGetRequest(*this, uri, operation.release()); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Layers/OrthancFrameLayerSource.h Tue May 16 22:12:41 2017 +0200 @@ -0,0 +1,72 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "LayerSourceBase.h" +#include "../Toolbox/IWebService.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h" + +namespace OrthancStone +{ + class OrthancFrameLayerSource : + public LayerSourceBase, + public IWebService::ICallback + { + private: + enum Content + { + Content_Tags, + Content_Frame + }; + + class Operation; + + IWebService& orthanc_; + std::string instanceId_; + unsigned int frame_; + std::auto_ptr<OrthancPlugins::FullOrthancDataset> dataset_; + Orthanc::PixelFormat format_; + + public: + OrthancFrameLayerSource(IWebService& orthanc, + const std::string& instanceId, + unsigned int frame); + + virtual void SetObserver(IObserver& observer); + + virtual void NotifyError(const std::string& uri, + Orthanc::IDynamicObject* payload); + + virtual void NotifySuccess(const std::string& uri, + const void* answer, + size_t answerSize, + Orthanc::IDynamicObject* payload); + + virtual bool GetExtent(double& x1, + double& y1, + double& x2, + double& y2, + const SliceGeometry& viewportSlice /* ignored */); + + virtual void ScheduleLayerCreation(const SliceGeometry& viewportSlice); + }; +}
--- a/Framework/Toolbox/GeometryToolbox.h Tue May 16 17:31:09 2017 +0200 +++ b/Framework/Toolbox/GeometryToolbox.h Tue May 16 22:12:41 2017 +0200 @@ -21,6 +21,12 @@ #pragma once +// Patch for Boost 1.64.0 +// https://github.com/dealii/dealii/issues/4302 +#if BOOST_VERSION >= 106300 // or 64, need to check +# include <boost/serialization/array_wrapper.hpp> +#endif + #include <boost/numeric/ublas/vector.hpp> #include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h"
--- a/Framework/Widgets/IWidget.h Tue May 16 17:31:09 2017 +0200 +++ b/Framework/Widgets/IWidget.h Tue May 16 22:12:41 2017 +0200 @@ -71,6 +71,8 @@ virtual void UpdateContent() = 0; + // Subclasses can call this method to signal the display of the + // widget must be refreshed virtual void NotifyChange() = 0; }; }
--- a/Resources/CMake/OrthancStone.cmake Tue May 16 17:31:09 2017 +0200 +++ b/Resources/CMake/OrthancStone.cmake Tue May 16 22:12:41 2017 +0200 @@ -187,19 +187,21 @@ ${ORTHANC_STONE_DIR}/Framework/Layers/DicomStructureSetRendererFactory.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/FrameRenderer.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/GrayscaleFrameRenderer.cpp + ${ORTHANC_STONE_DIR}/Framework/Layers/LayerSourceBase.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/LineLayerRenderer.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/LineMeasureTracker.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/RenderStyle.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/SeriesFrameRendererFactory.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/SiblingSliceLocationFactory.cpp ${ORTHANC_STONE_DIR}/Framework/Layers/SingleFrameRendererFactory.cpp + ${ORTHANC_STONE_DIR}/Framework/Layers/OrthancFrameLayerSource.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomFrameConverter.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomStructureSet.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/DownloadStack.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/GeometryToolbox.cpp - ${ORTHANC_STONE_DIR}/Framework/Toolbox/OrthancWebService.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/MessagingToolbox.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/OrthancSeriesLoader.cpp + ${ORTHANC_STONE_DIR}/Framework/Toolbox/OrthancWebService.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/ParallelSlices.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/ParallelSlicesCursor.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/SliceGeometry.cpp
--- a/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp Tue May 16 17:31:09 2017 +0200 +++ b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp Tue May 16 22:12:41 2017 +0200 @@ -169,7 +169,7 @@ FullOrthancDataset::FullOrthancDataset(const void* content, size_t size) { - IOrthancConnection::ParseJson(root_, content); + IOrthancConnection::ParseJson(root_, content, size); CheckRoot(); }
--- a/UnitTestsSources/UnitTestsMain.cpp Tue May 16 17:31:09 2017 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Tue May 16 22:12:41 2017 +0200 @@ -22,6 +22,62 @@ #include "gtest/gtest.h" #include "../Resources/Orthanc/Core/Logging.h" +#include "../Framework/Toolbox/OrthancWebService.h" +#include "../Framework/Layers/OrthancFrameLayerSource.h" + + +namespace OrthancStone +{ + class Tata : public ILayerSource::IObserver + { + public: + virtual void NotifySourceChange(ILayerSource& source) + { + printf("Source change\n"); + + OrthancStone::SliceGeometry slice; + double x1, y1, x2, y2; + printf(">> %d: ", source.GetExtent(x1, y1, x2, y2, slice)); + printf("(%f,%f) (%f,%f)\n", x1, y1, x2, y2); + } + + virtual void NotifySliceChange(ILayerSource& source, + const SliceGeometry& slice) + { + printf("Slice change\n"); + } + + virtual void NotifyLayerReady(ILayerRenderer* layer, + ILayerSource& source, + const SliceGeometry& viewportSlice) + { + std::auto_ptr<ILayerRenderer> tmp(layer); + + } + + virtual void NotifyLayerError(ILayerSource& source, + const SliceGeometry& viewportSlice) + { + } + }; +} + + + +TEST(Toto, Tutu) +{ + Orthanc::WebServiceParameters web; + OrthancStone::OrthancWebService orthanc(web); + OrthancStone::OrthancFrameLayerSource source(orthanc, "befb52a6-b4b04954-b5a019c3-fdada9d7-dddc9430", 0); + + OrthancStone::Tata tata; + source.SetObserver(tata); + + OrthancStone::SliceGeometry slice; + source.ScheduleLayerCreation(slice); +} + + int main(int argc, char **argv) {