opencodecs 0.6.0__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. {opencodecs-0.6.0 → opencodecs-0.7.0}/CHANGES.rst +42 -0
  2. {opencodecs-0.6.0/src/opencodecs.egg-info → opencodecs-0.7.0}/PKG-INFO +1 -1
  3. {opencodecs-0.6.0 → opencodecs-0.7.0}/pyproject.toml +1 -1
  4. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/__init__.py +1 -1
  5. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_czi_writer.py +127 -8
  6. {opencodecs-0.6.0 → opencodecs-0.7.0/src/opencodecs.egg-info}/PKG-INFO +1 -1
  7. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_recompress.py +109 -0
  8. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/VENDOR.toml +0 -0
  9. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bcdec/LICENSE +0 -0
  10. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bcdec/README.md +0 -0
  11. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bcdec/bcdec.h +0 -0
  12. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/LICENSE +0 -0
  13. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/README.rst +0 -0
  14. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/bitshuffle.c +0 -0
  15. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/bitshuffle.h +0 -0
  16. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/bitshuffle_core.c +0 -0
  17. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/bitshuffle_core.h +0 -0
  18. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/bitshuffle_internals.h +0 -0
  19. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/iochain.c +0 -0
  20. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/bitshuffle/iochain.h +0 -0
  21. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/License.txt +0 -0
  22. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/fits_hcompress.c +0 -0
  23. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/fits_hdecompress.c +0 -0
  24. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/fits_hdecompress_api.h +0 -0
  25. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/fitsio2.h +0 -0
  26. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/pliocomp.c +0 -0
  27. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/ricecomp.c +0 -0
  28. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/cfitsio/ricecomp.h +0 -0
  29. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/libspng/LICENSE +0 -0
  30. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/libspng/spng.c +0 -0
  31. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/libspng/spng.h +0 -0
  32. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_eer/LICENSE +0 -0
  33. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_eer/oc_eer.c +0 -0
  34. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_eer/oc_eer.h +0 -0
  35. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_giflzw/LICENSE +0 -0
  36. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_giflzw/oc_giflzw.c +0 -0
  37. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_giflzw/oc_giflzw.h +0 -0
  38. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_tifflzw/LICENSE +0 -0
  39. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_tifflzw/oc_tifflzw.c +0 -0
  40. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/oc_tifflzw/oc_tifflzw.h +0 -0
  41. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/qoi/LICENSE +0 -0
  42. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/qoi/qoi.h +0 -0
  43. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/rgbe/rgbe.c +0 -0
  44. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/rgbe/rgbe.h +0 -0
  45. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/rgbe/rgbe.txt +0 -0
  46. {opencodecs-0.6.0 → opencodecs-0.7.0}/3rdparty/vendor_hashes.json +0 -0
  47. {opencodecs-0.6.0 → opencodecs-0.7.0}/LICENSE +0 -0
  48. {opencodecs-0.6.0 → opencodecs-0.7.0}/MANIFEST.in +0 -0
  49. {opencodecs-0.6.0 → opencodecs-0.7.0}/README.md +0 -0
  50. {opencodecs-0.6.0 → opencodecs-0.7.0}/THIRD-PARTY.md +0 -0
  51. {opencodecs-0.6.0 → opencodecs-0.7.0}/bench/build_libjxl.sh +0 -0
  52. {opencodecs-0.6.0 → opencodecs-0.7.0}/patches/libjxl/README.md +0 -0
  53. {opencodecs-0.6.0 → opencodecs-0.7.0}/setup.cfg +0 -0
  54. {opencodecs-0.6.0 → opencodecs-0.7.0}/setup.py +0 -0
  55. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_aec_codec.py +0 -0
  56. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_avif_codec.py +0 -0
  57. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_avif_heif_params.py +0 -0
  58. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_b2nd_codec.py +0 -0
  59. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_bcn_codec.py +0 -0
  60. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_bitshuffle_codec.py +0 -0
  61. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_blosc2_codec.py +0 -0
  62. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_bmp_codec.py +0 -0
  63. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_brotli_codec.py +0 -0
  64. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_brunsli_codec.py +0 -0
  65. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_byteshuffle_codec.py +0 -0
  66. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_bz2_codec.py +0 -0
  67. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_cms_codec.py +0 -0
  68. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_czi_codec.py +0 -0
  69. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_czi_reader.py +0 -0
  70. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_deflate_codec.py +0 -0
  71. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_dicom.py +0 -0
  72. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_dicom_codec.py +0 -0
  73. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_dicom_pyramid.py +0 -0
  74. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_dicomrle_codec.py +0 -0
  75. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_dicomweb.py +0 -0
  76. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_dm.py +0 -0
  77. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_dm_codec.py +0 -0
  78. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_eer_reader.py +0 -0
  79. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_emd.py +0 -0
  80. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_emd_codec.py +0 -0
  81. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_ets.py +0 -0
  82. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_filter_args.py +0 -0
  83. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_fits.py +0 -0
  84. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_fits_codec.py +0 -0
  85. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_fits_compressed.py +0 -0
  86. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_gif_codec.py +0 -0
  87. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_gzip_codec.py +0 -0
  88. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_h5_common.py +0 -0
  89. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_hdf5_codec.py +0 -0
  90. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_hdf5_http.py +0 -0
  91. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_heif_codec.py +0 -0
  92. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_htj2k_codec.py +0 -0
  93. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_htj2k_pyramid.py +0 -0
  94. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_imaris.py +0 -0
  95. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_jpeg2k_codec.py +0 -0
  96. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_jpeg2k_pyramid.py +0 -0
  97. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_jpeg_codec.py +0 -0
  98. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_jpeg_pyramid.py +0 -0
  99. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_jpegls_codec.py +0 -0
  100. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_jxl_codec.py +0 -0
  101. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_lerc_codec.py +0 -0
  102. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_lif_codec.py +0 -0
  103. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_lif_native.py +0 -0
  104. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_lz4_codec.py +0 -0
  105. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_lzma_codec.py +0 -0
  106. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_mozjpeg_codec.py +0 -0
  107. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_mozjpeg_pyramid.py +0 -0
  108. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_mrc.py +0 -0
  109. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_mrc_codec.py +0 -0
  110. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_mrc_writer.py +0 -0
  111. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_n5.py +0 -0
  112. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_nd2_codec.py +0 -0
  113. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_nd2_native.py +0 -0
  114. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_ndtiff.py +0 -0
  115. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_ndtiff_pyramid.py +0 -0
  116. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_ndtiff_writer.py +0 -0
  117. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_nifti.py +0 -0
  118. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_nifti_codec.py +0 -0
  119. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_nifti_writer.py +0 -0
  120. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_none_codec.py +0 -0
  121. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_nrrd.py +0 -0
  122. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_nrrd_codec.py +0 -0
  123. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_numpy_codec.py +0 -0
  124. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_numpy_reader.py +0 -0
  125. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_oib_codec.py +0 -0
  126. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_oib_native.py +0 -0
  127. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_oir_codec.py +0 -0
  128. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_ole2.py +0 -0
  129. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_ome_xml.py +0 -0
  130. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_omezarr.py +0 -0
  131. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_omezarr_writer.py +0 -0
  132. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_packints_codec.py +0 -0
  133. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_pcodec_codec.py +0 -0
  134. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_png_codec.py +0 -0
  135. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_predictor_codec.py +0 -0
  136. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_pyramid_build.py +0 -0
  137. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_qoi_codec.py +0 -0
  138. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_quantize_codec.py +0 -0
  139. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_rcomp_codec.py +0 -0
  140. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_rgbe.py +0 -0
  141. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_rgbe_codec.py +0 -0
  142. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_scaled_pyramid.py +0 -0
  143. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_snappy_codec.py +0 -0
  144. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_sperr_codec.py +0 -0
  145. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_sz3_codec.py +0 -0
  146. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_tiff_codec.py +0 -0
  147. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_tiff_http.py +0 -0
  148. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_tiff_pyramid.py +0 -0
  149. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_tiff_writer.py +0 -0
  150. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_ultrahdr_codec.py +0 -0
  151. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_vsi_codec.py +0 -0
  152. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_vsi_pyramid.py +0 -0
  153. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_webp_codec.py +0 -0
  154. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_zarr_codecs.py +0 -0
  155. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_zfp_codec.py +0 -0
  156. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/_zstd_codec.py +0 -0
  157. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/__init__.py +0 -0
  158. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_aec.pyx +0 -0
  159. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_avif.pyx +0 -0
  160. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_b2nd.pyx +0 -0
  161. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_bcdec.pyx +0 -0
  162. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_bitshuffle.pyx +0 -0
  163. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_blosc2.pyx +0 -0
  164. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_bmp.pyx +0 -0
  165. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_brotli.pyx +0 -0
  166. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_brunsli.pyx +0 -0
  167. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_bytetools.pyx +0 -0
  168. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_charls.pyx +0 -0
  169. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_deflate.pyx +0 -0
  170. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_eer.pyx +0 -0
  171. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_gif.pyx +0 -0
  172. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_hcomp.pyx +0 -0
  173. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_heif.pyx +0 -0
  174. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_isal.pyx +0 -0
  175. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_jpeg.pyx +0 -0
  176. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_jpeg2k.pyx +0 -0
  177. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_jpeg_common.py +0 -0
  178. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_jpegxr.pyx +0 -0
  179. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_jxl.pyx +0 -0
  180. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_lerc.pyx +0 -0
  181. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_lz4.pyx +0 -0
  182. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_mozjpeg.pyx +0 -0
  183. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_ndtiff.pyx +0 -0
  184. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_openjph.pyx +0 -0
  185. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_pcodec.pyx +0 -0
  186. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_plio.pyx +0 -0
  187. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_png.pyx +0 -0
  188. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_qoi.pyx +0 -0
  189. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_rcomp.pyx +0 -0
  190. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_registry.py +0 -0
  191. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_rgbe.pyx +0 -0
  192. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_snappy.pyx +0 -0
  193. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_sperr.pyx +0 -0
  194. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_sz3.pyx +0 -0
  195. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_tiff.pyx +0 -0
  196. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_uhdr.pyx +0 -0
  197. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_webp.pyx +0 -0
  198. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_zfp.pyx +0 -0
  199. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/_zstd.pyx +0 -0
  200. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/avif.pxd +0 -0
  201. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/b2nd.pxd +0 -0
  202. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/b2nd_helpers.c +0 -0
  203. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/b2nd_helpers.h +0 -0
  204. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/bcdec.pxd +0 -0
  205. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/bitshuffle.pxd +0 -0
  206. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/blosc2.pxd +0 -0
  207. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/brotli.pxd +0 -0
  208. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/brunsli.pxd +0 -0
  209. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/byteplanes.h +0 -0
  210. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/charls.pxd +0 -0
  211. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/eer.pxd +0 -0
  212. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/giflib.pxd +0 -0
  213. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/heif.pxd +0 -0
  214. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/heif_shim.h +0 -0
  215. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/isal_shim.c +0 -0
  216. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/jpegxr_shim.c +0 -0
  217. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/jpegxr_shim.h +0 -0
  218. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/lerc.pxd +0 -0
  219. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/libaec.pxd +0 -0
  220. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/libjxl.pxd +0 -0
  221. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/libuhdr.pxd +0 -0
  222. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/lz4.pxd +0 -0
  223. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/mozjpeg.pxd +0 -0
  224. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/oc_decoder_vtable.h +0 -0
  225. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/openjpeg.pxd +0 -0
  226. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/openjph.pxd +0 -0
  227. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/openjph_shim.cpp +0 -0
  228. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/openjph_shim.h +0 -0
  229. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/pcodec.pxd +0 -0
  230. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/qoi.pxd +0 -0
  231. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/rgbe.pxd +0 -0
  232. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/snappy.pxd +0 -0
  233. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/sperr.pxd +0 -0
  234. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/spng.pxd +0 -0
  235. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/sz3c.pxd +0 -0
  236. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/turbojpeg.pxd +0 -0
  237. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/webp.pxd +0 -0
  238. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/webp_shim.c +0 -0
  239. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/webp_shim.h +0 -0
  240. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/zfp.pxd +0 -0
  241. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/zlib_h.pxd +0 -0
  242. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/codecs/zstd.pxd +0 -0
  243. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/__init__.py +0 -0
  244. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/_io_helpers.py +0 -0
  245. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/_optional_backend.py +0 -0
  246. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/_range_index.py +0 -0
  247. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/_sidecar_header.py +0 -0
  248. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/_write_helpers.py +0 -0
  249. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/buffers.py +0 -0
  250. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/checksums.py +0 -0
  251. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/codec.py +0 -0
  252. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/color.py +0 -0
  253. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/errors.py +0 -0
  254. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/io.py +0 -0
  255. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/native_source.py +0 -0
  256. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/parallel.py +0 -0
  257. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/pipeline.py +0 -0
  258. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/pyramid.py +0 -0
  259. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/rows.py +0 -0
  260. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/scratch.py +0 -0
  261. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/segment_compression.py +0 -0
  262. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/streaming.py +0 -0
  263. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/tile_cache.py +0 -0
  264. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/core/verification.py +0 -0
  265. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/jxl.py +0 -0
  266. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/parallel.py +0 -0
  267. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/tiff_reader.py +0 -0
  268. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/uhdr.py +0 -0
  269. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs/zarr.py +0 -0
  270. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs.egg-info/SOURCES.txt +0 -0
  271. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs.egg-info/dependency_links.txt +0 -0
  272. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs.egg-info/requires.txt +0 -0
  273. {opencodecs-0.6.0 → opencodecs-0.7.0}/src/opencodecs.egg-info/top_level.txt +0 -0
  274. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_auto_pyramid.py +0 -0
  275. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_avif_heif_params.py +0 -0
  276. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_avif_sequence.py +0 -0
  277. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_b2nd_file_reader.py +0 -0
  278. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_bcdec.py +0 -0
  279. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_bcn_bands.py +0 -0
  280. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_bcn_rounding.py +0 -0
  281. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_bitshuffle_format.py +0 -0
  282. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_blosc2_partial.py +0 -0
  283. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_blosc2_threads.py +0 -0
  284. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_bmp_headers.py +0 -0
  285. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_bounded_pipeline.py +0 -0
  286. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_brunsli.py +0 -0
  287. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_byteplanes.py +0 -0
  288. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_bytestream_standards.py +0 -0
  289. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_capability_manifest.py +0 -0
  290. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_charls.py +0 -0
  291. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_chunked_means_cheap.py +0 -0
  292. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_codec_registry.py +0 -0
  293. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_container_pipeline.py +0 -0
  294. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_container_streaming.py +0 -0
  295. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_core_codec_api.py +0 -0
  296. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus.py +0 -0
  297. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus_codec_decode.py +0 -0
  298. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus_manifest.py +0 -0
  299. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus_native_fixtures.py +0 -0
  300. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus_other.py +0 -0
  301. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus_png.py +0 -0
  302. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus_tiff.py +0 -0
  303. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_corpus_vendors.py +0 -0
  304. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_coverage_final.py +0 -0
  305. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_coverage_finishing.py +0 -0
  306. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_coverage_last.py +0 -0
  307. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_coverage_more.py +0 -0
  308. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_coverage_push.py +0 -0
  309. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_bounded_iteration.py +0 -0
  310. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_direct_decode.py +0 -0
  311. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_fixture.py +0 -0
  312. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_mixed_subblocks.py +0 -0
  313. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_parallel_write.py +0 -0
  314. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_pread_indices.py +0 -0
  315. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_pyramid.py +0 -0
  316. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_read_dispatch.py +0 -0
  317. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_read_out.py +0 -0
  318. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_region_index.py +0 -0
  319. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_region_windows.py +0 -0
  320. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_segment_parts.py +0 -0
  321. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_slide_geometry.py +0 -0
  322. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_verification.py +0 -0
  323. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_write_pipeline.py +0 -0
  324. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_writer.py +0 -0
  325. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_czi_writer_shuffle.py +0 -0
  326. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_data_source.py +0 -0
  327. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_decode_releases_gil.py +0 -0
  328. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_deflate.py +0 -0
  329. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_delta_parity.py +0 -0
  330. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dicom.py +0 -0
  331. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dicom_encodings.py +0 -0
  332. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dicom_parallel.py +0 -0
  333. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dicom_slide_selection.py +0 -0
  334. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dicom_wsi_pyramid.py +0 -0
  335. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dicomweb.py +0 -0
  336. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_direct_filter_outputs.py +0 -0
  337. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dm.py +0 -0
  338. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dm_offsets.py +0 -0
  339. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_dm_synthetic.py +0 -0
  340. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_edge_cases.py +0 -0
  341. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_eer.py +0 -0
  342. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_eer_parallel.py +0 -0
  343. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_eer_worker_budget.py +0 -0
  344. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_emd.py +0 -0
  345. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_encode_comprehensive.py +0 -0
  346. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_error_handling.py +0 -0
  347. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_fd_writes.py +0 -0
  348. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_filter_compat.py +0 -0
  349. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_filter_scratch.py +0 -0
  350. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_fits.py +0 -0
  351. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_fits_parallel.py +0 -0
  352. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_gif.py +0 -0
  353. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_gif_compositing.py +0 -0
  354. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_gzip_presized.py +0 -0
  355. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_hdf5_http.py +0 -0
  356. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_hdf5_local.py +0 -0
  357. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_hdf5_parallel.py +0 -0
  358. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_hdf5_remote.py +0 -0
  359. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_heif_avif_features.py +0 -0
  360. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_heif_multi_image.py +0 -0
  361. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_htj2k_compat.py +0 -0
  362. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_htj2k_conformance.py +0 -0
  363. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_http_byte_savings.py +0 -0
  364. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_http_prefetch.py +0 -0
  365. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_http_unified.py +0 -0
  366. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_imaris.py +0 -0
  367. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_incremental_byte_codecs.py +0 -0
  368. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_io_chunked.py +0 -0
  369. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_isal.py +0 -0
  370. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_jpeg.py +0 -0
  371. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_jpeg2k_compat.py +0 -0
  372. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_jpeg2k_region.py +0 -0
  373. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_jpegxr.py +0 -0
  374. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_jxl.py +0 -0
  375. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_lerc.py +0 -0
  376. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_lif_indexing.py +0 -0
  377. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_lif_native.py +0 -0
  378. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_live_archives.py +0 -0
  379. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_mozjpeg.py +0 -0
  380. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_mrc.py +0 -0
  381. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_mrc_mrcz_http.py +0 -0
  382. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_mrc_nifti_writers.py +0 -0
  383. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_n5.py +0 -0
  384. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_native_output_sinks.py +0 -0
  385. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_native_parity.py +0 -0
  386. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_native_source_callbacks.py +0 -0
  387. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_nd2_native.py +0 -0
  388. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_ndtiff.py +0 -0
  389. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_nifti.py +0 -0
  390. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_nrrd.py +0 -0
  391. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_nrrd_iteration.py +0 -0
  392. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_nrrd_slices.py +0 -0
  393. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_numpy_codec_format.py +0 -0
  394. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_offset_readers.py +0 -0
  395. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_oib_indexing.py +0 -0
  396. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_oib_native.py +0 -0
  397. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_ome_xml.py +0 -0
  398. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_omezarr.py +0 -0
  399. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_omezarr_sharded_range.py +0 -0
  400. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_open_pyramid.py +0 -0
  401. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_openjph.py +0 -0
  402. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_optional_backend.py +0 -0
  403. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_owned_color_context.py +0 -0
  404. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_owned_image_decoders.py +0 -0
  405. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_parallel_jxl.py +0 -0
  406. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_phase4_filters.py +0 -0
  407. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_phase5_icc.py +0 -0
  408. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_phase6_codecs.py +0 -0
  409. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_phase7_cms.py +0 -0
  410. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_pipeline_budget.py +0 -0
  411. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_pipeline_catalog.py +0 -0
  412. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_pipeline_executor.py +0 -0
  413. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_platform_branches.py +0 -0
  414. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_png_row_sessions.py +0 -0
  415. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_png_standard.py +0 -0
  416. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_public_output_buffers.py +0 -0
  417. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_pyramid_batched_regions.py +0 -0
  418. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_qoi_standard.py +0 -0
  419. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_range_pipeline_completion.py +0 -0
  420. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_rcomp_truncated_input.py +0 -0
  421. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_read_file_into.py +0 -0
  422. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_reader_contract.py +0 -0
  423. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_reader_source_kinds.py +0 -0
  424. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_reader_streaming.py +0 -0
  425. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_reference_parity.py +0 -0
  426. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_rgbe.py +0 -0
  427. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_rgbe_toplevel.py +0 -0
  428. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_scaled_pyramid.py +0 -0
  429. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_segment_encoder_binding.py +0 -0
  430. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_shared_io_regressions.py +0 -0
  431. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_sidecar_header.py +0 -0
  432. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_snappy.py +0 -0
  433. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_source_pool_lifetime.py +0 -0
  434. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_streaming_means_streaming.py +0 -0
  435. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_threading_policy.py +0 -0
  436. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tier1_scientific.py +0 -0
  437. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_codec_encode.py +0 -0
  438. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_fused_decode.py +0 -0
  439. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_http.py +0 -0
  440. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_native.py +0 -0
  441. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_parallel_decode.py +0 -0
  442. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_pipeline.py +0 -0
  443. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_predictor2_interop.py +0 -0
  444. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_predictor_loops.py +0 -0
  445. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_pyramid.py +0 -0
  446. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_read_path.py +0 -0
  447. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_reader.py +0 -0
  448. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_spool.py +0 -0
  449. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_stack_read.py +0 -0
  450. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_workers.py +0 -0
  451. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_writer.py +0 -0
  452. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_writer_float_predictor.py +0 -0
  453. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tiff_writer_verification.py +0 -0
  454. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_tile_cache.py +0 -0
  455. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_uhdr.py +0 -0
  456. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_unified_api.py +0 -0
  457. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_url_sources.py +0 -0
  458. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_vendor_provenance.py +0 -0
  459. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_verified_encoding.py +0 -0
  460. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_version_consistency.py +0 -0
  461. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_vsi_oir.py +0 -0
  462. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_vsi_pyramid.py +0 -0
  463. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_webp_animation.py +0 -0
  464. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_webp_decode_options.py +0 -0
  465. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_webp_encode_standard.py +0 -0
  466. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_wrapper_streams.py +0 -0
  467. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_writer_contract.py +0 -0
  468. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_writer_pipeline_completion.py +0 -0
  469. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_writer_verification.py +0 -0
  470. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_zarr_adapters.py +0 -0
  471. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_zarr_region_fast_path.py +0 -0
  472. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_zfp_blocks.py +0 -0
  473. {opencodecs-0.6.0 → opencodecs-0.7.0}/tests/test_zstd_owned_output.py +0 -0
