opencodecs 0.2.0__tar.gz → 0.3.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 (444) hide show
  1. {opencodecs-0.2.0 → opencodecs-0.3.0}/CHANGES.rst +101 -3
  2. {opencodecs-0.2.0 → opencodecs-0.3.0}/MANIFEST.in +1 -0
  3. {opencodecs-0.2.0/src/opencodecs.egg-info → opencodecs-0.3.0}/PKG-INFO +110 -30
  4. {opencodecs-0.2.0 → opencodecs-0.3.0}/README.md +109 -29
  5. {opencodecs-0.2.0 → opencodecs-0.3.0}/THIRD-PARTY.md +1 -1
  6. {opencodecs-0.2.0 → opencodecs-0.3.0}/pyproject.toml +3 -3
  7. {opencodecs-0.2.0 → opencodecs-0.3.0}/setup.py +38 -0
  8. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/__init__.py +1 -1
  9. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_aec_codec.py +5 -2
  10. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_avif_codec.py +40 -11
  11. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_b2nd_codec.py +70 -4
  12. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_bitshuffle_codec.py +7 -3
  13. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_blosc2_codec.py +8 -3
  14. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_brotli_codec.py +5 -2
  15. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_brunsli_codec.py +6 -5
  16. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_byteshuffle_codec.py +2 -1
  17. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_cms_codec.py +88 -2
  18. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_czi_codec.py +14 -2
  19. opencodecs-0.3.0/src/opencodecs/_czi_reader.py +2274 -0
  20. opencodecs-0.3.0/src/opencodecs/_czi_writer.py +841 -0
  21. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_deflate_codec.py +6 -4
  22. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_dicom.py +162 -1
  23. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_dicom_pyramid.py +32 -29
  24. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_dicomrle_codec.py +44 -64
  25. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_dicomweb.py +56 -5
  26. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_eer_reader.py +20 -5
  27. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_emd.py +5 -2
  28. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_fits.py +14 -9
  29. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_fits_codec.py +6 -3
  30. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_fits_compressed.py +62 -20
  31. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_gif_codec.py +64 -22
  32. opencodecs-0.3.0/src/opencodecs/_h5_common.py +203 -0
  33. opencodecs-0.3.0/src/opencodecs/_hdf5_codec.py +216 -0
  34. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_heif_codec.py +67 -21
  35. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_htj2k_codec.py +4 -2
  36. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_imaris.py +8 -3
  37. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_jpeg2k_codec.py +33 -6
  38. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_jpeg_codec.py +12 -2
  39. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_jpegls_codec.py +2 -1
  40. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_jxl_codec.py +26 -5
  41. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_lerc_codec.py +5 -2
  42. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_lz4_codec.py +5 -2
  43. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_mozjpeg_codec.py +12 -2
  44. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_mrc_codec.py +6 -11
  45. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_mrc_writer.py +53 -32
  46. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_n5.py +25 -4
  47. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_nd2_native.py +6 -2
  48. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_ndtiff.py +65 -36
  49. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_ndtiff_writer.py +175 -132
  50. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_nifti_codec.py +6 -10
  51. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_nifti_writer.py +23 -18
  52. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_none_codec.py +15 -2
  53. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_numpy_codec.py +23 -7
  54. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_oib_codec.py +9 -2
  55. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_oib_native.py +56 -7
  56. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_oir_codec.py +42 -8
  57. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_omezarr.py +337 -87
  58. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_omezarr_writer.py +171 -213
  59. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_packints_codec.py +40 -6
  60. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_pcodec_codec.py +5 -2
  61. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_png_codec.py +12 -1
  62. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_predictor_codec.py +77 -59
  63. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_qoi_codec.py +6 -3
  64. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_rcomp_codec.py +24 -1
  65. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_rgbe_codec.py +2 -1
  66. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_snappy_codec.py +5 -2
  67. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_sperr_codec.py +4 -3
  68. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_sz3_codec.py +5 -2
  69. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_tiff_codec.py +100 -66
  70. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_tiff_http.py +177 -141
  71. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_tiff_pyramid.py +96 -146
  72. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_tiff_writer.py +197 -141
  73. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_vsi_pyramid.py +53 -16
  74. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_webp_codec.py +11 -4
  75. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_zfp_codec.py +46 -26
  76. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_zstd_codec.py +7 -3
  77. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/__init__.py +1 -0
  78. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_avif.pyx +58 -8
  79. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_b2nd.pyx +103 -3
  80. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_blosc2.pyx +55 -50
  81. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_brotli.pyx +102 -0
  82. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_brunsli.pyx +45 -55
  83. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_bytetools.pyx +73 -1
  84. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_gif.pyx +16 -0
  85. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_heif.pyx +132 -22
  86. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_jpeg.pyx +41 -5
  87. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_jpeg2k.pyx +122 -30
  88. opencodecs-0.3.0/src/opencodecs/codecs/_jpegxr.pyx +138 -0
  89. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_jxl.pyx +38 -27
  90. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_lz4.pyx +118 -0
  91. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_mozjpeg.pyx +40 -4
  92. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_png.pyx +258 -1
  93. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_rcomp.pyx +20 -6
  94. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_sperr.pyx +3 -2
  95. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_tiff.pyx +21 -20
  96. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_zfp.pyx +1 -1
  97. opencodecs-0.3.0/src/opencodecs/codecs/_zstd.pyx +598 -0
  98. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/avif.pxd +14 -1
  99. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/b2nd.pxd +7 -0
  100. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/b2nd_helpers.c +44 -1
  101. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/b2nd_helpers.h +11 -1
  102. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/blosc2.pxd +19 -1
  103. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/brotli.pxd +17 -1
  104. opencodecs-0.3.0/src/opencodecs/codecs/byteplanes.h +49 -0
  105. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/heif.pxd +12 -1
  106. opencodecs-0.3.0/src/opencodecs/codecs/jpegxr_shim.c +125 -0
  107. opencodecs-0.3.0/src/opencodecs/codecs/jpegxr_shim.h +32 -0
  108. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/lz4.pxd +11 -0
  109. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/openjpeg.pxd +3 -2
  110. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/spng.pxd +16 -0
  111. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/zstd.pxd +24 -0
  112. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/_io_helpers.py +2 -1
  113. opencodecs-0.3.0/src/opencodecs/core/_range_index.py +76 -0
  114. opencodecs-0.3.0/src/opencodecs/core/_write_helpers.py +75 -0
  115. opencodecs-0.3.0/src/opencodecs/core/buffers.py +97 -0
  116. opencodecs-0.3.0/src/opencodecs/core/checksums.py +38 -0
  117. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/codec.py +45 -4
  118. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/io.py +13 -8
  119. opencodecs-0.3.0/src/opencodecs/core/native_source.py +87 -0
  120. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/parallel.py +81 -4
  121. opencodecs-0.3.0/src/opencodecs/core/pipeline.py +198 -0
  122. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/pyramid.py +124 -0
  123. opencodecs-0.3.0/src/opencodecs/core/rows.py +167 -0
  124. opencodecs-0.3.0/src/opencodecs/core/scratch.py +35 -0
  125. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/segment_compression.py +84 -5
  126. opencodecs-0.3.0/src/opencodecs/core/streaming.py +180 -0
  127. opencodecs-0.3.0/src/opencodecs/core/tile_cache.py +129 -0
  128. opencodecs-0.3.0/src/opencodecs/core/verification.py +222 -0
  129. {opencodecs-0.2.0 → opencodecs-0.3.0/src/opencodecs.egg-info}/PKG-INFO +110 -30
  130. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs.egg-info/SOURCES.txt +63 -1
  131. opencodecs-0.3.0/tests/test_b2nd_file_reader.py +78 -0
  132. opencodecs-0.3.0/tests/test_blosc2_threads.py +52 -0
  133. opencodecs-0.3.0/tests/test_bounded_pipeline.py +54 -0
  134. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_capability_manifest.py +24 -21
  135. opencodecs-0.3.0/tests/test_container_pipeline.py +152 -0
  136. opencodecs-0.3.0/tests/test_container_streaming.py +249 -0
  137. opencodecs-0.3.0/tests/test_czi_bounded_iteration.py +161 -0
  138. opencodecs-0.3.0/tests/test_czi_direct_decode.py +238 -0
  139. opencodecs-0.3.0/tests/test_czi_parallel_write.py +210 -0
  140. opencodecs-0.3.0/tests/test_czi_read_out.py +105 -0
  141. opencodecs-0.3.0/tests/test_czi_region_index.py +431 -0
  142. opencodecs-0.3.0/tests/test_czi_region_windows.py +305 -0
  143. opencodecs-0.3.0/tests/test_czi_segment_parts.py +180 -0
  144. opencodecs-0.3.0/tests/test_czi_slide_geometry.py +209 -0
  145. opencodecs-0.3.0/tests/test_czi_verification.py +323 -0
  146. opencodecs-0.3.0/tests/test_czi_write_pipeline.py +107 -0
  147. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_czi_writer.py +38 -2
  148. opencodecs-0.3.0/tests/test_czi_writer_shuffle.py +188 -0
  149. opencodecs-0.3.0/tests/test_dicom_slide_selection.py +138 -0
  150. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dicomweb.py +149 -75
  151. opencodecs-0.3.0/tests/test_direct_filter_outputs.py +94 -0
  152. opencodecs-0.3.0/tests/test_eer_worker_budget.py +50 -0
  153. opencodecs-0.3.0/tests/test_filter_scratch.py +51 -0
  154. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_hdf5_remote.py +5 -3
  155. opencodecs-0.3.0/tests/test_incremental_byte_codecs.py +165 -0
  156. opencodecs-0.3.0/tests/test_jpegxr.py +157 -0
  157. opencodecs-0.3.0/tests/test_native_output_sinks.py +117 -0
  158. opencodecs-0.3.0/tests/test_native_source_callbacks.py +181 -0
  159. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_nd2_native.py +24 -0
  160. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_ndtiff.py +7 -1
  161. opencodecs-0.3.0/tests/test_nrrd_iteration.py +50 -0
  162. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_omezarr.py +2 -0
  163. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_omezarr_sharded_range.py +30 -1
  164. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_open_pyramid.py +6 -18
  165. opencodecs-0.3.0/tests/test_owned_color_context.py +44 -0
  166. opencodecs-0.3.0/tests/test_owned_image_decoders.py +73 -0
  167. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_phase7_cms.py +0 -10
  168. opencodecs-0.3.0/tests/test_pipeline_budget.py +109 -0
  169. opencodecs-0.3.0/tests/test_pipeline_catalog.py +86 -0
  170. opencodecs-0.3.0/tests/test_pipeline_executor.py +116 -0
  171. opencodecs-0.3.0/tests/test_png_row_sessions.py +141 -0
  172. opencodecs-0.3.0/tests/test_public_output_buffers.py +203 -0
  173. opencodecs-0.3.0/tests/test_pyramid_batched_regions.py +227 -0
  174. opencodecs-0.3.0/tests/test_range_pipeline_completion.py +151 -0
  175. opencodecs-0.3.0/tests/test_segment_encoder_binding.py +24 -0
  176. opencodecs-0.3.0/tests/test_shared_io_regressions.py +255 -0
  177. opencodecs-0.3.0/tests/test_source_pool_lifetime.py +146 -0
  178. opencodecs-0.3.0/tests/test_tiff_pipeline.py +150 -0
  179. opencodecs-0.3.0/tests/test_tiff_spool.py +29 -0
  180. opencodecs-0.3.0/tests/test_tiff_writer_float_predictor.py +114 -0
  181. opencodecs-0.3.0/tests/test_tiff_writer_verification.py +183 -0
  182. opencodecs-0.3.0/tests/test_tile_cache.py +235 -0
  183. opencodecs-0.3.0/tests/test_verified_encoding.py +252 -0
  184. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_writer_contract.py +56 -0
  185. opencodecs-0.3.0/tests/test_writer_pipeline_completion.py +266 -0
  186. opencodecs-0.3.0/tests/test_writer_verification.py +139 -0
  187. opencodecs-0.3.0/tests/test_zarr_region_fast_path.py +99 -0
  188. opencodecs-0.3.0/tests/test_zstd_owned_output.py +36 -0
  189. opencodecs-0.2.0/src/opencodecs/_czi_reader.py +0 -1001
  190. opencodecs-0.2.0/src/opencodecs/_czi_writer.py +0 -522
  191. opencodecs-0.2.0/src/opencodecs/_h5_common.py +0 -44
  192. opencodecs-0.2.0/src/opencodecs/_hdf5_codec.py +0 -366
  193. opencodecs-0.2.0/src/opencodecs/codecs/_zstd.pyx +0 -255
  194. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/VENDOR.toml +0 -0
  195. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bcdec/LICENSE +0 -0
  196. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bcdec/README.md +0 -0
  197. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bcdec/bcdec.h +0 -0
  198. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/LICENSE +0 -0
  199. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/README.rst +0 -0
  200. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/bitshuffle.c +0 -0
  201. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/bitshuffle.h +0 -0
  202. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/bitshuffle_core.c +0 -0
  203. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/bitshuffle_core.h +0 -0
  204. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/bitshuffle_internals.h +0 -0
  205. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/iochain.c +0 -0
  206. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/bitshuffle/iochain.h +0 -0
  207. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/License.txt +0 -0
  208. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/fits_hcompress.c +0 -0
  209. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/fits_hdecompress.c +0 -0
  210. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/fits_hdecompress_api.h +0 -0
  211. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/fitsio2.h +0 -0
  212. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/pliocomp.c +0 -0
  213. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/ricecomp.c +0 -0
  214. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/cfitsio/ricecomp.h +0 -0
  215. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/libspng/LICENSE +0 -0
  216. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/libspng/spng.c +0 -0
  217. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/libspng/spng.h +0 -0
  218. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_eer/LICENSE +0 -0
  219. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_eer/oc_eer.c +0 -0
  220. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_eer/oc_eer.h +0 -0
  221. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_giflzw/LICENSE +0 -0
  222. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_giflzw/oc_giflzw.c +0 -0
  223. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_giflzw/oc_giflzw.h +0 -0
  224. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_tifflzw/LICENSE +0 -0
  225. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_tifflzw/oc_tifflzw.c +0 -0
  226. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/oc_tifflzw/oc_tifflzw.h +0 -0
  227. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/qoi/LICENSE +0 -0
  228. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/qoi/qoi.h +0 -0
  229. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/rgbe/rgbe.c +0 -0
  230. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/rgbe/rgbe.h +0 -0
  231. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/rgbe/rgbe.txt +0 -0
  232. {opencodecs-0.2.0 → opencodecs-0.3.0}/3rdparty/vendor_hashes.json +0 -0
  233. {opencodecs-0.2.0 → opencodecs-0.3.0}/LICENSE +0 -0
  234. {opencodecs-0.2.0 → opencodecs-0.3.0}/bench/build_libjxl.sh +0 -0
  235. {opencodecs-0.2.0 → opencodecs-0.3.0}/patches/libjxl/README.md +0 -0
  236. {opencodecs-0.2.0 → opencodecs-0.3.0}/setup.cfg +0 -0
  237. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_bcn_codec.py +0 -0
  238. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_bmp_codec.py +0 -0
  239. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_bz2_codec.py +0 -0
  240. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_dicom_codec.py +0 -0
  241. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_dm.py +0 -0
  242. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_dm_codec.py +0 -0
  243. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_emd_codec.py +0 -0
  244. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_ets.py +0 -0
  245. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_gzip_codec.py +0 -0
  246. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_hdf5_http.py +0 -0
  247. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_htj2k_pyramid.py +0 -0
  248. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_jpeg2k_pyramid.py +0 -0
  249. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_jpeg_pyramid.py +0 -0
  250. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_lif_codec.py +0 -0
  251. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_lif_native.py +0 -0
  252. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_lzma_codec.py +0 -0
  253. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_mozjpeg_pyramid.py +0 -0
  254. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_mrc.py +0 -0
  255. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_nd2_codec.py +0 -0
  256. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_ndtiff_pyramid.py +0 -0
  257. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_nifti.py +0 -0
  258. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_nrrd.py +0 -0
  259. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_nrrd_codec.py +0 -0
  260. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_numpy_reader.py +0 -0
  261. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_ole2.py +0 -0
  262. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_ome_xml.py +0 -0
  263. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_pyramid_build.py +0 -0
  264. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_quantize_codec.py +0 -0
  265. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_rgbe.py +0 -0
  266. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_scaled_pyramid.py +0 -0
  267. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_ultrahdr_codec.py +0 -0
  268. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_vsi_codec.py +0 -0
  269. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/_zarr_codecs.py +0 -0
  270. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_aec.pyx +0 -0
  271. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_bcdec.pyx +0 -0
  272. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_bitshuffle.pyx +0 -0
  273. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_bmp.pyx +0 -0
  274. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_charls.pyx +0 -0
  275. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_deflate.pyx +0 -0
  276. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_eer.pyx +0 -0
  277. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_hcomp.pyx +0 -0
  278. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_isal.pyx +0 -0
  279. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_lerc.pyx +0 -0
  280. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_ndtiff.pyx +0 -0
  281. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_openjph.pyx +0 -0
  282. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_pcodec.pyx +0 -0
  283. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_plio.pyx +0 -0
  284. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_qoi.pyx +0 -0
  285. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_registry.py +0 -0
  286. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_rgbe.pyx +0 -0
  287. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_snappy.pyx +0 -0
  288. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_sz3.pyx +0 -0
  289. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_uhdr.pyx +0 -0
  290. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/_webp.pyx +0 -0
  291. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/bcdec.pxd +0 -0
  292. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/bitshuffle.pxd +0 -0
  293. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/brunsli.pxd +0 -0
  294. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/charls.pxd +0 -0
  295. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/eer.pxd +0 -0
  296. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/giflib.pxd +0 -0
  297. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/heif_shim.h +0 -0
  298. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/isal_shim.c +0 -0
  299. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/lerc.pxd +0 -0
  300. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/libaec.pxd +0 -0
  301. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/libjxl.pxd +0 -0
  302. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/libuhdr.pxd +0 -0
  303. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/mozjpeg.pxd +0 -0
  304. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/openjph.pxd +0 -0
  305. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/openjph_shim.cpp +0 -0
  306. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/openjph_shim.h +0 -0
  307. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/pcodec.pxd +0 -0
  308. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/qoi.pxd +0 -0
  309. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/rgbe.pxd +0 -0
  310. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/snappy.pxd +0 -0
  311. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/sperr.pxd +0 -0
  312. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/sz3c.pxd +0 -0
  313. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/turbojpeg.pxd +0 -0
  314. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/webp.pxd +0 -0
  315. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/webp_shim.c +0 -0
  316. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/webp_shim.h +0 -0
  317. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/zfp.pxd +0 -0
  318. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/codecs/zlib_h.pxd +0 -0
  319. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/__init__.py +0 -0
  320. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/_optional_backend.py +0 -0
  321. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/_sidecar_header.py +0 -0
  322. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/color.py +0 -0
  323. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/core/errors.py +0 -0
  324. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/jxl.py +0 -0
  325. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/parallel.py +0 -0
  326. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/tiff_reader.py +0 -0
  327. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/tifffile_patch.py +0 -0
  328. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/uhdr.py +0 -0
  329. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs/zarr.py +0 -0
  330. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs.egg-info/dependency_links.txt +0 -0
  331. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs.egg-info/requires.txt +0 -0
  332. {opencodecs-0.2.0 → opencodecs-0.3.0}/src/opencodecs.egg-info/top_level.txt +0 -0
  333. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_auto_pyramid.py +0 -0
  334. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_avif_sequence.py +0 -0
  335. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_bcdec.py +0 -0
  336. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_bcn_bands.py +0 -0
  337. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_blosc2_partial.py +0 -0
  338. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_brunsli.py +0 -0
  339. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_charls.py +0 -0
  340. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_chunked_means_cheap.py +0 -0
  341. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_codec_registry.py +0 -0
  342. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_core_codec_api.py +0 -0
  343. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus.py +0 -0
  344. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus_codec_decode.py +0 -0
  345. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus_manifest.py +0 -0
  346. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus_native_fixtures.py +0 -0
  347. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus_other.py +0 -0
  348. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus_png.py +0 -0
  349. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus_tiff.py +0 -0
  350. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_corpus_vendors.py +0 -0
  351. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_coverage_final.py +0 -0
  352. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_coverage_finishing.py +0 -0
  353. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_coverage_last.py +0 -0
  354. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_coverage_more.py +0 -0
  355. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_coverage_push.py +0 -0
  356. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_czi_fixture.py +0 -0
  357. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_czi_pyramid.py +0 -0
  358. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_data_source.py +0 -0
  359. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_decode_releases_gil.py +0 -0
  360. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_deflate.py +0 -0
  361. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_delta_parity.py +0 -0
  362. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dicom.py +0 -0
  363. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dicom_encodings.py +0 -0
  364. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dicom_parallel.py +0 -0
  365. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dicom_wsi_pyramid.py +0 -0
  366. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dm.py +0 -0
  367. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dm_offsets.py +0 -0
  368. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_dm_synthetic.py +0 -0
  369. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_edge_cases.py +0 -0
  370. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_eer.py +0 -0
  371. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_eer_parallel.py +0 -0
  372. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_emd.py +0 -0
  373. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_encode_comprehensive.py +0 -0
  374. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_error_handling.py +0 -0
  375. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_fits.py +0 -0
  376. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_fits_parallel.py +0 -0
  377. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_gif.py +0 -0
  378. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_gzip_presized.py +0 -0
  379. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_hdf5_http.py +0 -0
  380. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_hdf5_local.py +0 -0
  381. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_hdf5_parallel.py +0 -0
  382. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_heif_avif_features.py +0 -0
  383. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_heif_multi_image.py +0 -0
  384. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_htj2k_conformance.py +0 -0
  385. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_http_byte_savings.py +0 -0
  386. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_http_prefetch.py +0 -0
  387. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_http_unified.py +0 -0
  388. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_imaris.py +0 -0
  389. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_io_chunked.py +0 -0
  390. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_isal.py +0 -0
  391. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_jpeg2k_region.py +0 -0
  392. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_jxl.py +0 -0
  393. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_lif_indexing.py +0 -0
  394. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_lif_native.py +0 -0
  395. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_live_archives.py +0 -0
  396. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_mozjpeg.py +0 -0
  397. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_mrc.py +0 -0
  398. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_mrc_mrcz_http.py +0 -0
  399. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_mrc_nifti_writers.py +0 -0
  400. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_n5.py +0 -0
  401. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_native_parity.py +0 -0
  402. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_nifti.py +0 -0
  403. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_nrrd.py +0 -0
  404. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_nrrd_slices.py +0 -0
  405. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_offset_readers.py +0 -0
  406. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_oib_indexing.py +0 -0
  407. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_oib_native.py +0 -0
  408. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_ome_xml.py +0 -0
  409. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_openjph.py +0 -0
  410. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_optional_backend.py +0 -0
  411. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_parallel_jxl.py +0 -0
  412. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_phase4_filters.py +0 -0
  413. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_phase5_icc.py +0 -0
  414. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_phase6_codecs.py +0 -0
  415. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_rcomp_truncated_input.py +0 -0
  416. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_reader_contract.py +0 -0
  417. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_reader_source_kinds.py +0 -0
  418. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_reader_streaming.py +0 -0
  419. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_reference_parity.py +0 -0
  420. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_rgbe.py +0 -0
  421. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_scaled_pyramid.py +0 -0
  422. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_sidecar_header.py +0 -0
  423. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_snappy.py +0 -0
  424. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_streaming_means_streaming.py +0 -0
  425. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tier1_scientific.py +0 -0
  426. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_codec_encode.py +0 -0
  427. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_http.py +0 -0
  428. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_native.py +0 -0
  429. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_parallel_decode.py +0 -0
  430. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_pyramid.py +0 -0
  431. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_read_path.py +0 -0
  432. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_reader.py +0 -0
  433. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tiff_writer.py +0 -0
  434. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_tifffile_patch.py +0 -0
  435. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_uhdr.py +0 -0
  436. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_unified_api.py +0 -0
  437. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_url_sources.py +0 -0
  438. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_vendor_provenance.py +0 -0
  439. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_version_consistency.py +0 -0
  440. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_vsi_oir.py +0 -0
  441. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_vsi_pyramid.py +0 -0
  442. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_webp_animation.py +0 -0
  443. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_zarr_adapters.py +0 -0
  444. {opencodecs-0.2.0 → opencodecs-0.3.0}/tests/test_zfp_blocks.py +0 -0
