Mercurial > hg > orthanc
comparison OrthancServer/OrthancRestApi/OrthancRestResources.cpp @ 3600:4066998150ef
/instances/{id}/preview route now takes the windowing into account
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Thu, 09 Jan 2020 18:54:40 +0100 |
parents | 810772486249 |
children | a77e7839012a |
comparison
equal
deleted
inserted
replaced
3599:e01900f913e7 | 3600:4066998150ef |
---|---|
37 #include "../../Core/Compression/GzipCompressor.h" | 37 #include "../../Core/Compression/GzipCompressor.h" |
38 #include "../../Core/DicomParsing/DicomWebJsonVisitor.h" | 38 #include "../../Core/DicomParsing/DicomWebJsonVisitor.h" |
39 #include "../../Core/DicomParsing/FromDcmtkBridge.h" | 39 #include "../../Core/DicomParsing/FromDcmtkBridge.h" |
40 #include "../../Core/DicomParsing/Internals/DicomImageDecoder.h" | 40 #include "../../Core/DicomParsing/Internals/DicomImageDecoder.h" |
41 #include "../../Core/HttpServer/HttpContentNegociation.h" | 41 #include "../../Core/HttpServer/HttpContentNegociation.h" |
42 #include "../../Core/Images/ImageProcessing.h" | |
42 #include "../../Core/Logging.h" | 43 #include "../../Core/Logging.h" |
43 #include "../DefaultDicomImageDecoder.h" | 44 #include "../DefaultDicomImageDecoder.h" |
44 #include "../OrthancConfiguration.h" | 45 #include "../OrthancConfiguration.h" |
45 #include "../Search/DatabaseLookup.h" | 46 #include "../Search/DatabaseLookup.h" |
46 #include "../ServerContext.h" | 47 #include "../ServerContext.h" |
500 } | 501 } |
501 }; | 502 }; |
502 } | 503 } |
503 | 504 |
504 | 505 |
506 void LookupWindowingTags(const ParsedDicomFile& dicom, float& windowCenter, float& windowWidth, float& rescaleSlope, float& rescaleIntercept, bool& invert) | |
507 { | |
508 DicomMap dicomTags; | |
509 dicom.ExtractDicomSummary(dicomTags); | |
510 | |
511 | |
512 unsigned int bitsStored = boost::lexical_cast<unsigned int>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_BITS_STORED, "8", false)); | |
513 windowWidth = static_cast<float>(2 << (bitsStored - 1)); | |
514 windowCenter = windowWidth / 2; | |
515 rescaleSlope = 1.0f; | |
516 rescaleIntercept = 0.0f; | |
517 invert = false; | |
518 | |
519 if (dicomTags.HasTag(Orthanc::DICOM_TAG_WINDOW_CENTER) && dicomTags.HasTag(Orthanc::DICOM_TAG_WINDOW_WIDTH)) | |
520 { | |
521 windowCenter = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_WINDOW_CENTER, "", false)); | |
522 windowWidth = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_WINDOW_WIDTH, "", false)); | |
523 } | |
524 | |
525 if (dicomTags.HasTag(Orthanc::DICOM_TAG_RESCALE_SLOPE) && dicomTags.HasTag(Orthanc::DICOM_TAG_RESCALE_INTERCEPT)) | |
526 { | |
527 rescaleSlope = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_RESCALE_SLOPE, "", false)); | |
528 rescaleIntercept = boost::lexical_cast<float>(dicomTags.GetStringValue(Orthanc::DICOM_TAG_RESCALE_INTERCEPT, "", false)); | |
529 } | |
530 | |
531 PhotometricInterpretation photometric; | |
532 if (dicom.LookupPhotometricInterpretation(photometric)) | |
533 { | |
534 invert = (photometric == PhotometricInterpretation_Monochrome1); | |
535 } | |
536 } | |
537 | |
505 template <enum ImageExtractionMode mode> | 538 template <enum ImageExtractionMode mode> |
506 static void GetImage(RestApiGetCall& call) | 539 static void GetImage(RestApiGetCall& call) |
507 { | 540 { |
508 ServerContext& context = OrthancRestApi::GetContext(call); | 541 ServerContext& context = OrthancRestApi::GetContext(call); |
509 | 542 |
518 { | 551 { |
519 return; | 552 return; |
520 } | 553 } |
521 | 554 |
522 bool invert = false; | 555 bool invert = false; |
556 float windowCenter = 128.0f; | |
557 float windowWidth = 256.0f; | |
558 float rescaleSlope = 1.0f; | |
559 float rescaleIntercept = 0.0f; | |
560 | |
523 std::auto_ptr<ImageAccessor> decoded; | 561 std::auto_ptr<ImageAccessor> decoded; |
524 | 562 |
525 try | 563 try |
526 { | 564 { |
527 std::string publicId = call.GetUriComponent("id", ""); | 565 std::string publicId = call.GetUriComponent("id", ""); |
547 // TODO Optimize this lookup for photometric interpretation: | 585 // TODO Optimize this lookup for photometric interpretation: |
548 // It should be implemented by the plugin to avoid parsing | 586 // It should be implemented by the plugin to avoid parsing |
549 // twice the DICOM file | 587 // twice the DICOM file |
550 ParsedDicomFile parsed(dicomContent); | 588 ParsedDicomFile parsed(dicomContent); |
551 | 589 |
552 PhotometricInterpretation photometric; | 590 LookupWindowingTags(dicomContent, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); |
553 if (parsed.LookupPhotometricInterpretation(photometric)) | |
554 { | |
555 invert = (photometric == PhotometricInterpretation_Monochrome1); | |
556 } | |
557 } | 591 } |
558 } | 592 } |
559 #endif | 593 #endif |
560 | 594 |
561 if (decoded.get() == NULL) | 595 if (decoded.get() == NULL) |
562 { | 596 { |
563 // Use Orthanc's built-in decoder, using the cache to speed-up | 597 // Use Orthanc's built-in decoder, using the cache to speed-up |
564 // things on multi-frame images | 598 // things on multi-frame images |
565 ServerContext::DicomCacheLocker locker(context, publicId); | 599 ServerContext::DicomCacheLocker locker(context, publicId); |
566 decoded.reset(DicomImageDecoder::Decode(locker.GetDicom(), frame)); | 600 decoded.reset(DicomImageDecoder::Decode(locker.GetDicom(), frame)); |
567 | 601 LookupWindowingTags(locker.GetDicom(), windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); |
568 PhotometricInterpretation photometric; | 602 |
569 if (mode == ImageExtractionMode_Preview && | 603 if (mode != ImageExtractionMode_Preview) |
570 locker.GetDicom().LookupPhotometricInterpretation(photometric)) | |
571 { | 604 { |
572 invert = (photometric == PhotometricInterpretation_Monochrome1); | 605 invert = false; |
573 } | 606 } |
574 } | 607 } |
575 } | 608 } |
576 catch (OrthancException& e) | 609 catch (OrthancException& e) |
577 { | 610 { |
589 } | 622 } |
590 | 623 |
591 call.GetOutput().Redirect(root + "app/images/unsupported.png"); | 624 call.GetOutput().Redirect(root + "app/images/unsupported.png"); |
592 } | 625 } |
593 return; | 626 return; |
627 } | |
628 | |
629 if (mode == ImageExtractionMode_Preview | |
630 && (decoded->GetFormat() == Orthanc::PixelFormat_Grayscale8 || decoded->GetFormat() == Orthanc::PixelFormat_Grayscale16)) | |
631 { | |
632 ImageProcessing::ApplyWindowing(*decoded, *decoded, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); | |
633 invert = false; // don't invert it later on when encoding it, it has been inverted in the ApplyWindowing function | |
594 } | 634 } |
595 | 635 |
596 ImageToEncode image(decoded, mode, invert); | 636 ImageToEncode image(decoded, mode, invert); |
597 | 637 |
598 HttpContentNegociation negociation; | 638 HttpContentNegociation negociation; |