@@ -10,6 +10,48 @@ Versions follow the same ``YYYY.M.D`` cadence as upstream when we
10
10
  publish; the entries below cluster work by date rather than by
11
11
  release because most of it has shipped continuously to ``main``.
12
12
 
13
+ 0.7.0 (2026-10-03)
14
+ ------------------
15
+
16
+ ``czi_recompress`` takes ``recompress_when``, a predicate over the reader's
17
+ ``CziSubBlockEntry``. Sub-blocks it accepts are decoded and re-encoded as
18
+ before; sub-blocks it rejects are carried across BYTE FOR BYTE, keeping their
19
+ original compression. The default stays ``None``, which re-encodes everything,
20
+ so existing callers are unaffected. The returned summary gains
21
+ ``recompressed`` and ``carried`` counts.
22
+
23
+ This exists because a sub-block's compression is not a detail to be
24
+ normalized away. Re-encoding one that is already compressed is wasted work,
25
+ and re-encoding a LOSSY one is destructive: the pixels are decoded from a
26
+ lossy encoding and written back losslessly, so the file grows and the
27
+ artifacts become permanent. Measured on a 505 MB Axioscan slide scan of 481
28
+ JPEG XR sub-blocks:
29
+
30
+ ==================================== ======== ========== ============
31
+ strategy time output vs source
32
+ ==================================== ======== ========== ============
33
+ carry JPEG XR across (predicate) 0.36 s 489 MB 0.97x
34
+ re-encode everything (no predicate) 12.6 s 1309 MB 2.59x
35
+ ==================================== ======== ========== ============
36
+
37
+ So the predicate is not a speed knob. Without it that file more than doubles
38
+ in size, takes 33x longer, and loses the option of ever recovering the
39
+ original encoding. This is what ZEISS's ``czicompress`` expresses with
40
+ ``--strategy``, and the three strategies map directly::
41
+
42
+ uncompressed lambda e: e.compression == 0
43
+ uncompressed+zstd lambda e: e.compression in (0, 5, 6)
44
+ all None
45
+
46
+ Supporting this needed a writer that can emit a sub-block it cannot itself
47
+ produce. ``_build_subblock`` gained ``encoded=``, which writes the payload
48
+ exactly as given and records the compression code as-is, with no encode step
49
+ and no look at the pixels. That is the only path by which a JPEG XR sub-block
50
+ can reach a file this writer wrote, and it is why carrying one across cannot
51
+ alter it. Verification is refused on that path: nothing was encoded, so there
52
+ is nothing to check. ``verify=True`` therefore applies only to the sub-blocks
53
+ that were re-encoded.
54
+
13
55
  0.6.0 (2026-10-03)