@@ -10,6 +10,104 @@ 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.3.0 (2026-09-27)
14
+ ------------------
15
+
16
+ Mostly a speed release. Figures below compare against 0.2.0 unless they
17
+ say otherwise; the README's Performance section has the full table for a
18
+ Mac and a Linux workstation.
19
+
20
+ **Shared bounded pipeline across readers and writers**
21
+
22
+ A common layer in ``opencodecs.core`` now carries the work that each
23
+ format used to do its own way: ordered, byte-bounded parallel
24
+ scheduling (``core.pipeline.map_bounded``) with a shared worker
25
+ budget, per-worker scratch buffers, caller-owned output buffers and
26
+ sinks for the native codecs, stateful streaming iterators for seven
27
+ byte codecs, native PNG row sessions, selective range sources, and
28
+ opt-in bit-exact verification of written segments. Each piece of work
29
+ is recorded, with its measured limits, in ``pipeline_catalog.toml``
30
+ and checked by ``ci/check_pipeline_catalog.py``.
31
+
32
+ **Zarr, TIFF and blosc2 under many threads**
33
+
34
+ - Zarr regional reads can run in parallel, with ``num_workers`` on
35
+ ``read_region`` or ``OmeZarrArray``; the default stays serial. Chunks
36
+ are grouped into tasks of about 2 MiB on a persistent pool, chunk files
37
+ are read with os-level calls, and plain zstd chunks decompress straight
38
+ into the output. A 4096 x 4096 array in 256 x 256 chunks, 0.2.0's serial
39
+ read against eight workers: zstd 72.9 to 19.6 ms on Linux (50.1 to
40
+ 14.9 ms on macOS), zlib 184 to 38.8 ms (80.5 to 25.9 ms).
41
+ - Zarr v2 ``blosc`` chunks decode through the native blosc2 extension
42
+ instead of numcodecs, whose binding serializes calls across threads:
43
+ the default serial read goes 37.5 to 20.0 ms on macOS and 35.1 to
44
+ 29.4 ms on Linux.
45
+ - Fix: blosc2 encode selected its compressor through process-global
46
+ state, so concurrent encodes could use another thread's compressor.
47
+ Encode, decode and partial decode now each use a context of their own,
48
+ which also stops them queuing on blosc2's global mutex: from eight
49
+ threads, 64 chunks of 1 MiB decode 6.2 to 6.5x and encode 6.6 to 7.1x
50
+ faster. Chunks written with item size 1 and shuffle carry slightly
51
+ different header flags; old and new chunks decode in both versions.
52
+ - TIFF tiles with the horizontal predictor decode into a writable array,
53
+ so the predictor no longer copies each tile first (1.1 to 1.2x on a
54
+ tiled 4096 x 4096 deflate image).
55
+
56
+ **CZI: faster reads and writes, and real slides read correctly**
57
+
58
+ - JPEG XR sub-blocks (compression 4, used by most Zeiss slide scans) now
59
+ decode through a new optional ``_jpegxr`` extension over jxrlib, built
60
+ when jxrlib is installed. Every tile of the Axioscan corpus slide and its
61
+ whole 20684 x 32751 level 0 match czifile exactly. The wheels build
62
+ jxrlib from source (conda-forge on Windows) and link it statically.
63
+ - Fix: overlapping mosaic tiles composed in directory order. Zen writes
64
+ tiles out of mosaic-index order, and libCZI and czifile draw the higher
65
+ mosaic index on top; each level now composes in that order, which on the
66
+ corpus slide changes 8.9 million overlap pixels at level 0.
67
+ - Fix: ``CziPyramidReader`` took sub-block starts as level pixels.
68
+ Zen stores them in full-resolution slide coordinates, often far from
69
+ zero and negative, so a real slide reported every level as ``(N, 0)``.
70
+ Levels now count from the slide origin (``reader.origin``, matching
71
+ czifile) and divide positions by the level's scale.
72
+ - Sub-blocks decode straight into their destination. Whole-stack
73
+ ``read`` accepts ``out=`` (``numpy.memmap`` included). zstd
74
+ decompression and the byte unshuffle run as one native call, which
75
+ let several threads decode small tiles at once: a stack read with eight
76
+ workers goes 12.0 to 3.9 ms on Linux (2.5 to 1.7 ms on macOS).
77
+ - Regional reads use a lazily built spatial index and write each tile
78
+ straight into the output; overlapping tiles still resolve to the
79
+ later one in the directory. ``PyramidReader.read_regions`` decodes
80
+ the union of a batch of boxes once, and ``decoded_cache_bytes`` adds
81
+ an opt-in decoded-tile cache.
82
+ - Opening is faster: the directory parses in about a third of the
83
+ time and the pyramid reader no longer rescans it per level (180 ms to
84
+ 3 ms on a 12k-sub-block slide).
85
+ - ``read_regions`` on CZI decodes each tile shared by several boxes once,
86
+ straight into every box's output: 50 disjoint crops take 5.1 ms on
87
+ Linux against 29.8 ms one call at a time in 0.2.0 (3.1 against 17.2 ms
88
+ on macOS).
89
+ - The writer shuffles natively, emits sub-blocks as parts without
90
+ copying unverified payloads, and ``write_many`` compresses frames on
91
+ workers while keeping the file byte-identical to sequential writes.
92
+ Eight 2048 x 2048 frames with zstd: 189 to 89 ms one frame at a time on
93
+ Linux and 41 ms with ``write_many`` (82 to 54 and 20 ms on macOS).
94
+ - ``CziWriter(background_encode=True)`` compresses frames of 1 MiB or
95
+ more on a background thread while the caller prepares the next one.
96
+ Opt-in: with work between frames it wrote 1.44 to 1.46x faster, with
97
+ frames ready and nothing to overlap it was 0.87 to 0.96x.
98
+
99
+ **Build and tests**
100
+
101
+ - Every wheel now carries the same 40 compiled extensions, the 39 of
102
+ 0.2.0 plus ``_jpegxr``, and ``ci/check_wheel_contents.py`` requires it.
103
+ - SZ3 3.3.2, since upstream deleted the 3.3.1 tag.
104
+ - The DICOMweb client is tested over HTTP against a local server
105
+ (``tests/_dicomweb_server.py``) serving a synthetic study written by
106
+ reference encoders, instead of a public demo server.
107
+ - Fix: the pipeline catalog check accepted a rooted evidence path such
108
+ as ``/etc/passwd`` on Windows, where ``Path.is_absolute()`` needs a
109
+ drive letter.
110
+
13
111
  0.2.0 (2026-09-09)
