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 }