opencodecs 0.1.1__tar.gz → 0.1.2__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 (204) hide show
  1. {opencodecs-0.1.1 → opencodecs-0.1.2}/CHANGES.rst +27 -0
  2. {opencodecs-0.1.1/src/opencodecs.egg-info → opencodecs-0.1.2}/PKG-INFO +128 -40
  3. {opencodecs-0.1.1 → opencodecs-0.1.2}/README.md +127 -39
  4. {opencodecs-0.1.1 → opencodecs-0.1.2}/pyproject.toml +1 -1
  5. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/__init__.py +1 -1
  6. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_ndtiff_writer.py +2 -2
  7. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_bcdec.c +152 -152
  8. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_bmp.c +152 -152
  9. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_eer.c +152 -152
  10. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_hcomp.c +152 -152
  11. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_png.c +152 -152
  12. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_qoi.c +152 -152
  13. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_rcomp.c +152 -152
  14. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_rgbe.c +152 -152
  15. {opencodecs-0.1.1 → opencodecs-0.1.2/src/opencodecs.egg-info}/PKG-INFO +128 -40
  16. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/bcdec/bcdec.h +0 -0
  17. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/bitshuffle/bitshuffle_core.c +0 -0
  18. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/bitshuffle/iochain.c +0 -0
  19. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/cfitsio/fits_hdecompress.c +0 -0
  20. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/cfitsio/ricecomp.c +0 -0
  21. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/imcd_eer/eer.c +0 -0
  22. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/imcd_eer/eer.h +0 -0
  23. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/imcd_lzw/lzw.c +0 -0
  24. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/imcd_lzw/lzw.h +0 -0
  25. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/libspng/spng.c +0 -0
  26. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/oc_tifflzw/oc_tifflzw.c +0 -0
  27. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/oc_tifflzw/oc_tifflzw.h +0 -0
  28. {opencodecs-0.1.1 → opencodecs-0.1.2}/3rdparty/rgbe/rgbe.c +0 -0
  29. {opencodecs-0.1.1 → opencodecs-0.1.2}/MANIFEST.in +0 -0
  30. {opencodecs-0.1.1 → opencodecs-0.1.2}/bench/build_libjxl.sh +0 -0
  31. {opencodecs-0.1.1 → opencodecs-0.1.2}/patches/libjxl/README.md +0 -0
  32. {opencodecs-0.1.1 → opencodecs-0.1.2}/setup.cfg +0 -0
  33. {opencodecs-0.1.1 → opencodecs-0.1.2}/setup.py +0 -0
  34. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_aec_codec.py +0 -0
  35. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_avif_codec.py +0 -0
  36. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_b2nd_codec.py +0 -0
  37. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_bcn_codec.py +0 -0
  38. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_bitshuffle_codec.py +0 -0
  39. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_blosc2_codec.py +0 -0
  40. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_bmp_codec.py +0 -0
  41. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_brotli_codec.py +0 -0
  42. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_brunsli_codec.py +0 -0
  43. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_byteshuffle_codec.py +0 -0
  44. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_bz2_codec.py +0 -0
  45. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_cms_codec.py +0 -0
  46. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_czi_codec.py +0 -0
  47. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_czi_reader.py +0 -0
  48. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_czi_writer.py +0 -0
  49. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_deflate_codec.py +0 -0
  50. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_dicomrle_codec.py +0 -0
  51. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_dicomweb.py +0 -0
  52. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_eer_reader.py +0 -0
  53. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_ets.py +0 -0
  54. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_fits.py +0 -0
  55. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_fits_codec.py +0 -0
  56. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_fits_compressed.py +0 -0
  57. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_gif_codec.py +0 -0
  58. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_gzip_codec.py +0 -0
  59. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_hdf5_codec.py +0 -0
  60. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_hdf5_http.py +0 -0
  61. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_heif_codec.py +0 -0
  62. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_htj2k_codec.py +0 -0
  63. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_jpeg2k_codec.py +0 -0
  64. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_jpeg_codec.py +0 -0
  65. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_jpegls_codec.py +0 -0
  66. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_jxl_codec.py +0 -0
  67. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_lerc_codec.py +0 -0
  68. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_lif_codec.py +0 -0
  69. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_lif_native.py +0 -0
  70. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_lz4_codec.py +0 -0
  71. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_lzma_codec.py +0 -0
  72. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_mozjpeg_codec.py +0 -0
  73. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_nd2_codec.py +0 -0
  74. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_nd2_native.py +0 -0
  75. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_ndtiff.py +0 -0
  76. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_ndtiff_pyramid.py +0 -0
  77. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_none_codec.py +0 -0
  78. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_numpy_codec.py +0 -0
  79. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_oib_codec.py +0 -0
  80. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_oib_native.py +0 -0
  81. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_oir_codec.py +0 -0
  82. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_ole2.py +0 -0
  83. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_ome_xml.py +0 -0
  84. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_omezarr.py +0 -0
  85. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_omezarr_writer.py +0 -0
  86. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_packints_codec.py +0 -0
  87. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_pcodec_codec.py +0 -0
  88. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_png_codec.py +0 -0
  89. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_predictor_codec.py +0 -0
  90. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_pyramid_build.py +0 -0
  91. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_qoi_codec.py +0 -0
  92. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_quantize_codec.py +0 -0
  93. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_rcomp_codec.py +0 -0
  94. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_rgbe.py +0 -0
  95. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_rgbe_codec.py +0 -0
  96. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_snappy_codec.py +0 -0
  97. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_sperr_codec.py +0 -0
  98. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_sz3_codec.py +0 -0
  99. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_tiff_codec.py +0 -0
  100. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_tiff_http.py +0 -0
  101. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_tiff_pyramid.py +0 -0
  102. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_tiff_writer.py +0 -0
  103. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_ultrahdr_codec.py +0 -0
  104. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_vsi_codec.py +0 -0
  105. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_webp_codec.py +0 -0
  106. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_zarr_codecs.py +0 -0
  107. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_zfp_codec.py +0 -0
  108. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/_zstd_codec.py +0 -0
  109. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/__init__.py +0 -0
  110. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_bitshuffle.c +0 -0
  111. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_bytetools.c +0 -0
  112. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_deflate.c +0 -0
  113. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_lz4.c +0 -0
  114. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_ndtiff.c +0 -0
  115. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_registry.py +0 -0
  116. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_tiff.c +0 -0
  117. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/codecs/_zstd.c +0 -0
  118. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/__init__.py +0 -0
  119. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/_io_helpers.py +0 -0
  120. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/_optional_backend.py +0 -0
  121. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/codec.py +0 -0
  122. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/color.py +0 -0
  123. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/errors.py +0 -0
  124. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/io.py +0 -0
  125. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/pyramid.py +0 -0
  126. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/core/segment_compression.py +0 -0
  127. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/jxl.py +0 -0
  128. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/parallel.py +0 -0
  129. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/tiff_reader.py +0 -0
  130. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/tifffile_patch.py +0 -0
  131. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs/zarr.py +0 -0
  132. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs.egg-info/SOURCES.txt +0 -0
  133. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs.egg-info/dependency_links.txt +0 -0
  134. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs.egg-info/requires.txt +0 -0
  135. {opencodecs-0.1.1 → opencodecs-0.1.2}/src/opencodecs.egg-info/top_level.txt +0 -0
  136. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_auto_pyramid.py +0 -0
  137. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_bcdec.py +0 -0
  138. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_brunsli.py +0 -0
  139. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_charls.py +0 -0
  140. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_core_codec_api.py +0 -0
  141. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_corpus.py +0 -0
  142. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_corpus_codec_decode.py +0 -0
  143. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_corpus_other.py +0 -0
  144. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_corpus_png.py +0 -0
  145. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_corpus_tiff.py +0 -0
  146. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_corpus_vendors.py +0 -0
  147. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_coverage_final.py +0 -0
  148. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_coverage_finishing.py +0 -0
  149. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_coverage_last.py +0 -0
  150. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_coverage_more.py +0 -0
  151. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_coverage_push.py +0 -0
  152. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_czi_fixture.py +0 -0
  153. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_czi_pyramid.py +0 -0
  154. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_czi_writer.py +0 -0
  155. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_data_source.py +0 -0
  156. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_deflate.py +0 -0
  157. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_dicomweb.py +0 -0
  158. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_edge_cases.py +0 -0
  159. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_eer.py +0 -0
  160. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_encode_comprehensive.py +0 -0
  161. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_error_handling.py +0 -0
  162. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_fits.py +0 -0
  163. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_gif.py +0 -0
  164. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_hdf5_http.py +0 -0
  165. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_hdf5_local.py +0 -0
  166. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_heif_avif_features.py +0 -0
  167. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_http_byte_savings.py +0 -0
  168. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_http_prefetch.py +0 -0
  169. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_http_unified.py +0 -0
  170. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_io_chunked.py +0 -0
  171. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_isal.py +0 -0
  172. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_jxl.py +0 -0
  173. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_lif_native.py +0 -0
  174. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_live_archives.py +0 -0
  175. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_mozjpeg.py +0 -0
  176. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_native_parity.py +0 -0
  177. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_nd2_native.py +0 -0
  178. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_ndtiff.py +0 -0
  179. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_oib_native.py +0 -0
  180. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_ome_xml.py +0 -0
  181. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_omezarr.py +0 -0
  182. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_omezarr_sharded_range.py +0 -0
  183. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_open_pyramid.py +0 -0
  184. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_openjph.py +0 -0
  185. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_optional_backend.py +0 -0
  186. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_parallel_jxl.py +0 -0
  187. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_phase4_filters.py +0 -0
  188. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_phase5_icc.py +0 -0
  189. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_phase6_codecs.py +0 -0
  190. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_phase7_cms.py +0 -0
  191. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_rgbe.py +0 -0
  192. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_snappy.py +0 -0
  193. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tier1_scientific.py +0 -0
  194. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tiff_codec_encode.py +0 -0
  195. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tiff_http.py +0 -0
  196. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tiff_native.py +0 -0
  197. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tiff_pyramid.py +0 -0
  198. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tiff_reader.py +0 -0
  199. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tiff_writer.py +0 -0
  200. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_tifffile_patch.py +0 -0
  201. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_ultrahdr.py +0 -0
  202. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_unified_api.py +0 -0
  203. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_vsi_oir.py +0 -0
  204. {opencodecs-0.1.1 → opencodecs-0.1.2}/tests/test_zarr_adapters.py +0 -0
