src/tiffFile.cpp (170 lines of code) (raw):

// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include <absl/strings/string_view.h> #include <memory> #include <string> #include <utility> #include <boost/log/trivial.hpp> #include "src/openslideUtil.h" #include "src/tiffFile.h" namespace wsiToDicomConverter { TiffFile::TiffFile(absl::string_view path, const int32_t dirIndex) : tiffFilePath_(path), currentDirectoryIndex_(dirIndex) { initalized_ = false; tileReadBufSize_ = 0; openslide_level_ = 0; std::string path_str = std::move(static_cast<std::string>(path)); tiffFile_ = TIFFOpen(path_str.c_str(), "r"); if (tiffFile_ == nullptr) { return; } do { // Uncomment to print description of tiff dir to stdio. // TIFFPrintDirectory(tiffFile_, stdout); tiffDir_.push_back(std::move(std::make_unique<TiffDirectory>(tiffFile_))); } while (TIFFReadDirectory(tiffFile_)); TIFFSetDirectory(tiffFile_, currentDirectoryIndex_); tileReadBufSize_ = TIFFTileSize(tiffFile_); initalized_ = true; } TiffFile::TiffFile(const TiffFile &tf, const int32_t dirIndex) : tiffFilePath_(tf.path()), currentDirectoryIndex_(dirIndex) { initalized_ = false; tileReadBufSize_ = 0; openslide_level_ = 0; tiffFile_ = TIFFOpen(tiffFilePath_.c_str(), "r"); if (tiffFile_ == nullptr) { return; } const size_t dirCount = tf.directoryCount(); for (size_t idx = 0; idx < dirCount; ++idx) { tiffDir_.push_back((std::move( std::make_unique<TiffDirectory>(*tf.directory(idx))))); } TIFFSetDirectory(tiffFile_, currentDirectoryIndex_); tileReadBufSize_ = tf.tileReadBufSize_; if (!fileDirectory()->isJpeg2kCompressed()) { osptr_ = nullptr; openslide_level_ = 0; } else { osptr_ = std::make_unique<OpenSlidePtr>(tf.path()); openslide_t* opslide = osptr_->osr(); int64_t level_width = -1; int64_t level_height = -1; const int64_t targetWidth = fileDirectory()->imageWidth(); const int64_t targetHeight = fileDirectory()->imageHeight(); if (openslide_get_error(opslide)) { BOOST_LOG_TRIVIAL(error) << openslide_get_error(opslide); throw 1; } const int32_t level_count = openslide_get_level_count(opslide); for (openslide_level_ = 0; openslide_level_ < level_count; ++openslide_level_) { openslide_get_level_dimensions(opslide, openslide_level_, &level_width, &level_height); if (level_width == targetWidth && level_height == targetHeight) { break; } } if (level_width != targetWidth && level_height != targetHeight) { BOOST_LOG_TRIVIAL(error) << "Could not find expected level in " "JPG2000 encoded tiff."; throw 1; } } initalized_ = true; } openslide_t * TiffFile::getOpenslidePtr() { return osptr_->osr(); } int32_t TiffFile::getOpenslideLevel() const { return openslide_level_; } TiffFile::~TiffFile() { osptr_ = nullptr; close(); } void TiffFile::close() { if (tiffFile_ == nullptr) { return; } TIFFClose(tiffFile_); tiffFile_ = nullptr; } std::string TiffFile::path() const { return tiffFilePath_; } int32_t TiffFile::directoryLevel() const { return currentDirectoryIndex_; } bool TiffFile::isLoaded() const { return (tiffFile_ != nullptr); } bool TiffFile::isInitalized() const { return initalized_; } bool TiffFile::hasExtractablePyramidImages() const { for (int32_t idx = 0; idx < tiffDir_.size(); ++idx) { if (tiffDir_[idx]->isExtractablePyramidImage()) { return true; } } return false; } int32_t TiffFile::getDirectoryIndexMatchingImageDimensions(uint32_t width, uint32_t height, bool isExtractablePyramidImage) const { for (int32_t idx = 0; idx < tiffDir_.size(); ++idx) { if (!isExtractablePyramidImage || tiffDir_[idx]->isExtractablePyramidImage()) { if (tiffDir_[idx]->doImageDimensionsMatch(width, height)) { return idx; } } } return -1; } const TiffDirectory *TiffFile::fileDirectory() const { return directory(currentDirectoryIndex_); } const TiffDirectory *TiffFile::directory(int64_t dirIndex) const { return tiffDir_[dirIndex].get(); } uint32_t TiffFile::directoryCount() const { return tiffDir_.size(); } class TileReadBuffer { public: explicit TileReadBuffer(uint64_t size); virtual ~TileReadBuffer(); tdata_t buffer_; }; TileReadBuffer::TileReadBuffer(uint64_t size) { buffer_ = _TIFFmalloc(size); } TileReadBuffer::~TileReadBuffer() { if (buffer_ != nullptr) { _TIFFfree(buffer_); } } std::unique_ptr<TiffTile> TiffFile::tile(uint32_t tileIndex) { if (tiffFile_ == nullptr) { return nullptr; } TileReadBuffer readBuffer(tileReadBufSize_); if (readBuffer.buffer_ == nullptr) { return nullptr; } uint32_t bufferSize = TIFFReadRawTile(tiffFile_, static_cast<ttile_t>(tileIndex), readBuffer.buffer_, tileReadBufSize_); if (bufferSize == 0) { return nullptr; } std::unique_ptr<uint8_t[]> mem_buffer = std::make_unique<uint8_t[]>(bufferSize); if (mem_buffer == nullptr) { return nullptr; } _TIFFmemcpy(mem_buffer.get(), readBuffer.buffer_, bufferSize); return std::make_unique<TiffTile>(directory(directoryLevel()), tileIndex, std::move(mem_buffer), bufferSize); } } // namespace wsiToDicomConverter