14
112
  ------------------
15
113
 
@@ -1029,9 +1127,9 @@ streaming write-out without changing their code.
1029
1127
  * Locally validated on a Windows VM (MSVC 14.44 — same as CI) and
1030
1128
  a Linux x86_64 host: ``bash bench/build_codec_libs.sh
1031
1129
  --only=mozjpeg`` followed by ``setup.py build_ext --inplace``
1032
- produces ``_mozjpeg.{pyd,so}`` cleanly. Per the new lesson in
1033
- CLAUDE.md, this iteration was validated end-to-end through the
1034
- same script CI runs, with the same env vars, before any push.
1130
+ produces ``_mozjpeg.{pyd,so}`` cleanly. This iteration was validated
1131
+ end-to-end through the same script CI runs, with the same env vars,
1132
+ before any push.
1035
1133
 
1036
1134
  **Post-publish wheel coverage check (CI hardening)**
1037
1135
 
@@ -21,6 +21,7 @@ recursive-include src/opencodecs *.pyx *.pxd *.h *.hpp
21
21
  include src/opencodecs/codecs/b2nd_helpers.c
22
22
  include src/opencodecs/codecs/isal_shim.c
23
23
  include src/opencodecs/codecs/webp_shim.c
24
+ include src/opencodecs/codecs/jpegxr_shim.c
24
25
  include src/opencodecs/codecs/openjph_shim.cpp
