From 6e5469dedfe1dff132522f5498382b5ccac4b731 Mon Sep 17 00:00:00 2001 From: Erik O Gabrielsson <83275777+erikogabrielsson@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:31:35 +0100 Subject: [PATCH] Compressed size (#84) * Add property for compressed size of image * Change from cytomine to openslide test data * Revert to installed turbojpeg --- .github/workflows/pytests.yaml | 3 --- CHANGELOG.md | 11 +++++++++-- opentile/__init__.py | 2 +- opentile/tiff_image.py | 13 +++++++++++++ pyproject.toml | 2 +- tests/download_test_images.py | 4 ++-- tests/test_histech_tiff_tiler.py | 9 +++++++++ tests/test_ndpi_tiler.py | 9 +++++++++ tests/test_ome_tiff_tiler.py | 9 +++++++++ tests/test_philips_tiff_tiler.py | 9 +++++++++ tests/test_svs_tiler.py | 10 ++++++++++ 11 files changed, 72 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pytests.yaml b/.github/workflows/pytests.yaml index eb945c6..cd503fb 100644 --- a/.github/workflows/pytests.yaml +++ b/.github/workflows/pytests.yaml @@ -60,9 +60,6 @@ jobs: - name: Set up Ubuntu if: matrix.os == 'ubuntu-latest' run: sudo apt-get install -y libturbojpeg - - name: Set up libjpegturbo OSX - if: matrix.os == 'macos-latest' - run: brew unlink jpeg-turbo && brew install jpeg-turbo --HEAD - name: Set up libjpegturbo Windows shell: pwsh if: matrix.os == 'windows-latest' diff --git a/CHANGELOG.md b/CHANGELOG.md index d815577..dcfc722 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] - +## [Unreleased] + +## [0.14.0] - 2025-01-29 + +### Added + +- Property `compressed_size` returning the size of all frames, with jpeg headers if separated. ## [0.13.4] - 2024-11-06 @@ -231,7 +237,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release of opentile. -[Unreleased]: https://github.com/imi-bigpicture/opentile/compare/v0.13.4..HEAD +[Unreleased]: https://github.com/imi-bigpicture/opentile/compare/v0.14.0..HEAD +[0.14.0]: https://github.com/imi-bigpicture/opentile/compare/v0.13.3..v0.14.0 [0.13.4]: https://github.com/imi-bigpicture/opentile/compare/v0.13.2..v0.13.3 [0.13.3]: https://github.com/imi-bigpicture/opentile/compare/v0.13.2..v0.13.3 [0.13.2]: https://github.com/imi-bigpicture/opentile/compare/v0.13.1..v0.13.2 diff --git a/opentile/__init__.py b/opentile/__init__.py index 29967dd..d1429d0 100644 --- a/opentile/__init__.py +++ b/opentile/__init__.py @@ -17,4 +17,4 @@ from opentile.opentile import OpenTile from opentile.metadata import Metadata -__version__ = "0.13.4" +__version__ = "0.14.0" diff --git a/opentile/tiff_image.py b/opentile/tiff_image.py index c8dfdf2..3a8aac0 100644 --- a/opentile/tiff_image.py +++ b/opentile/tiff_image.py @@ -14,6 +14,7 @@ """Base image classes.""" +from functools import cached_property import math from abc import ABCMeta, abstractmethod from pathlib import Path @@ -165,6 +166,18 @@ def pyramid_index(self) -> int: images not in pyramidal series.""" return self._pyramid_index + @cached_property + def compressed_size(self) -> int: + """Return the size of the compressed image data.""" + frames = sum(self._page.databytecounts) + if self._page.jpegheader is not None: + jpeg_header_length = len(self._page.jpegheader) + elif self._page.jpegtables is not None: + jpeg_header_length = len(self._page.jpegtables) + else: + jpeg_header_length = 0 + return frames + len(self._page.dataoffsets) * jpeg_header_length + @abstractmethod def get_tile(self, tile_position: Tuple[int, int]) -> bytes: """Should return image bytes for tile at tile position. diff --git a/pyproject.toml b/pyproject.toml index 1baf558..dba0836 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "opentile" -version = "0.13.4" +version = "0.14.0" description = "Read tiles from wsi-TIFF files" authors = ["Erik O Gabrielsson "] license = "Apache-2.0" diff --git a/tests/download_test_images.py b/tests/download_test_images.py index 9d2b211..c3752a7 100644 --- a/tests/download_test_images.py +++ b/tests/download_test_images.py @@ -20,11 +20,11 @@ FILES: Dict[str, Dict[str, Any]] = { "svs/CMU-1/CMU-1.svs": { - "url": "https://data.cytomine.coop/open/openslide/aperio-svs/CMU-1.svs", # NOQA + "url": "https://openslide.cs.cmu.edu/download/openslide-testdata/Aperio/CMU-1.svs", # NOQA "md5": {"CMU-1.svs": "751b0b86a3c5ff4dfc8567cf24daaa85"}, }, "ndpi/CMU-1/CMU-1.ndpi": { - "url": "https://data.cytomine.coop/open/openslide/hamamatsu-ndpi/CMU-1.ndpi", # NOQA + "url": "https://openslide.cs.cmu.edu/download/openslide-testdata/Hamamatsu/CMU-1.ndpi", # NOQA "md5": {"CMU-1.ndpi": "fb89dea54f85fb112e418a3cf4c7888a"}, }, } diff --git a/tests/test_histech_tiff_tiler.py b/tests/test_histech_tiff_tiler.py index 5755456..25c48af 100644 --- a/tests/test_histech_tiff_tiler.py +++ b/tests/test_histech_tiff_tiler.py @@ -109,3 +109,12 @@ def test_sumples_per_pixel(self, level: TiffImage): # Assert assert samples_per_pixel == 3 + + def test_compressed_size(self, level: TiffImage): + # Arrange + + # Act + compressed_size = level.compressed_size + + # Assert + assert compressed_size == 425684721 diff --git a/tests/test_ndpi_tiler.py b/tests/test_ndpi_tiler.py index 7423c45..19d5d03 100644 --- a/tests/test_ndpi_tiler.py +++ b/tests/test_ndpi_tiler.py @@ -484,3 +484,12 @@ def test_overview(self, tiler: NdpiTiler): # Assert assert md5(overview).hexdigest() == "c663698334b10cd57484a2d503b3bafa" + + def test_compressed_size(self, level: TiffImage): + # Arrange + + # Act + compressed_size = level.compressed_size + + # Assert + assert compressed_size == 262256667 diff --git a/tests/test_ome_tiff_tiler.py b/tests/test_ome_tiff_tiler.py index ba77cdb..fc3b4c2 100644 --- a/tests/test_ome_tiff_tiler.py +++ b/tests/test_ome_tiff_tiler.py @@ -72,3 +72,12 @@ def test_sumples_per_pixel(self, level: TiffImage): # Assert assert samples_per_pixel == 3 + + def test_compressed_size(self, level: TiffImage): + # Arrange + + # Act + compressed_size = level.compressed_size + + # Assert + assert compressed_size == 104115549 diff --git a/tests/test_philips_tiff_tiler.py b/tests/test_philips_tiff_tiler.py index fc0f1a4..59f0dd7 100644 --- a/tests/test_philips_tiff_tiler.py +++ b/tests/test_philips_tiff_tiler.py @@ -146,3 +146,12 @@ def test_metadata_aquisition_datetime(self, tiler: PhilipsTiffTiler): # Assert assert aquisition_datetime == datetime(2013, 7, 1, 18, 59, 4) + + def test_compressed_size(self, level: TiffImage): + # Arrange + + # Act + compressed_size = level.compressed_size + + # Assert + assert compressed_size == 486105413 diff --git a/tests/test_svs_tiler.py b/tests/test_svs_tiler.py index 6bb9729..1f3253c 100644 --- a/tests/test_svs_tiler.py +++ b/tests/test_svs_tiler.py @@ -21,6 +21,7 @@ from opentile.formats import SvsTiler from opentile.formats.svs.svs_image import SvsTiledImage +from opentile.tiff_image import TiffImage from opentile.geometry import Point from .filepaths import svs_file_path @@ -181,3 +182,12 @@ def test_metadata_aquisition_datetime(self, tiler: SvsTiler): # Assert assert aquisition_datetime == datetime(2009, 12, 29, 9, 59, 15) + + def test_compressed_size(self, level: TiffImage): + # Arrange + + # Act + compressed_size = level.compressed_size + + # Assert + assert compressed_size == 163831603