opencodecs 0.1.3__tar.gz → 0.1.6__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 (208) hide show
  1. opencodecs-0.1.6/3rdparty/cfitsio/pliocomp.c +331 -0
  2. {opencodecs-0.1.3 → opencodecs-0.1.6}/CHANGES.rst +222 -0
  3. {opencodecs-0.1.3/src/opencodecs.egg-info → opencodecs-0.1.6}/PKG-INFO +1 -1
  4. {opencodecs-0.1.3 → opencodecs-0.1.6}/pyproject.toml +7 -4
  5. {opencodecs-0.1.3 → opencodecs-0.1.6}/setup.py +199 -26
  6. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/__init__.py +1 -1
  7. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_eer_reader.py +35 -6
  8. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_fits_compressed.py +34 -4
  9. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_pyramid_build.py +66 -1
  10. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_tiff_http.py +83 -0
  11. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_tiff_pyramid.py +38 -2
  12. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_tiff_writer.py +51 -2
  13. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/__init__.py +15 -3
  14. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_bcdec.c +152 -152
  15. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_bmp.c +152 -152
  16. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_eer.c +152 -152
  17. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_hcomp.c +152 -152
  18. opencodecs-0.1.6/src/opencodecs/codecs/_plio.c +30037 -0
  19. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_png.c +152 -152
  20. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_qoi.c +152 -152
  21. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_rcomp.c +152 -152
  22. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_rgbe.c +152 -152
  23. opencodecs-0.1.6/src/opencodecs/uhdr.py +326 -0
  24. {opencodecs-0.1.3 → opencodecs-0.1.6/src/opencodecs.egg-info}/PKG-INFO +1 -1
  25. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs.egg-info/SOURCES.txt +4 -1
  26. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_eer.py +61 -9
  27. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_fits.py +14 -5
  28. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_omezarr.py +13 -0
  29. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tiff_http.py +74 -0
  30. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tiff_writer.py +68 -0
  31. opencodecs-0.1.6/tests/test_uhdr.py +392 -0
  32. opencodecs-0.1.3/tests/test_ultrahdr.py +0 -130
  33. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/bcdec/bcdec.h +0 -0
  34. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/bitshuffle/bitshuffle_core.c +0 -0
  35. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/bitshuffle/iochain.c +0 -0
  36. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/cfitsio/fits_hdecompress.c +0 -0
  37. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/cfitsio/ricecomp.c +0 -0
  38. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/imcd_eer/eer.c +0 -0
  39. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/imcd_eer/eer.h +0 -0
  40. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/imcd_lzw/lzw.c +0 -0
  41. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/imcd_lzw/lzw.h +0 -0
  42. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/libspng/spng.c +0 -0
  43. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/oc_tifflzw/oc_tifflzw.c +0 -0
  44. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/oc_tifflzw/oc_tifflzw.h +0 -0
  45. {opencodecs-0.1.3 → opencodecs-0.1.6}/3rdparty/rgbe/rgbe.c +0 -0
  46. {opencodecs-0.1.3 → opencodecs-0.1.6}/MANIFEST.in +0 -0
  47. {opencodecs-0.1.3 → opencodecs-0.1.6}/README.md +0 -0
  48. {opencodecs-0.1.3 → opencodecs-0.1.6}/bench/build_libjxl.sh +0 -0
  49. {opencodecs-0.1.3 → opencodecs-0.1.6}/patches/libjxl/README.md +0 -0
  50. {opencodecs-0.1.3 → opencodecs-0.1.6}/setup.cfg +0 -0
  51. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_aec_codec.py +0 -0
  52. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_avif_codec.py +0 -0
  53. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_b2nd_codec.py +0 -0
  54. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_bcn_codec.py +0 -0
  55. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_bitshuffle_codec.py +0 -0
  56. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_blosc2_codec.py +0 -0
  57. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_bmp_codec.py +0 -0
  58. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_brotli_codec.py +0 -0
  59. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_brunsli_codec.py +0 -0
  60. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_byteshuffle_codec.py +0 -0
  61. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_bz2_codec.py +0 -0
  62. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_cms_codec.py +0 -0
  63. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_czi_codec.py +0 -0
  64. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_czi_reader.py +0 -0
  65. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_czi_writer.py +0 -0
  66. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_deflate_codec.py +0 -0
  67. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_dicomrle_codec.py +0 -0
  68. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_dicomweb.py +0 -0
  69. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_ets.py +0 -0
  70. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_fits.py +0 -0
  71. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_fits_codec.py +0 -0
  72. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_gif_codec.py +0 -0
  73. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_gzip_codec.py +0 -0
  74. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_hdf5_codec.py +0 -0
  75. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_hdf5_http.py +0 -0
  76. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_heif_codec.py +0 -0
  77. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_htj2k_codec.py +0 -0
  78. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_jpeg2k_codec.py +0 -0
  79. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_jpeg_codec.py +0 -0
  80. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_jpegls_codec.py +0 -0
  81. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_jxl_codec.py +0 -0
  82. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_lerc_codec.py +0 -0
  83. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_lif_codec.py +0 -0
  84. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_lif_native.py +0 -0
  85. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_lz4_codec.py +0 -0
  86. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_lzma_codec.py +0 -0
  87. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_mozjpeg_codec.py +0 -0
  88. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_nd2_codec.py +0 -0
  89. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_nd2_native.py +0 -0
  90. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_ndtiff.py +0 -0
  91. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_ndtiff_pyramid.py +0 -0
  92. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_ndtiff_writer.py +0 -0
  93. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_none_codec.py +0 -0
  94. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_numpy_codec.py +0 -0
  95. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_oib_codec.py +0 -0
  96. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_oib_native.py +0 -0
  97. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_oir_codec.py +0 -0
  98. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_ole2.py +0 -0
  99. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_ome_xml.py +0 -0
  100. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_omezarr.py +0 -0
  101. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_omezarr_writer.py +0 -0
  102. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_packints_codec.py +0 -0
  103. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_pcodec_codec.py +0 -0
  104. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_png_codec.py +0 -0
  105. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_predictor_codec.py +0 -0
  106. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_qoi_codec.py +0 -0
  107. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_quantize_codec.py +0 -0
  108. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_rcomp_codec.py +0 -0
  109. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_rgbe.py +0 -0
  110. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_rgbe_codec.py +0 -0
  111. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_snappy_codec.py +0 -0
  112. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_sperr_codec.py +0 -0
  113. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_sz3_codec.py +0 -0
  114. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_tiff_codec.py +0 -0
  115. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_ultrahdr_codec.py +0 -0
  116. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_vsi_codec.py +0 -0
  117. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_webp_codec.py +0 -0
  118. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_zarr_codecs.py +0 -0
  119. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_zfp_codec.py +0 -0
  120. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/_zstd_codec.py +0 -0
  121. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_bitshuffle.c +0 -0
  122. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_bytetools.c +0 -0
  123. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_deflate.c +0 -0
  124. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_lz4.c +0 -0
  125. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_ndtiff.c +0 -0
  126. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_registry.py +0 -0
  127. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_tiff.c +0 -0
  128. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/codecs/_zstd.c +0 -0
  129. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/__init__.py +0 -0
  130. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/_io_helpers.py +0 -0
  131. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/_optional_backend.py +0 -0
  132. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/codec.py +0 -0
  133. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/color.py +0 -0
  134. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/errors.py +0 -0
  135. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/io.py +0 -0
  136. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/pyramid.py +0 -0
  137. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/core/segment_compression.py +0 -0
  138. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/jxl.py +0 -0
  139. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/parallel.py +0 -0
  140. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/tiff_reader.py +0 -0
  141. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/tifffile_patch.py +0 -0
  142. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs/zarr.py +0 -0
  143. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs.egg-info/dependency_links.txt +0 -0
  144. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs.egg-info/requires.txt +0 -0
  145. {opencodecs-0.1.3 → opencodecs-0.1.6}/src/opencodecs.egg-info/top_level.txt +0 -0
  146. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_auto_pyramid.py +0 -0
  147. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_bcdec.py +0 -0
  148. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_brunsli.py +0 -0
  149. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_charls.py +0 -0
  150. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_core_codec_api.py +0 -0
  151. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_corpus.py +0 -0
  152. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_corpus_codec_decode.py +0 -0
  153. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_corpus_other.py +0 -0
  154. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_corpus_png.py +0 -0
  155. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_corpus_tiff.py +0 -0
  156. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_corpus_vendors.py +0 -0
  157. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_coverage_final.py +0 -0
  158. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_coverage_finishing.py +0 -0
  159. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_coverage_last.py +0 -0
  160. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_coverage_more.py +0 -0
  161. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_coverage_push.py +0 -0
  162. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_czi_fixture.py +0 -0
  163. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_czi_pyramid.py +0 -0
  164. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_czi_writer.py +0 -0
  165. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_data_source.py +0 -0
  166. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_deflate.py +0 -0
  167. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_dicomweb.py +0 -0
  168. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_edge_cases.py +0 -0
  169. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_encode_comprehensive.py +0 -0
  170. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_error_handling.py +0 -0
  171. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_gif.py +0 -0
  172. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_hdf5_http.py +0 -0
  173. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_hdf5_local.py +0 -0
  174. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_heif_avif_features.py +0 -0
  175. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_http_byte_savings.py +0 -0
  176. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_http_prefetch.py +0 -0
  177. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_http_unified.py +0 -0
  178. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_io_chunked.py +0 -0
  179. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_isal.py +0 -0
  180. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_jxl.py +0 -0
  181. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_lif_native.py +0 -0
  182. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_live_archives.py +0 -0
  183. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_mozjpeg.py +0 -0
  184. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_native_parity.py +0 -0
  185. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_nd2_native.py +0 -0
  186. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_ndtiff.py +0 -0
  187. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_oib_native.py +0 -0
  188. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_ome_xml.py +0 -0
  189. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_omezarr_sharded_range.py +0 -0
  190. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_open_pyramid.py +0 -0
  191. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_openjph.py +0 -0
  192. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_optional_backend.py +0 -0
  193. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_parallel_jxl.py +0 -0
  194. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_phase4_filters.py +0 -0
  195. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_phase5_icc.py +0 -0
  196. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_phase6_codecs.py +0 -0
  197. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_phase7_cms.py +0 -0
  198. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_rgbe.py +0 -0
  199. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_snappy.py +0 -0
  200. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tier1_scientific.py +0 -0
  201. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tiff_codec_encode.py +0 -0
  202. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tiff_native.py +0 -0
  203. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tiff_pyramid.py +0 -0
  204. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tiff_reader.py +0 -0
  205. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_tifffile_patch.py +0 -0
  206. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_unified_api.py +0 -0
  207. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_vsi_oir.py +0 -0
  208. {opencodecs-0.1.3 → opencodecs-0.1.6}/tests/test_zarr_adapters.py +0 -0