25
26
  recursive-include 3rdparty *.c *.h *.hpp *.md *.rst *.txt *.toml *.json
26
27
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencodecs
3
- Version: 0.2.0
3
+ Version: 0.3.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
@@ -297,9 +297,14 @@ with open_remote_hdf5("https://bucket.s3.amazonaws.com/big.h5") as f:
297
297
  arr = f["img"][:1024, :1024] # all from cache
298
298
  ```
299
299
 
300
- `czi` decodes types 0 (uncompressed) and 6 (ZSTDHDR) — the entire
301
- modern Zen archive. JPEG-XR sub-blocks (rare in 2022+ output) raise
302
- `NotImplementedError`. The reader exposes `metadata_bytes` and
300
+ `czi` decodes compression types 0 (uncompressed), 5 (zstd), 6 (ZSTDHDR)
301
+ and 4 (JPEG XR). JPEG XR, which most Zeiss slide scans use, needs the
302
+ optional `_jpegxr` extension, built when jxrlib is installed (Homebrew
303
+ `jxrlib`, conda-forge `jxrlib`, Debian/Ubuntu `libjxr-dev`). The wheels
304
+ carry it from 0.3.0 on, statically linked on every platform. A JPEG XR
305
+ sub-block without it raises `CziError`. Pyramid levels are placed from the slide origin and scale, and
306
+ overlapping mosaic tiles compose with the higher mosaic index on top, as
307
+ libCZI and czifile do. The reader exposes `metadata_bytes` and
303
308
  `metadata_xml` as lazy zero-copy accessors.
304
309
 
305
310
  ### zarr v3 codecs
@@ -320,8 +325,66 @@ z = zarr.create_array(
320
325
 
321
326
  ## Performance
322
327
 
328
+ ### 0.3.0 against 0.2.0
329
+
330
+ 0.3.0 is mostly a speed release. Each row below ran both versions in fresh
331
+ processes on the same inputs, alternating which went first, and counts only
332
+ where both returned identical pixels. Medians in milliseconds, on a 20-core
333
+ Apple silicon Mac and a 64-core x86-64 Linux workstation.
334
+
335
+ | Workload | Mac 0.2.0 | Mac 0.3.0 | Mac speedup | Linux 0.2.0 | Linux 0.3.0 | Linux speedup |
336
+ |---|---:|---:|---:|---:|---:|---:|
337
+ | CZI | | | | | | |
338
+ | Open a whole-slide file | 77.6 | 27.9 | 2.8x | 88.4 | 48.7 | 1.8x |
339
+ | Open it and read the first crop | 255 | 39.1 | 6.5x | 267 | 58.7 | 4.6x |
340
+ | Build the pyramid reader | 174 | 3.4 | 51.1x | 164 | 4.7 | 35.0x |
341
+ | Read a 20 x 20 tile mosaic | 23.9 | 10.1 | 2.4x | 55.8 | 18.4 | 3.0x |
342
+ | Small crops of the mosaic | 69.5 | 26.6 | 2.6x | 121 | 54.7 | 2.2x |
343
+ | 50 disjoint crops, one call each | 17.2 | 6.7 | 2.6x | 29.8 | 11.3 | 2.6x |
344
+ | 50 disjoint crops, `read_regions` | 17.2 | 3.1 | 5.5x | 29.8 | 5.1 | 5.9x |
345
+ | Stack read, 8 workers | 2.5 | 1.7 | 1.5x | 12.0 | 3.9 | 3.1x |
346
+ | Write 8 frames, zstd | 82.1 | 53.9 | 1.5x | 189 | 89.3 | 2.1x |
347
+ | Write 8 frames, zstd, `write_many` | 82.1 | 19.9 | 4.1x | 189 | 40.9 | 4.6x |
348
+ | Write 8 frames, uncompressed | 28.9 | 10.1 | 2.8x | 226 | 38.3 | 5.9x |
349
+ | Zarr, 4096 x 4096 uint16 in 256 x 256 chunks, whole array | | | | | | |
350
+ | v2 zstd, default | 50.1 | 45.6 | 1.1x | 72.9 | 62.2 | 1.2x |
351
+ | v2 zstd, `num_workers=8` | 50.1 | 14.9 | 3.4x | 72.9 | 19.6 | 3.7x |
352
+ | v2 zlib, `num_workers=8` | 80.5 | 25.9 | 3.1x | 184 | 38.8 | 4.7x |
353
+ | v2 blosc, default | 37.5 | 20.0 | 1.9x | 35.1 | 29.4 | 1.2x |
354
+ | v3 zstd, `num_workers=8` | 51.3 | 14.6 | 3.5x | 62.1 | 19.4 | 3.2x |
355
+ | blosc2 from 8 threads, 64 chunks of 1 MiB | | | | | | |
356
+ | Decode | 25.4 | 3.9 | 6.5x | 38.0 | 6.1 | 6.2x |
357
+ | Encode | 32.9 | 5.0 | 6.6x | 47.9 | 6.8 | 7.1x |
358
+ | TIFF | | | | | | |
359
+ | Tiled, deflate with horizontal predictor, 4096 x 4096 | 20.5 | 17.5 | 1.2x | 25.4 | 23.4 | 1.1x |
360
+
361
+ Rows that name `num_workers=8`, `read_regions` or `write_many` use options
362
+ new in 0.3.0; they are compared with the only way 0.2.0 could do the same
363
+ work. Zarr regional reads stay serial unless you pass `num_workers`
364
+ (to `read_region` or `OmeZarrArray`).
365
+
366
+ Where it comes from:
367
+
368
+ - **CZI**: the directory parses with precompiled structs, pyramid levels
369
+ are grouped once instead of per level, and each tile is decompressed,
370
+ unshuffled and written into the output in one native call that releases
371
+ the GIL once. Separate calls made threads queue for the GIL between
372
+ steps. Regional reads use a spatial index and decode only the tiles a
373
+ box touches; `read_regions` decodes a tile shared by several boxes once.
374
+ - **Zarr**: parallel regional reads are new, with consecutive chunks
375
+ batched into tasks of about 2 MiB, plain zstd chunks decompressed
376
+ straight into the output, and v2 blosc chunks decoded through the native
377
+ blosc2 extension rather than numcodecs, whose binding serializes calls
378
+ across threads.
379
+ - **blosc2**: each call now has its own compression context. The old path
380
+ selected the compressor through process-global state behind a global
381
+ mutex, which serialized every thread and could hand one thread another's
382
+ compressor (a correctness bug, also fixed).
383
+
384
+ ### Across releases
385
+
323
386
  Headline numbers from the latest bench run (`bench/run_benchmarks.py