@@ -10,6 +10,33 @@ 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.1.2 (2026-05-22)
14
+ ------------------
15
+
16
+ **Windows wheels get the Tier 1 scientific compressors back**
17
+
18
+ * Restored ``_sz3``, ``_pcodec``, ``_sperr``, ``_brunsli`` on Windows.
19
+ Root cause was conda's bash putting ``gcc.exe`` ahead of ``cl.exe``
20
+ on PATH; CMake then produced gnu-format ``libSZ3c.dll.a`` import
21
+ libraries that cibuildwheel's MSVC link.exe couldn't consume.
22
+ * Workflow now uses ``ilammy/msvc-dev-cmd`` to source vcvars64.bat
23
+ before the SZ3+pcodec source-build step; CMake's auto-detect picks
24
+ cl.exe and produces MSVC-format ``SZ3c.lib`` / ``cpcodec.lib``.
25
+ * Validated end-to-end on a Windows 11 VM (clean SZ3 install with
26
+ Ninja + cl.exe + vcvars-sourced env).
27
+ * Windows wheels now match the macOS / Linux codec set.
28
+
29
+ **README rewrite for the released project**
30
+
31
+ * ``pip install opencodecs`` + PyPI badge at the top.
32
+ * New "Why opencodecs" table mapping common scientific-imaging needs
33
+ to concrete shipping capabilities.
34
+ * New "Streaming-reader examples" section with 3 copy-paste recipes:
35
+ HTTP region-fetch from a remote Aperio TIFF, TIFF → OME-Zarr v3
36
+ sharded conversion, and the native progressive JXL thumbnail path.
37
+ * Status / Install sections updated for the 0.1.x cadence.
38
+
39
+
13
40
  0.1.1 (2026-05-21)
