changeset 2229:8cbf31382b7b

added class BitmapLayout
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 25 Apr 2025 17:39:22 +0200
parents 0191a7693b50
children cbad54feb881
files OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake OrthancStone/Sources/Fonts/GlyphAlphabet.cpp OrthancStone/Sources/Toolbox/BitmapLayout.cpp OrthancStone/Sources/Toolbox/BitmapLayout.h OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp OrthancStone/Sources/Toolbox/DicomStructuredReport.h OrthancStone/UnitTestsSources/ImageToolboxTests.cpp
diffstat 7 files changed, 252 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake	Fri Apr 25 14:22:20 2025 +0200
+++ b/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake	Fri Apr 25 17:39:22 2025 +0200
@@ -320,6 +320,7 @@
   ${ORTHANC_STONE_ROOT}/StoneInitialization.cpp
 
   ${ORTHANC_STONE_ROOT}/Toolbox/AffineTransform2D.cpp
+  ${ORTHANC_STONE_ROOT}/Toolbox/BitmapLayout.cpp
   ${ORTHANC_STONE_ROOT}/Toolbox/BucketAccumulator1D.cpp
   ${ORTHANC_STONE_ROOT}/Toolbox/BucketAccumulator2D.cpp
   ${ORTHANC_STONE_ROOT}/Toolbox/CoordinateSystem3D.cpp