324
- --fast`, macOS M1 Ultra, vs `imagecodecs` / `tifffile` / `ndstorage`):
387
+ --fast`, Apple silicon Mac, vs `imagecodecs` / `tifffile` / `ndstorage`):
325
388
 
326
389
  | Workload | opencodecs | reference | ratio |
327
390
  |---|---:|---:|---:|
@@ -354,7 +417,7 @@ to 8× wall-clock).
354
417
  Scientific microscopy CZI (66 MB, 14 sub-blocks of 2000×2000 uint16,
355
418
  ZSTDHDR), single-file warm cache:
356
419
 
357
- | Reader | Mac M3 | Threadripper x86_64 |
420
+ | Reader | Apple silicon Mac | x86-64 Linux |
358
421
  |---------------|-------:|--------------------:|
359
422
  | czifile (Python ref) | 148 ms | 414 ms |
360
423
  | aicspylibczi (C++) | 17 ms | 140 ms |
@@ -396,9 +459,12 @@ caps = tomllib.load(open("capabilities.toml", "rb"))["codec"]
396
459
  [c["name"] for c in caps if c["pyramid"]] # codecs with a pyramid reader
397
460
  ```
398
461
 
399
- The manifest covers the codec registry, so the reader-only backends
400
- (Imaris, OME-Zarr, NDTiff, N5) are not in it; they are listed in the
401
- tables above and reached through `open_pyramid` / their own classes.
462
+ The runtime manifest covers the codec registry. The companion
463
+ [pipeline catalog](pipeline_catalog.toml) also covers direct adapters such as
464
+ Imaris, OME-Zarr, NDTiff and N5, and maps shared optimization work across all
465
+ registered codecs. See the [implementation plan](docs/pipeline_optimization_plan.md)
466
+ for priorities, source evidence, correctness prerequisites and acceptance tests.
467
+ Run `python ci/check_pipeline_catalog.py report` for the current worklist.
402
468
 
403
469
  ### Codec registry
404
470
 
@@ -543,10 +609,12 @@ prefix = jxl.thumbnail_bytes("scan.jxl")
543
609
  pip install opencodecs
544
610
  ```
545
611
 
546
- Wheels are published for CPython 3.10–3.13 on macOS (arm64),
547
- Linux (x86_64 + aarch64), and Windows (amd64). Each wheel
548
- bundles libjxl, libavif, libheif, libwebp, libdeflate,
549
- c-blosc2, and friends — no system dependencies needed.
612
+ Wheels are published for CPython 3.10 to 3.13 on macOS 15+ (arm64),
613
+ Linux (x86_64 + aarch64, manylinux_2_28), and Windows (amd64). Every
614
+ platform ships the same 39 compiled extensions, bundling libjxl,
615
+ libavif, libheif, libwebp, libdeflate, c-blosc2, CharLS and friends,
616
+ so no system dependencies are needed. Intel Macs and macOS releases
617
+ older than 15 install from the sdist instead.
550
618
 
551
619
  For a source install, system development headers, or to build a
