changeset 297:c1687b8fc800

refactoring
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 18 Jul 2023 07:13:36 +0200
parents 559499b80da8
children fa734a851551
files Applications/CMakeLists.txt Framework/Inputs/HierarchicalTiff.cpp Framework/Inputs/HierarchicalTiff.h Framework/TiffReader.cpp Framework/TiffReader.h NEWS
diffstat 6 files changed, 207 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/CMakeLists.txt	Tue Jul 18 06:45:44 2023 +0200
+++ b/Applications/CMakeLists.txt	Tue Jul 18 07:13:36 2023 +0200
@@ -133,6 +133,7 @@
   ${ORTHANC_WSI_DIR}/Framework/Outputs/TruncatedPyramidWriter.cpp
   ${ORTHANC_WSI_DIR}/Framework/Targets/FolderTarget.cpp
   ${ORTHANC_WSI_DIR}/Framework/Targets/OrthancTarget.cpp
+  ${ORTHANC_WSI_DIR}/Framework/TiffReader.cpp
   )
 
 EmbedResources(
--- a/Framework/Inputs/HierarchicalTiff.cpp	Tue Jul 18 06:45:44 2023 +0200
+++ b/Framework/Inputs/HierarchicalTiff.cpp	Tue Jul 18 07:13:36 2023 +0200
@@ -80,16 +80,6 @@
   };
 
 
-  void HierarchicalTiff::Finalize()
-  {
-    if (tiff_)
-    {
-      TIFFClose(tiff_);
-      tiff_ = NULL;
-    }
-  }
-
-
   void HierarchicalTiff::CheckLevel(unsigned int level) const
   {
     if (level >= levels_.size())
@@ -99,91 +89,10 @@
   }
 
 
-  bool HierarchicalTiff::GetCurrentDirectoryInformation(TIFF* tiff,
-                                                        ImageCompression& compression,
-                                                        Orthanc::PixelFormat& pixelFormat,
-                                                        Orthanc::PhotometricInterpretation& photometric)
-  {
-    uint16_t c;
-    if (!TIFFGetField(tiff, TIFFTAG_COMPRESSION, &c))
-    {
-      return false;
-    }
-
-    switch (c)
-    {
-      case COMPRESSION_NONE:
-        compression = ImageCompression_None;
-        break;
-
-      case COMPRESSION_JPEG:
-        compression = ImageCompression_Jpeg;
-        break;
-
-      default:
-        return false;
-    }
-
-    // http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
-
-    uint16_t channels, photometricTiff, bpp, planar;
-    if (!TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &channels) ||
-        channels == 0 ||
-        !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometricTiff) ||
-        !TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bpp) ||
-        !TIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar))
-    {
-      return false;
-    }
-
-    if (compression == ImageCompression_Jpeg &&
-        channels == 3 &&     // This is a color image
-        bpp == 8 &&
-        planar == PLANARCONFIG_CONTIG)  // This is interleaved RGB
-    {
-      pixelFormat = Orthanc::PixelFormat_RGB24;
-
-      switch (photometricTiff)
-      {
-        case PHOTOMETRIC_YCBCR:
-          photometric = Orthanc::PhotometricInterpretation_YBRFull422;
-          return true;
-          
-        case PHOTOMETRIC_RGB:
-          photometric = Orthanc::PhotometricInterpretation_RGB;
-          return true;
-
-        default:
-          LOG(ERROR) << "Unknown photometric interpretation in TIFF: " << photometricTiff;
-          return false;
-      }
-    }
-    else if (compression == ImageCompression_None &&
-             channels == 3 &&     // This is a color image
-             bpp == 8 &&
-             planar == PLANARCONFIG_CONTIG)  // This is interleaved RGB
-    {
-      pixelFormat = Orthanc::PixelFormat_RGB24;
-      photometric = Orthanc::PhotometricInterpretation_RGB;
-      return true;
-    }
-    else if (compression == ImageCompression_Jpeg &&
-             channels == 1 &&     // This is a grayscale image
-             bpp == 8)
-    {
-      pixelFormat = Orthanc::PixelFormat_Grayscale8;
-      photometric = Orthanc::PhotometricInterpretation_Monochrome2;
-    }
-    else
-    {
-      return false;
-    }
-
-    return true;
-  }
-
-
-  bool  HierarchicalTiff::Initialize()
+  HierarchicalTiff::HierarchicalTiff(const std::string& path) :
+    reader_(path),
+    tileWidth_(0),
+    tileHeight_(0)
   {
     bool first = true;
     tdir_t pos = 0;
@@ -195,16 +104,16 @@
       Orthanc::PixelFormat pixelFormat;
       Orthanc::PhotometricInterpretation photometric;
 
-      if (TIFFSetDirectory(tiff_, pos) &&
-          TIFFGetField(tiff_, TIFFTAG_IMAGEWIDTH, &w) &&
-          TIFFGetField(tiff_, TIFFTAG_IMAGELENGTH, &h) &&
-          TIFFGetField(tiff_, TIFFTAG_TILEWIDTH, &tw) &&
-          TIFFGetField(tiff_, TIFFTAG_TILELENGTH, &th) &&
+      if (TIFFSetDirectory(reader_.GetTiff(), pos) &&
+          TIFFGetField(reader_.GetTiff(), TIFFTAG_IMAGEWIDTH, &w) &&
+          TIFFGetField(reader_.GetTiff(), TIFFTAG_IMAGELENGTH, &h) &&
+          TIFFGetField(reader_.GetTiff(), TIFFTAG_TILEWIDTH, &tw) &&
+          TIFFGetField(reader_.GetTiff(), TIFFTAG_TILELENGTH, &th) &&
           w > 0 &&
           h > 0 &&
           tw > 0 &&
           th > 0 &&
-          GetCurrentDirectoryInformation(tiff_, compression, pixelFormat, photometric))
+          reader_.GetCurrentDirectoryInformation(compression, pixelFormat, photometric))
       {
         if (first)
         {
@@ -221,44 +130,23 @@
                  pixelFormat_ != pixelFormat ||
                  photometric_ != photometric)
         {
-          LOG(ERROR) << "The tile size or compression of the TIFF file varies along levels, this is not supported";
-          return false;
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                          "The tile size or compression of the TIFF file varies along levels, this is not supported");
         }
 
-        levels_.push_back(Level(tiff_, pos, w, h));
+        levels_.push_back(Level(reader_.GetTiff(), pos, w, h));
       }
 
       pos++;
     }
-    while (TIFFReadDirectory(tiff_));
+    while (TIFFReadDirectory(reader_.GetTiff()));
 
     if (levels_.size() == 0)
     {
-      LOG(ERROR) << "This is not a tiled TIFF image";
-      return false;
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "This is not a tiled TIFF image");
     }
 
     std::sort(levels_.begin(), levels_.end(), Comparator());
-    return true;
-  }
-
-
-  HierarchicalTiff::HierarchicalTiff(const std::string& path) :
-    tileWidth_(0),
-    tileHeight_(0)
-  {
-    tiff_ = TIFFOpen(path.c_str(), "r");
-    if (tiff_ == NULL)
-    {
-      LOG(ERROR) << "libtiff cannot open: " << path;
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile);
-    }
-
-    if (!Initialize())
-    {
-      Finalize();
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
   }
 
 
@@ -289,17 +177,17 @@
     compression = compression_;
 
     // Make the TIFF context point to the level of interest
-    if (!TIFFSetDirectory(tiff_, levels_[level].directory_))
+    if (!TIFFSetDirectory(reader_.GetTiff(), levels_[level].directory_))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile);
     }
 
     // Get the index of the tile
-    ttile_t index = TIFFComputeTile(tiff_, tileX * tileWidth_, tileY * tileHeight_, 0 /*z*/, 0 /*sample*/);
+    ttile_t index = TIFFComputeTile(reader_.GetTiff(), tileX * tileWidth_, tileY * tileHeight_, 0 /*z*/, 0 /*sample*/);
 
     // Read the raw tile
     toff_t *sizes;
-    if (!TIFFGetField(tiff_, TIFFTAG_TILEBYTECOUNTS, &sizes))
+    if (!TIFFGetField(reader_.GetTiff(), TIFFTAG_TILEBYTECOUNTS, &sizes))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile);
     }
@@ -307,7 +195,7 @@
     std::string raw;
     raw.resize(sizes[index]);
 
-    tsize_t read = TIFFReadRawTile(tiff_, index, &raw[0], raw.size());
+    tsize_t read = TIFFReadRawTile(reader_.GetTiff(), index, &raw[0], raw.size());
     if (read != static_cast<tsize_t>(sizes[index]))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile);
--- a/Framework/Inputs/HierarchicalTiff.h	Tue Jul 18 06:45:44 2023 +0200
+++ b/Framework/Inputs/HierarchicalTiff.h	Tue Jul 18 07:13:36 2023 +0200
@@ -23,9 +23,8 @@
 #pragma once
 
 #include "PyramidWithRawTiles.h"
+#include "../TiffReader.h"
 
-#include <tiff.h>
-#include <tiffio.h>
 #include <vector>
 #include <boost/thread.hpp>
 
@@ -50,7 +49,7 @@
     struct Comparator;
 
     boost::mutex          mutex_;
-    TIFF*                 tiff_;
+    TiffReader            reader_;
     Orthanc::PixelFormat  pixelFormat_;
     ImageCompression      compression_;
     unsigned int          tileWidth_;
@@ -58,20 +57,11 @@
     std::vector<Level>    levels_;
     Orthanc::PhotometricInterpretation  photometric_;
 
-    void Finalize();
-
     void CheckLevel(unsigned int level) const;
 
-    bool Initialize();
-
   public:
     explicit HierarchicalTiff(const std::string& path);
 