@@ -0,0 +1,331 @@
1
+ /* stdlib is needed for the abs function */
2
+ #include <stdlib.h>
3
+ /*
4
+ The following prototype code was provided by Doug Tody, NRAO, for
5
+ performing conversion between pixel arrays and line lists. The
6
+ compression technique is used in IRAF.
7
+ */
8
+ int pl_p2li (int *pxsrc, int xs, short *lldst, int npix);
9
+ int pl_l2pi (short *ll_src, int xs, int *px_dst, int npix);
10
+
11
+
12
+ /*
13
+ * PL_P2L -- Convert a pixel array to a line list. The length of the list is
14
+ * returned as the function value.
15
+ *
16
+ * Translated from the SPP version using xc -f, f2c. 8Sep99 DCT.
17
+ */
18
+
19
+ #ifndef min
20
+ #define min(a,b) (((a)<(b))?(a):(b))
21
+ #endif
22
+ #ifndef max
23
+ #define max(a,b) (((a)>(b))?(a):(b))
24
+ #endif
25
+
26
+ int pl_p2li (int *pxsrc, int xs, short *lldst, int npix)
27
+ /* int *pxsrc; input pixel array */
28
+ /* int xs; starting index in pxsrc (?) */
29
+ /* short *lldst; encoded line list */
30
+ /* int npix; number of pixels to convert */
31
+ {
32
+ /* System generated locals */
33
+ int ret_val, i__1, i__2, i__3;
34
+
35
+ /* Local variables */
36
+ int zero, v, x1, hi, ip, dv, xe, np, op, iz, nv = 0, pv, nz;
37
+
38
+ /* Parameter adjustments */
39
+ --lldst;
40
+ --pxsrc;
41
+
42
+ /* Function Body */
43
+ if (! (npix <= 0)) {
44
+ goto L110;
45
+ }
46
+ ret_val = 0;
47
+ goto L100;
48
+ L110:
49
+ lldst[3] = -100;
50
+ lldst[2] = 7;
51
+ lldst[1] = 0;
52
+ lldst[6] = 0;
53
+ lldst[7] = 0;
54
+ xe = xs + npix - 1;
55
+ op = 8;
56
+ zero = 0;
57
+ /* Computing MAX */
58
+ i__1 = zero, i__2 = pxsrc[xs];
59
+ pv = max(i__1,i__2);
60
+ x1 = xs;
61
+ iz = xs;
62
+ hi = 1;
63
+ i__1 = xe;
64
+ for (ip = xs; ip <= i__1; ++ip) {
65
+ if (! (ip < xe)) {
66
+ goto L130;
67
+ }
68
+ /* Computing MAX */
69
+ i__2 = zero, i__3 = pxsrc[ip + 1];
70
+ nv = max(i__2,i__3);
71
+ if (! (nv == pv)) {
72
+ goto L140;
73
+ }
74
+ goto L120;
75
+ L140:
76
+ if (! (pv == 0)) {
77
+ goto L150;
78
+ }
79
+ pv = nv;
80
+ x1 = ip + 1;
81
+ goto L120;
82
+ L150:
83
+ goto L131;
84
+ L130:
85
+ if (! (pv == 0)) {
86
+ goto L160;
87
+ }
88
+ x1 = xe + 1;
89
+ L160:
90
+ L131:
91
+ np = ip - x1 + 1;
92
+ nz = x1 - iz;
93
+ if (! (pv > 0)) {
94
+ goto L170;
95
+ }
96
+ dv = pv - hi;
97
+ if (! (dv != 0)) {
98
+ goto L180;
99
+ }
100
+ hi = pv;
101
+ if (! (abs(dv) > 4095)) {
102
+ goto L190;
103
+ }
104
+ lldst[op] = (short) ((pv & 4095) + 4096);
105
+ ++op;
106
+ lldst[op] = (short) (pv / 4096);
107
+ ++op;
108
+ goto L191;
109
+ L190:
110
+ if (! (dv < 0)) {
111
+ goto L200;
112
+ }
113
+ lldst[op] = (short) (-dv + 12288);
114
+ goto L201;
115
+ L200:
116
+ lldst[op] = (short) (dv + 8192);
117
+ L201:
118
+ ++op;
119
+ if (! (np == 1 && nz == 0)) {
120
+ goto L210;
121
+ }
122
+ v = lldst[op - 1];
123
+ lldst[op - 1] = (short) (v | 16384);
124
+ goto L91;
125
+ L210:
126
+ L191:
127
+ L180:
128
+ L170:
129
+ if (! (nz > 0)) {
130
+ goto L220;
131
+ }
132
+ L230:
133
+ if (! (nz > 0)) {
134
+ goto L232;
135
+ }
136
+ lldst[op] = (short) min(4095,nz);
137
+ ++op;
138
+ /* L231: */
139
+ nz += -4095;
140
+ goto L230;
141
+ L232:
142
+ if (! (np == 1 && pv > 0)) {
143
+ goto L240;
144
+ }
145
+ lldst[op - 1] = (short) (lldst[op - 1] + 20481);
146
+ goto L91;
147
+ L240:
148
+ L220:
149
+ L250:
150
+ if (! (np > 0)) {
151
+ goto L252;
152
+ }
153
+ lldst[op] = (short) (min(4095,np) + 16384);
154
+ ++op;
155
+ /* L251: */
156
+ np += -4095;
157
+ goto L250;
158
+ L252:
159
+ L91:
160
+ x1 = ip + 1;
161
+ iz = x1;
162
+ pv = nv;
163
+ L120:
164
+ ;
165
+ }
166
+ /* L121: */
167
+ lldst[4] = (short) ((op - 1) % 32768);
168
+ lldst[5] = (short) ((op - 1) / 32768);
169
+ ret_val = op - 1;
170
+ goto L100;
171
+ L100:
172
+ return ret_val;
173
+ } /* plp2li_ */
174
+
175
+ /*
176
+ * PL_L2PI -- Translate a PLIO line list into an integer pixel array.
177
+ * The number of pixels output (always npix) is returned as the function
178
+ * value.
179
+ *
180
+ * Translated from the SPP version using xc -f, f2c. 8Sep99 DCT.
181
+ */
182
+
183
+ int pl_l2pi (short *ll_src, int xs, int *px_dst, int npix)
184
+ /* short *ll_src; encoded line list */
185
+ /* int xs; starting index in ll_src */
186
+ /* int *px_dst; output pixel array */
187
+ /* int npix; number of pixels to convert */
188
+ {
189
+ /* System generated locals */
190
+ int ret_val, i__1, i__2;
191
+
192
+ /* Local variables */
193
+ int data, sw0001, otop, i__, lllen, i1, i2, x1, x2, ip, xe, np,
194
+ op, pv, opcode, llfirt;
195
+ int skipwd;
196
+
197
+ /* Parameter adjustments */
198
+ --px_dst;
199
+ --ll_src;
200
+
201
+ /* Function Body */
202
+ if (! (ll_src[3] > 0)) {
203
+ goto L110;
204
+ }
205
+ lllen = ll_src[3];
206
+ llfirt = 4;
207
+ goto L111;
208
+ L110:
209
+ lllen = (ll_src[5] << 15) + ll_src[4];
210
+ llfirt = ll_src[2] + 1;
211
+ L111:
212
+ if (! (npix <= 0 || lllen <= 0)) {
213
+ goto L120;
214
+ }
215
+ ret_val = 0;
216
+ goto L100;
217
+ L120:
218
+ xe = xs + npix - 1;
219
+ skipwd = 0;
220
+ op = 1;
221
+ x1 = 1;
222
+ pv = 1;
223
+ i__1 = lllen;
224
+ for (ip = llfirt; ip <= i__1; ++ip) {
225
+ if (! skipwd) {
226
+ goto L140;
227
+ }
228
+ skipwd = 0;
229
+ goto L130;
230
+ L140:
231
+ opcode = ll_src[ip] / 4096;
232
+ data = ll_src[ip] & 4095;
233
+ sw0001 = opcode;
234
+ goto L150;
235
+ L160:
236
+ x2 = x1 + data - 1;
237
+ i1 = max(x1,xs);
238
+ i2 = min(x2,xe);
239
+ np = i2 - i1 + 1;
240
+ if (! (np > 0)) {
241
+ goto L170;
242
+ }
243
+ otop = op + np - 1;
244
+ if (! (opcode == 4)) {
245
+ goto L180;
246
+ }
247
+ i__2 = otop;
248
+ for (i__ = op; i__ <= i__2; ++i__) {
249
+ px_dst[i__] = pv;
250
+ /* L190: */
251
+ }
252
+ /* L191: */
253
+ goto L181;
254
+ L180:
255
+ i__2 = otop;
256
+ for (i__ = op; i__ <= i__2; ++i__) {
257
+ px_dst[i__] = 0;
258
+ /* L200: */
259
+ }
260
+ /* L201: */
261
+ if (! (opcode == 5 && i2 == x2)) {
262
+ goto L210;
263
+ }
264
+ px_dst[otop] = pv;
265
+ L210:
266
+ L181:
267
+ op = otop + 1;
268
+ L170:
269
+ x1 = x2 + 1;
270
+ goto L151;
271
+ L220:
272
+ pv = (ll_src[ip + 1] << 12) + data;
273
+ skipwd = 1;
274
+ goto L151;
275
+ L230:
276
+ pv += data;
277
+ goto L151;
278
+ L240:
279
+ pv -= data;
280
+ goto L151;
281
+ L250:
282
+ pv += data;
283
+ goto L91;
284
+ L260:
285
+ pv -= data;
286
+ L91:
287
+ if (! (x1 >= xs && x1 <= xe)) {
288
+ goto L270;
289
+ }
290
+ px_dst[op] = pv;
291
+ ++op;
292
+ L270:
293
+ ++x1;
294
+ goto L151;
295
+ L150:
296
+ ++sw0001;
297
+ if (sw0001 < 1 || sw0001 > 8) {
298
+ goto L151;
299
+ }
300
+ switch ((int)sw0001) {
301
+ case 1: goto L160;
302
+ case 2: goto L220;
303
+ case 3: goto L230;
304
+ case 4: goto L240;
305
+ case 5: goto L160;
306
+ case 6: goto L160;
307
+ case 7: goto L250;
308
+ case 8: goto L260;
309
+ }
310
+ L151:
311
+ if (! (x1 > xe)) {
312
+ goto L280;
313
+ }
314
+ goto L131;
315
+ L280:
316
+ L130:
317
+ ;
318
+ }
319
+ L131:
320
+ i__1 = npix;
321
+ for (i__ = op; i__ <= i__1; ++i__) {
322
+ px_dst[i__] = 0;
323
+ /* L290: */
324
+ }
325
+ /* L291: */
326
+ ret_val = npix;
327
+ goto L100;
328
+ L100:
329
+ return ret_val;
330
+ } /* pll2pi_ */
331
+
@@ -10,6 +10,228 @@ 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.6 (2026-06-01)
14
+ ------------------
15
+
16
+ **libultrahdr now bundled (fixes missing ``_uhdr`` on PyPI wheels)**
17
+
18
+ * ``bench/build_codec_libs.sh::build_libultrahdr`` builds libuhdr
19
+ v1.4.0 (Apache-2.0) into ``$OPENCODECS_LIBS_PREFIX/{include,lib}``
20
+ alongside the other source-built codec libs. The Linux + Windows
21
+ CI ``--only=...`` lists pick it up; the macOS ``before-all`` brew
22
+ install now includes ``libultrahdr`` as well.
23
+ * setup.py's ``_uhdr`` Extension is now built by a probe
24
+ (``_maybe_build_uhdr_ext``) that finds the cached prefix, sets
25
+ ``library_dirs``, and bakes the rpath into the resulting ``.so``
26
+ so delocate / auditwheel / delvewheel can bundle ``libuhdr``'s
27
+ dylib/.so/.dll into the wheel.
28
+ * ``_uhdr`` is now in ``MUST_SHIP_ALL_PLATFORMS`` in
29
+ ``ci/check_wheel_contents.py``; a wheel without the Ultra-HDR
30
+ extension fails the wheel-coverage step.
31
+ * The stale ``_ultrahdr.pyx`` source file (orphaned in commit
32
+ ``c9347f5`` when the direct libuhdr binding shipped as ``_uhdr``)
33
+ is removed.
34
+
35
+ **New API: ``opencodecs.uhdr.decode_native``**
36
+
37
+ Fused-Cython fast-path Ultra-HDR decoder. Uses libuhdr's parser to
38
+ pull out the compressed SDR base + gain-map JPEGs + metadata (no
39
+ pixel decode), then decodes both JPEGs in parallel via
40
+ ``imagecodecs.jpeg_decode`` (libjpeg-turbo SIMD, GIL released) and
41
+ applies the gain map in a Cython kernel that uses the same sRGB
42
+ EOTF LUT + IEEE-754 polynomial ``exp2`` the encoder uses. ~1.4×
43
+ faster than libuhdr's reference decode on a 2k² float HDR (M-series
44
+ Mac: ~52 ms vs ~72 ms). Output matches libuhdr's decode to within
45
+ JPEG-q95 + 8-bit gain-quantisation noise. ``display_boost`` kwarg
46
+ exposes the ISO 21496-1 headroom scaler — default is full HDR
47
+ (``hdr_capacity_max``), pass ``1.0`` to match libuhdr's default
48
+ SDR-equivalent decode.
49
+
50
+ Backed by two new Cython helpers exposed for advanced callers:
51
+
52
+ * ``opencodecs.codecs._uhdr.extract_layers(data)`` — parse the
53
+ container, return ``{base_jpeg, gainmap_jpeg, gainmap_metadata,
54
+ width, height, gainmap_{width,height}}`` without decoding pixels.
55
+ * ``opencodecs.codecs._uhdr.apply_gainmap_fp32(sdr_u8, gain_u8,
56
+ metadata, display_boost=...)`` — the per-pixel gain-application
57
+ kernel.
58
+
59
+ **New API: ``opencodecs.uhdr.encode_to``**
60
+
61
+ Streaming variant of :func:`encode_native` — writes Ultra-HDR bytes
62
+ directly to a file-like (anything with ``write(bytes)``: open file,
63
+ ``io.BytesIO``, HTTP upload streamer). Returns the byte count.
64
+ Forward-compatible alias: the libuhdr api-4 path we currently use
65
+ for container assembly doesn't expose a streaming writer, so the
66
+ function is ``fp.write(encode_native(...))`` today; the API exists
67
+ so callers can adopt it now and pick up any future libuhdr
68
+ streaming write-out without changing their code.
69
+
70
+ **CI / build robustness**
71
+
72
+ * ``_uhdr`` extension now links ``-lmvec -lm`` on Linux. GCC at
73
+ ``-O3 -ffast-math`` auto-vectorises the sRGB LUT-init ``pow()``
74
+ calls into ``_ZGV*`` symbols from glibc's libmvec. AlmaLinux 8's
75
+ manylinux toolchain auto-links libmvec so the issue was masked
76
+ in CI, but Ubuntu's GCC doesn't — caught when verifying on a
77
+ threadripper Ubuntu 25.04 box.
78
+ * The libaec source URL moved from ``gitlab.dkrz.de`` (now
79
+ auth-gated; anonymous requests redirect to ``/users/sign_in``)
80
+ to DKRZ's GitHub mirror at
81
+ ``github.com/Deutsches-Klimarechenzentrum/libaec``.
82
+ * ``fetch_tar`` now has a 4-attempt shell retry loop with empty-
83
+ extract detection — covers transient mirror outages that
84
+ curl's own ``--retry`` doesn't see (e.g. 200 OK with a
85
+ truncated body).
86
+
87
+ 0.1.5 (2026-05-31)
88
+ ------------------
89
+
90
+ **New codecs**
91
+
92
+ * ``opencodecs.uhdr`` — Ultra-HDR / ISO 21496-1 (gainmap JPEG) via a
93
+ direct Cython binding to Google's libultrahdr. ``encode(hdr, ...)``
94
+ wraps libuhdr's full pipeline; ``encode_native(hdr, sdr=None, ...)``
95
+ is a fused-Cython fast path that computes SDR base + gain map in
96
+ ``nogil`` kernels (IEEE-754 polynomial log2/pow, cross-platform —
97
+ no Apple Accelerate intrinsics), JPEG-encodes both layers in
98
+ parallel via a 3-worker ThreadPoolExecutor, then hands the
99
+ pre-encoded JPEGs to libuhdr's api-4 for container assembly.
100
+ Measured 31 ms median for a 2000² float HDR on M-series Mac vs
101
+ ~173 ms for the libuhdr reference path — 5.5× faster. The
102
+ ``sdr=`` argument lets callers (notably tilescan pipelines) supply
103
+ their own SDR base instead of accepting the peak-normalised default.
104
+
105
+ * ``PLIO_1`` — IRAF run-length mask coding closes the last FITS
106
+ tile-compression gap. Vendors cfitsio's ``pliocomp.c`` (Doug Tody /
107
+ NRAO, public-domain) and adds the tiny
108
+ ``opencodecs.codecs._plio.decode_raw`` shim. Round-trip tested
109
+ against astropy. The ``COMPRESSED_DATA`` BINTABLE column walker
110
+ now tracks per-column element byte width so the ``1PI`` (int16
111
+ opcodes) layout PLIO uses works alongside the ``1PB`` byte VLA the
112
+ other compressors use.
113
+
114
+ **New API**
115
+
116
+ * ``EerReader.sum(start, stop, *, weights=None, dtype=...)`` —
117
+ per-frame dose curve. ``weights[k]`` multiplies the k-th frame in
118
+ the requested range; output promotes to float64 when weights are
119
+ given so fractional contributions don't truncate. Use case:
120
+ beam-induced-motion correction and temporal-binning schemes that
121
+ emphasise different exposures across the acquisition.
122
+
123
+ **Bug fixes**
124
+
125
+ * HEIF encode against libheif ≥ 1.18 — newer libheif calls
126
+ ``strlen()`` on the user write-callback's ``heif_error.message``
127
+ even on success and rejects a ``NULL`` pointer with *"heif_writer
128
+ callback returned a null error text"*. The callback now hands back
129
+ a static empty string on success and a descriptive string on OOM.
130
+ Six tests (``test_heif_*``, ``test_phase5_icc.py[heif]``) go back
131
+ to green across every CI matrix entry.
132
+
133
+ **CI / build**
134
+
135
+ * ``bench/build_codec_libs.sh`` — the ``is_built`` cache-marker now
136
+ records the install dir alongside the version and re-verifies the
137
+ install dir exists before short-circuiting a recipe. Without this,
138
+ cibuildwheel's manylinux cache (which only covers ``/cibw-jxl-prefix``)
139
+ preserved the marker for recipes that install to
140
+ ``~/.cache/opencodecs/<lib>/`` outside the cached prefix —
141
+ ``lerc``, ``mozjpeg``, ``brotli``, ``zstd``, ``giflib`` — so the
142
+ recipe thought it was done while the actual library files were
143
+ gone. ``_lerc`` + ``_mozjpeg`` had been silently dropped from
144
+ Linux wheels for this reason; the fix restores them.
145
+
146
+ * ``test_omezarr.py`` skips at module level on zarr-python < 3 —
147
+ fixtures use the v3 API surface, which doesn't exist on the v2
148
+ branch pip resolves on Python 3.10.
149
+
150
+ * ``test_eer_imagecodecs_cross_validate`` is now symmetric on
151
+ decoder error: if either implementation raises, both must raise
152
+ for the combo to count. Tolerates imagecodecs ≥ 2026.5's tighter
153
+ output-buffer sizing.
154
+
155
+ 0.1.4 (2026-05-25)
156
+ ------------------
157
+
158
+ **libvips-inspired streaming improvements**
159
+
160
+ * ``HTTPDataSource(access='sequential', sequential_chunk_bytes=4*1024*1024)``
161
+ — opt-in libvips-style sequential read mode. Replaces the LRU +
162
+ adaptive read-ahead with a single rolling buffer that slides forward
163
+ as the caller reads. Memory stays bounded to one chunk regardless of
164
+ file size. Target workload: tile-by-tile raster scan over a huge
165
+ COG / OME-TIFF served over HTTP. Backward seeks still work but
166
+ invalidate the buffer; ``stats['sequential_backward_seeks']`` tracks
167
+ the count so users can spot a workload that's actually random and
168
+ would benefit from ``access='random'``.
169
+
170
+ * ``TiffPyramidReader.read_region`` now parallelises tile decode
171
+ across a thread pool (default ``min(cpu_count(), 8)``). The
172
+ compressed-tile decoders (JPEG, JPEG-2000, deflate, zstd, LZW, WebP,
173
+ LERC) all release the GIL in their C path, so threads scale across
174
+ cores on CPython. Kicks in only when the region covers 4+ tiles —
175
+ fewer than that and thread-pool spin-up cost dominates. Pass
176
+ ``num_decode_workers=1`` to force the serial path for benchmarks /
177
+ regression-diff.
178
+
179
+ * ``TiffWriter.write_pyramid_auto`` gained ``stream_levels=True``
180
+ (default for COG layout). Computes and writes one level at a time
181
+ via a new ``iter_pyramid_levels`` generator, dropping each finished
182
+ level before computing the next. Peak memory drops from
183
+ ``~1.33 × level0`` (entire geometric series materialised) to
184
+ ``~2 × current_level``. Useful when level 0 already dominates RAM
185
+ (whole-slide pathology, cryo-EM tomograms). Output file is
186
+ byte-identical to the materialize-all path. SubIFD layout
187
+ (``subifds=True``) still uses the materialize path because that
188
+ layout writes sub-resolution IFD offsets into the main IFD's tag
189
+ 330 — sub-level offsets have to be known up front.
190
+
191
+ Validated via tests:
192
+ ``test_http_sequential_serves_from_rolling_buffer``,
193
+ ``test_http_sequential_backward_seek_counted``,
194
+ ``test_pyramid_reader_parallel_decode_matches_serial``,
195
+ ``test_pyramid_auto_stream_matches_materialize``,
196
+ ``test_iter_pyramid_levels_matches_make_pyramid_levels``.
197
+
198
+ **MozJPEG ships on every wheel**
199
+
200
+ * Added MozJPEG (Mozilla's libjpeg-turbo fork) to the cibuildwheel
201
+ codec-lib build set on Linux, macOS, and Windows. MozJPEG produces
202
+ JPEG files ~10-15% smaller than baseline libjpeg-turbo at the same
203
+ quality setting (progressive encoding + trellis quantization +
204
+ better quantization tables). The ``_mozjpeg`` extension has shipped
205
+ on macOS wheels for a while via brew; v0.1.4 brings it to
206
+ Linux + Windows so the codec is available everywhere.
207
+ * New ``build_mozjpeg`` recipe in ``bench/build_codec_libs.sh``
208
+ installs into a keg-style ``mozjpeg/`` subdir under the prefix
209
+ (rather than the shared ``$PREFIX/{include,lib}``) to avoid the
210
+ libturbojpeg / libjpeg name collision with the libjpeg-turbo 3.x
211
+ install. setup.py's mozjpeg probe was extended to recognise the
212
+ new candidate paths on Linux (``~/.cache/opencodecs/mozjpeg``),
213
+ Windows (``$CONDA_PREFIX/Library/mozjpeg``), and the Windows
214
+ fallback (no ``nm``: trust the keg-style directory name).
215
+ * Locally validated on win-vm (MSVC 14.44 — same as CI) and
216
+ kevin-tower (Linux x86_64): ``bash bench/build_codec_libs.sh
217
+ --only=mozjpeg`` followed by ``setup.py build_ext --inplace``
218
+ produces ``_mozjpeg.{pyd,so}`` cleanly. Per the new lesson in
219
+ CLAUDE.md, this iteration was validated end-to-end through the
220
+ same script CI runs, with the same env vars, before any push.
221
+
222
+ **Post-publish wheel coverage check (CI hardening)**
223
+
224
+ * New ``ci/check_wheel_contents.py`` runs in the wheel-build job
225
+ immediately after ``cibuildwheel`` produces each wheel. It unzips
226
+ the wheel, walks ``opencodecs/codecs/``, and asserts every codec
227
+ in the ``MUST_SHIP_ALL_PLATFORMS`` set has a ``.pyd``/``.so``
228
+ present. Missing codec → matrix job fails → publish step gated.
229
+ * Catches the v0.1.2-style "changelog overclaim" silent-drop class
230
+ of bugs at build time instead of after publish. v0.1.2's Windows
231
+ wheels shipped without ``_sperr``/``_brunsli`` despite the
232
+ changelog claim; this check would have failed that build.
233
+
234
+
13
235
  0.1.3 (2026-05-22)
14
236
  ------------------
15
237
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencodecs
3
- Version: 0.1.3
3
+ Version: 0.1.6
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opencodecs"
7
- version = "0.1.3"
7
+ version = "0.1.6"
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"
@@ -142,7 +142,7 @@ before-all = [
142
142
  # bench/build_codec_libs.sh into the cached /cibw-jxl-prefix mount.
143
143
  # Skips encoders (aom, x265) — wheel ships decode-only AVIF/HEIF to
144
144
  # keep build < 12 min cold + avoid GPL x265.
145
- "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'",
145
+ "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'",
146
146
  "bash bench/build_libjxl.sh",
147
147
  ]
148
148
  # Don't set OPENCODECS_*_PREFIX here — build_wheels.yml's
@@ -159,8 +159,11 @@ before-all = [
159
159
  # cache by bench/build_codec_libs.sh. brunsli vendors brotli as a
160
160
  # submodule so the brew brotli isn't required at link time.
161
161
  before-all = [
162
- "brew install jpeg-xl libavif libheif webp libpng jpeg-turbo openjpeg zstd brotli c-blosc2 lz4 libdeflate libaec liblerc zfp rust cmake ninja",
163
- "bash bench/build_codec_libs.sh --only=SZ3,pcodec,SPERR,brunsli",
162
+ # mozjpeg removed from this brew install the formula ships libjpeg
163
+ # only, not libturbojpeg, so the _mozjpeg probe couldn't find what it
164
+ # needed. Source-build via build_codec_libs.sh produces both libs.
165
+ "brew install jpeg-xl libavif libheif webp libpng jpeg-turbo openjpeg zstd brotli c-blosc2 lz4 libdeflate libaec liblerc zfp rust cmake ninja libultrahdr",
166
+ "bash bench/build_codec_libs.sh --only=SZ3,pcodec,SPERR,brunsli,mozjpeg",
164
167
  ]
165
168
  # macos-latest is now macOS 15 (Sequoia) on arm64. Homebrew formulas are
166
169
  # compiled for 15.x, so any wheel target lower than 15 fails the delocate