--- a/OrthancStone/Sources/Fonts/GlyphAlphabet.cpp	Fri Apr 25 14:22:20 2025 +0200
+++ b/OrthancStone/Sources/Fonts/GlyphAlphabet.cpp	Fri Apr 25 17:39:22 2025 +0200
@@ -267,8 +267,7 @@
     size_t pos = 0;
     while (pos < source.size())
     {
-      if (source[pos] == ' ' ||
-          (ignoreDeviceControl && IsDeviceControlCharacter(source[pos])))
+      if (source[pos] == ' ')
       {
         pos++;
       }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancStone/Sources/Toolbox/BitmapLayout.cpp	Fri Apr 25 17:39:22 2025 +0200
@@ -0,0 +1,149 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2023 Osimis S.A., Belgium
+ * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "BitmapLayout.h"
+
+#include <Images/Image.h>
+#include <Images/ImageProcessing.h>
+#include <OrthancException.h>
+
+#include <cassert>
+
+namespace OrthancStone
+{
+  class BitmapLayout::Block : public boost::noncopyable
+  {
+  private:
+    int  x_;
+    int  y_;
+    std::unique_ptr<Orthanc::ImageAccessor>  bitmap_;
+
+  public:
+    Block(int x,
+          int y,
+          Orthanc::ImageAccessor* bitmap) :
+      x_(x),
+      y_(y),
+      bitmap_(bitmap)
+    {
+      if (bitmap == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+    }
+
+    int GetX() const
+    {
+      return x_;
+    }
+
+    int GetY() const
+    {
+      return y_;
+    }
+
+    const Orthanc::ImageAccessor& GetBitmap() const
+    {
+      return *bitmap_;
+    }
+  };
+
+
+  BitmapLayout::BitmapLayout() :
+    left_(0),
+    top_(0),
+    right_(0),
+    bottom_(0)
+  {
+  }
+
+
+  BitmapLayout::~BitmapLayout()
+  {
+    for (Blocks::iterator it = blocks_.begin(); it != blocks_.end(); ++it)
+    {
+      assert(*it != NULL);
+      delete *it;
+    }
+  }
+
+
+  unsigned int BitmapLayout::GetWidth() const
+  {
+    assert(left_ <= right_);
+    return static_cast<unsigned int>(right_ - left_ + 1);
+  }
+
+
+  unsigned int BitmapLayout::GetHeight() const
+  {
+    assert(top_ <= bottom_);
+    return static_cast<unsigned int>(bottom_ - top_ + 1);
+  }
+
+
+  const Orthanc::ImageAccessor& BitmapLayout::AddBlock(int x,
+                                                       int y,
+                                                       Orthanc::ImageAccessor* bitmap)
+  {
+    if (bitmap == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    blocks_.push_back(new Block(x, y, bitmap));
+
+    left_ = std::min(left_, x);
+    top_ = std::min(top_, x);
+    right_ = std::max(right_, x + static_cast<int>(bitmap->GetWidth()) - 1);
+    bottom_ = std::max(bottom_, y + static_cast<int>(bitmap->GetHeight()) - 1);
+
+    return *bitmap;
+  }
+
+
+  Orthanc::ImageAccessor* BitmapLayout::Render(Orthanc::PixelFormat format) const
+  {
+    std::unique_ptr<Orthanc::ImageAccessor> layout(
+      new Orthanc::Image(format, GetWidth(), GetHeight(), true /* to be used as OpenGL texture */));
+
+    Orthanc::ImageProcessing::Set(*layout, 0);
+
+    for (Blocks::const_iterator it = blocks_.begin(); it != blocks_.end(); ++it)
+    {
+      assert(*it != NULL);
+
+      Orthanc::ImageAccessor region;
+      assert((*it)->GetX() >= GetLeft());
+      assert((*it)->GetY() >= GetTop());
+
+      layout->GetRegion(region, static_cast<unsigned int>((*it)->GetX() + GetLeft()),
+                        static_cast<unsigned int>((*it)->GetY() + GetTop()),
+                        (*it)->GetBitmap().GetWidth(), (*it)->GetBitmap().GetHeight());
+
+      Orthanc::ImageProcessing::Convert(region, (*it)->GetBitmap());
+    }
+
+    return layout.release();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancStone/Sources/Toolbox/BitmapLayout.h	Fri Apr 25 17:39:22 2025 +0200
@@ -0,0 +1,80 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2023 Osimis S.A., Belgium
+ * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <Images/ImageAccessor.h>
+
+#include <list>
+
+namespace OrthancStone
+{
+  class BitmapLayout : public boost::noncopyable
+  {
+  private:
+    class Block;
+
+    typedef std::list<Block*>  Blocks;
+
+    Blocks        blocks_;
+    int           left_;
+    int           top_;
+    int           right_;
+    int           bottom_;
+
+  public:
+    BitmapLayout();
+
+    ~BitmapLayout();
+
+    int GetLeft() const
+    {
+      return left_;
+    }
+
+    int GetTop() const
+    {
+      return top_;
+    }
+
+    int GetRight() const
+    {
+      return right_;
+    }
+
+    int GetBottom() const
+    {
+      return bottom_;
+    }
+
+    unsigned int GetWidth() const;
+
+    unsigned int GetHeight() const;
+
+    const Orthanc::ImageAccessor& AddBlock(int x,
+                                           int y,
+                                           Orthanc::ImageAccessor* bitmap /* takes ownership */);
+
+    Orthanc::ImageAccessor* Render(Orthanc::PixelFormat format) const;
+  };
+}
--- a/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp	Fri Apr 25 14:22:20 2025 +0200
+++ b/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp	Fri Apr 25 17:39:22 2025 +0200
@@ -654,6 +654,19 @@
 
     CheckStringValue(dataset, DCM_Modality, "SR");
 
+    title_ = mainDicomTags_.GetStringValue(Orthanc::DICOM_TAG_SERIES_DESCRIPTION, "?", false);
+
+    if (dataset.tagExists(DCM_ConceptNameCodeSequence))
+    {
+      DcmSequenceOfItems& concepts = GetSequenceValue(dataset, DCM_ConceptNameCodeSequence);
+      if (concepts.card() == 1 &&
+          concepts.getItem(0) != NULL &&
+          concepts.getItem(0)->tagExists(DCM_CodeMeaning))
+      {
+        title_ = GetStringValue(*concepts.getItem(0), DCM_CodeMeaning);
+      }
+    }
+
     ReadTextualReport(textualReport_, dataset);
 
     if (IsDicomConcept(dataset, "126000") /* Imaging measurement report */ &&
--- a/OrthancStone/Sources/Toolbox/DicomStructuredReport.h	Fri Apr 25 14:22:20 2025 +0200
+++ b/OrthancStone/Sources/Toolbox/DicomStructuredReport.h	Fri Apr 25 17:39:22 2025 +0200
@@ -210,6 +210,7 @@
     std::string                                 studyInstanceUid_;
     std::string                                 seriesInstanceUid_;
     std::string                                 sopInstanceUid_;
+    std::string                                 title_;
     Orthanc::DicomMap                           mainDicomTags_;
     Json::Value                                 textualReport_;
 
@@ -289,6 +290,11 @@
       return sopInstanceUid_;
     }
 
+    const std::string& GetTitle() const
+    {
+      return title_;
+    }
+
     const Orthanc::DicomMap& GetMainDicomTags() const
     {
       return mainDicomTags_;
--- a/OrthancStone/UnitTestsSources/ImageToolboxTests.cpp	Fri Apr 25 14:22:20 2025 +0200
+++ b/OrthancStone/UnitTestsSources/ImageToolboxTests.cpp	Fri Apr 25 17:39:22 2025 +0200
@@ -292,4 +292,6 @@
   OrthancStone::GlyphAlphabet::IndentUtf8(s, "X A\021B\022C\r\023D\024E Y", 11, false); ASSERT_EQ("X A\021B\022C\023D\024E\nY", s);
   OrthancStone::GlyphAlphabet::IndentUtf8(s, "X A\021B\022C\r\023D\024E Y", 12, false); ASSERT_EQ("X A\021B\022C\023D\024E\nY", s);
   OrthancStone::GlyphAlphabet::IndentUtf8(s, "X A\021B\022C\r\023D\024E Y", 13, false); ASSERT_EQ("X A\021B\022C\023D\024E Y", s);
+
+  OrthancStone::GlyphAlphabet::IndentUtf8(s, "\021Type:\022 Value", 20, false); ASSERT_EQ("\021Type:\022 Value", s);
 }