Mercurial > hg > orthanc-stone
comparison Applications/Samples/SingleFrameEditorApplication.h @ 338:b3b3fa0e3689 am-2
BitmapStack
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 19 Oct 2018 12:50:38 +0200 |
parents | c4d4213f095c |
children | 5a7915b23138 |
comparison
equal
deleted
inserted
replaced
337:c4d4213f095c | 338:b3b3fa0e3689 |
---|---|
23 | 23 |
24 #include "SampleApplicationBase.h" | 24 #include "SampleApplicationBase.h" |
25 | 25 |
26 #include "../../Framework/Layers/OrthancFrameLayerSource.h" | 26 #include "../../Framework/Layers/OrthancFrameLayerSource.h" |
27 | 27 |
28 #include <Core/DicomFormat/DicomArray.h> | |
29 #include <Core/Images/PamReader.h> | |
28 #include <Core/Logging.h> | 30 #include <Core/Logging.h> |
31 #include <Core/Toolbox.h> | |
32 #include <Plugins/Samples/Common/FullOrthancDataset.h> | |
29 | 33 |
30 namespace OrthancStone | 34 namespace OrthancStone |
31 { | 35 { |
32 | 36 class BitmapStack : |
33 class GrayscaleBitmapStack : | |
34 public WorldSceneWidget, | |
35 public IObserver, | 37 public IObserver, |
36 public IObservable | 38 public IObservable |
37 { | 39 { |
38 public: | 40 public: |
39 typedef OriginMessage<MessageType_Widget_GeometryChanged, GrayscaleBitmapStack> GeometryChangedMessage; | 41 typedef OriginMessage<MessageType_Widget_GeometryChanged, BitmapStack> GeometryChangedMessage; |
40 typedef OriginMessage<MessageType_Widget_ContentChanged, GrayscaleBitmapStack> ContentChangedMessage; | 42 typedef OriginMessage<MessageType_Widget_ContentChanged, BitmapStack> ContentChangedMessage; |
41 | 43 |
42 private: | 44 private: |
45 class Bitmap : public boost::noncopyable | |
46 { | |
47 private: | |
48 std::string uuid_; // TODO is this necessary? | |
49 std::auto_ptr<Orthanc::ImageAccessor> source_; | |
50 std::auto_ptr<Orthanc::ImageAccessor> converted_; // Float32 or RGB24 | |
51 std::auto_ptr<Orthanc::Image> alpha_; // Grayscale8 (if any) | |
52 std::auto_ptr<DicomFrameConverter> converter_; | |
53 | |
54 void ApplyConverter() | |
55 { | |
56 if (source_.get() != NULL && | |
57 converter_.get() != NULL) | |
58 { | |
59 printf("CONVERTED!\n"); | |
60 converted_.reset(converter_->ConvertFrame(*source_)); | |
61 } | |
62 } | |
63 | |
64 public: | |
65 Bitmap(const std::string& uuid) : | |
66 uuid_(uuid) | |
67 { | |
68 } | |
69 | |
70 void SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset) | |
71 { | |
72 converter_.reset(new DicomFrameConverter); | |
73 converter_->ReadParameters(dataset); | |
74 ApplyConverter(); | |
75 } | |
76 | |
77 void SetSourceImage(Orthanc::ImageAccessor* image) // Takes ownership | |
78 { | |
79 source_.reset(image); | |
80 ApplyConverter(); | |
81 } | |
82 | |
83 bool GetDefaultWindowing(float& center, | |
84 float& width) const | |
85 { | |
86 if (converter_.get() != NULL && | |
87 converter_->HasDefaultWindow()) | |
88 { | |
89 center = static_cast<float>(converter_->GetDefaultWindowCenter()); | |
90 width = static_cast<float>(converter_->GetDefaultWindowWidth()); | |
91 } | |
92 } | |
93 }; | |
94 | |
95 | |
96 typedef std::map<std::string, Bitmap*> Bitmaps; | |
97 | |
43 OrthancApiClient& orthanc_; | 98 OrthancApiClient& orthanc_; |
99 bool hasWindowing_; | |
100 float windowingCenter_; | |
101 float windowingWidth_; | |
102 Bitmaps bitmaps_; | |
103 | |
104 public: | |
105 BitmapStack(MessageBroker& broker, | |
106 OrthancApiClient& orthanc) : | |
107 IObserver(broker), | |
108 IObservable(broker), | |
109 orthanc_(orthanc), | |
110 hasWindowing_(false), | |
111 windowingCenter_(0), // Dummy initialization | |
112 windowingWidth_(0) // Dummy initialization | |
113 { | |
114 } | |
115 | |
116 | |
117 virtual ~BitmapStack() | |
118 { | |
119 for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); it++) | |
120 { | |
121 assert(it->second != NULL); | |
122 delete it->second; | |
123 } | |
124 } | |
125 | |
126 | |
127 std::string LoadFrame(const std::string& instance, | |
128 unsigned int frame, | |
129 bool httpCompression) | |
130 { | |
131 std::string uuid; | |
132 | |
133 for (;;) | |
134 { | |
135 uuid = Orthanc::Toolbox::GenerateUuid(); | |
136 if (bitmaps_.find(uuid) == bitmaps_.end()) | |
137 { | |
138 break; | |
139 } | |
140 } | |
141 | |
142 bitmaps_[uuid] = new Bitmap(uuid); | |
143 | |
144 | |
145 { | |
146 IWebService::Headers headers; | |
147 std::string uri = "/instances/" + instance + "/tags"; | |
148 orthanc_.GetBinaryAsync(uri, headers, | |
149 new Callable<BitmapStack, OrthancApiClient::BinaryResponseReadyMessage> | |
150 (*this, &BitmapStack::OnTagsReceived), NULL, | |
151 new Orthanc::SingleValueObject<std::string>(uuid)); | |
152 } | |
153 | |
154 { | |
155 IWebService::Headers headers; | |
156 headers["Accept"] = "image/x-portable-arbitrarymap"; | |
157 | |
158 if (httpCompression) | |
159 { | |
160 headers["Accept-Encoding"] = "gzip"; | |
161 } | |
162 | |
163 std::string uri = "/instances/" + instance + "/frames/" + boost::lexical_cast<std::string>(frame) + "/image-uint16"; | |
164 orthanc_.GetBinaryAsync(uri, headers, | |
165 new Callable<BitmapStack, OrthancApiClient::BinaryResponseReadyMessage> | |
166 (*this, &BitmapStack::OnFrameReceived), NULL, | |
167 new Orthanc::SingleValueObject<std::string>(uuid)); | |
168 } | |
169 | |
170 return uuid; | |
171 } | |
172 | |
173 | |
174 void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | |
175 { | |
176 const std::string& uuid = dynamic_cast<Orthanc::SingleValueObject<std::string>*>(message.Payload)->GetValue(); | |
177 | |
178 printf("JSON received: [%s] (%d bytes) for bitmap %s\n", | |
179 message.Uri.c_str(), message.AnswerSize, uuid.c_str()); | |
180 | |
181 Bitmaps::iterator bitmap = bitmaps_.find(uuid); | |
182 if (bitmap != bitmaps_.end()) | |
183 { | |
184 assert(bitmap->second != NULL); | |
185 | |
186 OrthancPlugins::FullOrthancDataset dicom(message.Answer, message.AnswerSize); | |
187 bitmap->second->SetDicomTags(dicom); | |
188 | |
189 float c, w; | |
190 if (!hasWindowing_ && | |
191 bitmap->second->GetDefaultWindowing(c, w)) | |
192 { | |
193 hasWindowing_ = true; | |
194 windowingCenter_ = c; | |
195 windowingWidth_ = w; | |
196 } | |
197 | |
198 EmitMessage(GeometryChangedMessage(*this)); | |
199 } | |
200 } | |
201 | |
202 | |
203 void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | |
204 { | |
205 const std::string& uuid = dynamic_cast<Orthanc::SingleValueObject<std::string>*>(message.Payload)->GetValue(); | |
206 | |
207 printf("Frame received: [%s] (%d bytes) for bitmap %s\n", message.Uri.c_str(), message.AnswerSize, uuid.c_str()); | |
208 | |
209 Bitmaps::iterator bitmap = bitmaps_.find(uuid); | |
210 if (bitmap != bitmaps_.end()) | |
211 { | |
212 assert(bitmap->second != NULL); | |
213 | |
214 std::string content; | |
215 if (message.AnswerSize > 0) | |
216 { | |
217 content.assign(reinterpret_cast<const char*>(message.Answer), message.AnswerSize); | |
218 } | |
219 | |
220 std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); | |
221 reader->ReadFromMemory(content); | |
222 bitmap->second->SetSourceImage(reader.release()); | |
223 | |
224 EmitMessage(ContentChangedMessage(*this)); | |
225 } | |
226 } | |
227 }; | |
228 | |
229 | |
230 class BitmapStackWidget : | |
231 public WorldSceneWidget, | |
232 public IObservable, | |
233 public IObserver | |
234 { | |
235 private: | |
236 BitmapStack& stack_; | |
44 | 237 |
45 protected: | 238 protected: |
46 virtual Extent2D GetSceneExtent() | 239 virtual Extent2D GetSceneExtent() |
47 { | 240 { |
48 return Extent2D(-1, -1, 1, 1); | 241 return Extent2D(-1, -1, 1, 1); |
53 { | 246 { |
54 return true; | 247 return true; |
55 } | 248 } |
56 | 249 |
57 public: | 250 public: |
58 GrayscaleBitmapStack(MessageBroker& broker, | 251 BitmapStackWidget(MessageBroker& broker, |
59 OrthancApiClient& orthanc, | 252 BitmapStack& stack, |
60 const std::string& name) : | 253 const std::string& name) : |
61 WorldSceneWidget(name), | 254 WorldSceneWidget(name), |
255 IObservable(broker), | |
62 IObserver(broker), | 256 IObserver(broker), |
63 IObservable(broker), | 257 stack_(stack) |
64 orthanc_(orthanc) | 258 { |
65 { | 259 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged)); |
66 } | 260 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged)); |
67 | 261 } |
68 void LoadDicom(const std::string& dicom) | 262 |
69 { | 263 void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message) |
70 orthanc_.GetBinaryAsync("/instances/" + dicom + "/file", "application/dicom", | 264 { |
71 new Callable<GrayscaleBitmapStack, OrthancApiClient::BinaryResponseReadyMessage>(*this, &GrayscaleBitmapStack::OnDicomReceived)); | 265 printf("Geometry has changed\n"); |
72 } | 266 FitContent(); |
73 | 267 } |
74 void OnDicomReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | 268 |
75 { | 269 void OnContentChanged(const BitmapStack::ContentChangedMessage& message) |
76 printf("DICOM received: [%s] (%d bytes)\n", message.Uri.c_str(), message.AnswerSize); | 270 { |
77 } | 271 printf("Content has changed\n"); |
78 | 272 NotifyContentChanged(); |
273 } | |
79 }; | 274 }; |
80 | 275 |
81 | 276 |
82 namespace Samples | 277 namespace Samples |
83 { | 278 { |
195 break; | 390 break; |
196 } | 391 } |
197 } | 392 } |
198 }; | 393 }; |
199 | 394 |
200 void OnGeometryChanged(const GrayscaleBitmapStack::GeometryChangedMessage& message) | |
201 { | |
202 mainWidget_->FitContent(); | |
203 } | |
204 | |
205 std::auto_ptr<Interactor> mainWidgetInteractor_; | 395 std::auto_ptr<Interactor> mainWidgetInteractor_; |
206 std::auto_ptr<OrthancApiClient> orthancApiClient_; | 396 std::auto_ptr<OrthancApiClient> orthancApiClient_; |
397 std::auto_ptr<BitmapStack> stack_; | |
207 Tools currentTool_; | 398 Tools currentTool_; |
208 const OrthancFrameLayerSource* source_; | 399 const OrthancFrameLayerSource* source_; |
209 unsigned int slice_; | 400 unsigned int slice_; |
210 | 401 |
211 public: | 402 public: |
249 std::string instance = parameters["instance"].as<std::string>(); | 440 std::string instance = parameters["instance"].as<std::string>(); |
250 int frame = parameters["frame"].as<unsigned int>(); | 441 int frame = parameters["frame"].as<unsigned int>(); |
251 | 442 |
252 orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService())); | 443 orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService())); |
253 | 444 |
254 | 445 stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); |
255 mainWidget_ = new GrayscaleBitmapStack(broker_, *orthancApiClient_, "main-widget"); | 446 stack_->LoadFrame(instance, frame, false); |
256 dynamic_cast<GrayscaleBitmapStack*>(mainWidget_)->LoadDicom(instance); | 447 stack_->LoadFrame(instance, frame, false); |
257 | 448 |
258 dynamic_cast<GrayscaleBitmapStack*>(mainWidget_)->RegisterObserverCallback( | 449 mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget"); |
259 new Callable<SingleFrameEditorApplication, | |
260 GrayscaleBitmapStack::GeometryChangedMessage> | |
261 (*this, &SingleFrameEditorApplication::OnGeometryChanged)); | |
262 | |
263 mainWidget_->SetTransmitMouseOver(true); | 450 mainWidget_->SetTransmitMouseOver(true); |
264 | 451 |
265 mainWidgetInteractor_.reset(new Interactor(*this)); | 452 mainWidgetInteractor_.reset(new Interactor(*this)); |
266 mainWidget_->SetInteractor(*mainWidgetInteractor_); | 453 mainWidget_->SetInteractor(*mainWidgetInteractor_); |
267 } | 454 } |