14
56
  ------------------
15
57
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencodecs
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Streaming, network-aware image codecs for scientific imaging (prototype: JPEG XL)
5
5
  Author: Kevin Cutler
6
6
  License-Expression: BSD-3-Clause
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "opencodecs"
10
- version = "0.6.0"
10
+ version = "0.7.0"
11
11
  description = "Streaming, network-aware image codecs for scientific imaging (prototype: JPEG XL)"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
@@ -349,4 +349,4 @@ __all__ = [
349
349
  "czi_recompress", "subblock_dims",
350
350
  ]
351
351
 
352
- __version__ = "0.6.0"
352
+ __version__ = "0.7.0"
@@ -74,6 +74,30 @@ class CziWriterError(RuntimeError):
74
74
  """Raised on writer state-machine violations."""
75
75
 
76
76
 
77
+ class _CarriedSubBlock:
78
+ """A sub-block copied across unchanged, not re-encoded.
79
+
80
+ Carries the encoded payload and the compression code it was written
81
+ with, plus a zero-filled array of the right shape and dtype so the
82
+ existing header path can read shape/dtype without the pixels ever being
83
+ decoded. ``np.empty`` would do, but zeros make an accidental use of
84
+ these pixels obvious rather than random.
85
+ """
86
+
87
+ __slots__ = ("payload", "compression", "dims", "pyramid_type",
88
+ "shape_array", "logical_shape", "pixel_type")
89
+
90
+ def __init__(self, payload, *, compression, dims, pyramid_type,
91
+ shape_array, logical_shape, pixel_type):
92
+ self.payload = payload
93
+ self.compression = compression
94
+ self.pixel_type = pixel_type
95
+ self.dims = dims
96
+ self.pyramid_type = pyramid_type
97
+ self.shape_array = shape_array
98
+ self.logical_shape = logical_shape
99
+
100
+
77
101
  class CziCancelled(CziWriterError):
