numcodecs.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. # tifffile/numcodecs.py
  2. # Copyright (c) 2021-2025, Christoph Gohlke
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are met:
  7. #
  8. # 1. Redistributions of source code must retain the above copyright notice,
  9. # this list of conditions and the following disclaimer.
  10. #
  11. # 2. Redistributions in binary form must reproduce the above copyright notice,
  12. # this list of conditions and the following disclaimer in the documentation
  13. # and/or other materials provided with the distribution.
  14. #
  15. # 3. Neither the name of the copyright holder nor the names of its
  16. # contributors may be used to endorse or promote products derived from
  17. # this software without specific prior written permission.
  18. #
  19. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  23. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. # POSSIBILITY OF SUCH DAMAGE.
  30. """TIFF codec for the Numcodecs package."""
  31. from __future__ import annotations
  32. __all__ = ['Tiff', 'register_codec']
  33. from io import BytesIO
  34. from typing import TYPE_CHECKING
  35. from numcodecs import registry
  36. from numcodecs.abc import Codec
  37. from .tifffile import TiffFile, TiffWriter
  38. if TYPE_CHECKING:
  39. from collections.abc import Iterable, Sequence
  40. from typing import Any
  41. from .tifffile import (
  42. COMPRESSION,
  43. EXTRASAMPLE,
  44. PHOTOMETRIC,
  45. PLANARCONFIG,
  46. PREDICTOR,
  47. ByteOrder,
  48. TagTuple,
  49. )
  50. class Tiff(Codec): # type: ignore[misc]
  51. """TIFF codec for Numcodecs."""
  52. codec_id = 'tifffile'
  53. def __init__(
  54. self,
  55. # TiffFile.asarray
  56. key: int | slice | Iterable[int] | None = None,
  57. series: int | None = None,
  58. level: int | None = None,
  59. # TiffWriter
  60. bigtiff: bool = False,
  61. byteorder: ByteOrder | None = None,
  62. imagej: bool = False,
  63. ome: bool | None = None,
  64. # TiffWriter.write
  65. photometric: PHOTOMETRIC | int | str | None = None,
  66. planarconfig: PLANARCONFIG | int | str | None = None,
  67. extrasamples: Sequence[EXTRASAMPLE | int | str] | None = None,
  68. volumetric: bool = False,
  69. tile: Sequence[int] | None = None,
  70. rowsperstrip: int | None = None,
  71. compression: COMPRESSION | int | str | None = None,
  72. compressionargs: dict[str, Any] | None = None,
  73. predictor: PREDICTOR | int | str | bool | None = None,
  74. subsampling: tuple[int, int] | None = None,
  75. metadata: dict[str, Any] | None = {}, # noqa: B006
  76. extratags: Sequence[TagTuple] | None = None,
  77. truncate: bool = False,
  78. maxworkers: int | None = None,
  79. ) -> None:
  80. self.key = key
  81. self.series = series
  82. self.level = level
  83. self.bigtiff = bigtiff
  84. self.byteorder = byteorder
  85. self.imagej = imagej
  86. self.ome = ome
  87. self.photometric = photometric
  88. self.planarconfig = planarconfig
  89. self.extrasamples = extrasamples
  90. self.volumetric = volumetric
  91. self.tile = tile
  92. self.rowsperstrip = rowsperstrip
  93. self.compression = compression
  94. self.compressionargs = compressionargs
  95. self.predictor = predictor
  96. self.subsampling = subsampling
  97. self.metadata = metadata
  98. self.extratags = extratags
  99. self.truncate = truncate
  100. self.maxworkers = maxworkers
  101. def encode(self, buf: Any) -> bytes:
  102. """Return TIFF file as bytes."""
  103. with BytesIO() as fh:
  104. with TiffWriter(
  105. fh,
  106. bigtiff=self.bigtiff,
  107. byteorder=self.byteorder,
  108. imagej=self.imagej,
  109. ome=self.ome,
  110. ) as tif:
  111. tif.write(
  112. buf,
  113. photometric=self.photometric,
  114. planarconfig=self.planarconfig,
  115. extrasamples=self.extrasamples,
  116. volumetric=self.volumetric,
  117. tile=self.tile,
  118. rowsperstrip=self.rowsperstrip,
  119. compression=self.compression,
  120. compressionargs=self.compressionargs,
  121. predictor=self.predictor,
  122. subsampling=self.subsampling,
  123. metadata=self.metadata,
  124. extratags=self.extratags,
  125. truncate=self.truncate,
  126. maxworkers=self.maxworkers,
  127. )
  128. return fh.getvalue()
  129. def decode(self, buf: Any, out: Any = None) -> Any:
  130. """Return decoded image as NumPy array."""
  131. with BytesIO(buf) as fh, TiffFile(fh) as tif:
  132. return tif.asarray(
  133. key=self.key,
  134. series=self.series,
  135. level=self.level,
  136. maxworkers=self.maxworkers,
  137. out=out,
  138. )
  139. def register_codec(cls: Codec = Tiff, codec_id: str | None = None) -> None:
  140. """Register :py:class:`Tiff` codec with Numcodecs."""
  141. registry.register_codec(cls, codec_id=codec_id)