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 */