Mercurial > hg > orthanc-webviewer
comparison Plugin/Plugin.cpp @ 133:3251ec958a29
Option "RestrictTransferSyntaxes" saying which transfer syntaxes should be decoded with GDCM
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 09 Jun 2016 17:04:58 +0200 |
parents | 5754d39b011d |
children | 16f8471e3872 |
comparison
equal
deleted
inserted
replaced
132:2fffa4d0f313 | 133:3251ec958a29 |
---|---|
22 #include <boost/lexical_cast.hpp> | 22 #include <boost/lexical_cast.hpp> |
23 #include <EmbeddedResources.h> | 23 #include <EmbeddedResources.h> |
24 #include <boost/filesystem.hpp> | 24 #include <boost/filesystem.hpp> |
25 | 25 |
26 #include "../Orthanc/Core/OrthancException.h" | 26 #include "../Orthanc/Core/OrthancException.h" |
27 #include "../Orthanc/Core/DicomFormat/DicomMap.h" | |
27 #include "ViewerToolbox.h" | 28 #include "ViewerToolbox.h" |
28 #include "ViewerPrefetchPolicy.h" | 29 #include "ViewerPrefetchPolicy.h" |
29 #include "DecodedImageAdapter.h" | 30 #include "DecodedImageAdapter.h" |
30 #include "SeriesInformationAdapter.h" | 31 #include "SeriesInformationAdapter.h" |
31 #include "../Orthanc/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.h" | 32 #include "../Orthanc/Plugins/Samples/GdcmDecoder/GdcmDecoderCache.h" |
32 #include "../Orthanc/Core/Toolbox.h" | 33 #include "../Orthanc/Core/Toolbox.h" |
33 | 34 |
34 | 35 |
35 static OrthancPluginContext* context_ = NULL; | 36 static OrthancPluginContext* context_ = NULL; |
36 | 37 static bool restrictTransferSyntaxes_ = false; |
38 static std::set<std::string> enabledTransferSyntaxes_; | |
37 | 39 |
38 | 40 |
39 class CacheContext | 41 class CacheContext |
40 { | 42 { |
41 private: | 43 private: |
321 return OrthancPluginErrorCode_Plugin; | 323 return OrthancPluginErrorCode_Plugin; |
322 } | 324 } |
323 } | 325 } |
324 | 326 |
325 | 327 |
328 | |
329 static bool ExtractTransferSyntax(std::string& transferSyntax, | |
330 const void* dicom, | |
331 const uint32_t size) | |
332 { | |
333 Orthanc::DicomMap header; | |
334 if (!Orthanc::DicomMap::ParseDicomMetaInformation(header, reinterpret_cast<const char*>(dicom), size)) | |
335 { | |
336 return false; | |
337 } | |
338 | |
339 const Orthanc::DicomValue* tag = header.TestAndGetValue(0x0002, 0x0010); | |
340 if (tag == NULL || | |
341 tag->IsNull() || | |
342 tag->IsBinary()) | |
343 { | |
344 return false; | |
345 } | |
346 else | |
347 { | |
348 // Stripping spaces should not be required, as this is a UI value | |
349 // representation whose stripping is supported by the Orthanc | |
350 // core, but let's be careful... | |
351 transferSyntax = Orthanc::Toolbox::StripSpaces(tag->GetContent()); | |
352 return true; | |
353 } | |
354 } | |
355 | |
356 | |
357 static bool IsTransferSyntaxEnabled(const void* dicom, | |
358 const uint32_t size) | |
359 { | |
360 std::string formattedSize; | |
361 | |
362 { | |
363 char tmp[16]; | |
364 sprintf(tmp, "%0.1fMB", static_cast<float>(size) / (1024.0f * 1024.0f)); | |
365 formattedSize.assign(tmp); | |
366 } | |
367 | |
368 if (!restrictTransferSyntaxes_) | |
369 { | |
370 std::string s = "Decoding one DICOM instance of " + formattedSize + " using GDCM"; | |
371 OrthancPluginLogInfo(context_, s.c_str()); | |
372 return true; | |
373 } | |
374 | |
375 std::string transferSyntax; | |
376 if (!ExtractTransferSyntax(transferSyntax, dicom, size)) | |
377 { | |
378 std::string s = ("Cannot extract the transfer syntax of this instance of " + | |
379 formattedSize + ", will use GDCM to decode it"); | |
380 OrthancPluginLogInfo(context_, s.c_str()); | |
381 return true; | |
382 } | |
383 | |
384 if (enabledTransferSyntaxes_.find(transferSyntax) != enabledTransferSyntaxes_.end()) | |
385 { | |
386 // Decoding for this transfer syntax is enabled | |
387 std::string s = ("Using GDCM to decode this instance of " + | |
388 formattedSize + " with transfer syntax " + transferSyntax); | |
389 OrthancPluginLogInfo(context_, s.c_str()); | |
390 return true; | |
391 } | |
392 else | |
393 { | |
394 std::string s = ("Won't use GDCM to decode this instance of " + | |
395 formattedSize + ", as its transfer syntax " + transferSyntax + " is disabled"); | |
396 OrthancPluginLogInfo(context_, s.c_str()); | |
397 return false; | |
398 } | |
399 } | |
400 | |
401 | |
326 static OrthancPluginErrorCode DecodeImageCallback(OrthancPluginImage** target, | 402 static OrthancPluginErrorCode DecodeImageCallback(OrthancPluginImage** target, |
327 const void* dicom, | 403 const void* dicom, |
328 const uint32_t size, | 404 const uint32_t size, |
329 uint32_t frameIndex) | 405 uint32_t frameIndex) |
330 { | 406 { |
331 try | 407 try |
332 { | 408 { |
409 if (!IsTransferSyntaxEnabled(dicom, size)) | |
410 { | |
411 *target = NULL; | |
412 return OrthancPluginErrorCode_Success; | |
413 } | |
414 | |
333 std::auto_ptr<OrthancPlugins::OrthancImageWrapper> image; | 415 std::auto_ptr<OrthancPlugins::OrthancImageWrapper> image; |
334 | 416 |
335 #if 0 | 417 #if 0 |
336 // Do not use the cache | 418 // Do not use the cache |
337 OrthancPlugins::GdcmImageDecoder decoder(dicom, size); | 419 OrthancPlugins::GdcmImageDecoder decoder(dicom, size); |
362 return OrthancPluginErrorCode_Plugin; | 444 return OrthancPluginErrorCode_Plugin; |
363 } | 445 } |
364 } | 446 } |
365 | 447 |
366 | 448 |
449 void ParseConfiguration(bool& enableGdcm, | |
450 int& decodingThreads, | |
451 boost::filesystem::path& cachePath, | |
452 int& cacheSize) | |
453 { | |
454 /* Read the configuration of the Web viewer */ | |
455 Json::Value configuration; | |
456 if (!OrthancPlugins::ReadConfiguration(configuration, context_)) | |
457 { | |
458 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
459 } | |
460 | |
461 // By default, the cache of the Web viewer is located inside the | |
462 // "StorageDirectory" of Orthanc | |
463 cachePath = OrthancPlugins::GetStringValue(configuration, "StorageDirectory", "."); | |
464 cachePath /= "WebViewerCache"; | |
465 | |
466 static const char* CONFIG_WEB_VIEWER = "WebViewer"; | |
467 if (configuration.isMember(CONFIG_WEB_VIEWER)) | |
468 { | |
469 | |
470 std::string key = "CachePath"; | |
471 if (!configuration[CONFIG_WEB_VIEWER].isMember(key)) | |
472 { | |
473 // For backward compatibility with the initial release of the Web viewer | |
474 key = "Cache"; | |
475 } | |
476 | |
477 cachePath = OrthancPlugins::GetStringValue(configuration[CONFIG_WEB_VIEWER], key, cachePath.string()); | |
478 cacheSize = OrthancPlugins::GetIntegerValue(configuration[CONFIG_WEB_VIEWER], "CacheSize", cacheSize); | |
479 decodingThreads = OrthancPlugins::GetIntegerValue(configuration[CONFIG_WEB_VIEWER], "Threads", decodingThreads); | |
480 | |
481 static const char* CONFIG_ENABLE_GDCM = "EnableGdcm"; | |
482 if (configuration[CONFIG_WEB_VIEWER].isMember(CONFIG_ENABLE_GDCM)) | |
483 { | |
484 if (configuration[CONFIG_WEB_VIEWER][CONFIG_ENABLE_GDCM].type() != Json::booleanValue) | |
485 { | |
486 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
487 } | |
488 else | |
489 { | |
490 enableGdcm = configuration[CONFIG_WEB_VIEWER][CONFIG_ENABLE_GDCM].asBool(); | |
491 } | |
492 } | |
493 | |
494 static const char* CONFIG_RESTRICT_TRANSFER_SYNTAXES = "RestrictTransferSyntaxes"; | |
495 if (enableGdcm) | |
496 { | |
497 if (configuration[CONFIG_WEB_VIEWER].isMember(CONFIG_RESTRICT_TRANSFER_SYNTAXES)) | |
498 { | |
499 const Json::Value& config = configuration[CONFIG_WEB_VIEWER][CONFIG_RESTRICT_TRANSFER_SYNTAXES]; | |
500 | |
501 if (config.type() != Json::arrayValue) | |
502 { | |
503 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
504 } | |
505 | |
506 restrictTransferSyntaxes_ = true; | |
507 for (Json::Value::ArrayIndex i = 0; i < config.size(); i++) | |
508 { | |
509 if (config[i].type() != Json::stringValue) | |
510 { | |
511 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
512 } | |
513 else | |
514 { | |
515 std::string s = "Web viewer will use GDCM to decode transfer syntax " + config[i].asString(); | |
516 enabledTransferSyntaxes_.insert(config[i].asString()); | |
517 OrthancPluginLogWarning(context_, s.c_str()); | |
518 } | |
519 } | |
520 } | |
521 } | |
522 } | |
523 | |
524 if (decodingThreads <= 0 || | |
525 cacheSize <= 0) | |
526 { | |
527 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
528 } | |
529 | |
530 } | |
531 | |
532 | |
533 | |
367 extern "C" | 534 extern "C" |
368 { | 535 { |
369 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | 536 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) |
370 { | 537 { |
371 using namespace OrthancPlugins; | 538 using namespace OrthancPlugins; |
398 } | 565 } |
399 | 566 |
400 /* By default, use GDCM */ | 567 /* By default, use GDCM */ |
401 bool enableGdcm = true; | 568 bool enableGdcm = true; |
402 | 569 |
570 /* By default, a cache of 100 MB is used */ | |
571 int cacheSize = 100; | |
403 | 572 |
404 try | 573 try |
405 { | 574 { |
406 /* Read the configuration of the Web viewer */ | 575 boost::filesystem::path cachePath; |
407 Json::Value configuration; | 576 ParseConfiguration(enableGdcm, decodingThreads, cachePath, cacheSize); |
408 if (!ReadConfiguration(configuration, context)) | |
409 { | |
410 OrthancPluginLogError(context_, "Unable to read the configuration file of Orthanc"); | |
411 return -1; | |
412 } | |
413 | |
414 // By default, the cache of the Web viewer is located inside the | |
415 // "StorageDirectory" of Orthanc | |
416 boost::filesystem::path cachePath = GetStringValue(configuration, "StorageDirectory", "."); | |
417 cachePath /= "WebViewerCache"; | |
418 int cacheSize = 100; // By default, a cache of 100 MB is used | |
419 | |
420 if (configuration.isMember("WebViewer")) | |
421 { | |
422 std::string key = "CachePath"; | |
423 if (!configuration["WebViewer"].isMember(key)) | |
424 { | |
425 // For backward compatibility with the initial release of the Web viewer | |
426 key = "Cache"; | |
427 } | |
428 | |
429 cachePath = GetStringValue(configuration["WebViewer"], key, cachePath.string()); | |
430 cacheSize = GetIntegerValue(configuration["WebViewer"], "CacheSize", cacheSize); | |
431 decodingThreads = GetIntegerValue(configuration["WebViewer"], "Threads", decodingThreads); | |
432 | |
433 if (configuration["WebViewer"].isMember("EnableGdcm") && | |
434 configuration["WebViewer"]["EnableGdcm"].type() == Json::booleanValue) | |
435 { | |
436 enableGdcm = configuration["WebViewer"]["EnableGdcm"].asBool(); | |
437 } | |
438 } | |
439 | 577 |
440 std::string message = ("Web viewer using " + boost::lexical_cast<std::string>(decodingThreads) + | 578 std::string message = ("Web viewer using " + boost::lexical_cast<std::string>(decodingThreads) + |
441 " threads for the decoding of the DICOM images"); | 579 " threads for the decoding of the DICOM images"); |
442 OrthancPluginLogWarning(context_, message.c_str()); | 580 OrthancPluginLogWarning(context_, message.c_str()); |
443 | |
444 if (decodingThreads <= 0 || | |
445 cacheSize <= 0) | |
446 { | |
447 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
448 } | |
449 | 581 |
450 message = "Storing the cache of the Web viewer in folder: " + cachePath.string(); | 582 message = "Storing the cache of the Web viewer in folder: " + cachePath.string(); |
451 OrthancPluginLogWarning(context_, message.c_str()); | 583 OrthancPluginLogWarning(context_, message.c_str()); |
452 | 584 |
453 | 585 |
513 OrthancPluginLogError(context_, e.what()); | 645 OrthancPluginLogError(context_, e.what()); |
514 return -1; | 646 return -1; |
515 } | 647 } |
516 catch (Orthanc::OrthancException& e) | 648 catch (Orthanc::OrthancException& e) |
517 { | 649 { |
518 OrthancPluginLogError(context_, e.What()); | 650 if (e.GetErrorCode() == Orthanc::ErrorCode_BadFileFormat) |
651 { | |
652 OrthancPluginLogError(context_, "Unable to read the configuration of the Web viewer plugin"); | |
653 } | |
654 else | |
655 { | |
656 OrthancPluginLogError(context_, e.What()); | |
657 } | |
519 return -1; | 658 return -1; |
520 } | 659 } |
521 | 660 |
522 | 661 |
523 /* Configure the DICOM decoder */ | 662 /* Configure the DICOM decoder */ |