Mercurial > hg > orthanc-stone
comparison OrthancStone/Sources/Loaders/DicomResourcesLoader.cpp @ 1512:244ad1e4e76a
reorganization of folders
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 07 Jul 2020 16:21:02 +0200 |
parents | Framework/Loaders/DicomResourcesLoader.cpp@121d01aa328e |
children | d3cafeef07bb |
comparison
equal
deleted
inserted
replaced
1511:9dfeee74c1e6 | 1512:244ad1e4e76a |
---|---|
1 /** | |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "DicomResourcesLoader.h" | |
23 | |
24 #if !defined(ORTHANC_ENABLE_DCMTK) | |
25 # error The macro ORTHANC_ENABLE_DCMTK must be defined | |
26 #endif | |
27 | |
28 #if ORTHANC_ENABLE_DCMTK == 1 | |
29 # include "../Oracle/ParseDicomFromFileCommand.h" | |
30 # include <DicomParsing/ParsedDicomDir.h> | |
31 # include <DicomParsing/ParsedDicomFile.h> | |
32 #endif | |
33 | |
34 #include <boost/filesystem/path.hpp> | |
35 | |
36 namespace OrthancStone | |
37 { | |
38 static std::string GetUri(Orthanc::ResourceType level) | |
39 { | |
40 switch (level) | |
41 { | |
42 case Orthanc::ResourceType_Patient: | |
43 return "patients"; | |
44 | |
45 case Orthanc::ResourceType_Study: | |
46 return "studies"; | |
47 | |
48 case Orthanc::ResourceType_Series: | |
49 return "series"; | |
50 | |
51 case Orthanc::ResourceType_Instance: | |
52 return "instances"; | |
53 | |
54 default: | |
55 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
56 } | |
57 } | |
58 | |
59 | |
60 class DicomResourcesLoader::Handler : public Orthanc::IDynamicObject | |
61 { | |
62 private: | |
63 boost::shared_ptr<DicomResourcesLoader> loader_; | |
64 boost::shared_ptr<LoadedDicomResources> target_; | |
65 int priority_; | |
66 DicomSource source_; | |
67 boost::shared_ptr<Orthanc::IDynamicObject> userPayload_; | |
68 | |
69 public: | |
70 Handler(boost::shared_ptr<DicomResourcesLoader> loader, | |
71 boost::shared_ptr<LoadedDicomResources> target, | |
72 int priority, | |
73 const DicomSource& source, | |
74 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
75 loader_(loader), | |
76 target_(target), | |
77 priority_(priority), | |
78 source_(source), | |
79 userPayload_(userPayload) | |
80 { | |
81 if (!loader || | |
82 !target) | |
83 { | |
84 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
85 } | |
86 } | |
87 | |
88 virtual ~Handler() | |
89 { | |
90 } | |
91 | |
92 void BroadcastSuccess() | |
93 { | |
94 SuccessMessage message(*loader_, target_, priority_, source_, userPayload_.get()); | |
95 loader_->BroadcastMessage(message); | |
96 } | |
97 | |
98 boost::shared_ptr<DicomResourcesLoader> GetLoader() | |
99 { | |
100 assert(loader_); | |
101 return loader_; | |
102 } | |
103 | |
104 boost::shared_ptr<LoadedDicomResources> GetTarget() | |
105 { | |
106 assert(target_); | |
107 return target_; | |
108 } | |
109 | |
110 int GetPriority() const | |
111 { | |
112 return priority_; | |
113 } | |
114 | |
115 const DicomSource& GetSource() const | |
116 { | |
117 return source_; | |
118 } | |
119 | |
120 const boost::shared_ptr<Orthanc::IDynamicObject> GetUserPayload() const | |
121 { | |
122 return userPayload_; | |
123 } | |
124 }; | |
125 | |
126 | |
127 class DicomResourcesLoader::StringHandler : public DicomResourcesLoader::Handler | |
128 { | |
129 public: | |
130 StringHandler(boost::shared_ptr<DicomResourcesLoader> loader, | |
131 boost::shared_ptr<LoadedDicomResources> target, | |
132 int priority, | |
133 const DicomSource& source, | |
134 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
135 Handler(loader, target, priority, source, userPayload) | |
136 { | |
137 } | |
138 | |
139 virtual void HandleJson(const Json::Value& body) = 0; | |
140 | |
141 virtual void HandleString(const std::string& body) | |
142 { | |
143 Json::Reader reader; | |
144 Json::Value value; | |
145 if (reader.parse(body, value)) | |
146 { | |
147 HandleJson(value); | |
148 } | |
149 else | |
150 { | |
151 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
152 } | |
153 } | |
154 }; | |
155 | |
156 | |
157 class DicomResourcesLoader::DicomWebHandler : public StringHandler | |
158 { | |
159 public: | |
160 DicomWebHandler(boost::shared_ptr<DicomResourcesLoader> loader, | |
161 boost::shared_ptr<LoadedDicomResources> target, | |
162 int priority, | |
163 const DicomSource& source, | |
164 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
165 StringHandler(loader, target, priority, source, userPayload) | |
166 { | |
167 } | |
168 | |
169 virtual void HandleJson(const Json::Value& body) | |
170 { | |
171 GetTarget()->AddFromDicomWeb(body); | |
172 BroadcastSuccess(); | |
173 } | |
174 }; | |
175 | |
176 | |
177 class DicomResourcesLoader::OrthancHandler : public StringHandler | |
178 { | |
179 private: | |
180 boost::shared_ptr<unsigned int> remainingCommands_; | |
181 | |
182 protected: | |
183 void CloseCommand() | |
184 { | |
185 assert(remainingCommands_); | |
186 | |
187 if (*remainingCommands_ == 0) | |
188 { | |
189 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
190 } | |
191 | |
192 (*remainingCommands_) --; | |
193 | |
194 if (*remainingCommands_ == 0) | |
195 { | |
196 BroadcastSuccess(); | |
197 } | |
198 } | |
199 | |
200 public: | |
201 OrthancHandler(boost::shared_ptr<DicomResourcesLoader> loader, | |
202 boost::shared_ptr<LoadedDicomResources> target, | |
203 int priority, | |
204 const DicomSource& source, | |
205 boost::shared_ptr<unsigned int> remainingCommands, | |
206 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
207 StringHandler(loader, target, priority, source, userPayload), | |
208 remainingCommands_(remainingCommands) | |
209 { | |
210 if (!remainingCommands) | |
211 { | |
212 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
213 } | |
214 | |
215 (*remainingCommands) ++; | |
216 } | |
217 | |
218 boost::shared_ptr<unsigned int> GetRemainingCommands() | |
219 { | |
220 assert(remainingCommands_); | |
221 return remainingCommands_; | |
222 } | |
223 }; | |
224 | |
225 | |
226 class DicomResourcesLoader::OrthancInstanceTagsHandler : public OrthancHandler | |
227 { | |
228 public: | |
229 OrthancInstanceTagsHandler(boost::shared_ptr<DicomResourcesLoader> loader, | |
230 boost::shared_ptr<LoadedDicomResources> target, | |
231 int priority, | |
232 const DicomSource& source, | |
233 boost::shared_ptr<unsigned int> remainingCommands, | |
234 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
235 OrthancHandler(loader, target, priority, source, remainingCommands, userPayload) | |
236 { | |
237 } | |
238 | |
239 virtual void HandleJson(const Json::Value& body) | |
240 { | |
241 GetTarget()->AddFromOrthanc(body); | |
242 CloseCommand(); | |
243 } | |
244 }; | |
245 | |
246 | |
247 class DicomResourcesLoader::OrthancOneChildInstanceHandler : public OrthancHandler | |
248 { | |
249 public: | |
250 OrthancOneChildInstanceHandler(boost::shared_ptr<DicomResourcesLoader> loader, | |
251 boost::shared_ptr<LoadedDicomResources> target, | |
252 int priority, | |
253 const DicomSource& source, | |
254 boost::shared_ptr<unsigned int> remainingCommands, | |
255 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
256 OrthancHandler(loader, target, priority, source, remainingCommands, userPayload) | |
257 { | |
258 } | |
259 | |
260 virtual void HandleJson(const Json::Value& body) | |
261 { | |
262 static const char* const ID = "ID"; | |
263 | |
264 if (body.type() == Json::arrayValue) | |
265 { | |
266 if (body.size() > 0) | |
267 { | |
268 if (body[0].type() == Json::objectValue && | |
269 body[0].isMember(ID) && | |
270 body[0][ID].type() == Json::stringValue) | |
271 { | |
272 GetLoader()->ScheduleLoadOrthancInstanceTags | |
273 (GetTarget(), GetPriority(), GetSource(), body[0][ID].asString(), GetRemainingCommands(), GetUserPayload()); | |
274 CloseCommand(); | |
275 } | |
276 else | |
277 { | |
278 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
279 } | |
280 } | |
281 } | |
282 else | |
283 { | |
284 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
285 } | |
286 } | |
287 }; | |
288 | |
289 | |
290 class DicomResourcesLoader::OrthancAllChildrenInstancesHandler : public OrthancHandler | |
291 { | |
292 private: | |
293 Orthanc::ResourceType bottomLevel_; | |
294 | |
295 public: | |
296 OrthancAllChildrenInstancesHandler(boost::shared_ptr<DicomResourcesLoader> loader, | |
297 boost::shared_ptr<LoadedDicomResources> target, | |
298 int priority, | |
299 const DicomSource& source, | |
300 boost::shared_ptr<unsigned int> remainingCommands, | |
301 Orthanc::ResourceType bottomLevel, | |
302 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
303 OrthancHandler(loader, target, priority, source, remainingCommands, userPayload), | |
304 bottomLevel_(bottomLevel) | |
305 { | |
306 } | |
307 | |
308 virtual void HandleJson(const Json::Value& body) | |
309 { | |
310 static const char* const ID = "ID"; | |
311 static const char* const INSTANCES = "Instances"; | |
312 | |
313 if (body.type() == Json::arrayValue) | |
314 { | |
315 for (Json::Value::ArrayIndex i = 0; i < body.size(); i++) | |
316 { | |
317 switch (bottomLevel_) | |
318 { | |
319 case Orthanc::ResourceType_Patient: | |
320 case Orthanc::ResourceType_Study: | |
321 if (body[i].type() == Json::objectValue && | |
322 body[i].isMember(ID) && | |
323 body[i][ID].type() == Json::stringValue) | |
324 { | |
325 GetLoader()->ScheduleLoadOrthancOneChildInstance | |
326 (GetTarget(), GetPriority(), GetSource(), bottomLevel_, | |
327 body[i][ID].asString(), GetRemainingCommands(), GetUserPayload()); | |
328 } | |
329 else | |
330 { | |
331 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
332 } | |
333 | |
334 break; | |
335 | |
336 case Orthanc::ResourceType_Series: | |
337 // At the series level, avoid a call to | |
338 // "/series/.../instances", as we already have this | |
339 // information in the JSON | |
340 if (body[i].type() == Json::objectValue && | |
341 body[i].isMember(INSTANCES) && | |
342 body[i][INSTANCES].type() == Json::arrayValue) | |
343 { | |
344 if (body[i][INSTANCES].size() > 0) | |
345 { | |
346 if (body[i][INSTANCES][0].type() == Json::stringValue) | |
347 { | |
348 GetLoader()->ScheduleLoadOrthancInstanceTags | |
349 (GetTarget(), GetPriority(), GetSource(), | |
350 body[i][INSTANCES][0].asString(), GetRemainingCommands(), GetUserPayload()); | |
351 } | |
352 else | |
353 { | |
354 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
355 } | |
356 } | |
357 } | |
358 | |
359 break; | |
360 | |
361 case Orthanc::ResourceType_Instance: | |
362 if (body[i].type() == Json::objectValue && | |
363 body[i].isMember(ID) && | |
364 body[i][ID].type() == Json::stringValue) | |
365 { | |
366 GetLoader()->ScheduleLoadOrthancInstanceTags | |
367 (GetTarget(), GetPriority(), GetSource(), | |
368 body[i][ID].asString(), GetRemainingCommands(), GetUserPayload()); | |
369 } | |
370 else | |
371 { | |
372 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
373 } | |
374 | |
375 break; | |
376 | |
377 default: | |
378 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
379 } | |
380 } | |
381 } | |
382 | |
383 CloseCommand(); | |
384 } | |
385 }; | |
386 | |
387 | |
388 #if ORTHANC_ENABLE_DCMTK == 1 | |
389 static void ExploreDicomDir(OrthancStone::LoadedDicomResources& instances, | |
390 const Orthanc::ParsedDicomDir& dicomDir, | |
391 Orthanc::ResourceType level, | |
392 size_t index, | |
393 const Orthanc::DicomMap& parent) | |
394 { | |
395 std::string expectedType; | |
396 | |
397 switch (level) | |
398 { | |
399 case Orthanc::ResourceType_Patient: | |
400 expectedType = "PATIENT"; | |
401 break; | |
402 | |
403 case Orthanc::ResourceType_Study: | |
404 expectedType = "STUDY"; | |
405 break; | |
406 | |
407 case Orthanc::ResourceType_Series: | |
408 expectedType = "SERIES"; | |
409 break; | |
410 | |
411 case Orthanc::ResourceType_Instance: | |
412 expectedType = "IMAGE"; | |
413 break; | |
414 | |
415 default: | |
416 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
417 } | |
418 | |
419 for (;;) | |
420 { | |
421 std::unique_ptr<Orthanc::DicomMap> current(dicomDir.GetItem(index).Clone()); | |
422 current->RemoveBinaryTags(); | |
423 current->Merge(parent); | |
424 | |
425 std::string type; | |
426 if (!current->LookupStringValue(type, Orthanc::DICOM_TAG_DIRECTORY_RECORD_TYPE, false)) | |
427 { | |
428 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
429 } | |
430 | |
431 if (type == expectedType) | |
432 { | |
433 if (level == Orthanc::ResourceType_Instance) | |
434 { | |
435 instances.AddResource(*current); | |
436 } | |
437 else | |
438 { | |
439 size_t lower; | |
440 if (dicomDir.LookupLower(lower, index)) | |
441 { | |
442 ExploreDicomDir(instances, dicomDir, Orthanc::GetChildResourceType(level), lower, *current); | |
443 } | |
444 } | |
445 } | |
446 | |
447 size_t next; | |
448 if (dicomDir.LookupNext(next, index)) | |
449 { | |
450 index = next; | |
451 } | |
452 else | |
453 { | |
454 return; | |
455 } | |
456 } | |
457 } | |
458 #endif | |
459 | |
460 | |
461 #if ORTHANC_ENABLE_DCMTK == 1 | |
462 void DicomResourcesLoader::GetDicomDirInstances(LoadedDicomResources& target, | |
463 const Orthanc::ParsedDicomDir& dicomDir) | |
464 { | |
465 Orthanc::DicomMap parent; | |
466 ExploreDicomDir(target, dicomDir, Orthanc::ResourceType_Patient, 0, parent); | |
467 } | |
468 #endif | |
469 | |
470 | |
471 #if ORTHANC_ENABLE_DCMTK == 1 | |
472 class DicomResourcesLoader::DicomDirHandler : public StringHandler | |
473 { | |
474 public: | |
475 DicomDirHandler(boost::shared_ptr<DicomResourcesLoader> loader, | |
476 boost::shared_ptr<LoadedDicomResources> target, | |
477 int priority, | |
478 const DicomSource& source, | |
479 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) : | |
480 StringHandler(loader, target, priority, source, userPayload) | |
481 { | |
482 } | |
483 | |
484 virtual void HandleJson(const Json::Value& body) | |
485 { | |
486 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
487 } | |
488 | |
489 virtual void HandleString(const std::string& body) | |
490 { | |
491 Orthanc::ParsedDicomDir dicomDir(body); | |
492 GetDicomDirInstances(*GetTarget(), dicomDir); | |
493 BroadcastSuccess(); | |
494 } | |
495 }; | |
496 #endif | |
497 | |
498 | |
499 void DicomResourcesLoader::Handle(const HttpCommand::SuccessMessage& message) | |
500 { | |
501 if (message.GetOrigin().HasPayload()) | |
502 { | |
503 dynamic_cast<StringHandler&>(message.GetOrigin().GetPayload()).HandleString(message.GetAnswer()); | |
504 } | |
505 } | |
506 | |
507 | |
508 void DicomResourcesLoader::Handle(const OrthancRestApiCommand::SuccessMessage& message) | |
509 { | |
510 if (message.GetOrigin().HasPayload()) | |
511 { | |
512 dynamic_cast<StringHandler&>(message.GetOrigin().GetPayload()).HandleString(message.GetAnswer()); | |
513 } | |
514 } | |
515 | |
516 | |
517 void DicomResourcesLoader::Handle(const ReadFileCommand::SuccessMessage& message) | |
518 { | |
519 if (message.GetOrigin().HasPayload()) | |
520 { | |
521 dynamic_cast<StringHandler&>(message.GetOrigin().GetPayload()).HandleString(message.GetContent()); | |
522 } | |
523 } | |
524 | |
525 | |
526 #if ORTHANC_ENABLE_DCMTK == 1 | |
527 void DicomResourcesLoader::Handle(const ParseDicomSuccessMessage& message) | |
528 { | |
529 if (message.GetOrigin().HasPayload()) | |
530 { | |
531 Handler& handler = dynamic_cast<Handler&>(message.GetOrigin().GetPayload()); | |
532 | |
533 std::set<Orthanc::DicomTag> ignoreTagLength; | |
534 ignoreTagLength.insert(Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR); // Needed for RT-DOSE | |
535 | |
536 Orthanc::DicomMap summary; | |
537 message.GetDicom().ExtractDicomSummary(summary, ignoreTagLength); | |
538 handler.GetTarget()->AddResource(summary); | |
539 | |
540 handler.BroadcastSuccess(); | |
541 } | |
542 } | |
543 #endif | |
544 | |
545 | |
546 void DicomResourcesLoader::Handle(const OracleCommandExceptionMessage& message) | |
547 { | |
548 // TODO | |
549 LOG(ERROR) << "Exception: " << message.GetException().What(); | |
550 } | |
551 | |
552 | |
553 void DicomResourcesLoader::ScheduleLoadOrthancInstanceTags(boost::shared_ptr<LoadedDicomResources> target, | |
554 int priority, | |
555 const DicomSource& source, | |
556 const std::string& instanceId, | |
557 boost::shared_ptr<unsigned int> remainingCommands, | |
558 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) | |
559 { | |
560 std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
561 command->SetUri("/instances/" + instanceId + "/tags"); | |
562 command->AcquirePayload(new OrthancInstanceTagsHandler(shared_from_this(), target, priority, | |
563 source, remainingCommands, userPayload)); | |
564 | |
565 { | |
566 std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); | |
567 lock->Schedule(GetSharedObserver(), priority, command.release()); | |
568 } | |
569 } | |
570 | |
571 | |
572 void DicomResourcesLoader::ScheduleLoadOrthancOneChildInstance(boost::shared_ptr<LoadedDicomResources> target, | |
573 int priority, | |
574 const DicomSource& source, | |
575 Orthanc::ResourceType level, | |
576 const std::string& id, | |
577 boost::shared_ptr<unsigned int> remainingCommands, | |
578 boost::shared_ptr<Orthanc::IDynamicObject> userPayload) | |
579 { | |
580 std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
581 command->SetUri("/" + GetUri(level) + "/" + id + "/instances"); | |
582 command->AcquirePayload(new OrthancOneChildInstanceHandler(shared_from_this(), target, priority, | |
583 source, remainingCommands, userPayload)); | |
584 | |
585 { | |
586 std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); | |
587 lock->Schedule(GetSharedObserver(), priority, command.release()); | |
588 } | |
589 } | |
590 | |
591 | |
592 | |
593 const Orthanc::IDynamicObject& DicomResourcesLoader::SuccessMessage::GetUserPayload() const | |
594 { | |
595 if (userPayload_ == NULL) | |
596 { | |
597 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
598 } | |
599 else | |
600 { | |
601 return *userPayload_; | |
602 } | |
603 } | |
604 | |
605 | |
606 boost::shared_ptr<DicomResourcesLoader> DicomResourcesLoader::Create(ILoadersContext::ILock& stone) | |
607 { | |
608 boost::shared_ptr<DicomResourcesLoader> result(new DicomResourcesLoader(stone.GetContext())); | |
609 result->Register<HttpCommand::SuccessMessage>(stone.GetOracleObservable(), &DicomResourcesLoader::Handle); | |
610 result->Register<OracleCommandExceptionMessage>(stone.GetOracleObservable(), &DicomResourcesLoader::Handle); | |
611 result->Register<OrthancRestApiCommand::SuccessMessage>(stone.GetOracleObservable(), &DicomResourcesLoader::Handle); | |
612 result->Register<ReadFileCommand::SuccessMessage>(stone.GetOracleObservable(), &DicomResourcesLoader::Handle); | |
613 | |
614 #if ORTHANC_ENABLE_DCMTK == 1 | |
615 result->Register<ParseDicomSuccessMessage>(stone.GetOracleObservable(), &DicomResourcesLoader::Handle); | |
616 #endif | |
617 | |
618 return result; | |
619 } | |
620 | |
621 | |
622 static void SetIncludeTags(std::map<std::string, std::string>& arguments, | |
623 const std::set<Orthanc::DicomTag>& includeTags) | |
624 { | |
625 if (!includeTags.empty()) | |
626 { | |
627 std::string s; | |
628 bool first = true; | |
629 | |
630 for (std::set<Orthanc::DicomTag>::const_iterator | |
631 it = includeTags.begin(); it != includeTags.end(); ++it) | |
632 { | |
633 if (first) | |
634 { | |
635 first = false; | |
636 } | |
637 else | |
638 { | |
639 s += ","; | |
640 } | |
641 | |
642 char buf[16]; | |
643 sprintf(buf, "%04X%04X", it->GetGroup(), it->GetElement()); | |
644 s += std::string(buf); | |
645 } | |
646 | |
647 arguments["includefield"] = s; | |
648 } | |
649 } | |
650 | |
651 | |
652 void DicomResourcesLoader::ScheduleGetDicomWeb(boost::shared_ptr<LoadedDicomResources> target, | |
653 int priority, | |
654 const DicomSource& source, | |
655 const std::string& uri, | |
656 const std::set<Orthanc::DicomTag>& includeTags, | |
657 Orthanc::IDynamicObject* userPayload) | |
658 { | |
659 boost::shared_ptr<Orthanc::IDynamicObject> protection(userPayload); | |
660 | |
661 if (!source.IsDicomWeb()) | |
662 { | |
663 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, "Not a DICOMweb source"); | |
664 } | |
665 | |
666 std::map<std::string, std::string> arguments, headers; | |
667 SetIncludeTags(arguments, includeTags); | |
668 | |
669 std::unique_ptr<IOracleCommand> command( | |
670 source.CreateDicomWebCommand(uri, arguments, headers, | |
671 new DicomWebHandler(shared_from_this(), target, priority, source, protection))); | |
672 | |
673 { | |
674 std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); | |
675 lock->Schedule(GetSharedObserver(), priority, command.release()); | |
676 } | |
677 } | |
678 | |
679 | |
680 void DicomResourcesLoader::ScheduleQido(boost::shared_ptr<LoadedDicomResources> target, | |
681 int priority, | |
682 const DicomSource& source, | |
683 Orthanc::ResourceType level, | |
684 const Orthanc::DicomMap& filter, | |
685 const std::set<Orthanc::DicomTag>& includeTags, | |
686 Orthanc::IDynamicObject* userPayload) | |
687 { | |
688 boost::shared_ptr<Orthanc::IDynamicObject> protection(userPayload); | |
689 | |
690 if (!source.IsDicomWeb()) | |
691 { | |
692 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, "Not a DICOMweb source"); | |
693 } | |
694 | |
695 std::string uri; | |
696 switch (level) | |
697 { | |
698 case Orthanc::ResourceType_Study: | |
699 uri = "/studies"; | |
700 break; | |
701 | |
702 case Orthanc::ResourceType_Series: | |
703 uri = "/series"; | |
704 break; | |
705 | |
706 case Orthanc::ResourceType_Instance: | |
707 uri = "/instances"; | |
708 break; | |
709 | |
710 default: | |
711 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
712 } | |
713 | |
714 std::set<Orthanc::DicomTag> tags; | |
715 filter.GetTags(tags); | |
716 | |
717 std::map<std::string, std::string> arguments, headers; | |
718 | |
719 for (std::set<Orthanc::DicomTag>::const_iterator it = tags.begin(); it != tags.end(); ++it) | |
720 { | |
721 std::string s; | |
722 if (filter.LookupStringValue(s, *it, false /* no binary */)) | |
723 { | |
724 char buf[16]; | |
725 sprintf(buf, "%04X%04X", it->GetGroup(), it->GetElement()); | |
726 arguments[buf] = s; | |
727 } | |
728 } | |
729 | |
730 SetIncludeTags(arguments, includeTags); | |
731 | |
732 std::unique_ptr<IOracleCommand> command( | |
733 source.CreateDicomWebCommand(uri, arguments, headers, | |
734 new DicomWebHandler(shared_from_this(), target, priority, source, protection))); | |
735 | |
736 | |
737 { | |
738 std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); | |
739 lock->Schedule(GetSharedObserver(), priority, command.release()); | |
740 } | |
741 } | |
742 | |
743 | |
744 void DicomResourcesLoader::ScheduleLoadOrthancResources(boost::shared_ptr<LoadedDicomResources> target, | |
745 int priority, | |
746 const DicomSource& source, | |
747 Orthanc::ResourceType topLevel, | |
748 const std::string& topId, | |
749 Orthanc::ResourceType bottomLevel, | |
750 Orthanc::IDynamicObject* userPayload) | |
751 { | |
752 boost::shared_ptr<Orthanc::IDynamicObject> protection(userPayload); | |
753 | |
754 if (!source.IsOrthanc()) | |
755 { | |
756 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, "Not an Orthanc source"); | |
757 } | |
758 | |
759 bool ok = false; | |
760 | |
761 switch (topLevel) | |
762 { | |
763 case Orthanc::ResourceType_Patient: | |
764 ok = (bottomLevel == Orthanc::ResourceType_Patient || | |
765 bottomLevel == Orthanc::ResourceType_Study || | |
766 bottomLevel == Orthanc::ResourceType_Series || | |
767 bottomLevel == Orthanc::ResourceType_Instance); | |
768 break; | |
769 | |
770 case Orthanc::ResourceType_Study: | |
771 ok = (bottomLevel == Orthanc::ResourceType_Study || | |
772 bottomLevel == Orthanc::ResourceType_Series || | |
773 bottomLevel == Orthanc::ResourceType_Instance); | |
774 break; | |
775 | |
776 case Orthanc::ResourceType_Series: | |
777 ok = (bottomLevel == Orthanc::ResourceType_Series || | |
778 bottomLevel == Orthanc::ResourceType_Instance); | |
779 break; | |
780 | |
781 case Orthanc::ResourceType_Instance: | |
782 ok = (bottomLevel == Orthanc::ResourceType_Instance); | |
783 break; | |
784 | |
785 default: | |
786 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
787 } | |
788 | |
789 if (!ok) | |
790 { | |
791 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
792 } | |
793 | |
794 boost::shared_ptr<unsigned int> remainingCommands(new unsigned int(0)); | |
795 | |
796 if (topLevel == Orthanc::ResourceType_Instance) | |
797 { | |
798 ScheduleLoadOrthancInstanceTags(target, priority, source, topId, remainingCommands, protection); | |
799 } | |
800 else if (topLevel == bottomLevel) | |
801 { | |
802 ScheduleLoadOrthancOneChildInstance(target, priority, source, topLevel, topId, remainingCommands, protection); | |
803 } | |
804 else | |
805 { | |
806 std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
807 command->SetUri("/" + GetUri(topLevel) + "/" + topId + "/" + GetUri(bottomLevel)); | |
808 command->AcquirePayload(new OrthancAllChildrenInstancesHandler | |
809 (shared_from_this(), target, priority, source, | |
810 remainingCommands, bottomLevel, protection)); | |
811 | |
812 { | |
813 std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); | |
814 | |
815 // GetSharedObserver() means "this" (for use as an IObserver), as a | |
816 // shared_ptr | |
817 // The oracle will thus call "this" | |
818 lock->Schedule(GetSharedObserver(), priority, command.release()); | |
819 } | |
820 } | |
821 } | |
822 | |
823 | |
824 void DicomResourcesLoader::ScheduleLoadDicomDir(boost::shared_ptr<LoadedDicomResources> target, | |
825 int priority, | |
826 const DicomSource& source, | |
827 const std::string& path, | |
828 Orthanc::IDynamicObject* userPayload) | |
829 { | |
830 boost::shared_ptr<Orthanc::IDynamicObject> protection(userPayload); | |
831 | |
832 if (!source.IsDicomDir()) | |
833 { | |
834 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, "Not a DICOMDIR source"); | |
835 } | |
836 | |
837 if (target->GetIndexedTag() == Orthanc::DICOM_TAG_SOP_INSTANCE_UID) | |
838 { | |
839 LOG(WARNING) << "If loading DICOMDIR, it is advised to index tag " | |
840 << "ReferencedSopInstanceUidInFile (0004,1511)"; | |
841 } | |
842 | |
843 #if ORTHANC_ENABLE_DCMTK == 1 | |
844 std::unique_ptr<ReadFileCommand> command(new ReadFileCommand(path)); | |
845 command->AcquirePayload(new DicomDirHandler(shared_from_this(), target, priority, source, protection)); | |
846 | |
847 { | |
848 std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); | |
849 lock->Schedule(GetSharedObserver(), priority, command.release()); | |
850 } | |
851 #else | |
852 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, | |
853 "DCMTK is disabled, cannot load DICOMDIR"); | |
854 #endif | |
855 } | |
856 | |
857 | |
858 void DicomResourcesLoader::ScheduleLoadDicomFile(boost::shared_ptr<LoadedDicomResources> target, | |
859 int priority, | |
860 const DicomSource& source, | |
861 const std::string& path, | |
862 bool includePixelData, | |
863 Orthanc::IDynamicObject* userPayload) | |
864 { | |
865 boost::shared_ptr<Orthanc::IDynamicObject> protection(userPayload); | |
866 | |
867 #if ORTHANC_ENABLE_DCMTK == 1 | |
868 std::unique_ptr<ParseDicomFromFileCommand> command(new ParseDicomFromFileCommand(source, path)); | |
869 command->SetPixelDataIncluded(includePixelData); | |
870 command->AcquirePayload(new Handler(shared_from_this(), target, priority, source, protection)); | |
871 | |
872 { | |
873 std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); | |
874 lock->Schedule(GetSharedObserver(), priority, command.release()); | |
875 } | |
876 #else | |
877 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, | |
878 "DCMTK is disabled, cannot load DICOM files"); | |
879 #endif | |
880 } | |
881 | |
882 | |
883 bool DicomResourcesLoader::ScheduleLoadDicomFile(boost::shared_ptr<LoadedDicomResources> target, | |
884 int priority, | |
885 const DicomSource& source, | |
886 const std::string& dicomDirPath, | |
887 const Orthanc::DicomMap& dicomDirEntry, | |
888 bool includePixelData, | |
889 Orthanc::IDynamicObject* userPayload) | |
890 { | |
891 std::unique_ptr<Orthanc::IDynamicObject> protection(userPayload); | |
892 | |
893 #if ORTHANC_ENABLE_DCMTK == 1 | |
894 std::string file; | |
895 if (dicomDirEntry.LookupStringValue(file, Orthanc::DICOM_TAG_REFERENCED_FILE_ID, false)) | |
896 { | |
897 ScheduleLoadDicomFile(target, priority, source, ParseDicomFromFileCommand::GetDicomDirPath(dicomDirPath, file), | |
898 includePixelData, protection.release()); | |
899 return true; | |
900 } | |
901 else | |
902 { | |
903 return false; | |
904 } | |
905 #else | |
906 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, | |
907 "DCMTK is disabled, cannot load DICOM files"); | |
908 #endif | |
909 } | |
910 } |