552
620
  tuned local libjxl, see [INSTALL.md](INSTALL.md). Wheel publishing
@@ -569,29 +637,41 @@ build).
569
637
 
570
638
  ## Status
571
639
 
572
- - **v0.1.1** on PyPI (May 2026). Core API stable; **1066 tests passing**
573
- on Mac M1 Ultra + Linux x86_64/aarch64 + Windows VM
574
- - Native readers + writers for the common scientific containers
575
- (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL, FITS,
576
- OME-Zarr v2 + v3 sharded)
577
- - Cross-platform bench coverage: Mac arm64 (canonical), Windows 11 LTSC
578
- (libvirt VM), Linux x86_64 (Threadripper-class)
640
+ - **v0.3.0** on PyPI (September 2026). Every wheel carries the same 40
641
+ compiled extensions, and `ci/check_wheel_contents.py` fails the
642
+ release build if one goes missing.
643
+ - About 4,000 tests locally, including a 40-dataset conformance corpus;
644
+ CI runs the corpus-independent suite on macOS, Linux and Windows for
645
+ Python 3.10 and 3.13.
646
+ - Native readers and writers for the common scientific containers
647
+ (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL, FITS, OME-Zarr v2 +
648
+ v3 sharded), and pyramid readers for TIFF/COG/SVS, OME-Zarr, CZI,
649
+ Imaris, DICOM VL Whole Slide Microscopy and Olympus VSI/ETS
650
+ - Shared source adapters support paths, buffers, file objects and remote URLs.
651
+ Indexed readers use checked range requests, covering caches and adaptive
652
+ read-ahead; whole-stream codecs retain their documented eager input paths.
653
+ - Multi-frame AVIF, animated WebP and GIF decode to a frame stack; HEIF
654
+ exposes every top-level image
579
655
  - Compression backend auto-detect (libdeflate → zlib-ng-compat → stdlib)
580
- - Cloud I/O primitives (`HTTPDataSource` with covering-cache + adaptive
581
- read-ahead) wired into TIFF / HDF5 / DICOMweb / CZI / FITS / Zarr v3
582
- readers
583
656
  - `tifffile_patch` opt-in shim reroutes tifffile's codec dispatch through
584
657
  opencodecs for users who want only a partial swap
658
+ - `capabilities.toml` records what each codec actually supports, checked
659
+ against the built extensions, with no open gaps
585
660
 
586
661
  Deferred work (see [`docs/TODO_DEFERRED.md`](docs/TODO_DEFERRED.md)):
587
662
 
588
- - **Windows wheels currently miss `_sz3`, `_pcodec`, `_sperr`, `_brunsli`**
589
- — toolchain mismatch (conda's bash picks GCC over MSVC for CMake);
590
- v0.1.2 will restore them. macOS + Linux wheels have the full set.
591
- - CCITT Fax3/Fax4 encode — legacy fax; zero scientific users
592
- - JPEG-XR — abandoned format outside niche DICOM
593
- - libspng `filter_sum` SIMD — off the bench-tracked workload (`h2h_png_4mp_rgb`
594
- is at 1.14× already); filter-bound PNG-encode users could see another 2-3×
663
+ - CCITT Fax3/Fax4 encode: legacy fax, zero scientific users
664
+ - JPEG XR encode (decode exists for CZI; see above)
665
+
666
+ GIF and JPEG XL destination writers now drain encoded frame output before close.
667
+ The shared pipeline also supplies bounded independent-piece scheduling, seven
668
+ stateful byte-codec iterators, native PNG row sessions, selective native sources,
669
+ and checked caller-owned destinations.
670
+
671
+ Shared streaming, buffering, and overlap mechanisms and remaining integration
672
+ work are documented in [the pipeline catalog](docs/shared_pipeline_capabilities.md).
673
+
674
+ See [CHANGES.rst](CHANGES.rst) for release history.
595
675
 
596
676
  ## License
597
677
 
@@ -245,9 +245,14 @@ with open_remote_hdf5("https://bucket.s3.amazonaws.com/big.h5") as f:
245
245
  arr = f["img"][:1024, :1024] # all from cache
246
246
  ```
247
247
 
248
- `czi` decodes types 0 (uncompressed) and 6 (ZSTDHDR) — the entire
249
- modern Zen archive. JPEG-XR sub-blocks (rare in 2022+ output) raise
250
- `NotImplementedError`. The reader exposes `metadata_bytes` and
248
+ `czi` decodes compression types 0 (uncompressed), 5 (zstd), 6 (ZSTDHDR)
249
+ and 4 (JPEG XR). JPEG XR, which most Zeiss slide scans use, needs the
250
+ optional `_jpegxr` extension, built when jxrlib is installed (Homebrew
251
+ `jxrlib`, conda-forge `jxrlib`, Debian/Ubuntu `libjxr-dev`). The wheels
252
+ carry it from 0.3.0 on, statically linked on every platform. A JPEG XR
253
+ sub-block without it raises `CziError`. Pyramid levels are placed from the slide origin and scale, and
254
+ overlapping mosaic tiles compose with the higher mosaic index on top, as
255
+ libCZI and czifile do. The reader exposes `metadata_bytes` and
251
256
  `metadata_xml` as lazy zero-copy accessors.
252
257
 
253
258
  ### zarr v3 codecs
@@ -268,8 +273,66 @@ z = zarr.create_array(
268
273
 
269
274
  ## Performance
270
275
 
276
+ ### 0.3.0 against 0.2.0
277
+
278
+ 0.3.0 is mostly a speed release. Each row below ran both versions in fresh
279
+ processes on the same inputs, alternating which went first, and counts only
280
+ where both returned identical pixels. Medians in milliseconds, on a 20-core
281
+ Apple silicon Mac and a 64-core x86-64 Linux workstation.
282
+
283
+ | Workload | Mac 0.2.0 | Mac 0.3.0 | Mac speedup | Linux 0.2.0 | Linux 0.3.0 | Linux speedup |
284
+ |---|---:|---:|---:|---:|---:|---:|
285
+ | CZI | | | | | | |
286
+ | Open a whole-slide file | 77.6 | 27.9 | 2.8x | 88.4 | 48.7 | 1.8x |
287
+ | Open it and read the first crop | 255 | 39.1 | 6.5x | 267 | 58.7 | 4.6x |
288
+ | Build the pyramid reader | 174 | 3.4 | 51.1x | 164 | 4.7 | 35.0x |
289
+ | Read a 20 x 20 tile mosaic | 23.9 | 10.1 | 2.4x | 55.8 | 18.4 | 3.0x |
290
+ | Small crops of the mosaic | 69.5 | 26.6 | 2.6x | 121 | 54.7 | 2.2x |
291
+ | 50 disjoint crops, one call each | 17.2 | 6.7 | 2.6x | 29.8 | 11.3 | 2.6x |
292
+ | 50 disjoint crops, `read_regions` | 17.2 | 3.1 | 5.5x | 29.8 | 5.1 | 5.9x |
293
+ | Stack read, 8 workers | 2.5 | 1.7 | 1.5x | 12.0 | 3.9 | 3.1x |
294
+ | Write 8 frames, zstd | 82.1 | 53.9 | 1.5x | 189 | 89.3 | 2.1x |
295
+ | Write 8 frames, zstd, `write_many` | 82.1 | 19.9 | 4.1x | 189 | 40.9 | 4.6x |
296
+ | Write 8 frames, uncompressed | 28.9 | 10.1 | 2.8x | 226 | 38.3 | 5.9x |
297
+ | Zarr, 4096 x 4096 uint16 in 256 x 256 chunks, whole array | | | | | | |
298
+ | v2 zstd, default | 50.1 | 45.6 | 1.1x | 72.9 | 62.2 | 1.2x |
299
+ | v2 zstd, `num_workers=8` | 50.1 | 14.9 | 3.4x | 72.9 | 19.6 | 3.7x |
300
+ | v2 zlib, `num_workers=8` | 80.5 | 25.9 | 3.1x | 184 | 38.8 | 4.7x |
301
+ | v2 blosc, default | 37.5 | 20.0 | 1.9x | 35.1 | 29.4 | 1.2x |
302
+ | v3 zstd, `num_workers=8` | 51.3 | 14.6 | 3.5x | 62.1 | 19.4 | 3.2x |
303
+ | blosc2 from 8 threads, 64 chunks of 1 MiB | | | | | | |
304
+ | Decode | 25.4 | 3.9 | 6.5x | 38.0 | 6.1 | 6.2x |
305
+ | Encode | 32.9 | 5.0 | 6.6x | 47.9 | 6.8 | 7.1x |
306
+ | TIFF | | | | | | |
307
+ | Tiled, deflate with horizontal predictor, 4096 x 4096 | 20.5 | 17.5 | 1.2x | 25.4 | 23.4 | 1.1x |
308
+
309
+ Rows that name `num_workers=8`, `read_regions` or `write_many` use options
310
+ new in 0.3.0; they are compared with the only way 0.2.0 could do the same
311
+ work. Zarr regional reads stay serial unless you pass `num_workers`
312
+ (to `read_region` or `OmeZarrArray`).
313
+
314
+ Where it comes from:
315
+
316
+ - **CZI**: the directory parses with precompiled structs, pyramid levels
317
+ are grouped once instead of per level, and each tile is decompressed,
318
+ unshuffled and written into the output in one native call that releases
319
+ the GIL once. Separate calls made threads queue for the GIL between
320
+ steps. Regional reads use a spatial index and decode only the tiles a
321
+ box touches; `read_regions` decodes a tile shared by several boxes once.
322
+ - **Zarr**: parallel regional reads are new, with consecutive chunks
323
+ batched into tasks of about 2 MiB, plain zstd chunks decompressed
324
+ straight into the output, and v2 blosc chunks decoded through the native
325
+ blosc2 extension rather than numcodecs, whose binding serializes calls
326
+ across threads.
327
+ - **blosc2**: each call now has its own compression context. The old path
328
+ selected the compressor through process-global state behind a global
329
+ mutex, which serialized every thread and could hand one thread another's
330
+ compressor (a correctness bug, also fixed).
331
+
332
+ ### Across releases
333
+
271
334
  Headline numbers from the latest bench run (`bench/run_benchmarks.py
272
- --fast`, macOS M1 Ultra, vs `imagecodecs` / `tifffile` / `ndstorage`):
335
+ --fast`, Apple silicon Mac, vs `imagecodecs` / `tifffile` / `ndstorage`):
273
336
 