78
102
  """Raised when a caller's ``should_continue`` stops a rewrite.
79
103
 
@@ -339,6 +363,7 @@ def _build_subblock(
339
363
  dims: tuple | None = None,
340
364
  verification_input: list | None = None,
341
365
  scratch=None,
366
+ encoded: object | None = None,
342
367
  ) -> tuple[_SubBlockSegment, dict]:
343
368
  """Build one ZISRAWSUBBLOCK segment as parts.
344
369
 
@@ -351,7 +376,21 @@ def _build_subblock(
351
376
  check runs after this returns while the producer may already be
352
377
  refilling ``array``. Without it nothing here outlives the call, so the
353
378
  array's own buffer feeds the compressor or becomes the raw payload.
379
+
380
+ With ``encoded`` the payload is written exactly as given and
381
+ ``compression_code`` is recorded as-is, with no encode step and no look
382
+ at the pixels. That is how a sub-block is carried across unchanged, and
383
+ it is the only path that can emit a compression this writer cannot
384
+ produce (JPEG XR, for instance). ``array`` is then used only for its
385
+ shape and dtype, so a zero-filled array of the right shape is enough.
386
+ Verification is not available on this path: there is nothing to check,
387
+ because nothing was encoded.
354
388
  """
389
+ if encoded is not None and verification_input is not None:
390
+ raise CziWriterError(
391
+ "czi: verification_input cannot be combined with encoded; a "
392
+ "carried-across sub-block is not re-encoded, so there is "
393
+ "nothing to verify")
355
394
  h, w = array.shape[:2]
356
395
  logical_h, logical_w = logical_shape
357
396
  start_y, start_x = location
@@ -390,7 +429,10 @@ def _build_subblock(
390
429
  pixels = memoryview(contiguous).cast("B")
391
430
  keep = contiguous
392
431
  itemsize = array.dtype.itemsize
393
- if compression_code == 0:
432
+ if encoded is not None:
433
+ data = encoded
434
+ keep = encoded
435
+ elif compression_code == 0:
394
436
  data = pixels
395
437
  elif compression_code == 5:
396
438
  from .codecs._zstd import encode as zstd_encode
@@ -687,6 +729,17 @@ class _CziStreamWriter(Writer):
687
729
  workers = resolve_workers(None, 1 << 30, output_bytes=None, max_workers=8)
688
730
  workers = max(1, int(workers))
689
731
 
732
+ def item_bytes(item):
733
+ """Cost of one snapshotted item, for batching and reservation.
734
+
735
+ A carried sub-block has no array: its cost is the encoded payload
736
+ it already owns. Both batching sites go through here so they
737
+ cannot disagree about what an item weighs.
738
+ """
739
+ if isinstance(item, _CarriedSubBlock):
740
+ return len(item.payload)
741
+ return item[0].nbytes
742
+
690
743
  def snapshot(frame):
691
744
  """Own the frame's pixels before the producer can touch them.
692
745
 
@@ -695,6 +748,10 @@ class _CziStreamWriter(Writer):
695
748
  it is a down-scaled level. Those forms are what make a faithful
696
749
  re-encode possible on this path as well as on ``write_frame``.
697
750
  """
751
+ if isinstance(frame, _CarriedSubBlock):
752
+ # Nothing to snapshot: the payload is already bytes we own,
753
+ # and the pixels are never looked at.
754
+ return frame
698
755
  dims = override_pyramid = None
699
756
  if isinstance(frame, tuple):
700
757
  if len(frame) == 2:
@@ -728,7 +785,7 @@ class _CziStreamWriter(Writer):
728
785
  batch, batch_bytes = [], 0
729
786
  for frame in frames:
730
787
  item = snapshot(frame)
731
- n = item[0].nbytes
788
+ n = item_bytes(item)
732
789
  if batch and batch_bytes + n > batch_limit:
733
790
  yield batch
734
791
  batch, batch_bytes = [], 0
@@ -738,7 +795,7 @@ class _CziStreamWriter(Writer):
738
795
  yield batch
739
796
 
740
797
  def size(batch):
741
- n = sum(item[0].nbytes for item in batch)
798
+ n = sum(item_bytes(item) for item in batch)
742
799
  # Snapshot + encoded output (bounded by the input for these
743
800
  # codecs) + decoded verification result and comparison scratch.
744
801
  return 2 * n + (verification_reservation(n) if verify else 0)
@@ -746,7 +803,19 @@ class _CziStreamWriter(Writer):
746
803
  def encode(batch):
747
804
  out = []
748
805
  scratch = _worker_scratch()
749
- for pixels, logical_shape, pyramid_type, dims in batch:
806
+ for item in batch:
807
+ if isinstance(item, _CarriedSubBlock):
808
+ segment, entry = _build_subblock(
809
+ item.shape_array,
810
+ pixel_type=item.pixel_type,
811
+ compression_code=item.compression, hilo=self._hilo,
812
+ file_position=0, logical_shape=item.logical_shape,
813
+ pyramid_type=item.pyramid_type, dims=item.dims,
814
+ verification_input=None, scratch=None,
815
+ encoded=item.payload)
816
+ out.append((segment, entry))
817
+ continue
818
+ pixels, logical_shape, pyramid_type, dims = item
750
819
  captured = [] if verify else None
751
820
  segment, entry = _build_subblock(
752
821
  pixels, pixel_type=_DTYPE_TO_PIXELTYPE[pixels.dtype],
@@ -992,7 +1061,8 @@ __all__ = ["CziWriter", "CziPyramidWriter", "CziWriterError"]
992
1061
  def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
993
1062
  workers=None, verify: bool = False,
994
1063
  background_encode: bool = False,
995
- should_continue=None) -> dict:
1064
+ should_continue=None,
1065
+ recompress_when=None) -> dict:
996
1066
  """Rewrite a CZI with different compression, keeping the container.
997
1067
 
998
1068
  Every sub-block keeps its dimension coordinates, its scene and mosaic
@@ -1016,8 +1086,30 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
1016
1086
  know which. Encodes already dispatched still finish, so cancellation
1017
1087
  takes effect within roughly ``workers`` sub-blocks rather than instantly.
1018
1088
 
1019
- Returns a summary dict: sub-block count, input and output sizes, and the
1020
- compression that was applied.
1089
+ ``recompress_when`` is an optional predicate over the reader's
1090
+ ``CziSubBlockEntry``. Sub-blocks it accepts are decoded and re-encoded;
1091
+ sub-blocks it rejects are carried across BYTE FOR BYTE, keeping their
1092
+ original compression. Default ``None`` re-encodes everything, which is
1093
+ what earlier versions did.
1094
+
1095
+ This is what makes the selective strategies of ZEISS's ``czicompress``
1096
+ expressible, and the reason they exist: re-encoding an already-compressed
1097
+ sub-block is at best wasted work, and for a lossy one it is destructive.
1098
+ A JPEG XR sub-block decoded and re-encoded as lossless zstdhdr grows,
1099
+ and bakes the lossy artifacts in permanently. Carrying it across cannot
1100
+ do that.
1101
+
1102
+ uncompressed only lambda e: e.compression == 0
1103
+ uncompressed+zstd lambda e: e.compression in (0, 5, 6)
1104
+ everything None
1105
+
1106
+ ``verify=True`` applies only to the sub-blocks that were re-encoded; a
1107
+ carried-across payload is unchanged by definition, so there is nothing
1108
+ to check.
1109
+
1110
+ Returns a summary dict: sub-block count, input and output sizes, the
1111
+ compression that was applied, and how many sub-blocks were re-encoded
1112
+ versus carried across.
1021
1113
  """
1022
1114
  import os
1023
1115
 
@@ -1029,6 +1121,8 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
1029
1121
  raise CziWriterError(f"czi: {src} has no sub-blocks to recompress")
1030
1122
  metadata = reader.metadata_bytes or b"<Metadata/>"
1031
1123
 
1124
+ counts = {"recompressed": 0, "carried": 0}
1125
+
1032
1126
  def frames():
1033
1127
  # One sub-block at a time: a slide scan does not fit in memory,
1034
1128
  # and write_many only needs the next frame, not all of them.
@@ -1038,7 +1132,30 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
1038
1132
  f"czi: recompress of {src} cancelled after "
1039
1133
  f"{i} of {n} sub-blocks")
1040
1134
  entry = reader.entries[i]
1041
- yield reader[i], subblock_dims(entry), entry.pyramid_type
1135
+ if recompress_when is None or recompress_when(entry):
1136
+ counts["recompressed"] += 1
1137
+ yield reader[i], subblock_dims(entry), entry.pyramid_type
1138
+ else:
1139
+ # Carried across: the encoded bytes are copied straight
1140
+ # from the source and the original compression is kept,
1141
+ # so the pixels are never decoded and cannot change.
1142
+ counts["carried"] += 1
1143
+ d = subblock_dims(entry)
1144
+ axes = {name.rstrip(b"\x00"): (size, stored)
1145
+ for name, _start, size, _co, stored in d}
1146
+ log_h, st_h = axes[b"Y"]
1147
+ log_w, st_w = axes[b"X"]
1148
+ with reader._payload(entry) as view:
1149
+ # Copy: the reader hands back a buffer it reuses, so
1150
+ # a borrowed view would be overwritten by the next
1151
+ # sub-block before the writer emits this one.
1152
+ payload = bytes(view)
1153
+ yield _CarriedSubBlock(
1154
+ payload, compression=entry.compression,
1155
+ dims=d, pyramid_type=entry.pyramid_type,
1156
+ shape_array=np.zeros((st_h, st_w), entry.dtype),
1157
+ logical_shape=(log_h, log_w),
1158
+ pixel_type=entry.pixel_type)
1042
1159
 
1043
1160
  try:
1044
1161
  with CziWriter(str(dst), compression=compression, hilo=hilo,
@@ -1061,4 +1178,6 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
1061
1178
  "src_bytes": os.path.getsize(src),
1062
1179
  "dst_bytes": os.path.getsize(dst),
1063
1180
  "compression": compression,
1181
+ "recompressed": counts["recompressed"],
1182
+ "carried": counts["carried"],
1064
1183
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencodecs
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Streaming, network-aware image codecs for scientific imaging (prototype: JPEG XL)
5
5
  Author: Kevin Cutler
6
6
  License-Expression: BSD-3-Clause
@@ -351,3 +351,112 @@ def test_a_failing_predicate_also_leaves_no_output(tmp_path):
351
351
  with pytest.raises(ValueError):
352
352
  czi_recompress(src, dst, workers=PARTIAL_WORKERS, should_continue=boom)
353
353
  assert not dst.exists()
354
+
355
+
356
+ # ------------------------------------------- selective recompression
357
+ # `recompress_when` exists so the selective strategies of ZEISS's czicompress
358
+ # are expressible. The point is NOT speed: re-encoding an already-compressed
359
+ # sub-block is wasted work, and for a LOSSY one it is destructive, because a
360
+ # JPEG XR block decoded and re-encoded as lossless zstdhdr grows and bakes the
361
+ # lossy artifacts in permanently.
362
+ #
363
+ # Every assertion here is on the OUTPUT'S COMPRESSION CODES, not just its
364
+ # pixels. A pass-through that quietly re-encoded would still produce a
365
+ # readable file with identical pixels, so comparing arrays cannot catch it.
366
+
367
+ def _mixed_src(tmp_path):
368
+ """Two uncompressed sub-blocks and two already-zstd ones."""
369
+ raw = [(_tile(64, 64, 200 + i), (0, i * 64), [(b"C", i)]) for i in range(2)]
370
+ src_u = tmp_path / "u.czi"
371
+ src_u.write_bytes(mosaic_czi_bytes(raw, compression=0))
372
+ pre = tmp_path / "pre.czi"
373
+ czi_recompress(src_u, pre, compression="zstdhdr")
374
+ return src_u, pre
375
+
376
+
377
+ def _codes(path):
378
+ with CziReader(str(path)) as r:
379
+ return [e.compression for e in r.entries]
380
+
381
+
382
+ def test_default_still_recompresses_everything(tmp_path):
383
+ src, _ = _mixed_src(tmp_path)
384
+ dst = tmp_path / "d.czi"
385
+ info = czi_recompress(src, dst, compression="zstdhdr")
386
+ assert info["recompressed"] == 2 and info["carried"] == 0
387
+ assert set(_codes(dst)) == {6}
388
+
389
+
390
+ def test_uncompressed_only_leaves_compressed_blocks_alone(tmp_path):
391
+ """The czicompress default: only code 0 is touched."""
392
+ _, pre = _mixed_src(tmp_path)
393
+ assert set(_codes(pre)) == {6}, "fixture is not already compressed"
394
+ dst = tmp_path / "d.czi"
395
+ info = czi_recompress(pre, dst, compression="zstdhdr",
396
+ recompress_when=lambda e: e.compression == 0)
397
+ assert info["recompressed"] == 0, "re-encoded a block it was told to skip"
398
+ assert info["carried"] == 2
399
+ assert _codes(dst) == _codes(pre)
400
+ _assert_faithful(pre, dst)
401
+
402
+
403
+ def test_carried_payload_is_byte_identical(tmp_path):
404
+ """Carried means copied, so the encoded bytes must match exactly."""
405
+ _, pre = _mixed_src(tmp_path)
406
+ dst = tmp_path / "d.czi"
407
+ czi_recompress(pre, dst, compression="none",
408
+ recompress_when=lambda e: False)
409
+ with CziReader(str(pre)) as a, CziReader(str(dst)) as b:
410
+ for ea, eb in zip(a.entries, b.entries):
411
+ with a._payload(ea) as pa, b._payload(eb) as pb:
412
+ assert bytes(pa) == bytes(pb), "carried payload was altered"
413
+ assert ea.compression == eb.compression
414
+
415
+
416
+ def test_carried_blocks_keep_their_code_while_others_change(tmp_path):
417
+ """A mixed file: some blocks re-encoded, some carried, in one pass."""
418
+ _, pre = _mixed_src(tmp_path)
419
+ extra = [(_tile(64, 64, 300 + i), (0, (i + 2) * 64), [(b"C", i + 2)])
420
+ for i in range(2)]
421
+ mixed = tmp_path / "mixed.czi"
422
+ mixed.write_bytes(mosaic_czi_bytes(extra, compression=0))
423
+ dst = tmp_path / "d.czi"
424
+ info = czi_recompress(mixed, dst, compression="zstdhdr",
425
+ recompress_when=lambda e: e.compression == 0)
426
+ assert info["recompressed"] == 2 and info["carried"] == 0
427
+ assert set(_codes(dst)) == {6}
428
+
429
+
430
+ def test_predicate_sees_a_real_entry(tmp_path):
431
+ """The predicate gets the reader's entry, not an opaque index."""
432
+ src, _ = _mixed_src(tmp_path)
433
+ seen = []
434
+
435
+ def pred(e):
436
+ seen.append((e.compression, e.pixel_type, e.pyramid_type))
437
+ return True
438
+
439
+ czi_recompress(src, tmp_path / "d.czi", recompress_when=pred)
440
+ assert len(seen) == 2
441
+ assert all(c == 0 for c, _p, _y in seen)
442
+
443
+
444
+ def test_verify_applies_only_to_recompressed_blocks(tmp_path):
445
+ """verify=True must not choke on a carried block it never encoded."""
446
+ _, pre = _mixed_src(tmp_path)
447
+ dst = tmp_path / "d.czi"
448
+ info = czi_recompress(pre, dst, compression="zstdhdr", verify=True,
449
+ recompress_when=lambda e: e.compression == 0)
450
+ assert info["carried"] == 2
451
+ _assert_faithful(pre, dst)
452
+
453
+
454
+ def test_encoded_and_verification_input_are_refused():
455
+ """Verifying a carried block is meaningless; the writer says so."""
456
+ import numpy as np
457
+ from opencodecs._czi_writer import _build_subblock
458
+ with pytest.raises(CziWriterError, match="nothing to verify"):
459
+ _build_subblock(np.zeros((4, 4), "uint16"), pixel_type=1,
460
+ compression_code=0, hilo=False, file_position=0,
461
+ logical_shape=(4, 4), verification_input=[],
462
+ encoded=b"x")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes