Mercurial > hg > orthanc-wsi
changeset 57:91fc9583b2de
big refactoring to support sparse tiling
line wrap: on
line diff
--- a/Applications/CMakeLists.txt Thu Nov 24 15:41:21 2016 +0100 +++ b/Applications/CMakeLists.txt Thu Nov 24 17:48:24 2016 +0100 @@ -9,6 +9,7 @@ # Generic parameters SET(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") +SET(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof") # Optional components SET(ENABLE_SSL OFF CACHE BOOL "Include support for SSL") @@ -314,3 +315,23 @@ else() message("Doxygen not found. The documentation will not be built.") endif() + + + + + + + + + + + + + + +add_executable(Hello + Hello.cpp + ApplicationToolbox.cpp + ) + +target_link_libraries(Hello OrthancWSIFramework ${DCMTK_LIBRARIES})
--- a/Applications/DicomToTiff.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Applications/DicomToTiff.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -21,6 +21,7 @@ #include "../Framework/DicomToolbox.h" #include "../Framework/ImageToolbox.h" #include "../Framework/Inputs/DicomPyramid.h" +#include "../Framework/Inputs/TiledPyramidStatistics.h" #include "../Framework/Messaging/CurlOrthancConnection.h" #include "../Framework/Orthanc/Core/Logging.h" #include "../Framework/Orthanc/Core/OrthancException.h" @@ -114,7 +115,8 @@ << std::endl << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." << std::endl << std::endl - << "Convert a DICOM for digital pathology stored in some Orthanc server as a standard hierarchical TIFF." + << "Convert a DICOM image for digital pathology stored in some Orthanc server as a" << std::endl + << "standard hierarchical TIFF (whose tiles are all encoded using JPEG)." << std::endl; std::cout << allWithoutHidden << "\n"; @@ -167,56 +169,8 @@ -static void RunTranscode(OrthancWSI::ITiledPyramid& source, - const boost::program_options::variables_map& options) -{ - OrthancWSI::HierarchicalTiffWriter target(options["output"].as<std::string>(), - source.GetPixelFormat(), - source.GetImageCompression(), - source.GetTileWidth(), - source.GetTileHeight()); - - std::auto_ptr<Orthanc::ImageAccessor> empty(CreateEmptyTile(target, options)); - - for (unsigned int level = 0; level < source.GetLevelCount(); level++) - { - LOG(WARNING) << "Creating level " << level << " of size " - << source.GetLevelWidth(level) << "x" << source.GetLevelHeight(level); - target.AddLevel(source.GetLevelWidth(level), source.GetLevelHeight(level)); - } - - for (unsigned int level = 0; level < source.GetLevelCount(); level++) - { - LOG(WARNING) << "Transcoding level " << level; - - unsigned int countX = OrthancWSI::CeilingDivision(source.GetLevelWidth(level), source.GetTileWidth()); - unsigned int countY = OrthancWSI::CeilingDivision(source.GetLevelHeight(level), source.GetTileHeight()); - - for (unsigned int tileY = 0; tileY < countY; tileY++) - { - for (unsigned int tileX = 0; tileX < countX; tileX++) - { - LOG(INFO) << "Dealing with tile (" << tileX << "," << tileY << ") at level " << level; - std::string tile; - - if (source.ReadRawTile(tile, level, tileX, tileY)) - { - target.WriteRawTile(tile, source.GetImageCompression(), level, tileX, tileY); - } - else - { - target.EncodeTile(*empty, level, tileX, tileY); - } - } - } - - target.Flush(); - } -} - - -static void RunReencode(OrthancWSI::ITiledPyramid& source, - const boost::program_options::variables_map& options) +static void Run(OrthancWSI::ITiledPyramid& source, + const boost::program_options::variables_map& options) { OrthancWSI::HierarchicalTiffWriter target(options["output"].as<std::string>(), source.GetPixelFormat(), @@ -224,6 +178,9 @@ source.GetTileWidth(), source.GetTileHeight()); + bool reencode = (options.count("reencode") && + options["reencode"].as<bool>()); + if (options.count("jpeg-quality")) { target.SetJpegQuality(options["jpeg-quality"].as<int>()); @@ -240,7 +197,7 @@ for (unsigned int level = 0; level < source.GetLevelCount(); level++) { - LOG(WARNING) << "Reencoding level " << level; + LOG(WARNING) << std::string(reencode ? "Reencoding" : "Transcoding") << " level " << level; unsigned int countX = OrthancWSI::CeilingDivision(source.GetLevelWidth(level), source.GetTileWidth()); unsigned int countY = OrthancWSI::CeilingDivision(source.GetLevelHeight(level), source.GetTileHeight()); @@ -251,14 +208,58 @@ { LOG(INFO) << "Dealing with tile (" << tileX << "," << tileY << ") at level " << level; - std::auto_ptr<Orthanc::ImageAccessor> tile(source.DecodeTile(level, tileX, tileY)); - if (tile.get() == NULL) + bool missing = false; + bool success = true; + + // Give a first try to get the raw tile + std::string tile; + OrthancWSI::ImageCompression compression; + if (source.ReadRawTile(tile, compression, level, tileX, tileY)) { - target.EncodeTile(*empty, level, tileX, tileY); + if (reencode || + compression == OrthancWSI::ImageCompression_Jpeg) + { + target.WriteRawTile(tile, compression, level, tileX, tileY); + } + else + { + success = false; // Re-encoding is mandatory + } } else { - target.EncodeTile(*tile, level, tileX, tileY); + // Give a second try to get the decoded tile + compression = OrthancWSI::ImageCompression_Unknown; + + std::auto_ptr<Orthanc::ImageAccessor> tile(source.DecodeTile(level, tileX, tileY)); + if (tile.get() == NULL) + { + // Unable to read the raw tile or to decode it: The tile is missing (sparse tiling) + missing = true; + } + else if (reencode) + { + target.EncodeTile(*empty, level, tileX, tileY); + } + else + { + success = false; // Re-encoding is mandatory + } + } + + if (!success) + { + LOG(WARNING) << "Cannot transcode a DICOM image that is not encoded using JPEG (it is " + << OrthancWSI::EnumerationToString(compression) + << "), please use the --reencode=1 option"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + if (missing) + { + LOG(WARNING) << "Sparse tiling: Using an empty image for missing tile (" + << tileX << "," << tileY << ") at level " << level; + target.EncodeTile(*empty, level, tileX, tileY); } } } @@ -300,15 +301,8 @@ OrthancWSI::CurlOrthancConnection orthanc(params); OrthancWSI::DicomPyramid source(orthanc, options["input"].as<std::string>()); - if (options.count("reencode") && - options["reencode"].as<bool>()) - { - RunReencode(source, options); - } - else - { - RunTranscode(source, options); - } + OrthancWSI::TiledPyramidStatistics stats(source); + Run(stats, options); } } catch (Orthanc::OrthancException& e)
--- a/Applications/Dicomizer.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Applications/Dicomizer.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -133,7 +133,6 @@ OrthancWSI::TiledPyramidStatistics stats(source); LOG(WARNING) << "Size of source tiles: " << stats.GetTileWidth() << "x" << stats.GetTileHeight(); - LOG(WARNING) << "Source image compression: " << OrthancWSI::EnumerationToString(stats.GetImageCompression()); LOG(WARNING) << "Pixel format: " << Orthanc::EnumerationToString(stats.GetPixelFormat()); LOG(WARNING) << "Smoothing is " << (parameters.IsSmoothEnabled() ? "enabled" : "disabled"); @@ -338,12 +337,13 @@ static void EnrichDataset(DcmDataset& dataset, const OrthancWSI::ITiledPyramid& source, + OrthancWSI::ImageCompression sourceCompression, const OrthancWSI::DicomizerParameters& parameters, const OrthancWSI::ImagedVolumeParameters& volume) { Orthanc::Encoding encoding = Orthanc::FromDcmtkBridge::DetectEncoding(dataset, Orthanc::Encoding_Latin1); - if (source.GetImageCompression() == OrthancWSI::ImageCompression_Jpeg || + if (sourceCompression == OrthancWSI::ImageCompression_Jpeg || parameters.GetTargetCompression() == OrthancWSI::ImageCompression_Jpeg) { // Takes as estimation a 1:10 compression ratio @@ -796,7 +796,8 @@ } -OrthancWSI::ITiledPyramid* OpenInputPyramid(const std::string& path, +OrthancWSI::ITiledPyramid* OpenInputPyramid(OrthancWSI::ImageCompression& sourceCompression, + const std::string& path, const OrthancWSI::DicomizerParameters& parameters) { LOG(WARNING) << "The input image is: " << path; @@ -807,20 +808,28 @@ switch (format) { case OrthancWSI::ImageCompression_Png: + { + sourceCompression = OrthancWSI::ImageCompression_Unknown; return new OrthancWSI::TiledPngImage(path, parameters.GetTargetTileWidth(512), parameters.GetTargetTileHeight(512)); + } case OrthancWSI::ImageCompression_Jpeg: + { + sourceCompression = OrthancWSI::ImageCompression_Unknown; return new OrthancWSI::TiledJpegImage(path, parameters.GetTargetTileWidth(512), parameters.GetTargetTileHeight(512)); + } case OrthancWSI::ImageCompression_Tiff: { try { - return new OrthancWSI::HierarchicalTiff(path); + std::auto_ptr<OrthancWSI::HierarchicalTiff> tiff(new OrthancWSI::HierarchicalTiff(path)); + sourceCompression = tiff->GetImageCompression(); + return tiff.release(); } catch (Orthanc::OrthancException&) { @@ -835,6 +844,7 @@ try { LOG(WARNING) << "Trying to open the input pyramid with OpenSlide"; + sourceCompression = OrthancWSI::ImageCompression_Unknown; return new OrthancWSI::OpenSlidePyramid(path, parameters.GetTargetTileWidth(512), parameters.GetTargetTileHeight(512)); @@ -860,15 +870,20 @@ if (ParseParameters(exitStatus, parameters, volume, argc, argv)) { - std::auto_ptr<OrthancWSI::ITiledPyramid> source(OpenInputPyramid(parameters.GetInputFile(), parameters)); + OrthancWSI::ImageCompression sourceCompression; + std::auto_ptr<OrthancWSI::ITiledPyramid> source; + + source.reset(OpenInputPyramid(sourceCompression, parameters.GetInputFile(), parameters)); if (source.get() == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } + + LOG(WARNING) << "Compression of the individual source tiles: " << OrthancWSI::EnumerationToString(sourceCompression); // Create the shared DICOM tags std::auto_ptr<DcmDataset> dataset(ParseDataset(parameters.GetDatasetPath())); - EnrichDataset(*dataset, *source, parameters, volume); + EnrichDataset(*dataset, *source, sourceCompression, parameters, volume); std::auto_ptr<OrthancWSI::IFileTarget> output(parameters.CreateTarget()); Recompress(*output, *source, *dataset, parameters, volume);
--- a/Framework/Algorithms/PyramidReader.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Algorithms/PyramidReader.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -32,11 +32,12 @@ class PyramidReader::SourceTile : public boost::noncopyable { private: - PyramidReader& that_; - unsigned int tileX_; - unsigned int tileY_; - bool hasRawTile_; - std::string rawTile_; + PyramidReader& that_; + unsigned int tileX_; + unsigned int tileY_; + bool hasRawTile_; + std::string rawTile_; + ImageCompression rawTileCompression_; std::auto_ptr<Orthanc::ImageAccessor> decoded_; @@ -96,7 +97,7 @@ { if (!that_.parameters_.IsForceReencode() && !IsRepaintNeeded() && - that_.source_.ReadRawTile(rawTile_, that_.level_, tileX, tileY)) + that_.source_.ReadRawTile(rawTile_, rawTileCompression_, that_.level_, tileX, tileY)) { hasRawTile_ = true; } @@ -113,9 +114,17 @@ } } - bool HasRawTile() const + bool HasRawTile(ImageCompression& compression) const { - return hasRawTile_; + if (hasRawTile_) + { + compression = rawTileCompression_; + return true; + } + else + { + return false; + } } const std::string& GetRawTile() const @@ -139,7 +148,7 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } - decoded_.reset(ImageToolbox::DecodeTile(rawTile_, that_.source_.GetImageCompression())); + decoded_.reset(ImageToolbox::DecodeTile(rawTile_, rawTileCompression_)); if (decoded_.get() == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); @@ -180,11 +189,12 @@ } - void PyramidReader::CheckTileSize(const std::string& tile) const + void PyramidReader::CheckTileSize(const std::string& tile, + ImageCompression compression) const { if (parameters_.IsSafetyCheck()) { - std::auto_ptr<Orthanc::ImageAccessor> decoded(ImageToolbox::DecodeTile(tile, source_.GetImageCompression())); + std::auto_ptr<Orthanc::ImageAccessor> decoded(ImageToolbox::DecodeTile(tile, compression)); CheckTileSize(*decoded); } } @@ -225,9 +235,9 @@ levelHeight_(source.GetLevelHeight(level)), sourceTileWidth_(source.GetTileWidth()), sourceTileHeight_(source.GetTileHeight()), - targetTileWidth_(targetTileWidth), - targetTileHeight_(targetTileHeight), - parameters_(parameters) + targetTileWidth_(targetTileWidth), + targetTileHeight_(targetTileHeight), + parameters_(parameters) { if (sourceTileWidth_ % targetTileWidth_ != 0 || sourceTileHeight_ % targetTileHeight_ != 0) @@ -248,7 +258,8 @@ } - const std::string* PyramidReader::GetRawTile(unsigned int tileX, + const std::string* PyramidReader::GetRawTile(ImageCompression& compression, + unsigned int tileX, unsigned int tileY) { if (sourceTileWidth_ != targetTileWidth_ || @@ -258,9 +269,10 @@ } SourceTile& source = AccessSourceTile(MapTargetToSourceLocation(tileX, tileY)); - if (source.HasRawTile()) + + if (source.HasRawTile(compression)) { - CheckTileSize(source.GetRawTile()); + CheckTileSize(source.GetRawTile(), compression); return &source.GetRawTile(); } else
--- a/Framework/Algorithms/PyramidReader.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Algorithms/PyramidReader.h Thu Nov 24 17:48:24 2016 +0100 @@ -56,7 +56,8 @@ void CheckTileSize(const Orthanc::ImageAccessor& tile) const; - void CheckTileSize(const std::string& tile) const; + void CheckTileSize(const std::string& tile, + ImageCompression compression) const; SourceTile& AccessSourceTile(const Location& location); @@ -77,17 +78,13 @@ return parameters_; } - ImageCompression GetImageCompression() const - { - return source_.GetImageCompression(); - } - Orthanc::PixelFormat GetPixelFormat() const { return source_.GetPixelFormat(); } - const std::string* GetRawTile(unsigned int tileX, + const std::string* GetRawTile(ImageCompression& compression, + unsigned int tileX, unsigned int tileY); Orthanc::ImageAccessor GetDecodedTile(unsigned int tileX,
--- a/Framework/Algorithms/ReconstructPyramidCommand.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Algorithms/ReconstructPyramidCommand.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -51,12 +51,13 @@ { result.reset(new Orthanc::ImageAccessor(source_.GetDecodedTile(x, y))); - const std::string* rawTile = source_.GetRawTile(x, y); + ImageCompression compression; + const std::string* rawTile = source_.GetRawTile(compression, x, y); if (rawTile != NULL) { // Simple transcoding - target_.WriteRawTile(*rawTile, source_.GetImageCompression(), level + shiftTargetLevel_, x, y); + target_.WriteRawTile(*rawTile, compression, level + shiftTargetLevel_, x, y); } else {
--- a/Framework/Algorithms/TranscodeTileCommand.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Algorithms/TranscodeTileCommand.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -61,12 +61,14 @@ for (unsigned int y = y_; y < y_ + countTilesY_; y++) { LOG(INFO) << "Adding tile (" << x << "," << y << ") at level " << level_; - const std::string* rawTile = source_.GetRawTile(x, y); + + ImageCompression compression; + const std::string* rawTile = source_.GetRawTile(compression, x, y); if (rawTile != NULL) { // Simple transcoding - target_.WriteRawTile(*rawTile, source_.GetImageCompression(), level_, x, y); + target_.WriteRawTile(*rawTile, compression, level_, x, y); } else {
--- a/Framework/Inputs/DecodedTiledPyramid.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/DecodedTiledPyramid.h Thu Nov 24 17:48:24 2016 +0100 @@ -59,12 +59,8 @@ unsigned int tileX, unsigned int tileY); - virtual ImageCompression GetImageCompression() const - { - return ImageCompression_None; - } - virtual bool ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY)
--- a/Framework/Inputs/DicomPyramid.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/DicomPyramid.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -200,19 +200,22 @@ bool DicomPyramid::ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY) { CheckLevel(level); - ImageCompression compression; Orthanc::PixelFormat format; - if (levels_[level]->DownloadRawTile(compression, format, tile, orthanc_, tileX, tileY)) + if (levels_[level]->DownloadRawTile(tile, format, compression, orthanc_, tileX, tileY)) { - assert(compression == GetImageCompression() && - format == GetPixelFormat()); + if (format != GetPixelFormat()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + return true; } else @@ -222,13 +225,6 @@ } - ImageCompression DicomPyramid::GetImageCompression() const - { - assert(!instances_.empty() && instances_[0] != NULL); - return instances_[0]->GetImageCompression(orthanc_); - } - - Orthanc::PixelFormat DicomPyramid::GetPixelFormat() const { assert(!instances_.empty() && instances_[0] != NULL);
--- a/Framework/Inputs/DicomPyramid.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/DicomPyramid.h Thu Nov 24 17:48:24 2016 +0100 @@ -72,12 +72,11 @@ virtual unsigned int GetTileHeight() const; virtual bool ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY); - virtual ImageCompression GetImageCompression() const; - virtual Orthanc::PixelFormat GetPixelFormat() const; }; }
--- a/Framework/Inputs/DicomPyramidLevel.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/DicomPyramidLevel.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -116,9 +116,9 @@ } - bool DicomPyramidLevel::DownloadRawTile(ImageCompression& compression /* out */, + bool DicomPyramidLevel::DownloadRawTile(std::string& raw /* out */, Orthanc::PixelFormat& format /* out */, - std::string& raw /* out */, + ImageCompression& compression /* out */, IOrthancConnection& orthanc, unsigned int tileX, unsigned int tileY) const
--- a/Framework/Inputs/DicomPyramidLevel.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/DicomPyramidLevel.h Thu Nov 24 17:48:24 2016 +0100 @@ -84,9 +84,9 @@ return tileHeight_; } - bool DownloadRawTile(ImageCompression& compression /* out */, + bool DownloadRawTile(std::string& raw /* out */, Orthanc::PixelFormat& format /* out */, - std::string& raw /* out */, + ImageCompression& compression /* out */, IOrthancConnection& orthanc, unsigned int tileX, unsigned int tileY) const;
--- a/Framework/Inputs/HierarchicalTiff.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/HierarchicalTiff.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -245,6 +245,7 @@ bool HierarchicalTiff::ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY) @@ -253,6 +254,8 @@ CheckLevel(level); + compression = compression_; + // Make the TIFF context point to the level of interest if (!TIFFSetDirectory(tiff_, levels_[level].directory_)) {
--- a/Framework/Inputs/HierarchicalTiff.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/HierarchicalTiff.h Thu Nov 24 17:48:24 2016 +0100 @@ -94,18 +94,19 @@ } virtual bool ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY); - virtual ImageCompression GetImageCompression() const - { - return compression_; - } - virtual Orthanc::PixelFormat GetPixelFormat() const { return pixelFormat_; } + + ImageCompression GetImageCompression() + { + return compression_; + } }; }
--- a/Framework/Inputs/ITiledPyramid.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/ITiledPyramid.h Thu Nov 24 17:48:24 2016 +0100 @@ -52,6 +52,7 @@ virtual unsigned int GetTileHeight() const = 0; virtual bool ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY) = 0; @@ -60,9 +61,6 @@ unsigned int tileX, unsigned int tileY) = 0; - // Only makes sense for images with raw access to tiles - virtual ImageCompression GetImageCompression() const = 0; - virtual Orthanc::PixelFormat GetPixelFormat() const = 0; }; }
--- a/Framework/Inputs/PyramidWithRawTiles.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/PyramidWithRawTiles.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -33,14 +33,16 @@ unsigned int tileY) { std::string tile; - if (!ReadRawTile(tile, level, tileX, tileY)) + ImageCompression compression; + + if (!ReadRawTile(tile, compression, level, tileX, tileY)) { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + return NULL; } std::auto_ptr<Orthanc::ImageAccessor> result; - switch (GetImageCompression()) + switch (compression) { case ImageCompression_None: result.reset(new Orthanc::ImageAccessor);
--- a/Framework/Inputs/TiledPyramidStatistics.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/TiledPyramidStatistics.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -43,11 +43,12 @@ bool TiledPyramidStatistics::ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY) { - if (source_.ReadRawTile(tile, level, tileX, tileY)) + if (source_.ReadRawTile(tile, compression, level, tileX, tileY)) { boost::mutex::scoped_lock lock(mutex_); countRawAccesses_++;
--- a/Framework/Inputs/TiledPyramidStatistics.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Inputs/TiledPyramidStatistics.h Thu Nov 24 17:48:24 2016 +0100 @@ -30,7 +30,7 @@ { private: boost::mutex mutex_; - ITiledPyramid& source_; + ITiledPyramid& source_; // This is a facade design pattern unsigned int countRawAccesses_; unsigned int countDecodedTiles_; @@ -64,17 +64,13 @@ return source_.GetTileHeight(); } - virtual ImageCompression GetImageCompression() const - { - return source_.GetImageCompression(); - } - virtual Orthanc::PixelFormat GetPixelFormat() const { return source_.GetPixelFormat(); } virtual bool ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY);
--- a/Framework/Outputs/InMemoryTiledImage.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Outputs/InMemoryTiledImage.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -88,6 +88,7 @@ bool InMemoryTiledImage::ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY)
--- a/Framework/Outputs/InMemoryTiledImage.h Thu Nov 24 15:41:21 2016 +0100 +++ b/Framework/Outputs/InMemoryTiledImage.h Thu Nov 24 17:48:24 2016 +0100 @@ -77,6 +77,7 @@ } virtual bool ReadRawTile(std::string& tile, + ImageCompression& compression, unsigned int level, unsigned int tileX, unsigned int tileY); @@ -85,11 +86,6 @@ unsigned int tileX, unsigned int tileY); - virtual ImageCompression GetImageCompression() const - { - return ImageCompression_None; - } - virtual Orthanc::PixelFormat GetPixelFormat() const { return format_;
--- a/TODO Thu Nov 24 15:41:21 2016 +0100 +++ b/TODO Thu Nov 24 17:48:24 2016 +0100 @@ -6,8 +6,9 @@ General ------- -* Support sparse tiling (both in encoder and decoder) +* Thoroughly test sparse tiling (both in encoder and decoder) * Display physical scale in Web viewer +* Viewer: Configure how missing tiles are displayed for sparse tiling ----------- @@ -30,4 +31,3 @@ --------- * Move "Framework/Orthanc/" as "Resources/Orthanc/" -* Publish history of code size on Web site
--- a/ViewerPlugin/Plugin.cpp Thu Nov 24 15:41:21 2016 +0100 +++ b/ViewerPlugin/Plugin.cpp Thu Nov 24 17:48:24 2016 +0100 @@ -22,6 +22,7 @@ #include "../Framework/Inputs/DicomPyramid.h" #include "../Framework/Jpeg2000Reader.h" #include "../Framework/Messaging/PluginOrthancConnection.h" +#include "../Framework/Orthanc/Core/Images/ImageProcessing.h" #include "../Framework/Orthanc/Core/Images/PngWriter.h" #include "../Framework/Orthanc/Core/MultiThreading/Semaphore.h" #include "../Framework/Orthanc/Core/OrthancException.h" @@ -106,6 +107,26 @@ std::auto_ptr<OrthancWSI::PluginOrthancConnection> orthanc_; std::auto_ptr<OrthancWSI::DicomPyramidCache> cache_; std::auto_ptr<Orthanc::Semaphore> transcoderSemaphore_; +std::string sparseTile_; + + +static void AnswerSparseTile(OrthancPluginRestOutput* output, + unsigned int tileWidth, + unsigned int tileHeight) +{ + Orthanc::Image tile(Orthanc::PixelFormat_RGB24, tileWidth, tileHeight, false); + + // Black (TODO parameter) + uint8_t red = 0; + uint8_t green = 0; + uint8_t blue = 0; + Orthanc::ImageProcessing::Set(tile, red, green, blue, 255); + + // TODO Cache the tile + OrthancPluginCompressAndAnswerPngImage(context_, output, OrthancPluginPixelFormat_RGB24, + tile.GetWidth(), tile.GetHeight(), + tile.GetPitch(), tile.GetBuffer()); +} static bool DisplayPerformanceWarning() @@ -182,16 +203,17 @@ { OrthancWSI::DicomPyramidCache::Locker locker(*cache_, seriesId); - compression = locker.GetPyramid().GetImageCompression(); format = locker.GetPyramid().GetPixelFormat(); tileWidth = locker.GetPyramid().GetTileWidth(); tileHeight = locker.GetPyramid().GetTileHeight(); - if (!locker.GetPyramid().ReadRawTile(tile, + if (!locker.GetPyramid().ReadRawTile(tile, compression, static_cast<unsigned int>(level), static_cast<unsigned int>(tileX), static_cast<unsigned int>(tileY))) { + // Handling of missing tile (for sparse tiling): TODO parameter? + // AnswerSparseTile(output, tileWidth, tileHeight); return; throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); } }