-    virtual ~HierarchicalTiff()
-    {
-      Finalize();
-    }
-
     virtual unsigned int GetLevelCount() const ORTHANC_OVERRIDE
     {
       return levels_.size();
@@ -111,10 +101,5 @@
     {
       return compression_;
     }
-
-    static bool GetCurrentDirectoryInformation(TIFF* tiff,
-                                               ImageCompression& compression,
-                                               Orthanc::PixelFormat& pixelFormat,
-                                               Orthanc::PhotometricInterpretation& photometric);
   };
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/TiffReader.cpp	Tue Jul 18 07:13:36 2023 +0200
@@ -0,0 +1,131 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * 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-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "TiffReader.h"
+
+#include <Logging.h>
+#include <OrthancException.h>
+
+namespace OrthancWSI
+{
+  TiffReader::TiffReader(const std::string& path)
+  {
+    tiff_ = TIFFOpen(path.c_str(), "r");
+    if (tiff_ == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile,
+                                      "libtiff cannot open: " + path);
+    }
+  }
+
+
+  TiffReader::~TiffReader()
+  {
+    if (tiff_)
+    {
+      TIFFClose(tiff_);
+      tiff_ = NULL;
+    }
+  }
+
+
+  bool TiffReader::GetCurrentDirectoryInformation(ImageCompression& compression,
+                                                  Orthanc::PixelFormat& pixelFormat,
+                                                  Orthanc::PhotometricInterpretation& photometric)
+  {
+    uint16_t c;
+    if (!TIFFGetField(tiff_, TIFFTAG_COMPRESSION, &c))
+    {
+      return false;
+    }
+
+    switch (c)
+    {
+      case COMPRESSION_NONE:
+        compression = ImageCompression_None;
+        break;
+
+      case COMPRESSION_JPEG:
+        compression = ImageCompression_Jpeg;
+        break;
+
+      default:
+        return false;
+    }
+
+    // http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
+
+    uint16_t channels, photometricTiff, bpp, planar;
+    if (!TIFFGetField(tiff_, TIFFTAG_SAMPLESPERPIXEL, &channels) ||
+        channels == 0 ||
+        !TIFFGetField(tiff_, TIFFTAG_PHOTOMETRIC, &photometricTiff) ||
+        !TIFFGetField(tiff_, TIFFTAG_BITSPERSAMPLE, &bpp) ||
+        !TIFFGetField(tiff_, TIFFTAG_PLANARCONFIG, &planar))
+    {
+      return false;
+    }
+
+    if (compression == ImageCompression_Jpeg &&
+        channels == 3 &&     // This is a color image
+        bpp == 8 &&
+        planar == PLANARCONFIG_CONTIG)  // This is interleaved RGB
+    {
+      pixelFormat = Orthanc::PixelFormat_RGB24;
+
+      switch (photometricTiff)
+      {
+        case PHOTOMETRIC_YCBCR:
+          photometric = Orthanc::PhotometricInterpretation_YBRFull422;
+          break;
+
+        case PHOTOMETRIC_RGB:
+          photometric = Orthanc::PhotometricInterpretation_RGB;
+          break;
+
+        default:
+          LOG(ERROR) << "Unknown photometric interpretation in TIFF: " << photometricTiff;
+          return false;
+      }
+    }
+    else if (compression == ImageCompression_None &&
+             channels == 3 &&     // This is a color image
+             bpp == 8 &&
+             planar == PLANARCONFIG_CONTIG)  // This is interleaved RGB
+    {
+      pixelFormat = Orthanc::PixelFormat_RGB24;
+      photometric = Orthanc::PhotometricInterpretation_RGB;
+    }
+    else if (compression == ImageCompression_Jpeg &&
+             channels == 1 &&     // This is a grayscale image
+             bpp == 8)
+    {
+      pixelFormat = Orthanc::PixelFormat_Grayscale8;
+      photometric = Orthanc::PhotometricInterpretation_Monochrome2;
+    }
+    else
+    {
+      return false;
+    }
+
+    return true;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/TiffReader.h	Tue Jul 18 07:13:36 2023 +0200
@@ -0,0 +1,52 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * 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-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "Enumerations.h"
+
+#include <tiff.h>
+#include <tiffio.h>
+#include <boost/noncopyable.hpp>
+
+namespace OrthancWSI
+{
+  class TiffReader : public boost::noncopyable
+  {
+  private:
+    TIFF*  tiff_;
+
+  public:
+    TiffReader(const std::string& path);
+
+    ~TiffReader();
+
+    TIFF* GetTiff()
+    {
+      return tiff_;
+    }
+
+    bool GetCurrentDirectoryInformation(ImageCompression& compression,
+                                        Orthanc::PixelFormat& pixelFormat,
+                                        Orthanc::PhotometricInterpretation& photometric);
+  };
+}
--- a/NEWS	Tue Jul 18 06:45:44 2023 +0200
+++ b/NEWS	Tue Jul 18 07:13:36 2023 +0200
@@ -1,6 +1,8 @@
 Pending changes in the mainline
 ===============================
 
+* OrthancWSIDicomizer supports plain TIFF, besides hierarchical TIFF
+
 
 Version 2.0 (2023-10-07)
 ========================