Mercurial > hg > orthanc-stone
comparison Applications/Samples/SingleFrameEditorApplication.h @ 359:100df90bf0ea am-2
preparing to implement Export
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 30 Oct 2018 08:11:06 +0100 |
parents | b8eeb49f3e65 |
children | 8262e4e9826d |
comparison
equal
deleted
inserted
replaced
358:b8eeb49f3e65 | 359:100df90bf0ea |
---|---|
21 | 21 |
22 #pragma once | 22 #pragma once |
23 | 23 |
24 #include "SampleApplicationBase.h" | 24 #include "SampleApplicationBase.h" |
25 | 25 |
26 #include "../../Framework/Toolbox/GeometryToolbox.h" | |
27 #include "../../Framework/Toolbox/ImageGeometry.h" | 26 #include "../../Framework/Toolbox/ImageGeometry.h" |
28 #include "../../Framework/Layers/OrthancFrameLayerSource.h" | 27 #include "../../Framework/Toolbox/OrthancApiClient.h" |
29 | 28 #include "../../Framework/Toolbox/DicomFrameConverter.h" |
30 #include <Core/DicomFormat/DicomArray.h> | 29 |
31 #include <Core/Images/FontRegistry.h> | 30 #include <Core/Images/FontRegistry.h> |
31 #include <Core/Images/Image.h> | |
32 #include <Core/Images/ImageProcessing.h> | 32 #include <Core/Images/ImageProcessing.h> |
33 #include <Core/Images/PamReader.h> | 33 #include <Core/Images/PamReader.h> |
34 #include <Core/Images/PngWriter.h> //TODO | |
35 #include <Core/Logging.h> | 34 #include <Core/Logging.h> |
35 #include <Plugins/Samples/Common/DicomDatasetReader.h> | |
36 #include <Plugins/Samples/Common/FullOrthancDataset.h> | 36 #include <Plugins/Samples/Common/FullOrthancDataset.h> |
37 #include <Plugins/Samples/Common/DicomDatasetReader.h> | |
38 | 37 |
39 | 38 |
40 #include <boost/math/constants/constants.hpp> | 39 #include <boost/math/constants/constants.hpp> |
41 | 40 |
42 namespace OrthancStone | 41 namespace OrthancStone |
2205 private: | 2204 private: |
2206 BitmapStack& stack_; | 2205 BitmapStack& stack_; |
2207 std::auto_ptr<Orthanc::Image> floatBuffer_; | 2206 std::auto_ptr<Orthanc::Image> floatBuffer_; |
2208 std::auto_ptr<CairoSurface> cairoBuffer_; | 2207 std::auto_ptr<CairoSurface> cairoBuffer_; |
2209 bool invert_; | 2208 bool invert_; |
2209 ImageInterpolation interpolation_; | |
2210 | 2210 |
2211 virtual bool RenderInternal(unsigned int width, | 2211 virtual bool RenderInternal(unsigned int width, |
2212 unsigned int height, | 2212 unsigned int height, |
2213 ImageInterpolation interpolation) | 2213 ImageInterpolation interpolation) |
2214 { | 2214 { |
2238 cairoBuffer_.reset(new CairoSurface(width, height)); | 2238 cairoBuffer_.reset(new CairoSurface(width, height)); |
2239 } | 2239 } |
2240 | 2240 |
2241 stack_.Render(*floatBuffer_, GetView(), interpolation); | 2241 stack_.Render(*floatBuffer_, GetView(), interpolation); |
2242 | 2242 |
2243 // TODO => rendering quality | 2243 // Very similar to GrayscaleFrameRenderer => TODO MERGE? |
2244 | |
2245 // As in GrayscaleFrameRenderer => TODO MERGE? | |
2246 | 2244 |
2247 Orthanc::ImageAccessor target; | 2245 Orthanc::ImageAccessor target; |
2248 cairoBuffer_->GetAccessor(target); | 2246 cairoBuffer_->GetAccessor(target); |
2249 | 2247 |
2250 for (unsigned int y = 0; y < height; y++) | 2248 for (unsigned int y = 0; y < height; y++) |
2267 { | 2265 { |
2268 // https://en.wikipedia.org/wiki/Linear_interpolation | 2266 // https://en.wikipedia.org/wiki/Linear_interpolation |
2269 v = static_cast<uint8_t>(255.0f * (*p - x0) / (x1 - x0)); // (*) | 2267 v = static_cast<uint8_t>(255.0f * (*p - x0) / (x1 - x0)); // (*) |
2270 } | 2268 } |
2271 | 2269 |
2272 // TODO MONOCHROME1 | |
2273 if (invert_) | 2270 if (invert_) |
2274 { | 2271 { |
2275 v = 255 - v; | 2272 v = 255 - v; |
2276 } | 2273 } |
2277 | 2274 |
2294 } | 2291 } |
2295 | 2292 |
2296 virtual bool RenderScene(CairoContext& context, | 2293 virtual bool RenderScene(CairoContext& context, |
2297 const ViewportGeometry& view) | 2294 const ViewportGeometry& view) |
2298 { | 2295 { |
2299 ImageInterpolation interpolation = ImageInterpolation_Nearest; // TODO PARAMETER? | |
2300 | |
2301 cairo_t* cr = context.GetObject(); | 2296 cairo_t* cr = context.GetObject(); |
2302 | 2297 |
2303 if (RenderInternal(context.GetWidth(), context.GetHeight(), interpolation)) | 2298 if (RenderInternal(context.GetWidth(), context.GetHeight(), interpolation_)) |
2304 { | 2299 { |
2305 // https://www.cairographics.org/FAQ/#paint_from_a_surface | 2300 // https://www.cairographics.org/FAQ/#paint_from_a_surface |
2306 cairo_save(cr); | 2301 cairo_save(cr); |
2307 cairo_identity_matrix(cr); | 2302 cairo_identity_matrix(cr); |
2308 cairo_set_source_surface(cr, cairoBuffer_->GetObject(), 0, 0); | 2303 cairo_set_source_surface(cr, cairoBuffer_->GetObject(), 0, 0); |
2327 const std::string& name) : | 2322 const std::string& name) : |
2328 WorldSceneWidget(name), | 2323 WorldSceneWidget(name), |
2329 IObservable(broker), | 2324 IObservable(broker), |
2330 IObserver(broker), | 2325 IObserver(broker), |
2331 stack_(stack), | 2326 stack_(stack), |
2332 invert_(false) | 2327 invert_(false), |
2328 interpolation_(ImageInterpolation_Nearest) | |
2333 { | 2329 { |
2334 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged)); | 2330 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::GeometryChangedMessage>(*this, &BitmapStackWidget::OnGeometryChanged)); |
2335 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged)); | 2331 stack.RegisterObserverCallback(new Callable<BitmapStackWidget, BitmapStack::ContentChangedMessage>(*this, &BitmapStackWidget::OnContentChanged)); |
2336 } | 2332 } |
2337 | 2333 |
2352 NotifyContentChanged(); | 2348 NotifyContentChanged(); |
2353 } | 2349 } |
2354 | 2350 |
2355 void SetInvert(bool invert) | 2351 void SetInvert(bool invert) |
2356 { | 2352 { |
2357 invert_ = invert; | 2353 if (invert_ != invert) |
2358 NotifyContentChanged(); | 2354 { |
2355 invert_ = invert; | |
2356 NotifyContentChanged(); | |
2357 } | |
2359 } | 2358 } |
2360 | 2359 |
2361 void SwitchInvert() | 2360 void SwitchInvert() |
2362 { | 2361 { |
2363 invert_ = !invert_; | 2362 invert_ = !invert_; |
2365 } | 2364 } |
2366 | 2365 |
2367 bool IsInvert() const | 2366 bool IsInvert() const |
2368 { | 2367 { |
2369 return invert_; | 2368 return invert_; |
2369 } | |
2370 | |
2371 void SetInterpolation(ImageInterpolation interpolation) | |
2372 { | |
2373 if (interpolation_ != interpolation) | |
2374 { | |
2375 interpolation_ = interpolation; | |
2376 NotifyContentChanged(); | |
2377 } | |
2378 } | |
2379 | |
2380 ImageInterpolation GetInterpolation() const | |
2381 { | |
2382 return interpolation_; | |
2370 } | 2383 } |
2371 }; | 2384 }; |
2372 | 2385 |
2373 | 2386 |
2374 class BitmapStackInteractor : public IWorldSceneInteractor | 2387 class BitmapStackInteractor : public IWorldSceneInteractor |
2382 Tool_Resize, | 2395 Tool_Resize, |
2383 Tool_Windowing | 2396 Tool_Windowing |
2384 }; | 2397 }; |
2385 | 2398 |
2386 | 2399 |
2387 UndoRedoStack undoRedoStack_; | 2400 UndoRedoStack undoRedoStack_; |
2388 Tool tool_; | 2401 Tool tool_; |
2402 OrthancApiClient *orthanc_; | |
2389 | 2403 |
2390 | 2404 |
2391 static double GetHandleSize() | 2405 static double GetHandleSize() |
2392 { | 2406 { |
2393 return 10.0; | 2407 return 10.0; |
2406 } | 2420 } |
2407 | 2421 |
2408 | 2422 |
2409 public: | 2423 public: |
2410 BitmapStackInteractor() : | 2424 BitmapStackInteractor() : |
2411 tool_(Tool_Move) | 2425 tool_(Tool_Move), |
2426 orthanc_(NULL) | |
2412 { | 2427 { |
2413 } | 2428 } |
2414 | 2429 |
2415 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, | 2430 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, |
2416 const ViewportGeometry& view, | 2431 const ViewportGeometry& view, |
2580 | 2595 |
2581 case 'c': | 2596 case 'c': |
2582 tool_ = Tool_Crop; | 2597 tool_ = Tool_Crop; |
2583 break; | 2598 break; |
2584 | 2599 |
2600 case 'e': | |
2601 Export(); | |
2602 break; | |
2603 | |
2585 case 'i': | 2604 case 'i': |
2586 dynamic_cast<BitmapStackWidget&>(widget).SwitchInvert(); | 2605 dynamic_cast<BitmapStackWidget&>(widget).SwitchInvert(); |
2587 break; | 2606 break; |
2588 | 2607 |
2589 case 'm': | 2608 case 'm': |
2590 tool_ = Tool_Move; | 2609 tool_ = Tool_Move; |
2591 break; | 2610 break; |
2592 | 2611 |
2612 case 'n': | |
2613 { | |
2614 BitmapStackWidget& w = dynamic_cast<BitmapStackWidget&>(widget); | |
2615 | |
2616 switch (w.GetInterpolation()) | |
2617 { | |
2618 case ImageInterpolation_Nearest: | |
2619 LOG(INFO) << "Switching to bilinear interpolation"; | |
2620 w.SetInterpolation(ImageInterpolation_Bilinear); | |
2621 break; | |
2622 | |
2623 case ImageInterpolation_Bilinear: | |
2624 LOG(INFO) << "Switching to nearest neighbor interpolation"; | |
2625 w.SetInterpolation(ImageInterpolation_Nearest); | |
2626 break; | |
2627 | |
2628 default: | |
2629 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
2630 } | |
2631 | |
2632 break; | |
2633 } | |
2634 | |
2593 case 'r': | 2635 case 'r': |
2594 tool_ = Tool_Rotate; | 2636 tool_ = Tool_Rotate; |
2595 break; | 2637 break; |
2596 | 2638 |
2597 case 's': | 2639 case 's': |
2619 break; | 2661 break; |
2620 | 2662 |
2621 default: | 2663 default: |
2622 break; | 2664 break; |
2623 } | 2665 } |
2666 } | |
2667 | |
2668 | |
2669 void SetOrthanc(OrthancApiClient& orthanc) | |
2670 { | |
2671 orthanc_ = &orthanc; | |
2672 } | |
2673 | |
2674 | |
2675 void Export() | |
2676 { | |
2677 if (orthanc_ == NULL) | |
2678 { | |
2679 return; | |
2680 } | |
2681 | |
2682 // TODO | |
2683 LOG(WARNING) << "Exporting DICOM"; | |
2624 } | 2684 } |
2625 }; | 2685 }; |
2626 | 2686 |
2627 | 2687 |
2628 | 2688 |
2664 | 2724 |
2665 context_ = context; | 2725 context_ = context; |
2666 | 2726 |
2667 statusBar.SetMessage("Use the key \"a\" to reinitialize the layout"); | 2727 statusBar.SetMessage("Use the key \"a\" to reinitialize the layout"); |
2668 statusBar.SetMessage("Use the key \"c\" to crop"); | 2728 statusBar.SetMessage("Use the key \"c\" to crop"); |
2729 statusBar.SetMessage("Use the key \"e\" to export DICOM to the Orthanc server"); | |
2669 statusBar.SetMessage("Use the key \"f\" to switch full screen"); | 2730 statusBar.SetMessage("Use the key \"f\" to switch full screen"); |
2670 statusBar.SetMessage("Use the key \"i\" to invert contrast"); | 2731 statusBar.SetMessage("Use the key \"i\" to invert contrast"); |
2671 statusBar.SetMessage("Use the key \"m\" to move objects"); | 2732 statusBar.SetMessage("Use the key \"m\" to move objects"); |
2733 statusBar.SetMessage("Use the key \"n\" to switch between nearest neighbor and bilinear interpolation"); | |
2672 statusBar.SetMessage("Use the key \"r\" to rotate objects"); | 2734 statusBar.SetMessage("Use the key \"r\" to rotate objects"); |
2673 statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM bitmaps)"); | 2735 statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM bitmaps)"); |
2674 statusBar.SetMessage("Use the key \"w\" to change windowing"); | 2736 statusBar.SetMessage("Use the key \"w\" to change windowing"); |
2675 | 2737 |
2676 statusBar.SetMessage("Use the key \"ctrl-z\" to undo action"); | 2738 statusBar.SetMessage("Use the key \"ctrl-z\" to undo action"); |
2684 | 2746 |
2685 std::string instance = parameters["instance"].as<std::string>(); | 2747 std::string instance = parameters["instance"].as<std::string>(); |
2686 int frame = parameters["frame"].as<unsigned int>(); | 2748 int frame = parameters["frame"].as<unsigned int>(); |
2687 | 2749 |
2688 orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService())); | 2750 orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService())); |
2751 interactor_.SetOrthanc(*orthancApiClient_); | |
2689 | 2752 |
2690 Orthanc::FontRegistry fonts; | 2753 Orthanc::FontRegistry fonts; |
2691 fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); | 2754 fonts.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); |
2692 | 2755 |
2693 stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); | 2756 stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); |
2694 stack_->LoadFrame(instance, frame, false).SetPan(200, 0); | 2757 stack_->LoadFrame(instance, frame, false).SetPan(200, 0); |
2695 //stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false); | 2758 //stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false); |
2696 | 2759 |
2697 { | 2760 { |
2698 BitmapStack::Bitmap& bitmap = stack_->LoadText(fonts.GetFont(0), "Hello\nworld\nBonjour, Alain"); | 2761 BitmapStack::Bitmap& bitmap = stack_->LoadText(fonts.GetFont(0), "Hello\nworld"); |
2699 //dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetForegroundValue(256); | 2762 //dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetForegroundValue(256); |
2700 dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetResizeable(true); | 2763 dynamic_cast<BitmapStack::AlphaBitmap&>(bitmap).SetResizeable(true); |
2701 } | 2764 } |
2702 | 2765 |
2703 { | 2766 { |
2712 mainWidget_->SetTransmitMouseOver(true); | 2775 mainWidget_->SetTransmitMouseOver(true); |
2713 mainWidget_->SetInteractor(interactor_); | 2776 mainWidget_->SetInteractor(interactor_); |
2714 | 2777 |
2715 //stack_->SetWindowing(128, 256); | 2778 //stack_->SetWindowing(128, 256); |
2716 } | 2779 } |
2717 | |
2718 | |
2719 void Invert() | |
2720 { | |
2721 // TODO | |
2722 } | |
2723 | |
2724 void Rotate(int degrees) | |
2725 { | |
2726 // TODO | |
2727 } | |
2728 | |
2729 void Export() | |
2730 { | |
2731 // TODO: export dicom file to a temporary file | |
2732 } | |
2733 }; | 2780 }; |
2734 | |
2735 | |
2736 } | 2781 } |
2737 } | 2782 } |