# HG changeset patch # User Sebastien Jodogne # Date 1541005829 -3600 # Node ID ef31240a73f6d799fa95e1a55ace3145c0a68e4a # Parent aad2f9293089ebe213a5bf4f50e7c0712b540167 no automatic call to moc and uic, CircleMeasureTracker using Orthanc fonts diff -r aad2f9293089 -r ef31240a73f6 Applications/Samples/CMakeLists.txt --- a/Applications/Samples/CMakeLists.txt Wed Oct 31 11:06:25 2018 +0100 +++ b/Applications/Samples/CMakeLists.txt Wed Oct 31 18:10:29 2018 +0100 @@ -95,10 +95,20 @@ list(APPEND SAMPLE_APPLICATIONS_SOURCES ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleQtApplicationRunner.h ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.cpp + ) + + ORTHANC_QT_WRAP_UI(SAMPLE_APPLICATIONS_SOURCES ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.ui - ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.cpp ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.ui ) + + ORTHANC_QT_WRAP_CPP(SAMPLE_APPLICATIONS_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h + ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.h + ) endif() if (ENABLE_NATIVE) @@ -144,7 +154,18 @@ ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/mainQt.cpp ) - elseif (ENABLE_WASM) + + ORTHANC_QT_WRAP_UI(SIMPLE_VIEWER_APPLICATION_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui + ) + + ORTHANC_QT_WRAP_CPP(SIMPLE_VIEWER_APPLICATION_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h + ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.h + ) + +elseif (ENABLE_WASM) list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/mainWasm.cpp ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp diff -r aad2f9293089 -r ef31240a73f6 Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp --- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp Wed Oct 31 11:06:25 2018 +0100 +++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp Wed Oct 31 18:10:29 2018 +0100 @@ -42,7 +42,8 @@ } else if (application_.GetCurrentTool() == SimpleViewerApplication::Tools_CircleMeasure) { - return new CircleMeasureTracker(statusBar, dynamic_cast(widget).GetSlice(), x, y, 255, 0, 0, 10); + return new CircleMeasureTracker(statusBar, dynamic_cast(widget).GetSlice(), + x, y, 255, 0, 0, application_.GetFont()); } else if (application_.GetCurrentTool() == SimpleViewerApplication::Tools_Crop) { diff -r aad2f9293089 -r ef31240a73f6 Applications/Samples/SimpleViewer/SimpleViewerApplication.h --- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.h Wed Oct 31 11:06:25 2018 +0100 +++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.h Wed Oct 31 18:10:29 2018 +0100 @@ -40,6 +40,7 @@ #include "Qt/SimpleViewerMainWindow.h" #endif +#include #include #include "ThumbnailInteractor.h" @@ -94,7 +95,7 @@ LayoutWidget* thumbnailsLayout_; LayerWidget* mainWidget_; std::vector thumbnails_; - std::map> instancesIdsPerSeriesId_; + std::map > instancesIdsPerSeriesId_; std::map seriesTags_; BaseCommandBuilder commandBuilder_; @@ -106,6 +107,8 @@ std::unique_ptr smartLoader_; std::unique_ptr orthancApiClient_; + Orthanc::Font font_; + public: SimpleViewerApplication(MessageBroker& broker) : IObserver(broker), @@ -116,6 +119,7 @@ wasmViewport1_(NULL), wasmViewport2_(NULL) { + font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); } virtual void Finalize() {} @@ -141,7 +145,16 @@ void SelectSeriesInMainViewport(const std::string& seriesId); void SelectTool(Tools tool); - Tools GetCurrentTool() const {return currentTool_;} + + Tools GetCurrentTool() const + { + return currentTool_; + } + + const Orthanc::Font& GetFont() const + { + return font_; + } void ExecuteAction(Actions action); diff -r aad2f9293089 -r ef31240a73f6 Applications/Samples/SimpleViewerApplicationSingleFile.h --- a/Applications/Samples/SimpleViewerApplicationSingleFile.h Wed Oct 31 11:06:25 2018 +0100 +++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h Wed Oct 31 18:10:29 2018 +0100 @@ -36,6 +36,7 @@ #include "../../Platforms/Wasm/Defaults.h" #endif +#include #include namespace OrthancStone @@ -127,7 +128,8 @@ } else if (application_.currentTool_ == Tools_CircleMeasure) { - return new CircleMeasureTracker(statusBar, dynamic_cast(widget).GetSlice(), x, y, 255, 0, 0, 10); + return new CircleMeasureTracker(statusBar, dynamic_cast(widget).GetSlice(), + x, y, 255, 0, 0, application_.GetFont()); } } return NULL; @@ -234,6 +236,8 @@ std::auto_ptr smartLoader_; std::auto_ptr orthancApiClient_; + Orthanc::Font font_; + public: SimpleViewerApplication(MessageBroker& broker) : IObserver(broker), @@ -243,6 +247,7 @@ wasmViewport1_(NULL), wasmViewport2_(NULL) { + font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); // DeclareIgnoredMessage(MessageType_Widget_ContentChanged); } @@ -390,6 +395,11 @@ smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0); } + const Orthanc::Font& GetFont() const + { + return font_; + } + virtual void OnPushButton1Clicked() {} virtual void OnPushButton2Clicked() {} virtual void OnTool1Clicked() { currentTool_ = Tools_LineMeasure;} diff -r aad2f9293089 -r ef31240a73f6 Applications/Samples/SingleFrameEditorApplication.h --- a/Applications/Samples/SingleFrameEditorApplication.h Wed Oct 31 11:06:25 2018 +0100 +++ b/Applications/Samples/SingleFrameEditorApplication.h Wed Oct 31 18:10:29 2018 +0100 @@ -2788,7 +2788,7 @@ // WARNING: The order of PixelSpacing is Y/X char buf[32]; - sprintf(buf, "%0.08f\\%0.08f", pixelSpacingY, pixelSpacingX); + sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX); json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf; diff -r aad2f9293089 -r ef31240a73f6 Framework/Layers/CircleMeasureTracker.cpp --- a/Framework/Layers/CircleMeasureTracker.cpp Wed Oct 31 11:06:25 2018 +0100 +++ b/Framework/Layers/CircleMeasureTracker.cpp Wed Oct 31 18:10:29 2018 +0100 @@ -24,8 +24,6 @@ #include "CircleMeasureTracker.h" -#include "../Viewport/CairoFont.h" - #include namespace OrthancStone @@ -37,14 +35,14 @@ uint8_t red, uint8_t green, uint8_t blue, - unsigned int fontSize) : + const Orthanc::Font& font) : statusBar_(statusBar), slice_(slice), x1_(x), y1_(y), x2_(x), y2_(y), - fontSize_(fontSize) + font_(font) { color_[0] = red; color_[1] = green; @@ -73,14 +71,8 @@ cairo_stroke(cr); cairo_restore(cr); - if (fontSize_ != 0) - { - cairo_move_to(cr, x, y); -#if ORTHANC_ENABLE_NATIVE==1 // text rendering currently fails in wasm - CairoFont font("sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - font.Draw(context, FormatRadius(), static_cast(fontSize_) / zoom); -#endif - } + //context.SetSourceColor(0, 255, 0); + context.DrawText(font_, FormatRadius(), x, y); } diff -r aad2f9293089 -r ef31240a73f6 Framework/Layers/CircleMeasureTracker.h --- a/Framework/Layers/CircleMeasureTracker.h Wed Oct 31 11:06:25 2018 +0100 +++ b/Framework/Layers/CircleMeasureTracker.h Wed Oct 31 18:10:29 2018 +0100 @@ -26,19 +26,21 @@ #include "../Viewport/IStatusBar.h" #include "../Toolbox/CoordinateSystem3D.h" +#include + namespace OrthancStone { class CircleMeasureTracker : public IWorldSceneMouseTracker { private: - IStatusBar* statusBar_; - CoordinateSystem3D slice_; - double x1_; - double y1_; - double x2_; - double y2_; - uint8_t color_[3]; - unsigned int fontSize_; + IStatusBar* statusBar_; + CoordinateSystem3D slice_; + double x1_; + double y1_; + double x2_; + double y2_; + uint8_t color_[3]; + const Orthanc::Font& font_; public: CircleMeasureTracker(IStatusBar* statusBar, @@ -48,7 +50,7 @@ uint8_t red, uint8_t green, uint8_t blue, - unsigned int fontSize); + const Orthanc::Font& font); virtual bool HasRender() const { diff -r aad2f9293089 -r ef31240a73f6 Framework/Viewport/CairoContext.cpp --- a/Framework/Viewport/CairoContext.cpp Wed Oct 31 11:06:25 2018 +0100 +++ b/Framework/Viewport/CairoContext.cpp Wed Oct 31 18:10:29 2018 +0100 @@ -59,4 +59,81 @@ static_cast(green) / 255.0f, static_cast(blue) / 255.0f); } + + + class CairoContext::AlphaSurface : public boost::noncopyable + { + private: + cairo_surface_t *surface_; + + public: + AlphaSurface(unsigned int width, + unsigned int height) + { + surface_ = cairo_image_surface_create(CAIRO_FORMAT_A8, width, height); + + if (!surface_) + { + // Should never occur + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + if (cairo_surface_status(surface_) != CAIRO_STATUS_SUCCESS) + { + LOG(ERROR) << "Cannot create a Cairo surface"; + cairo_surface_destroy(surface_); + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + ~AlphaSurface() + { + cairo_surface_destroy(surface_); + } + + void GetAccessor(Orthanc::ImageAccessor& target) + { + target.AssignWritable(Orthanc::PixelFormat_Grayscale8, + cairo_image_surface_get_width(surface_), + cairo_image_surface_get_height(surface_), + cairo_image_surface_get_stride(surface_), + cairo_image_surface_get_data(surface_)); + } + + void Fill(cairo_t* cr, + double x, + double y) + { + cairo_surface_mark_dirty(surface_); + cairo_mask_surface(cr, surface_, x, y); + cairo_fill(cr); + } + }; + + + void CairoContext::DrawText(const Orthanc::Font& font, + const std::string& text, + double x, + double y) + { + unsigned int width, height; + font.ComputeTextExtent(width, height, text); + + AlphaSurface surface(width, height); + + Orthanc::ImageAccessor accessor; + surface.GetAccessor(accessor); + font.Draw(accessor, text, 0, 0, 255); + + double pixelX = x; + double pixelY = y; + cairo_user_to_device(context_, &pixelX, &pixelY); + + cairo_save(context_); + cairo_identity_matrix(context_); + + surface.Fill(context_, pixelX, pixelY); + + cairo_restore(context_); + } } diff -r aad2f9293089 -r ef31240a73f6 Framework/Viewport/CairoContext.h --- a/Framework/Viewport/CairoContext.h Wed Oct 31 11:06:25 2018 +0100 +++ b/Framework/Viewport/CairoContext.h Wed Oct 31 18:10:29 2018 +0100 @@ -23,12 +23,16 @@ #include "CairoSurface.h" +#include + namespace OrthancStone { // This is a RAII wrapper around the Cairo drawing context class CairoContext : public boost::noncopyable { private: + class AlphaSurface; + cairo_t* context_; unsigned int width_; unsigned int height_; @@ -61,5 +65,10 @@ { SetSourceColor(color[0], color[1], color[2]); } + + void DrawText(const Orthanc::Font& font, + const std::string& text, + double x, + double y); }; } diff -r aad2f9293089 -r ef31240a73f6 Framework/Viewport/CairoFont.h --- a/Framework/Viewport/CairoFont.h Wed Oct 31 11:06:25 2018 +0100 +++ b/Framework/Viewport/CairoFont.h Wed Oct 31 18:10:29 2018 +0100 @@ -21,6 +21,14 @@ #pragma once +#if !defined(ORTHANC_SANDBOXED) +# error The macro ORTHANC_SANDBOXED must be defined +#endif + +#if ORTHANC_SANDBOXED == 1 +# error The class CairoFont cannot be used in sandboxed environments +#endif + #include "CairoContext.h" namespace OrthancStone diff -r aad2f9293089 -r ef31240a73f6 Framework/Widgets/CairoWidget.cpp --- a/Framework/Widgets/CairoWidget.cpp Wed Oct 31 11:06:25 2018 +0100 +++ b/Framework/Widgets/CairoWidget.cpp Wed Oct 31 18:10:29 2018 +0100 @@ -32,8 +32,8 @@ return true; } - CairoWidget::CairoWidget(const std::string& name) - : WidgetBase(name) + CairoWidget::CairoWidget(const std::string& name) : + WidgetBase(name) { } diff -r aad2f9293089 -r ef31240a73f6 Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Wed Oct 31 11:06:25 2018 +0100 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Wed Oct 31 18:10:29 2018 +0100 @@ -181,6 +181,7 @@ if (NOT ORTHANC_SANDBOXED) set(PLATFORM_SOURCES + ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoFont.cpp ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServiceCommandBase.cpp ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServiceGetCommand.cpp ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServicePostCommand.cpp @@ -271,7 +272,6 @@ ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ViewportGeometry.cpp ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoContext.cpp - ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoFont.cpp ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoSurface.cpp ${ORTHANC_STONE_ROOT}/Framework/Viewport/IStatusBar.h ${ORTHANC_STONE_ROOT}/Framework/Viewport/IViewport.h diff -r aad2f9293089 -r ef31240a73f6 Resources/CMake/QtConfiguration.cmake --- a/Resources/CMake/QtConfiguration.cmake Wed Oct 31 11:06:25 2018 +0100 +++ b/Resources/CMake/QtConfiguration.cmake Wed Oct 31 18:10:29 2018 +0100 @@ -17,10 +17,8 @@ # along with this program. If not, see . -# Instruct CMake to run moc automatically when needed. -set(CMAKE_AUTOMOC ON) -SET(CMAKE_AUTOUIC ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC OFF) +set(CMAKE_AUTOUIC OFF) # Find the QtWidgets library find_package(Qt5Widgets QUIET) @@ -32,12 +30,32 @@ Qt5::Widgets Qt5::Core ) + + # Create aliases for the CMake commands + macro(ORTHANC_QT_WRAP_UI) + QT5_WRAP_UI(${ARGN}) + endmacro() + + macro(ORTHANC_QT_WRAP_CPP) + QT5_WRAP_CPP(${ARGN}) + endmacro() + else() message("Qt5 has not been found, trying with Qt4") find_package(Qt4 REQUIRED QtGui) link_libraries( Qt4::QtGui ) + + # Create aliases for the CMake commands + macro(ORTHANC_QT_WRAP_UI) + QT4_WRAP_UI(${ARGN}) + endmacro() + + macro(ORTHANC_QT_WRAP_CPP) + QT4_WRAP_CPP(${ARGN}) + endmacro() + endif() list(APPEND QT_SOURCES @@ -46,5 +64,14 @@ ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.cpp ) -include_directories(${ORTHANC_STONE_ROOT}/Applications/Qt/) + +# NB: Including CMAKE_CURRENT_BINARY_DIR is mandatory, as the CMake +# macros for Qt will put their result in that directory, which cannot +# be changed. +# https://stackoverflow.com/a/4016784/881731 +include_directories( + ${ORTHANC_STONE_ROOT}/Applications/Qt/ + ${CMAKE_CURRENT_BINARY_DIR} + ) +