14
41
  ------------------
15
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencodecs
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Streaming, network-aware image codecs for scientific imaging (prototype: JPEG XL)
5
5
  Author: Kevin Cutler
6
6
  License: BSD-3-Clause
@@ -28,41 +28,65 @@ Requires-Dist: zarr; extra == "test"
28
28
 
29
29
  # opencodecs
30
30
 
31
+ [![PyPI](https://img.shields.io/pypi/v/opencodecs.svg)](https://pypi.org/project/opencodecs/)
31
32
  [![Tests](https://github.com/kevinjohncutler/opencodecs/actions/workflows/tests.yml/badge.svg)](https://github.com/kevinjohncutler/opencodecs/actions/workflows/tests.yml)
32
33
  [![Build wheels](https://github.com/kevinjohncutler/opencodecs/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/kevinjohncutler/opencodecs/actions/workflows/build_wheels.yml)
33
34
 
34
- Native, parallel-decode codecs for scientific imaging. One unified Codec
35
- / Reader / Writer API across compression streams, single images,
36
- multi-frame stacks, and chunked containers.
35
+ Native, parallel, cloud-aware codecs for scientific imaging. One
36
+ unified Codec / Reader / Writer API across compression streams,
37
+ single images, multi-frame stacks, and chunked containers — with
38
+ HTTP range-fetch and per-chunk parallelism wired in at the bottom
39
+ of the stack, not bolted on.
37
40
 
38
- Built for fast modern storage (NVMe, 10 G NAS) where the bottleneck is
39
- codec dispatch and per-tile parallelism, not raw I/O bandwidth. Native
40
- implementations of every codec — no runtime delegation to
41
- [imagecodecs](https://github.com/cgohlke/imagecodecs) — though we use
42
- its excellent test suite as a parity reference.
41
+ Built for fast modern storage (NVMe, 10 G NAS, S3) where the
42
+ bottleneck is codec dispatch and per-tile parallelism, not raw I/O
43
+ bandwidth. Native implementations of every codec — no runtime
44
+ delegation to [imagecodecs](https://github.com/cgohlke/imagecodecs) —
45
+ though we use its excellent test suite as a parity reference.
46
+
47
+ ```sh
48
+ pip install opencodecs
49
+ ```
43
50
 
44
51
  ```python
45
52
  import opencodecs as oc
46
53
 
54
+ # 1. Look at any scientific image file
47
55
  arr = oc.read("scan.czi") # auto-detect by extension
48
56
  arr = oc.read("photo.jxl")
49
57
  arr = oc.read(blob) # auto-detect by magic bytes
50
58
 
59
+ # 2. Write with the right codec for the data
51
60
  oc.write("out.jxl", arr, lossless=True)
52
61
  oc.write("out.zst", b"...payload...", level=10)
53
62
 
54
- # Streaming reader for multi-frame / chunked formats
63
+ # 3. Stream multi-frame / chunked formats
55
64
  with oc.get_codec("czi").open(path) as r:
56
65
  print(r.shape, r.dtype, r.n_frames)
57
66
  for tile in r: # iter_frames
58
67
  ...
59
68
  tile5 = r[5] # random access
60
69
 
70
+ # 4. Fetch tiles of a remote pyramidal TIFF over HTTPS by range request
71
+ with oc.open_pyramid("https://example.com/slide.svs") as p:
72
+ region = p.read_region(level=2, y=(1024, 2048), x=(1024, 2048))
73
+ # → 2-3 HTTP Range requests, not a full slide download
74
+
61
75
  # Discovery
62
76
  oc.list_codecs() # capability table
63
77
  oc.has_codec("avif")
64
78
  ```
65
79
 
80
+ ## Why opencodecs
81
+
82
+ | Need | What you get |
83
+ |---|---|
84
+ | **Decode regions of cloud-hosted TIFF/Zarr/HDF5 without downloading the whole file** | Native `HTTPDataSource` with range-coalescing + adaptive read-ahead, wired into the TIFF/NDTiff/HDF5/Zarr/FITS pyramid readers |
85
+ | **Per-chunk parallel decode of CZI/OME-TIFF/NDTiff stacks** | Built-in `ThreadPoolExecutor` orchestration with nogil-released codec calls; 3–10× over single-threaded reference readers on large stacks |
86
+ | **Modern codec coverage (JPEG XL, AVIF, HEIF, JPEG-LS, Brunsli, Ultra HDR, OME-Zarr v3 sharded)** | All shipped, all with native bindings — no `pip install ten-other-packages` |
87
+ | **Tier-1 scientific compressors (LERC, ZFP, SZ3, SPERR, pcodec, bitshuffle, blosc2, libaec)** | All shipped, source-built with `-O3 + LTO + hidden-visibility` for Pareto wins over distro builds |
88
+ | **Lossless drop-in replacement for `imagecodecs`** | `tifffile_patch` opt-in shim reroutes tifffile's codec dispatch through opencodecs without changing your tifffile code |
89
+
66
90
  ## Codec capability matrix
67
91
 
68
92
  All codecs below are native implementations linking against system or
@@ -365,61 +389,125 @@ reader.dataset_names # all numeric datasets in the file
365
389
  reader.select(name) # switch to a different dataset
366
390
  ```
367
391
 
368
- ## Install
392
+ ## Streaming-reader examples
369
393
 
370
- See [INSTALL.md](INSTALL.md) for system dependencies per platform and
371
- build instructions, and [docs/publishing.md](docs/publishing.md) for
372
- the wheel-publishing pipeline (TestPyPI / PyPI via Trusted Publishing).
373
- Short version:
394
+ ### 1. Fetch a region of a remote Aperio whole-slide TIFF
395
+
396
+ ```python
397
+ import opencodecs as oc
398
+
399
+ # Pyramidal SVS (Aperio) hosted on S3 / any HTTPS endpoint with Range support.
400
+ with oc.open_pyramid("https://example.com/slide.svs") as p:
401
+ print(p.levels) # [(80000, 60000, 3), (40000, 30000, 3), ...]
402
+ region = p.read_region(level=2, y=(1024, 3072), x=(2048, 4096))
403
+ # Total HTTP traffic: ~6 Range requests covering only the tiles
404
+ # that intersect this 2048×2048 bbox — typically 200 KB–2 MB,
405
+ # not the 4 GB whole slide.
406
+ ```
407
+
408
+ The pyramid reader auto-detects the best level for the requested
409
+ region, fetches only the intersecting TIFF tiles via HTTP Range,
410
+ and assembles the output in-memory. Works the same on local files,
411
+ NFS, SMB, S3, or any range-capable HTTP server.
412
+
413
+ ### 2. Convert a multi-level pyramid to OME-Zarr v3 sharded
414
+
415
+ ```python
416
+ import opencodecs as oc
417
+
418
+ with oc.open_pyramid("input.ome.tiff") as p:
419
+ levels = [p.read_region(level=i) for i in range(len(p.levels))]
420
+
421
+ oc.write_omezarr_pyramid(
422
+ "output.zarr",
423
+ levels,
424
+ chunks=(512, 512),
425
+ shards=(2048, 2048), # 16 chunks per shard, one file each
426
+ compressor="zstd",
427
+ zarr_format=3,
428
+ )
429
+ # 1 file per shard on disk instead of 1 file per chunk; per-chunk
430
+ # random access still works via Range fetches into the shard.
431
+ ```
432
+
433
+ For data going to S3, sharded Zarr v3 cuts your `PUT` and `LIST`
434
+ costs by 1–2 orders of magnitude vs unsharded chunks while
435
+ preserving per-chunk random-access via HTTP Range — the reader
436
+ above understands the shard index automatically.
437
+
438
+ ### 3. Fast JPEG XL thumbnails (native progressive decode)
439
+
440
+ ```python
441
+ import opencodecs.jxl as jxl
442
+
443
+ # downsample=8 uses libjxl's native progressive decoder — stops at
444
+ # the DC pass without reconstructing full-resolution pixels.
445
+ thumb = jxl.read("scan.jxl", downsample=8, subsample="center")
446
+ # 4Kx4K input → 512x512 ndarray in ~28 ms on macOS arm64
447
+ # (vs ~40 ms for a full decode), positionally centroid-correct
448
+ # so SVG / GL renderers don't get a ½-block shift.
449
+
450
+ # For a partial JXL bitstream usable as a tiny browser-direct
451
+ # thumbnail (works in Safari + modern Chrome):
452
+ prefix = jxl.thumbnail_bytes("scan.jxl")
453
+ # → ~85 KB out of a 3.5 MB source for a 4Kx4K image
454
+ ```
455
+
456
+ ## Install
374
457
 
375
458
  ```sh
376
- # macOS
377
- brew install jpeg-turbo webp libavif libheif openjpeg libtiff hdf5 c-blosc2 \
378
- charls openjph libdeflate zlib-ng-compat
459
+ pip install opencodecs
460
+ ```
461
+
462
+ Wheels are published for CPython 3.10–3.13 on macOS (arm64),
463
+ Linux (x86_64 + aarch64), and Windows (amd64). Each wheel
464
+ bundles libjxl, libavif, libheif, libwebp, libdeflate,
465
+ c-blosc2, and friends — no system dependencies needed.
379
466
 
380
- # Ubuntu / Debian
381
- sudo apt install -y libturbojpeg0-dev libwebp-dev libavif-dev libheif-dev \
382
- libopenjp2-7-dev libblosc2-dev libcharls-dev \
383
- liblz4-dev libspng-dev libtiff-dev libhdf5-dev \
384
- libdeflate-dev libopenjph-dev zlib1g-dev
467
+ For a source install, system development headers, or to build a
468
+ tuned local libjxl, see [INSTALL.md](INSTALL.md). Wheel publishing
469
+ runs through [docs/publishing.md](docs/publishing.md).
385
470
 
386
- # Build
471
+ ```sh
472
+ # Source install — auto-detects system libs, source-builds libjxl
473
+ git clone https://github.com/kevinjohncutler/opencodecs.git
387
474
  cd opencodecs
388
475
  pip install -e .
389
- # or
390
- python setup.py build_ext --inplace
391
476
  ```
392
477
 
393
478
  The build skips cleanly for any system library that's missing — useful
394
- extensions still build, missing ones print a one-line notice.
395
-
396
- libjxl 0.11.2 is vendored via `bench/build_libjxl.sh` (auto-builds + caches
397
- to `~/Library/Caches/opencodecs/libjxl/` on Mac, `~/.cache/opencodecs/libjxl/`
398
- on Linux). See INSTALL.md for the rationale (Homebrew/apt builds are
399
- 0.5-0.7× slower than a tuned `-O3 + LTO` build).
479
+ extensions still build, missing ones print a one-line notice. libjxl
480
+ 0.11.2 is auto-built from source via `bench/build_libjxl.sh` and
481
+ cached under `~/Library/Caches/opencodecs/` (macOS) /
482
+ `~/.cache/opencodecs/` (Linux). See INSTALL.md for the rationale
483
+ (Homebrew/apt builds are 0.5-0.7× slower than a tuned `-O3 + LTO`
484
+ build).
400
485
 
401
486
  ## Status
402
487
 
403
- - Core API stable; **1066 tests passing** (Mac M1 Ultra + Linux + Windows VM)
488
+ - **v0.1.1** on PyPI (May 2026). Core API stable; **1066 tests passing**
489
+ on Mac M1 Ultra + Linux x86_64/aarch64 + Windows VM
404
490
  - Native readers + writers for the common scientific containers
405
- (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL)
491
+ (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL, FITS,
492
+ OME-Zarr v2 + v3 sharded)
406
493
  - Cross-platform bench coverage: Mac arm64 (canonical), Windows 11 LTSC
407
- (libvirt VM), Linux x86_64 (Threadripper)
494
+ (libvirt VM), Linux x86_64 (Threadripper-class)
408
495
  - Compression backend auto-detect (libdeflate → zlib-ng-compat → stdlib)
409
- - Cloud I/O primitives (`HTTPDataSource.read_many`, range coalescing,
410
- HTTP/1.1 keep-alive) wired into TIFF / HDF5 / DICOMweb / CZI readers
496
+ - Cloud I/O primitives (`HTTPDataSource` with covering-cache + adaptive
497
+ read-ahead) wired into TIFF / HDF5 / DICOMweb / CZI / FITS / Zarr v3
498
+ readers
411
499
  - `tifffile_patch` opt-in shim reroutes tifffile's codec dispatch through
412
500
  opencodecs for users who want only a partial swap
413
501
 
414
502
  Deferred work (see [`docs/TODO_DEFERRED.md`](docs/TODO_DEFERRED.md)):
415
503
 
416
- - SPERR (error-bounded lossy scientific compression) CMake build needed
417
- - Brunsli (lossless JPEG transcoder) source build needed; no brew formula
504
+ - **Windows wheels currently miss `_sz3`, `_pcodec`, `_sperr`, `_brunsli`**
505
+ toolchain mismatch (conda's bash picks GCC over MSVC for CMake);
506
+ v0.1.2 will restore them. macOS + Linux wheels have the full set.
418
507
  - CCITT Fax3/Fax4 encode — legacy fax; zero scientific users
419
508
  - JPEG-XR — abandoned format outside niche DICOM
420
509
  - libspng `filter_sum` SIMD — off the bench-tracked workload (`h2h_png_4mp_rgb`
421
510
  is at 1.14× already); filter-bound PNG-encode users could see another 2-3×
422
- - Wheels / PyPI release — install from source for now
423
511
 
424
512
  ## License
425
513
 
@@ -2,41 +2,65 @@
2
2
 
3
3
  # opencodecs
4
4
 
5
+ [![PyPI](https://img.shields.io/pypi/v/opencodecs.svg)](https://pypi.org/project/opencodecs/)
5
6
  [![Tests](https://github.com/kevinjohncutler/opencodecs/actions/workflows/tests.yml/badge.svg)](https://github.com/kevinjohncutler/opencodecs/actions/workflows/tests.yml)
6
7
  [![Build wheels](https://github.com/kevinjohncutler/opencodecs/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/kevinjohncutler/opencodecs/actions/workflows/build_wheels.yml)
7
8
 
8
- Native, parallel-decode codecs for scientific imaging. One unified Codec
9
- / Reader / Writer API across compression streams, single images,
10
- multi-frame stacks, and chunked containers.
9
+ Native, parallel, cloud-aware codecs for scientific imaging. One
10
+ unified Codec / Reader / Writer API across compression streams,
11
+ single images, multi-frame stacks, and chunked containers — with
12
+ HTTP range-fetch and per-chunk parallelism wired in at the bottom
13
+ of the stack, not bolted on.
11
14
 
12
- Built for fast modern storage (NVMe, 10 G NAS) where the bottleneck is
13
- codec dispatch and per-tile parallelism, not raw I/O bandwidth. Native
14
- implementations of every codec — no runtime delegation to
15
- [imagecodecs](https://github.com/cgohlke/imagecodecs) — though we use
16
- its excellent test suite as a parity reference.
15
+ Built for fast modern storage (NVMe, 10 G NAS, S3) where the
16
+ bottleneck is codec dispatch and per-tile parallelism, not raw I/O
17
+ bandwidth. Native implementations of every codec — no runtime
18
+ delegation to [imagecodecs](https://github.com/cgohlke/imagecodecs) —
19
+ though we use its excellent test suite as a parity reference.
20
+
21
+ ```sh
22
+ pip install opencodecs
23
+ ```
17
24
 
18
25
  ```python
19
26
  import opencodecs as oc
20
27
 
28
+ # 1. Look at any scientific image file
21
29
  arr = oc.read("scan.czi") # auto-detect by extension
22
30
  arr = oc.read("photo.jxl")
23
31
  arr = oc.read(blob) # auto-detect by magic bytes
24
32
 
33
+ # 2. Write with the right codec for the data
25
34
  oc.write("out.jxl", arr, lossless=True)
26
35
  oc.write("out.zst", b"...payload...", level=10)
27
36
 
28
- # Streaming reader for multi-frame / chunked formats
37
+ # 3. Stream multi-frame / chunked formats
29
38
  with oc.get_codec("czi").open(path) as r:
30
39
  print(r.shape, r.dtype, r.n_frames)
31
40
  for tile in r: # iter_frames
32
41
  ...
33
42
  tile5 = r[5] # random access
34
43
 
44
+ # 4. Fetch tiles of a remote pyramidal TIFF over HTTPS by range request
45
+ with oc.open_pyramid("https://example.com/slide.svs") as p:
46
+ region = p.read_region(level=2, y=(1024, 2048), x=(1024, 2048))
47
+ # → 2-3 HTTP Range requests, not a full slide download
48
+
35
49
  # Discovery
36
50
  oc.list_codecs() # capability table
37
51
  oc.has_codec("avif")
38
52
  ```
39
53
 
54
+ ## Why opencodecs
55
+
56
+ | Need | What you get |
57
+ |---|---|
58
+ | **Decode regions of cloud-hosted TIFF/Zarr/HDF5 without downloading the whole file** | Native `HTTPDataSource` with range-coalescing + adaptive read-ahead, wired into the TIFF/NDTiff/HDF5/Zarr/FITS pyramid readers |
59
+ | **Per-chunk parallel decode of CZI/OME-TIFF/NDTiff stacks** | Built-in `ThreadPoolExecutor` orchestration with nogil-released codec calls; 3–10× over single-threaded reference readers on large stacks |
60
+ | **Modern codec coverage (JPEG XL, AVIF, HEIF, JPEG-LS, Brunsli, Ultra HDR, OME-Zarr v3 sharded)** | All shipped, all with native bindings — no `pip install ten-other-packages` |
61
+ | **Tier-1 scientific compressors (LERC, ZFP, SZ3, SPERR, pcodec, bitshuffle, blosc2, libaec)** | All shipped, source-built with `-O3 + LTO + hidden-visibility` for Pareto wins over distro builds |
62
+ | **Lossless drop-in replacement for `imagecodecs`** | `tifffile_patch` opt-in shim reroutes tifffile's codec dispatch through opencodecs without changing your tifffile code |
63
+
40
64
  ## Codec capability matrix
41
65
 
42
66
  All codecs below are native implementations linking against system or
@@ -339,61 +363,125 @@ reader.dataset_names # all numeric datasets in the file
339
363
  reader.select(name) # switch to a different dataset
340
364
  ```
341
365
 
342
- ## Install
366
+ ## Streaming-reader examples
343
367
 
344
- See [INSTALL.md](INSTALL.md) for system dependencies per platform and
345
- build instructions, and [docs/publishing.md](docs/publishing.md) for
346
- the wheel-publishing pipeline (TestPyPI / PyPI via Trusted Publishing).
347
- Short version:
368
+ ### 1. Fetch a region of a remote Aperio whole-slide TIFF
369
+
370
+ ```python
371
+ import opencodecs as oc
372
+
373
+ # Pyramidal SVS (Aperio) hosted on S3 / any HTTPS endpoint with Range support.
374
+ with oc.open_pyramid("https://example.com/slide.svs") as p:
375
+ print(p.levels) # [(80000, 60000, 3), (40000, 30000, 3), ...]
376
+ region = p.read_region(level=2, y=(1024, 3072), x=(2048, 4096))
377
+ # Total HTTP traffic: ~6 Range requests covering only the tiles
378
+ # that intersect this 2048×2048 bbox — typically 200 KB–2 MB,
379
+ # not the 4 GB whole slide.
380
+ ```
381
+
382
+ The pyramid reader auto-detects the best level for the requested
383
+ region, fetches only the intersecting TIFF tiles via HTTP Range,
384
+ and assembles the output in-memory. Works the same on local files,
385
+ NFS, SMB, S3, or any range-capable HTTP server.
386
+
387
+ ### 2. Convert a multi-level pyramid to OME-Zarr v3 sharded
388
+
389
+ ```python
390
+ import opencodecs as oc
391
+
392
+ with oc.open_pyramid("input.ome.tiff") as p:
393
+ levels = [p.read_region(level=i) for i in range(len(p.levels))]
394
+
395
+ oc.write_omezarr_pyramid(
396
+ "output.zarr",
397
+ levels,
398
+ chunks=(512, 512),
399
+ shards=(2048, 2048), # 16 chunks per shard, one file each
400
+ compressor="zstd",
401
+ zarr_format=3,
402
+ )
403
+ # 1 file per shard on disk instead of 1 file per chunk; per-chunk
404
+ # random access still works via Range fetches into the shard.
405
+ ```
406
+
407
+ For data going to S3, sharded Zarr v3 cuts your `PUT` and `LIST`
408
+ costs by 1–2 orders of magnitude vs unsharded chunks while
409
+ preserving per-chunk random-access via HTTP Range — the reader
410
+ above understands the shard index automatically.
411
+
412
+ ### 3. Fast JPEG XL thumbnails (native progressive decode)
413
+
414
+ ```python
415
+ import opencodecs.jxl as jxl
416
+
417
+ # downsample=8 uses libjxl's native progressive decoder — stops at
418
+ # the DC pass without reconstructing full-resolution pixels.
419
+ thumb = jxl.read("scan.jxl", downsample=8, subsample="center")
420
+ # 4Kx4K input → 512x512 ndarray in ~28 ms on macOS arm64
421
+ # (vs ~40 ms for a full decode), positionally centroid-correct
422
+ # so SVG / GL renderers don't get a ½-block shift.
423
+
424
+ # For a partial JXL bitstream usable as a tiny browser-direct
425
+ # thumbnail (works in Safari + modern Chrome):
426
+ prefix = jxl.thumbnail_bytes("scan.jxl")
427
+ # → ~85 KB out of a 3.5 MB source for a 4Kx4K image
428
+ ```
429
+
430
+ ## Install
348
431
 
349
432
  ```sh
350
- # macOS
351
- brew install jpeg-turbo webp libavif libheif openjpeg libtiff hdf5 c-blosc2 \
352
- charls openjph libdeflate zlib-ng-compat
433
+ pip install opencodecs
434
+ ```
435
+
436
+ Wheels are published for CPython 3.10–3.13 on macOS (arm64),
437
+ Linux (x86_64 + aarch64), and Windows (amd64). Each wheel
438
+ bundles libjxl, libavif, libheif, libwebp, libdeflate,
439
+ c-blosc2, and friends — no system dependencies needed.
353
440
 
354
- # Ubuntu / Debian
355
- sudo apt install -y libturbojpeg0-dev libwebp-dev libavif-dev libheif-dev \
356
- libopenjp2-7-dev libblosc2-dev libcharls-dev \
357
- liblz4-dev libspng-dev libtiff-dev libhdf5-dev \
358
- libdeflate-dev libopenjph-dev zlib1g-dev
441
+ For a source install, system development headers, or to build a
442
+ tuned local libjxl, see [INSTALL.md](INSTALL.md). Wheel publishing
443
+ runs through [docs/publishing.md](docs/publishing.md).
359
444
 
360
- # Build
445
+ ```sh
446
+ # Source install — auto-detects system libs, source-builds libjxl
447
+ git clone https://github.com/kevinjohncutler/opencodecs.git
361
448
  cd opencodecs
362
449
  pip install -e .
363
- # or
364
- python setup.py build_ext --inplace
365
450
  ```
366
451
 
367
452
  The build skips cleanly for any system library that's missing — useful
368
- extensions still build, missing ones print a one-line notice.
369
-
370
- libjxl 0.11.2 is vendored via `bench/build_libjxl.sh` (auto-builds + caches
371
- to `~/Library/Caches/opencodecs/libjxl/` on Mac, `~/.cache/opencodecs/libjxl/`
372
- on Linux). See INSTALL.md for the rationale (Homebrew/apt builds are
373
- 0.5-0.7× slower than a tuned `-O3 + LTO` build).
453
+ extensions still build, missing ones print a one-line notice. libjxl
454
+ 0.11.2 is auto-built from source via `bench/build_libjxl.sh` and
455
+ cached under `~/Library/Caches/opencodecs/` (macOS) /
456
+ `~/.cache/opencodecs/` (Linux). See INSTALL.md for the rationale
457
+ (Homebrew/apt builds are 0.5-0.7× slower than a tuned `-O3 + LTO`
458
+ build).
374
459
 
375
460
  ## Status
376
461
 
377
- - Core API stable; **1066 tests passing** (Mac M1 Ultra + Linux + Windows VM)
462
+ - **v0.1.1** on PyPI (May 2026). Core API stable; **1066 tests passing**
463
+ on Mac M1 Ultra + Linux x86_64/aarch64 + Windows VM
378
464
  - Native readers + writers for the common scientific containers
379
- (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL)
465
+ (TIFF, BigTIFF, OME-TIFF, CZI, NDTiff, HDF5, JXL, FITS,
466
+ OME-Zarr v2 + v3 sharded)
380
467
  - Cross-platform bench coverage: Mac arm64 (canonical), Windows 11 LTSC
381
- (libvirt VM), Linux x86_64 (Threadripper)
468
+ (libvirt VM), Linux x86_64 (Threadripper-class)
382
469
  - Compression backend auto-detect (libdeflate → zlib-ng-compat → stdlib)
383
- - Cloud I/O primitives (`HTTPDataSource.read_many`, range coalescing,
384
- HTTP/1.1 keep-alive) wired into TIFF / HDF5 / DICOMweb / CZI readers
470
+ - Cloud I/O primitives (`HTTPDataSource` with covering-cache + adaptive
471
+ read-ahead) wired into TIFF / HDF5 / DICOMweb / CZI / FITS / Zarr v3
472
+ readers
385
473
  - `tifffile_patch` opt-in shim reroutes tifffile's codec dispatch through
386
474
  opencodecs for users who want only a partial swap
387
475
 
388
476
  Deferred work (see [`docs/TODO_DEFERRED.md`](docs/TODO_DEFERRED.md)):
389
477
 
390
- - SPERR (error-bounded lossy scientific compression) CMake build needed
391
- - Brunsli (lossless JPEG transcoder) source build needed; no brew formula
478
+ - **Windows wheels currently miss `_sz3`, `_pcodec`, `_sperr`, `_brunsli`**
479
+ toolchain mismatch (conda's bash picks GCC over MSVC for CMake);
480
+ v0.1.2 will restore them. macOS + Linux wheels have the full set.
392
481
  - CCITT Fax3/Fax4 encode — legacy fax; zero scientific users
393
482
  - JPEG-XR — abandoned format outside niche DICOM
394
483
  - libspng `filter_sum` SIMD — off the bench-tracked workload (`h2h_png_4mp_rgb`
395
484
  is at 1.14× already); filter-bound PNG-encode users could see another 2-3×
396
- - Wheels / PyPI release — install from source for now
397
485
 
398
486
  ## License
399
487
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opencodecs"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "Streaming, network-aware image codecs for scientific imaging (prototype: JPEG XL)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -191,4 +191,4 @@ __all__ = [
191
191
  "CziWriter", "CziPyramidWriter",
192
192
  ]
193
193
 
194
- __version__ = "0.1.1"
194
+ __version__ = "0.1.2"
@@ -333,12 +333,12 @@ class NDTiffWriter:
333
333
  self._cur_path = self._dir / self._stack_filename(self._stack_index)
334
334
  flags = os.O_RDWR | os.O_CREAT | os.O_TRUNC | getattr(os, "O_BINARY", 0)
335
335
  self._fd = os.open(str(self._cur_path), flags, 0o644)
336
- if sys.platform == "win32": # pragma: no cover - covered by win-vm bench
336
+ if sys.platform == "win32": # pragma: no cover - covered by windows-vm bench
337
337
  # On Windows NTFS we *skip* the 4 GiB pre-extension
338
338
  # entirely. Both ``os.ftruncate`` and ``lseek + write
339
339
  # sentinel`` perturb the file's valid-data-length so that
340
340
  # the close-time ``ftruncate(actual)`` measurably stalls
341
- # (3.9 s -> 7.7 s bimodal in win-vm/qcow2). The on-demand
341
+ # (3.9 s -> 7.7 s bimodal in windows-vm/qcow2). The on-demand
342
342
  # extension path is fast and correct; we only lose the
343
343
  # marginal contiguous-extent hint that pre-allocation
344
344
  # would have given the filesystem.