274
337
  | Workload | opencodecs | reference | ratio |
275
338
  |---|---:|---:|---:|
@@ -302,7 +365,7 @@ to 8× wall-clock).
302
365
  Scientific microscopy CZI (66 MB, 14 sub-blocks of 2000×2000 uint16,
303
366
  ZSTDHDR), single-file warm cache:
304
367
 
305
- | Reader | Mac M3 | Threadripper x86_64 |
368
+ | Reader | Apple silicon Mac | x86-64 Linux |
306
369
  |---------------|-------:|--------------------:|
307
370
  | czifile (Python ref) | 148 ms | 414 ms |
308
371
  | aicspylibczi (C++) | 17 ms | 140 ms |
@@ -344,9 +407,12 @@ caps = tomllib.load(open("capabilities.toml", "rb"))["codec"]
344
407
  [c["name"] for c in caps if c["pyramid"]] # codecs with a pyramid reader
345
408
  ```
346
409
 
347
- The manifest covers the codec registry, so the reader-only backends
348
- (Imaris, OME-Zarr, NDTiff, N5) are not in it; they are listed in the
349
- tables above and reached through `open_pyramid` / their own classes.
410
+ The runtime manifest covers the codec registry. The companion
411
+ [pipeline catalog](pipeline_catalog.toml) also covers direct adapters such as
412
+ Imaris, OME-Zarr, NDTiff and N5, and maps shared optimization work across all
413
+ registered codecs. See the [implementation plan](docs/pipeline_optimization_plan.md)
414
+ for priorities, source evidence, correctness prerequisites and acceptance tests.
415
+ Run `python ci/check_pipeline_catalog.py report` for the current worklist.
350
416
 
351
417
  ### Codec registry
352
418
 
@@ -491,10 +557,12 @@ prefix = jxl.thumbnail_bytes("scan.jxl")
491
557
  pip install opencodecs
492
558
  ```
493
559
 
494
- Wheels are published for CPython 3.10–3.13 on macOS (arm64),
495
- Linux (x86_64 + aarch64), and Windows (amd64). Each wheel
496
- bundles libjxl, libavif, libheif, libwebp, libdeflate,
497
- c-blosc2, and friends — no system dependencies needed.
560
+ Wheels are published for CPython 3.10 to 3.13 on macOS 15+ (arm64),
561
+ Linux (x86_64 + aarch64, manylinux_2_28), and Windows (amd64). Every
562
+ platform ships the same 39 compiled extensions, bundling libjxl,
563
+ libavif, libheif, libwebp, libdeflate, c-blosc2, CharLS and friends,
564
+ so no system dependencies are needed. Intel Macs and macOS releases
565
+ older than 15 install from the sdist instead.
498
566
 
499
567
  For a source install, system development headers, or to build a
500
568
  tuned local libjxl, see [INSTALL.md](INSTALL.md). Wheel publishing
@@ -517,29 +585,41 @@ build).
517
585
 
518
586
  ## Status
519
587
 
520
- - **v0.1.1** on PyPI (May 2026). Core API stable; **1066 tests passing**
521
- on Mac M1 Ultra + Linux x86_64/aarch64 + Windows VM
522
- - Native readers + writers for the common scientific containers
523
- (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL, FITS,
524
- OME-Zarr v2 + v3 sharded)
525
- - Cross-platform bench coverage: Mac arm64 (canonical), Windows 11 LTSC
526
- (libvirt VM), Linux x86_64 (Threadripper-class)
588
+ - **v0.3.0** on PyPI (September 2026). Every wheel carries the same 40
589
+ compiled extensions, and `ci/check_wheel_contents.py` fails the
590
+ release build if one goes missing.
591
+ - About 4,000 tests locally, including a 40-dataset conformance corpus;
592
+ CI runs the corpus-independent suite on macOS, Linux and Windows for
593
+ Python 3.10 and 3.13.
594
+ - Native readers and writers for the common scientific containers
595
+ (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL, FITS, OME-Zarr v2 +
596
+ v3 sharded), and pyramid readers for TIFF/COG/SVS, OME-Zarr, CZI,
597
+ Imaris, DICOM VL Whole Slide Microscopy and Olympus VSI/ETS
598
+ - Shared source adapters support paths, buffers, file objects and remote URLs.
599
+ Indexed readers use checked range requests, covering caches and adaptive
600
+ read-ahead; whole-stream codecs retain their documented eager input paths.
601
+ - Multi-frame AVIF, animated WebP and GIF decode to a frame stack; HEIF
602
+ exposes every top-level image
527
603
  - Compression backend auto-detect (libdeflate → zlib-ng-compat → stdlib)
528
- - Cloud I/O primitives (`HTTPDataSource` with covering-cache + adaptive
529
- read-ahead) wired into TIFF / HDF5 / DICOMweb / CZI / FITS / Zarr v3
530
- readers
531
604
  - `tifffile_patch` opt-in shim reroutes tifffile's codec dispatch through
532
605
  opencodecs for users who want only a partial swap
606
+ - `capabilities.toml` records what each codec actually supports, checked
607
+ against the built extensions, with no open gaps
533
608
 
534
609
  Deferred work (see [`docs/TODO_DEFERRED.md`](docs/TODO_DEFERRED.md)):
535
610
 
536
- - **Windows wheels currently miss `_sz3`, `_pcodec`, `_sperr`, `_brunsli`**
537
- — toolchain mismatch (conda's bash picks GCC over MSVC for CMake);
538
- v0.1.2 will restore them. macOS + Linux wheels have the full set.
539
- - CCITT Fax3/Fax4 encode — legacy fax; zero scientific users
540
- - JPEG-XR — abandoned format outside niche DICOM
541
- - libspng `filter_sum` SIMD — off the bench-tracked workload (`h2h_png_4mp_rgb`
542
- is at 1.14× already); filter-bound PNG-encode users could see another 2-3×
611
+ - CCITT Fax3/Fax4 encode: legacy fax, zero scientific users
612
+ - JPEG XR encode (decode exists for CZI; see above)
613
+
614
+ GIF and JPEG XL destination writers now drain encoded frame output before close.
615
+ The shared pipeline also supplies bounded independent-piece scheduling, seven
616
+ stateful byte-codec iterators, native PNG row sessions, selective native sources,
617
+ and checked caller-owned destinations.
618
+
619
+ Shared streaming, buffering, and overlap mechanisms and remaining integration
620
+ work are documented in [the pipeline catalog](docs/shared_pipeline_capabilities.md).
621
+
622
+ See [CHANGES.rst](CHANGES.rst) for release history.
543
623
 
544
624
  ## License
545
625
 
@@ -165,7 +165,7 @@ each library.
165
165
  | libaec | 1.1.6 | BSD-2-Clause |
166
166
  | lerc | 4.1.0 | Apache-2.0 |
167
167
  | zfp | 1.0.1 | BSD-3-Clause |
168
- | SZ3 | 3.3.1 | BSD-3-Clause |
168
+ | SZ3 | 3.3.2 | BSD-3-Clause |
169
169
  | SPERR | 0.8.5 | Apache-2.0 |
170
170
  | pcodec | 1.0.2 | Apache-2.0 |
171
171
  | brunsli | master | MIT |
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "opencodecs"
10
- version = "0.2.0"
10
+ version = "0.3.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"
@@ -194,7 +194,7 @@ before-all = [
194
194
  # bench/build_codec_libs.sh into the cached /cibw-jxl-prefix mount.
195
195
  # Skips encoders (aom, x265) — wheel ships decode-only AVIF/HEIF to
196
196
  # keep build < 12 min cold + avoid GPL x265.
197
- "bash -c 'PATH=$HOME/.cargo/bin:$PATH bash bench/build_codec_libs.sh --only=libjpeg-turbo,c-blosc2,libde265,dav1d,libavif,libheif,libaec,lerc,zfp,SZ3,pcodec,SPERR,brunsli,mozjpeg,libultrahdr,openjph,CharLS'",
197
+ "bash -c 'PATH=$HOME/.cargo/bin:$PATH bash bench/build_codec_libs.sh --only=libjpeg-turbo,c-blosc2,libde265,dav1d,libavif,libheif,libaec,lerc,zfp,SZ3,pcodec,SPERR,brunsli,mozjpeg,libultrahdr,openjph,CharLS,jxrlib'",
198
198
  "bash bench/build_libjxl.sh",
199
199
  ]
200
200
  # Don't set OPENCODECS_*_PREFIX here — build_wheels.yml's
@@ -215,7 +215,7 @@ before-all = [
215
215
  # only, not libturbojpeg, so the _mozjpeg probe couldn't find what it
216
216
  # needed. Source-build via build_codec_libs.sh produces both libs.
217
217
  "brew install jpeg-xl libavif libheif webp libpng jpeg-turbo openjpeg zstd brotli c-blosc2 lz4 libdeflate libaec liblerc zfp rust cmake ninja libultrahdr giflib snappy charls isa-l",
218
- "bash bench/build_codec_libs.sh --only=SZ3,pcodec,SPERR,brunsli,mozjpeg,openjph",
218
+ "bash bench/build_codec_libs.sh --only=SZ3,pcodec,SPERR,brunsli,mozjpeg,openjph,jxrlib",
219
219
  ]
220
220
  # macos-latest is now macOS 15 (Sequoia) on arm64. Homebrew formulas are
221
221
  # compiled for 15.x, so any wheel target lower than 15 fails the delocate
@@ -1362,6 +1362,10 @@ extensions = [
1362
1362
  Extension(
1363
1363
  name="opencodecs.codecs._zstd",
1364
1364
  sources=["src/opencodecs/codecs/_zstd.pyx"],
1365
+ # The fused decode calls run the byte-plane loop in byteplanes.h,
1366
+ # whose restrict pointers let clang vectorize it; gcc also needs
1367
+ # -O3, as conda's default -O2 leaves it scalar (see _bytetools).
1368
+ extra_compile_args=["-O3"] if sys.platform != "win32" else ["/O2"],
1365
1369
  include_dirs=[
1366
1370
  str(PKG_CODECS),
1367
1371
  *_resolve_include_dirs("zstd.h"),
@@ -1661,6 +1665,32 @@ extensions = [
1661
1665
  define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")],
1662
1666
  language="c",
1663
1667
  ),
1668
+ # JPEG XR decode via jxrlib, for CZI sub-blocks with compression 4
1669
+ # (most Zeiss whole-slide scans). jxrlib installs its headers under
1670
+ # include/jxrlib/ and needs __ANSI__ off Windows; the shim declares
1671
+ # the in-memory stream constructor its public headers leave out.
1672
+ Extension(
1673
+ name="opencodecs.codecs._jpegxr",
1674
+ sources=[
1675
+ "src/opencodecs/codecs/_jpegxr.pyx",
1676
+ "src/opencodecs/codecs/jpegxr_shim.c",
1677
+ ],
1678
+ include_dirs=[
1679
+ str(PKG_CODECS),
1680
+ numpy.get_include(),
1681
+ *[str(Path(d) / "jxrlib")
1682
+ for d in _resolve_include_dirs("jxrlib/JXRGlue.h")],
1683
+ ],
1684
+ library_dirs=_lib_dirs_for_probes(),
1685
+ # conda-forge on Windows ships static libjxrglue.lib / libjpegxr.lib.
1686
+ libraries=[_libname("jxrglue", "libjxrglue"), _libname("jpegxr", "libjpegxr")],
1687
+ define_macros=[
1688
+ ("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION"),
1689
+ *([] if sys.platform == "win32" else [("__ANSI__", "1")]),
1690
+ ("DISABLE_PERF_MEASUREMENT", "1"),
1691
+ ],
1692
+ language="c",
1693
+ ),
1664
1694
  # JPEG-2000 via OpenJPEG. The header lives in a versioned subdir on
1665
1695
  # most platforms (openjpeg-2.5/), but conda-forge installs it directly
1666
1696
  # at <prefix>/Library/include/openjpeg.h. Probe both layouts.
@@ -1721,6 +1751,13 @@ extensions = [
1721
1751
  name="opencodecs.codecs._bytetools",
1722
1752
  sources=["src/opencodecs/codecs/_bytetools.pyx"],
1723
1753
  include_dirs=[str(PKG_CODECS)],
1754
+ # Byte-plane shuffles are strided byte loops that only pay when the
1755
+ # compiler vectorizes them. conda's default CFLAGS build at -O2,
1756
+ # where gcc's cheap-cost vectorizer leaves them scalar: measured on
1757
+ # x86-64 Linux, the native encode was 1.4-1.7x SLOWER than a
1758
+ # NumPy transpose at -O2. clang vectorizes at -O2 (arm64 macOS
1759
+ # measured 6-10x faster than NumPy), so this only moves gcc.
1760
+ extra_compile_args=["-O3"] if sys.platform != "win32" else ["/O2"],
1724
1761
  language="c",
1725
1762
  ),
1726
1763
  # Native TIFF IFD walker — pure-Python parsing logic in Cython for
@@ -2104,6 +2141,7 @@ _REQUIRED_HEADERS = {
2104
2141
  "opencodecs.codecs._uhdr": ("ultrahdr_api.h",),
2105
2142
  "opencodecs.codecs._isal": ("isa-l/igzip_lib.h",),
2106
2143
  "opencodecs.codecs._webp": ("webp/encode.h",),
2144
+ "opencodecs.codecs._jpegxr": ("jxrlib/JXRGlue.h",),
2107
2145
  "opencodecs.codecs._jpeg2k": ("openjpeg-2.5/openjpeg.h", "openjpeg-2.4/openjpeg.h"),
2108
2146
  "opencodecs.codecs._avif": ("avif/avif.h",),
2109
2147
  "opencodecs.codecs._heif": ("libheif/heif.h",),
@@ -342,4 +342,4 @@ __all__ = [
342
342
  "CziWriter", "CziPyramidWriter",
343
343
  ]
344
344
 
345
- __version__ = "0.2.0"
345
+ __version__ = "0.3.0"
@@ -29,6 +29,7 @@ from typing import Any
29
29
  import numpy as np
30
30
 
31
31
  from .core.codec import Codec
32
+ from .core.buffers import byte_output
32
33
  from .core._io_helpers import read_src as _read_src, write_dest as _write_dest
33
34
  from .core._optional_backend import import_or_stubs
34
35
 
@@ -126,8 +127,10 @@ class AecCodec(Codec):
126
127
  )
127
128
  return _write_dest(out, dest)
128
129
 
129
- def decode(self, src: Any, **opts) -> bytes:
130
- return _aec_decode(_read_src(src))
130
+ def decode(self, src: Any, *, out=None, **opts) -> bytes | memoryview:
131
+ if out is None:
132
+ return _aec_decode(_read_src(src))
133
+ return _aec_decode(_read_src(src), out=byte_output(out))
131
134
 
132
135
 
133
136
  __all__ = ["AecCodec"]