opencodecs 0.6.0__tar.gz → 0.7.1__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.
- {opencodecs-0.6.0 → opencodecs-0.7.1}/CHANGES.rst +121 -0
- {opencodecs-0.6.0/src/opencodecs.egg-info → opencodecs-0.7.1}/PKG-INFO +13 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/pyproject.toml +16 -2
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/__init__.py +1 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_czi_reader.py +4 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_czi_writer.py +195 -14
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_jxl_codec.py +17 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_omezarr.py +4 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_omezarr_writer.py +19 -7
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/segment_compression.py +6 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1/src/opencodecs.egg-info}/PKG-INFO +13 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs.egg-info/SOURCES.txt +2 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs.egg-info/requires.txt +12 -0
- opencodecs-0.7.1/tests/test_czi_foreign_readers.py +163 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_pread_indices.py +3 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_read_dispatch.py +7 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_recompress.py +211 -1
- opencodecs-0.7.1/tests/test_foreign_readers.py +653 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_segment_encoder_binding.py +3 -1
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/VENDOR.toml +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bcdec/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bcdec/README.md +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bcdec/bcdec.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/README.rst +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/bitshuffle.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/bitshuffle.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/bitshuffle_core.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/bitshuffle_core.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/bitshuffle_internals.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/iochain.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/bitshuffle/iochain.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/License.txt +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/fits_hcompress.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/fits_hdecompress.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/fits_hdecompress_api.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/fitsio2.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/pliocomp.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/ricecomp.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/cfitsio/ricecomp.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/libspng/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/libspng/spng.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/libspng/spng.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_eer/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_eer/oc_eer.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_eer/oc_eer.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_giflzw/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_giflzw/oc_giflzw.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_giflzw/oc_giflzw.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_tifflzw/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_tifflzw/oc_tifflzw.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/oc_tifflzw/oc_tifflzw.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/qoi/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/qoi/qoi.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/rgbe/rgbe.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/rgbe/rgbe.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/rgbe/rgbe.txt +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/3rdparty/vendor_hashes.json +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/LICENSE +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/MANIFEST.in +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/README.md +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/THIRD-PARTY.md +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/bench/build_libjxl.sh +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/patches/libjxl/README.md +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/setup.cfg +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/setup.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_aec_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_avif_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_avif_heif_params.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_b2nd_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_bcn_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_bitshuffle_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_blosc2_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_bmp_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_brotli_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_brunsli_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_byteshuffle_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_bz2_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_cms_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_czi_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_deflate_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_dicom.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_dicom_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_dicom_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_dicomrle_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_dicomweb.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_dm.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_dm_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_eer_reader.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_emd.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_emd_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_ets.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_filter_args.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_fits.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_fits_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_fits_compressed.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_gif_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_gzip_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_h5_common.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_hdf5_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_hdf5_http.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_heif_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_htj2k_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_htj2k_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_imaris.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_jpeg2k_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_jpeg2k_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_jpeg_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_jpeg_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_jpegls_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_lerc_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_lif_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_lif_native.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_lz4_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_lzma_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_mozjpeg_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_mozjpeg_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_mrc.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_mrc_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_mrc_writer.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_n5.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_nd2_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_nd2_native.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_ndtiff.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_ndtiff_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_ndtiff_writer.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_nifti.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_nifti_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_nifti_writer.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_none_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_nrrd.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_nrrd_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_numpy_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_numpy_reader.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_oib_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_oib_native.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_oir_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_ole2.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_ome_xml.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_packints_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_pcodec_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_png_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_predictor_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_pyramid_build.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_qoi_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_quantize_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_rcomp_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_rgbe.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_rgbe_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_scaled_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_snappy_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_sperr_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_sz3_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_tiff_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_tiff_http.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_tiff_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_tiff_writer.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_ultrahdr_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_vsi_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_vsi_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_webp_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_zarr_codecs.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_zfp_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/_zstd_codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/__init__.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_aec.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_avif.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_b2nd.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_bcdec.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_bitshuffle.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_blosc2.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_bmp.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_brotli.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_brunsli.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_bytetools.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_charls.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_deflate.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_eer.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_gif.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_hcomp.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_heif.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_isal.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_jpeg.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_jpeg2k.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_jpeg_common.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_jpegxr.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_jxl.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_lerc.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_lz4.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_mozjpeg.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_ndtiff.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_openjph.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_pcodec.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_plio.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_png.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_qoi.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_rcomp.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_registry.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_rgbe.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_snappy.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_sperr.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_sz3.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_tiff.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_uhdr.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_webp.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_zfp.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/_zstd.pyx +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/avif.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/b2nd.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/b2nd_helpers.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/b2nd_helpers.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/bcdec.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/bitshuffle.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/blosc2.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/brotli.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/brunsli.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/byteplanes.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/charls.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/eer.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/giflib.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/heif.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/heif_shim.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/isal_shim.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/jpegxr_shim.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/jpegxr_shim.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/lerc.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/libaec.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/libjxl.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/libuhdr.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/lz4.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/mozjpeg.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/oc_decoder_vtable.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/openjpeg.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/openjph.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/openjph_shim.cpp +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/openjph_shim.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/pcodec.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/qoi.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/rgbe.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/snappy.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/sperr.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/spng.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/sz3c.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/turbojpeg.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/webp.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/webp_shim.c +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/webp_shim.h +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/zfp.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/zlib_h.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/codecs/zstd.pxd +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/__init__.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/_io_helpers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/_optional_backend.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/_range_index.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/_sidecar_header.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/_write_helpers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/buffers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/checksums.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/codec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/color.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/errors.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/io.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/native_source.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/parallel.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/pipeline.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/rows.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/scratch.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/streaming.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/tile_cache.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/core/verification.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/jxl.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/parallel.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/tiff_reader.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/uhdr.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs/zarr.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs.egg-info/dependency_links.txt +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/src/opencodecs.egg-info/top_level.txt +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_auto_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_avif_heif_params.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_avif_sequence.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_b2nd_file_reader.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_bcdec.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_bcn_bands.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_bcn_rounding.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_bitshuffle_format.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_blosc2_partial.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_blosc2_threads.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_bmp_headers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_bounded_pipeline.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_brunsli.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_byteplanes.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_bytestream_standards.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_capability_manifest.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_charls.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_chunked_means_cheap.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_codec_registry.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_container_pipeline.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_container_streaming.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_core_codec_api.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus_codec_decode.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus_manifest.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus_native_fixtures.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus_other.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus_png.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus_tiff.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_corpus_vendors.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_coverage_final.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_coverage_finishing.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_coverage_last.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_coverage_more.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_coverage_push.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_bounded_iteration.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_direct_decode.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_fixture.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_mixed_subblocks.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_parallel_write.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_read_out.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_region_index.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_region_windows.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_segment_parts.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_slide_geometry.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_verification.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_write_pipeline.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_writer.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_czi_writer_shuffle.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_data_source.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_decode_releases_gil.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_deflate.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_delta_parity.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dicom.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dicom_encodings.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dicom_parallel.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dicom_slide_selection.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dicom_wsi_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dicomweb.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_direct_filter_outputs.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dm.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dm_offsets.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_dm_synthetic.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_edge_cases.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_eer.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_eer_parallel.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_eer_worker_budget.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_emd.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_encode_comprehensive.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_error_handling.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_fd_writes.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_filter_compat.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_filter_scratch.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_fits.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_fits_parallel.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_gif.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_gif_compositing.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_gzip_presized.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_hdf5_http.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_hdf5_local.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_hdf5_parallel.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_hdf5_remote.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_heif_avif_features.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_heif_multi_image.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_htj2k_compat.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_htj2k_conformance.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_http_byte_savings.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_http_prefetch.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_http_unified.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_imaris.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_incremental_byte_codecs.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_io_chunked.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_isal.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_jpeg.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_jpeg2k_compat.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_jpeg2k_region.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_jpegxr.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_jxl.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_lerc.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_lif_indexing.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_lif_native.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_live_archives.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_mozjpeg.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_mrc.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_mrc_mrcz_http.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_mrc_nifti_writers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_n5.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_native_output_sinks.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_native_parity.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_native_source_callbacks.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_nd2_native.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_ndtiff.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_nifti.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_nrrd.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_nrrd_iteration.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_nrrd_slices.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_numpy_codec_format.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_offset_readers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_oib_indexing.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_oib_native.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_ome_xml.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_omezarr.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_omezarr_sharded_range.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_open_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_openjph.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_optional_backend.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_owned_color_context.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_owned_image_decoders.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_parallel_jxl.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_phase4_filters.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_phase5_icc.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_phase6_codecs.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_phase7_cms.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_pipeline_budget.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_pipeline_catalog.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_pipeline_executor.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_platform_branches.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_png_row_sessions.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_png_standard.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_public_output_buffers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_pyramid_batched_regions.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_qoi_standard.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_range_pipeline_completion.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_rcomp_truncated_input.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_read_file_into.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_reader_contract.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_reader_source_kinds.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_reader_streaming.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_reference_parity.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_rgbe.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_rgbe_toplevel.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_scaled_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_shared_io_regressions.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_sidecar_header.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_snappy.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_source_pool_lifetime.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_streaming_means_streaming.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_threading_policy.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tier1_scientific.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_codec_encode.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_fused_decode.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_http.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_native.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_parallel_decode.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_pipeline.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_predictor2_interop.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_predictor_loops.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_read_path.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_reader.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_spool.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_stack_read.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_workers.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_writer.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_writer_float_predictor.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tiff_writer_verification.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_tile_cache.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_uhdr.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_unified_api.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_url_sources.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_vendor_provenance.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_verified_encoding.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_version_consistency.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_vsi_oir.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_vsi_pyramid.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_webp_animation.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_webp_decode_options.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_webp_encode_standard.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_wrapper_streams.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_writer_contract.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_writer_pipeline_completion.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_writer_verification.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_zarr_adapters.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_zarr_region_fast_path.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_zfp_blocks.py +0 -0
- {opencodecs-0.6.0 → opencodecs-0.7.1}/tests/test_zstd_owned_output.py +0 -0
|
@@ -10,6 +10,127 @@ Versions follow the same ``YYYY.M.D`` cadence as upstream when we
|
|
|
10
10
|
publish; the entries below cluster work by date rather than by
|
|
11
11
|
release because most of it has shipped continuously to ``main``.
|
|
12
12
|
|
|
13
|
+
0.7.1 (unreleased)
|
|
14
|
+
------------------
|
|
15
|
+
|
|
16
|
+
Every encoder is now tested against a decoder that is not ours.
|
|
17
|
+
``tests/test_foreign_readers.py`` encodes with each of the 46 codecs that can
|
|
18
|
+
encode and decodes with the format's own library where it has a Python
|
|
19
|
+
binding (zstandard, lz4, brotli, python-blosc2, cramjam, lerc, zfpy, pcodec,
|
|
20
|
+
qoi, pillow-heif, the standard library), imagecodecs, and format readers
|
|
21
|
+
(tifffile, mrcfile, nibabel, pydicom, numcodecs, numpy); it also opens the
|
|
22
|
+
files every writer produces (TIFF with each compression, pyramids, NDTiff,
|
|
23
|
+
OME-Zarr, MRC, NIfTI, RGBE, JPEG XL animation, CZI pyramids). A codec that
|
|
24
|
+
gains an encoder without a case fails the suite. CI installs these readers.
|
|
25
|
+
It found:
|
|
26
|
+
|
|
27
|
+
- Fix: the JPEG XL encoder refused ``level``, so ``TiffWriter`` and the NDTiff
|
|
28
|
+
writer raised for JPEG XL with ``compression_level``, which their
|
|
29
|
+
documentation promised to pass through. ``level`` now means what it means
|
|
30
|
+
in ``imagecodecs.jpegxl_encode``: 100 or below is lossy at that quality,
|
|
31
|
+
above 100 lossless. Passing both ``level`` and ``quality`` raises.
|
|
32
|
+
- Fix: OME-Zarr stores written with ``compressor="blosc2"`` opened only in
|
|
33
|
+
opencodecs. No zarr specification defines Blosc2; the one numcodecs plugin
|
|
34
|
+
for it, ocf-blosc2 (Open Climate Fix), registers the id ``blosc2`` with
|
|
35
|
+
the parameters ``cname`` and ``clevel``, where the writer recorded
|
|
36
|
+
``level``, which that plugin refuses. v2 stores now record ``cname`` and
|
|
37
|
+
``clevel``, and v3 stores name the codec ``numcodecs.blosc2``, as zarr
|
|
38
|
+
names a numcodecs codec. With ocf-blosc2 installed, zarr opens both and
|
|
39
|
+
reads the pixels exactly. The chunks themselves are unchanged, and stores
|
|
40
|
+
written the old way still read here.
|
|
41
|
+
- Fix: on Windows, which has no ``os.preadv``, the CZI reader maps the file,
|
|
42
|
+
and ``close()`` left the closed mapping in place: the next call raised the
|
|
43
|
+
mapping's ``ValueError: mmap closed or invalid`` instead of the reader's
|
|
44
|
+
own closed-reader ``CziError``. Two tests encoded the positional-read path
|
|
45
|
+
as universal (the payload index is kept on every path; a stored stack is
|
|
46
|
+
one copy out of the mapping on one worker there) and now assert each
|
|
47
|
+
path's own behavior.
|
|
48
|
+
|
|
49
|
+
- Fix: a CZI this library wrote with default metadata could not be opened by
|
|
50
|
+
libCZI, so not by czicompress and not by ZEN. ``CziWriter``'s default
|
|
51
|
+
metadata was a bare ``<Metadata/>``, and libCZI requires the document to be
|
|
52
|
+
rooted at ``ImageDocument``; it refuses anything else outright with
|
|
53
|
+
``Root-node "ImageDocument" not found``. Every round-trip test in this
|
|
54
|
+
suite passed because every one of them read the file back with our own
|
|
55
|
+
reader, which accepts it. Metadata lacking the root is now wrapped in one,
|
|
56
|
+
so a caller writing a new file cannot produce an unopenable one.
|
|
57
|
+
``czi_recompress`` passes ``metadata_as_is=True``: it promises the source's
|
|
58
|
+
metadata is carried across unchanged, and rewriting it there would break
|
|
59
|
+
that promise, while silently "fixing" a source libCZI could not open either
|
|
60
|
+
is a surprise rather than a service. Its output is then exactly as openable
|
|
61
|
+
as its input.
|
|
62
|
+
- ``tests/test_czi_foreign_readers.py`` never uses opencodecs to read. It
|
|
63
|
+
writes with opencodecs and opens with pylibCZIrw (libCZI itself, so what
|
|
64
|
+
ZEN and czicompress see), czifile (an independent implementation) and
|
|
65
|
+
aicspylibczi, skipping any reader that is absent rather than passing
|
|
66
|
+
silently. It covers all three compressions, a foreign decoder reading
|
|
67
|
+
pixels back exactly, both metadata regressions, a recompressed real file,
|
|
68
|
+
and 481 JPEG XR sub-blocks carried across. Its header records what to
|
|
69
|
+
assume when one fails: the writer is wrong, not the reader, because all
|
|
70
|
+
three open ZEN files and we are the new participant in a format we did not
|
|
71
|
+
define.
|
|
72
|
+
- ``tests/_czi_fixture.py`` takes the same default. That serializer is an
|
|
73
|
+
independent reimplementation of the layout, and
|
|
74
|
+
``test_file_bytes_match_the_fixture_serializer`` compares the writer's bytes
|
|
75
|
+
against it, so the two have to agree on the default; it is written as a
|
|
76
|
+
literal on both sides rather than imported, because importing would make
|
|
77
|
+
them agree by construction and hollow the test out. Fixture files are also
|
|
78
|
+
the sources for the ``czi_recompress`` tests, so that corpus now produces
|
|
79
|
+
files libCZI accepts.
|
|
80
|
+
- Documented why the ZSTDHDR zstd level is 3 and not a parameter. Measured end
|
|
81
|
+
to end on a 503 MB uncompressed CZI, against ZEISS czicompress at 0.87 s and
|
|
82
|
+
319.9 MB on the same file: level 3 gives 0.24 s and 318.3 MB, level 6 gives
|
|
83
|
+
0.92 s and 315.3 MB, level 9 gives 1.38 s and 314.4 MB. The encode cost
|
|
84
|
+
transfers almost 1:1 into wall clock because this path is encode-bound
|
|
85
|
+
rather than I/O-bound, so 32 workers hide none of it, and level 6 is already
|
|
86
|
+
slower than the tool it replaces. About 1% of size for 4 to 6x the time is
|
|
87
|
+
not a trade worth a default. The hi-lo byte-plane shuffle is where the gain
|
|
88
|
+
actually is, and it is already on: on real microscopy pixels it takes the
|
|
89
|
+
ratio from 0.537 to 0.485 while being faster than raw zstd, 923 against
|
|
90
|
+
199 MB/s.
|
|
91
|
+
|
|
92
|
+
0.7.0 (2026-10-03)
|
|
93
|
+
------------------
|
|
94
|
+
|
|
95
|
+
``czi_recompress`` takes ``recompress_when``, a predicate over the reader's
|
|
96
|
+
``CziSubBlockEntry``. Sub-blocks it accepts are decoded and re-encoded as
|
|
97
|
+
before; sub-blocks it rejects are carried across BYTE FOR BYTE, keeping their
|
|
98
|
+
original compression. The default stays ``None``, which re-encodes everything,
|
|
99
|
+
so existing callers are unaffected. The returned summary gains
|
|
100
|
+
``recompressed`` and ``carried`` counts.
|
|
101
|
+
|
|
102
|
+
This exists because a sub-block's compression is not a detail to be
|
|
103
|
+
normalized away. Re-encoding one that is already compressed is wasted work,
|
|
104
|
+
and re-encoding a LOSSY one is destructive: the pixels are decoded from a
|
|
105
|
+
lossy encoding and written back losslessly, so the file grows and the
|
|
106
|
+
artifacts become permanent. Measured on a 505 MB Axioscan slide scan of 481
|
|
107
|
+
JPEG XR sub-blocks:
|
|
108
|
+
|
|
109
|
+
==================================== ======== ========== ============
|
|
110
|
+
strategy time output vs source
|
|
111
|
+
==================================== ======== ========== ============
|
|
112
|
+
carry JPEG XR across (predicate) 0.36 s 489 MB 0.97x
|
|
113
|
+
re-encode everything (no predicate) 12.6 s 1309 MB 2.59x
|
|
114
|
+
==================================== ======== ========== ============
|
|
115
|
+
|
|
116
|
+
So the predicate is not a speed knob. Without it that file more than doubles
|
|
117
|
+
in size, takes 33x longer, and loses the option of ever recovering the
|
|
118
|
+
original encoding. This is what ZEISS's ``czicompress`` expresses with
|
|
119
|
+
``--strategy``, and the three strategies map directly::
|
|
120
|
+
|
|
121
|
+
uncompressed lambda e: e.compression == 0
|
|
122
|
+
uncompressed+zstd lambda e: e.compression in (0, 5, 6)
|
|
123
|
+
all None
|
|
124
|
+
|
|
125
|
+
Supporting this needed a writer that can emit a sub-block it cannot itself
|
|
126
|
+
produce. ``_build_subblock`` gained ``encoded=``, which writes the payload
|
|
127
|
+
exactly as given and records the compression code as-is, with no encode step
|
|
128
|
+
and no look at the pixels. That is the only path by which a JPEG XR sub-block
|
|
129
|
+
can reach a file this writer wrote, and it is why carrying one across cannot
|
|
130
|
+
alter it. Verification is refused on that path: nothing was encoded, so there
|
|
131
|
+
is nothing to check. ``verify=True`` therefore applies only to the sub-blocks
|
|
132
|
+
that were re-encoded.
|
|
133
|
+
|
|
13
134
|
0.6.0 (2026-10-03)
|
|
14
135
|
------------------
|
|
15
136
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencodecs
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
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
|
|
@@ -39,6 +39,18 @@ Requires-Dist: nd2; extra == "reference"
|
|
|
39
39
|
Requires-Dist: readlif; extra == "reference"
|
|
40
40
|
Requires-Dist: oiffile; extra == "reference"
|
|
41
41
|
Requires-Dist: blosc2; extra == "reference"
|
|
42
|
+
Requires-Dist: zstandard; extra == "reference"
|
|
43
|
+
Requires-Dist: lz4; extra == "reference"
|
|
44
|
+
Requires-Dist: brotli; extra == "reference"
|
|
45
|
+
Requires-Dist: cramjam; extra == "reference"
|
|
46
|
+
Requires-Dist: lerc; extra == "reference"
|
|
47
|
+
Requires-Dist: zfpy; extra == "reference"
|
|
48
|
+
Requires-Dist: pcodec; extra == "reference"
|
|
49
|
+
Requires-Dist: ocf-blosc2; extra == "reference"
|
|
50
|
+
Requires-Dist: qoi; extra == "reference"
|
|
51
|
+
Requires-Dist: pillow-heif; extra == "reference"
|
|
52
|
+
Requires-Dist: pylibCZIrw; extra == "reference"
|
|
53
|
+
Requires-Dist: aicspylibczi; extra == "reference"
|
|
42
54
|
Provides-Extra: test
|
|
43
55
|
Requires-Dist: pytest>=8; extra == "test"
|
|
44
56
|
Requires-Dist: pytest-cov; extra == "test"
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "opencodecs"
|
|
10
|
-
version = "0.
|
|
10
|
+
version = "0.7.1"
|
|
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"
|
|
@@ -54,7 +54,21 @@ reference = [
|
|
|
54
54
|
"nd2", # ND2
|
|
55
55
|
"readlif", # LIF
|
|
56
56
|
"oiffile", # OIB
|
|
57
|
-
"blosc2", # MRCZ
|
|
57
|
+
"blosc2", # MRCZ, and Blosc2 / B2ND streams
|
|
58
|
+
# The libraries' own bindings, which test_foreign_readers.py decodes
|
|
59
|
+
# our streams with alongside imagecodecs.
|
|
60
|
+
"zstandard", # zstd
|
|
61
|
+
"lz4", # LZ4 frame
|
|
62
|
+
"brotli", # Brotli
|
|
63
|
+
"cramjam", # Snappy raw and framed
|
|
64
|
+
"lerc", # LERC
|
|
65
|
+
"zfpy", # ZFP
|
|
66
|
+
"pcodec", # pcodec
|
|
67
|
+
"ocf-blosc2", # Blosc2 in zarr (no zarr spec defines it)
|
|
68
|
+
"qoi", # QOI
|
|
69
|
+
"pillow-heif", # HEIF, libheif's decoder
|
|
70
|
+
"pylibCZIrw", # CZI through libCZI
|
|
71
|
+
"aicspylibczi", # CZI, the Allen Institute's libCZI binding
|
|
58
72
|
]
|
|
59
73
|
test = [
|
|
60
74
|
"pytest>=8",
|
|
@@ -813,6 +813,10 @@ class CziReader(Reader):
|
|
|
813
813
|
finally:
|
|
814
814
|
os.close(self._fd)
|
|
815
815
|
self._owns_fd = False
|
|
816
|
+
# As on the positional-read path: a closed reader has no
|
|
817
|
+
# buffer, so the next call raises the reader's own "closed"
|
|
818
|
+
# error, not the mapping's "mmap closed or invalid".
|
|
819
|
+
self._mmap = None
|
|
816
820
|
|
|
817
821
|
@classmethod
|
|
818
822
|
def from_http(
|
|
@@ -70,10 +70,67 @@ _CMP_NAME_TO_CODE = {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
#: libCZI refuses metadata that is not rooted at ``ImageDocument``, with
|
|
74
|
+
#: ``Root-node "ImageDocument" not found``. That means czicompress and ZEN
|
|
75
|
+
#: cannot open the file at all -- not a degraded read, no read. The writer's
|
|
76
|
+
#: old default was a bare ``<Metadata/>``, which opencodecs' own reader
|
|
77
|
+
#: accepts, so every round-trip test passed while the files were unreadable
|
|
78
|
+
#: by every other CZI tool. Found 2026-10-04 when czicompress rejected a file
|
|
79
|
+
#: this writer had just produced.
|
|
80
|
+
#:
|
|
81
|
+
#: So metadata lacking the root is WRAPPED in one, and a caller writing a NEW
|
|
82
|
+
#: file cannot produce an unopenable one by accident or on purpose.
|
|
83
|
+
#:
|
|
84
|
+
#: ``metadata_as_is=True`` opts out, and exactly one caller needs it:
|
|
85
|
+
#: ``czi_recompress``, which promises the source's metadata is carried across
|
|
86
|
+
#: UNCHANGED. Rewriting it there would break that promise, and silently
|
|
87
|
+
#: "fixing" a source that libCZI could not open either is a surprise, not a
|
|
88
|
+
#: service -- the output is then exactly as openable as the input, which is
|
|
89
|
+
#: what faithful means.
|
|
90
|
+
_DEFAULT_METADATA = b"<ImageDocument><Metadata/></ImageDocument>"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _ensure_image_document(xml: bytes) -> bytes:
|
|
94
|
+
"""Return ``xml`` rooted at ImageDocument, wrapping it if it is not."""
|
|
95
|
+
head = xml.lstrip()
|
|
96
|
+
decl = b""
|
|
97
|
+
if head.startswith(b"<?xml"):
|
|
98
|
+
end = head.find(b"?>")
|
|
99
|
+
if end != -1:
|
|
100
|
+
decl, head = head[:end + 2], head[end + 2:].lstrip()
|
|
101
|
+
if head.startswith(b"<ImageDocument>") or head.startswith(b"<ImageDocument "):
|
|
102
|
+
return xml
|
|
103
|
+
return decl + b"<ImageDocument>" + head + b"</ImageDocument>"
|
|
104
|
+
|
|
105
|
+
|
|
73
106
|
class CziWriterError(RuntimeError):
|
|
74
107
|
"""Raised on writer state-machine violations."""
|
|
75
108
|
|
|
76
109
|
|
|
110
|
+
class _CarriedSubBlock:
|
|
111
|
+
"""A sub-block copied across unchanged, not re-encoded.
|
|
112
|
+
|
|
113
|
+
Carries the encoded payload and the compression code it was written
|
|
114
|
+
with, plus a zero-filled array of the right shape and dtype so the
|
|
115
|
+
existing header path can read shape/dtype without the pixels ever being
|
|
116
|
+
decoded. ``np.empty`` would do, but zeros make an accidental use of
|
|
117
|
+
these pixels obvious rather than random.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
__slots__ = ("payload", "compression", "dims", "pyramid_type",
|
|
121
|
+
"shape_array", "logical_shape", "pixel_type")
|
|
122
|
+
|
|
123
|
+
def __init__(self, payload, *, compression, dims, pyramid_type,
|
|
124
|
+
shape_array, logical_shape, pixel_type):
|
|
125
|
+
self.payload = payload
|
|
126
|
+
self.compression = compression
|
|
127
|
+
self.pixel_type = pixel_type
|
|
128
|
+
self.dims = dims
|
|
129
|
+
self.pyramid_type = pyramid_type
|
|
130
|
+
self.shape_array = shape_array
|
|
131
|
+
self.logical_shape = logical_shape
|
|
132
|
+
|
|
133
|
+
|
|
77
134
|
class CziCancelled(CziWriterError):
|
|
78
135
|
"""Raised when a caller's ``should_continue`` stops a rewrite.
|
|
79
136
|
|
|
@@ -239,6 +296,27 @@ def _zstdhdr_encode(pixel_bytes, itemsize: int, hilo: bool, *, scratch=None):
|
|
|
239
296
|
before this returns, and verification later reads the encoded payload
|
|
240
297
|
and the caller's own pixel snapshot rather than this buffer, so the
|
|
241
298
|
next frame may reuse it.
|
|
299
|
+
|
|
300
|
+
WHY LEVEL 3, AND WHY IT IS NOT A PARAMETER
|
|
301
|
+
Measured end to end through this pipeline on a 503 MB uncompressed CZI
|
|
302
|
+
(2026-10-04), against ZEISS czicompress at 0.87 s / 319.9 MB on the same
|
|
303
|
+
file:
|
|
304
|
+
|
|
305
|
+
level 3 0.24 s 318.3 MB beats czicompress on size AND speed
|
|
306
|
+
level 6 0.92 s 315.3 MB 0.93% smaller, 3.91x slower
|
|
307
|
+
level 9 1.38 s 314.4 MB 1.23% smaller, 5.83x slower
|
|
308
|
+
|
|
309
|
+
The encode cost transfers almost 1:1 into wall clock, because this path is
|
|
310
|
+
encode-bound rather than I/O-bound: there is no I/O to hide it behind, even
|
|
311
|
+
with 32 workers. So a higher level buys about 1% of size for 4-6x the time,
|
|
312
|
+
and level 6 is already slower than the tool we replaced. Level 3 is the
|
|
313
|
+
only setting that wins on both axes.
|
|
314
|
+
|
|
315
|
+
The hi-lo shuffle, by contrast, is free and large: on real microscopy
|
|
316
|
+
pixels it took the ratio from 0.537 to 0.485 (9.7% smaller) while being
|
|
317
|
+
FASTER than raw zstd, 923 MB/s against 199 MB/s, because shuffled byte
|
|
318
|
+
planes are far more compressible. That is where the gain is, and it is
|
|
319
|
+
already on by default.
|
|
242
320
|
"""
|
|
243
321
|
from .codecs._zstd import encode as zstd_encode
|
|
244
322
|
if hilo and itemsize > 1:
|
|
@@ -339,6 +417,7 @@ def _build_subblock(
|
|
|
339
417
|
dims: tuple | None = None,
|
|
340
418
|
verification_input: list | None = None,
|
|
341
419
|
scratch=None,
|
|
420
|
+
encoded: object | None = None,
|
|
342
421
|
) -> tuple[_SubBlockSegment, dict]:
|
|
343
422
|
"""Build one ZISRAWSUBBLOCK segment as parts.
|
|
344
423
|
|
|
@@ -351,7 +430,21 @@ def _build_subblock(
|
|
|
351
430
|
check runs after this returns while the producer may already be
|
|
352
431
|
refilling ``array``. Without it nothing here outlives the call, so the
|
|
353
432
|
array's own buffer feeds the compressor or becomes the raw payload.
|
|
433
|
+
|
|
434
|
+
With ``encoded`` the payload is written exactly as given and
|
|
435
|
+
``compression_code`` is recorded as-is, with no encode step and no look
|
|
436
|
+
at the pixels. That is how a sub-block is carried across unchanged, and
|
|
437
|
+
it is the only path that can emit a compression this writer cannot
|
|
438
|
+
produce (JPEG XR, for instance). ``array`` is then used only for its
|
|
439
|
+
shape and dtype, so a zero-filled array of the right shape is enough.
|
|
440
|
+
Verification is not available on this path: there is nothing to check,
|
|
441
|
+
because nothing was encoded.
|
|
354
442
|
"""
|
|
443
|
+
if encoded is not None and verification_input is not None:
|
|
444
|
+
raise CziWriterError(
|
|
445
|
+
"czi: verification_input cannot be combined with encoded; a "
|
|
446
|
+
"carried-across sub-block is not re-encoded, so there is "
|
|
447
|
+
"nothing to verify")
|
|
355
448
|
h, w = array.shape[:2]
|
|
356
449
|
logical_h, logical_w = logical_shape
|
|
357
450
|
start_y, start_x = location
|
|
@@ -390,7 +483,10 @@ def _build_subblock(
|
|
|
390
483
|
pixels = memoryview(contiguous).cast("B")
|
|
391
484
|
keep = contiguous
|
|
392
485
|
itemsize = array.dtype.itemsize
|
|
393
|
-
if
|
|
486
|
+
if encoded is not None:
|
|
487
|
+
data = encoded
|
|
488
|
+
keep = encoded
|
|
489
|
+
elif compression_code == 0:
|
|
394
490
|
data = pixels
|
|
395
491
|
elif compression_code == 5:
|
|
396
492
|
from .codecs._zstd import encode as zstd_encode
|
|
@@ -477,15 +573,22 @@ class _CziStreamWriter(Writer):
|
|
|
477
573
|
"""Shared sub-block sink with optional bounded pixel verification."""
|
|
478
574
|
|
|
479
575
|
def __init__(self, path: str | Path, *, compression: str = "none",
|
|
480
|
-
hilo: bool = True, metadata_xml: bytes | str =
|
|
481
|
-
verify: bool = False, background_encode: bool = False
|
|
576
|
+
hilo: bool = True, metadata_xml: bytes | str | None = None,
|
|
577
|
+
verify: bool = False, background_encode: bool = False,
|
|
578
|
+
metadata_as_is: bool = False):
|
|
482
579
|
if compression not in _CMP_NAME_TO_CODE:
|
|
483
580
|
raise CziWriterError(f"unknown compression {compression!r}")
|
|
484
581
|
self._path = Path(path)
|
|
485
582
|
self._cmp_code = _CMP_NAME_TO_CODE[compression]
|
|
486
583
|
self._hilo = bool(hilo)
|
|
487
|
-
|
|
488
|
-
|
|
584
|
+
if metadata_xml is None:
|
|
585
|
+
xml = _DEFAULT_METADATA
|
|
586
|
+
elif isinstance(metadata_xml, str):
|
|
587
|
+
xml = metadata_xml.encode("utf-8")
|
|
588
|
+
else:
|
|
589
|
+
xml = metadata_xml
|
|
590
|
+
self._metadata_segment = _build_metadata_segment(
|
|
591
|
+
xml if metadata_as_is else _ensure_image_document(xml))
|
|
489
592
|
self._header_size = (32 + 88 + 31) // 32 * 32
|
|
490
593
|
self._position = self._header_size + len(self._metadata_segment)
|
|
491
594
|
self._entries: list[dict] = []
|
|
@@ -687,6 +790,17 @@ class _CziStreamWriter(Writer):
|
|
|
687
790
|
workers = resolve_workers(None, 1 << 30, output_bytes=None, max_workers=8)
|
|
688
791
|
workers = max(1, int(workers))
|
|
689
792
|
|
|
793
|
+
def item_bytes(item):
|
|
794
|
+
"""Cost of one snapshotted item, for batching and reservation.
|
|
795
|
+
|
|
796
|
+
A carried sub-block has no array: its cost is the encoded payload
|
|
797
|
+
it already owns. Both batching sites go through here so they
|
|
798
|
+
cannot disagree about what an item weighs.
|
|
799
|
+
"""
|
|
800
|
+
if isinstance(item, _CarriedSubBlock):
|
|
801
|
+
return len(item.payload)
|
|
802
|
+
return item[0].nbytes
|
|
803
|
+
|
|
690
804
|
def snapshot(frame):
|
|
691
805
|
"""Own the frame's pixels before the producer can touch them.
|
|
692
806
|
|
|
@@ -695,6 +809,10 @@ class _CziStreamWriter(Writer):
|
|
|
695
809
|
it is a down-scaled level. Those forms are what make a faithful
|
|
696
810
|
re-encode possible on this path as well as on ``write_frame``.
|
|
697
811
|
"""
|
|
812
|
+
if isinstance(frame, _CarriedSubBlock):
|
|
813
|
+
# Nothing to snapshot: the payload is already bytes we own,
|
|
814
|
+
# and the pixels are never looked at.
|
|
815
|
+
return frame
|
|
698
816
|
dims = override_pyramid = None
|
|
699
817
|
if isinstance(frame, tuple):
|
|
700
818
|
if len(frame) == 2:
|
|
@@ -728,7 +846,7 @@ class _CziStreamWriter(Writer):
|
|
|
728
846
|
batch, batch_bytes = [], 0
|
|
729
847
|
for frame in frames:
|
|
730
848
|
item = snapshot(frame)
|
|
731
|
-
n = item
|
|
849
|
+
n = item_bytes(item)
|
|
732
850
|
if batch and batch_bytes + n > batch_limit:
|
|
733
851
|
yield batch
|
|
734
852
|
batch, batch_bytes = [], 0
|
|
@@ -738,7 +856,7 @@ class _CziStreamWriter(Writer):
|
|
|
738
856
|
yield batch
|
|
739
857
|
|
|
740
858
|
def size(batch):
|
|
741
|
-
n = sum(item
|
|
859
|
+
n = sum(item_bytes(item) for item in batch)
|
|
742
860
|
# Snapshot + encoded output (bounded by the input for these
|
|
743
861
|
# codecs) + decoded verification result and comparison scratch.
|
|
744
862
|
return 2 * n + (verification_reservation(n) if verify else 0)
|
|
@@ -746,7 +864,19 @@ class _CziStreamWriter(Writer):
|
|
|
746
864
|
def encode(batch):
|
|
747
865
|
out = []
|
|
748
866
|
scratch = _worker_scratch()
|
|
749
|
-
for
|
|
867
|
+
for item in batch:
|
|
868
|
+
if isinstance(item, _CarriedSubBlock):
|
|
869
|
+
segment, entry = _build_subblock(
|
|
870
|
+
item.shape_array,
|
|
871
|
+
pixel_type=item.pixel_type,
|
|
872
|
+
compression_code=item.compression, hilo=self._hilo,
|
|
873
|
+
file_position=0, logical_shape=item.logical_shape,
|
|
874
|
+
pyramid_type=item.pyramid_type, dims=item.dims,
|
|
875
|
+
verification_input=None, scratch=None,
|
|
876
|
+
encoded=item.payload)
|
|
877
|
+
out.append((segment, entry))
|
|
878
|
+
continue
|
|
879
|
+
pixels, logical_shape, pyramid_type, dims = item
|
|
750
880
|
captured = [] if verify else None
|
|
751
881
|
segment, entry = _build_subblock(
|
|
752
882
|
pixels, pixel_type=_DTYPE_TO_PIXELTYPE[pixels.dtype],
|
|
@@ -992,7 +1122,8 @@ __all__ = ["CziWriter", "CziPyramidWriter", "CziWriterError"]
|
|
|
992
1122
|
def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
|
|
993
1123
|
workers=None, verify: bool = False,
|
|
994
1124
|
background_encode: bool = False,
|
|
995
|
-
should_continue=None
|
|
1125
|
+
should_continue=None,
|
|
1126
|
+
recompress_when=None) -> dict:
|
|
996
1127
|
"""Rewrite a CZI with different compression, keeping the container.
|
|
997
1128
|
|
|
998
1129
|
Every sub-block keeps its dimension coordinates, its scene and mosaic
|
|
@@ -1016,8 +1147,30 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
|
|
|
1016
1147
|
know which. Encodes already dispatched still finish, so cancellation
|
|
1017
1148
|
takes effect within roughly ``workers`` sub-blocks rather than instantly.
|
|
1018
1149
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1150
|
+
``recompress_when`` is an optional predicate over the reader's
|
|
1151
|
+
``CziSubBlockEntry``. Sub-blocks it accepts are decoded and re-encoded;
|
|
1152
|
+
sub-blocks it rejects are carried across BYTE FOR BYTE, keeping their
|
|
1153
|
+
original compression. Default ``None`` re-encodes everything, which is
|
|
1154
|
+
what earlier versions did.
|
|
1155
|
+
|
|
1156
|
+
This is what makes the selective strategies of ZEISS's ``czicompress``
|
|
1157
|
+
expressible, and the reason they exist: re-encoding an already-compressed
|
|
1158
|
+
sub-block is at best wasted work, and for a lossy one it is destructive.
|
|
1159
|
+
A JPEG XR sub-block decoded and re-encoded as lossless zstdhdr grows,
|
|
1160
|
+
and bakes the lossy artifacts in permanently. Carrying it across cannot
|
|
1161
|
+
do that.
|
|
1162
|
+
|
|
1163
|
+
uncompressed only lambda e: e.compression == 0
|
|
1164
|
+
uncompressed+zstd lambda e: e.compression in (0, 5, 6)
|
|
1165
|
+
everything None
|
|
1166
|
+
|
|
1167
|
+
``verify=True`` applies only to the sub-blocks that were re-encoded; a
|
|
1168
|
+
carried-across payload is unchanged by definition, so there is nothing
|
|
1169
|
+
to check.
|
|
1170
|
+
|
|
1171
|
+
Returns a summary dict: sub-block count, input and output sizes, the
|
|
1172
|
+
compression that was applied, and how many sub-blocks were re-encoded
|
|
1173
|
+
versus carried across.
|
|
1021
1174
|
"""
|
|
1022
1175
|
import os
|
|
1023
1176
|
|
|
@@ -1027,7 +1180,9 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
|
|
|
1027
1180
|
n = len(reader.entries)
|
|
1028
1181
|
if not n:
|
|
1029
1182
|
raise CziWriterError(f"czi: {src} has no sub-blocks to recompress")
|
|
1030
|
-
metadata = reader.metadata_bytes or
|
|
1183
|
+
metadata = reader.metadata_bytes or _DEFAULT_METADATA
|
|
1184
|
+
|
|
1185
|
+
counts = {"recompressed": 0, "carried": 0}
|
|
1031
1186
|
|
|
1032
1187
|
def frames():
|
|
1033
1188
|
# One sub-block at a time: a slide scan does not fit in memory,
|
|
@@ -1038,12 +1193,36 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
|
|
|
1038
1193
|
f"czi: recompress of {src} cancelled after "
|
|
1039
1194
|
f"{i} of {n} sub-blocks")
|
|
1040
1195
|
entry = reader.entries[i]
|
|
1041
|
-
|
|
1196
|
+
if recompress_when is None or recompress_when(entry):
|
|
1197
|
+
counts["recompressed"] += 1
|
|
1198
|
+
yield reader[i], subblock_dims(entry), entry.pyramid_type
|
|
1199
|
+
else:
|
|
1200
|
+
# Carried across: the encoded bytes are copied straight
|
|
1201
|
+
# from the source and the original compression is kept,
|
|
1202
|
+
# so the pixels are never decoded and cannot change.
|
|
1203
|
+
counts["carried"] += 1
|
|
1204
|
+
d = subblock_dims(entry)
|
|
1205
|
+
axes = {name.rstrip(b"\x00"): (size, stored)
|
|
1206
|
+
for name, _start, size, _co, stored in d}
|
|
1207
|
+
log_h, st_h = axes[b"Y"]
|
|
1208
|
+
log_w, st_w = axes[b"X"]
|
|
1209
|
+
with reader._payload(entry) as view:
|
|
1210
|
+
# Copy: the reader hands back a buffer it reuses, so
|
|
1211
|
+
# a borrowed view would be overwritten by the next
|
|
1212
|
+
# sub-block before the writer emits this one.
|
|
1213
|
+
payload = bytes(view)
|
|
1214
|
+
yield _CarriedSubBlock(
|
|
1215
|
+
payload, compression=entry.compression,
|
|
1216
|
+
dims=d, pyramid_type=entry.pyramid_type,
|
|
1217
|
+
shape_array=np.zeros((st_h, st_w), entry.dtype),
|
|
1218
|
+
logical_shape=(log_h, log_w),
|
|
1219
|
+
pixel_type=entry.pixel_type)
|
|
1042
1220
|
|
|
1043
1221
|
try:
|
|
1044
1222
|
with CziWriter(str(dst), compression=compression, hilo=hilo,
|
|
1045
1223
|
metadata_xml=metadata, verify=verify,
|
|
1046
|
-
background_encode=background_encode
|
|
1224
|
+
background_encode=background_encode,
|
|
1225
|
+
metadata_as_is=True) as writer:
|
|
1047
1226
|
writer.write_many(frames(), workers=workers, copy_frames=False)
|
|
1048
1227
|
except BaseException:
|
|
1049
1228
|
# An interrupted rewrite must not leave a file behind. A CZI
|
|
@@ -1061,4 +1240,6 @@ def czi_recompress(src, dst, *, compression: str = "zstdhdr", hilo: bool = True,
|
|
|
1061
1240
|
"src_bytes": os.path.getsize(src),
|
|
1062
1241
|
"dst_bytes": os.path.getsize(dst),
|
|
1063
1242
|
"compression": compression,
|
|
1243
|
+
"recompressed": counts["recompressed"],
|
|
1244
|
+
"carried": counts["carried"],
|
|
1064
1245
|
}
|
|
@@ -139,6 +139,22 @@ class JpegXLReader(Reader):
|
|
|
139
139
|
self._inner.close()
|
|
140
140
|
|
|
141
141
|
|
|
142
|
+
def jxl_level_as_quality(opts: dict) -> dict:
|
|
143
|
+
"""imagecodecs.jpegxl_encode's ``level`` is a quality: 100 or below is
|
|
144
|
+
lossy at that quality, above 100 lossless. The encoder's ``quality``
|
|
145
|
+
has exactly that meaning, so ``level`` is passed as ``quality``.
|
|
146
|
+
Writers that take one compression level for every codec (TIFF,
|
|
147
|
+
NDTiff) reach JPEG XL through this too."""
|
|
148
|
+
if opts.get("level") is None:
|
|
149
|
+
opts.pop("level", None)
|
|
150
|
+
return opts
|
|
151
|
+
if opts.get("quality") is not None:
|
|
152
|
+
raise TypeError("jxl: pass level or quality, not both")
|
|
153
|
+
opts = dict(opts)
|
|
154
|
+
opts["quality"] = opts.pop("level")
|
|
155
|
+
return opts
|
|
156
|
+
|
|
157
|
+
|
|
142
158
|
class JpegXLCodec(Codec):
|
|
143
159
|
"""Native JPEG XL codec (libjxl 0.11).
|
|
144
160
|
|
|
@@ -176,7 +192,7 @@ class JpegXLCodec(Codec):
|
|
|
176
192
|
return _jxl_check_signature(head)
|
|
177
193
|
|
|
178
194
|
def encode(self, arr: np.ndarray, *, dest=None, **opts) -> bytes | None:
|
|
179
|
-
return _jxl_encode(arr, dest=dest, **opts)
|
|
195
|
+
return _jxl_encode(arr, dest=dest, **jxl_level_as_quality(opts))
|
|
180
196
|
|
|
181
197
|
def decode(self, src: Any, **opts) -> np.ndarray:
|
|
182
198
|
"""Decode a JXL codestream.
|
|
@@ -496,7 +496,10 @@ def _run_decoder(name: str, cfg: dict, data: bytes) -> bytes:
|
|
|
496
496
|
_DECODER_CACHE["blosc2"] = fn
|
|
497
497
|
if fn:
|
|
498
498
|
return fn(data)
|
|
499
|
-
if name
|
|
499
|
+
if name in ("blosc2", "numcodecs.blosc2"):
|
|
500
|
+
# "numcodecs.blosc2" is ocf-blosc2's v3 name, which our writer
|
|
501
|
+
# uses; plain "blosc2" is the v2 id, and what v3 stores this
|
|
502
|
+
# package wrote before 0.7.0 carry.
|
|
500
503
|
fn = _DECODER_CACHE.get("blosc2")
|
|
501
504
|
if not fn:
|
|
502
505
|
from .codecs._blosc2 import decode as _b_decode
|
|
@@ -53,7 +53,10 @@ _CODEC_NAME_MAP = {
|
|
|
53
53
|
"none": (None, None),
|
|
54
54
|
"raw": (None, None),
|
|
55
55
|
"zstd": ("zstd", "zstd"),
|
|
56
|
-
|
|
56
|
+
# No zarr specification defines Blosc2. These are the names ocf-blosc2,
|
|
57
|
+
# the one numcodecs plugin for it, registers: "blosc2" for v2, and
|
|
58
|
+
# "numcodecs.blosc2" for v3, which is how zarr names a numcodecs codec.
|
|
59
|
+
"blosc2": ("blosc2", "numcodecs.blosc2"),
|
|
57
60
|
"gzip": ("gzip", "gzip"),
|
|
58
61
|
"blosc": ("blosc", None), # v2-only (no v3 spec)
|
|
59
62
|
}
|
|
@@ -68,6 +71,16 @@ class OmeZarrWriterError(RuntimeError):
|
|
|
68
71
|
# ---------------------------------------------------------------------------
|
|
69
72
|
|
|
70
73
|
|
|
74
|
+
def _blosc2_config(level: int | None, v3: bool = False) -> dict:
|
|
75
|
+
"""The parameters ocf-blosc2's Blosc2(cname, clevel) takes, so zarr with
|
|
76
|
+
that plugin installed opens the store. cname names the inner codec;
|
|
77
|
+
_encode_chunk compresses with zstd, blosc2's default, and ocf-blosc2
|
|
78
|
+
reads "zstd" as that. (Before 0.7.0 the writer recorded "level", which
|
|
79
|
+
no reader but opencodecs accepted; those stores still read here.)"""
|
|
80
|
+
config = {"cname": "zstd", "clevel": level if level is not None else 5}
|
|
81
|
+
return config if v3 else {"id": "blosc2", **config}
|
|
82
|
+
|
|
83
|
+
|
|
71
84
|
def _encode_chunk(raw: bytes, codec: str, level: int | None) -> bytes:
|
|
72
85
|
"""Compress one chunk's bytes."""
|
|
73
86
|
if codec in (None, "none", "raw"):
|
|
@@ -309,8 +322,7 @@ def _write_v2(
|
|
|
309
322
|
metadata["compressor"] = {"id": "zstd",
|
|
310
323
|
"level": level if level is not None else 3}
|
|
311
324
|
elif compressor == "blosc2":
|
|
312
|
-
metadata["compressor"] =
|
|
313
|
-
"level": level if level is not None else 5}
|
|
325
|
+
metadata["compressor"] = _blosc2_config(level)
|
|
314
326
|
elif compressor == "gzip":
|
|
315
327
|
metadata["compressor"] = {"id": "gzip",
|
|
316
328
|
"level": level if level is not None else 6}
|
|
@@ -375,8 +387,8 @@ def _write_v3(
|
|
|
375
387
|
})
|
|
376
388
|
elif compressor == "blosc2":
|
|
377
389
|
codecs.append({
|
|
378
|
-
"name": "blosc2",
|
|
379
|
-
"configuration":
|
|
390
|
+
"name": "numcodecs.blosc2",
|
|
391
|
+
"configuration": _blosc2_config(level, v3=True),
|
|
380
392
|
})
|
|
381
393
|
elif compressor == "gzip":
|
|
382
394
|
codecs.append({
|
|
@@ -460,8 +472,8 @@ def _v3_codecs_for_shard_inner(
|
|
|
460
472
|
})
|
|
461
473
|
elif compressor == "blosc2":
|
|
462
474
|
codecs.append({
|
|
463
|
-
"name": "blosc2",
|
|
464
|
-
"configuration":
|
|
475
|
+
"name": "numcodecs.blosc2",
|
|
476
|
+
"configuration": _blosc2_config(level, v3=True),
|
|
465
477
|
})
|
|
466
478
|
elif compressor == "gzip":
|
|
467
479
|
codecs.append({
|
|
@@ -254,6 +254,9 @@ def encode_segment(data, codec: str | int, *, level: int | None = None,
|
|
|
254
254
|
kw["level"] = level
|
|
255
255
|
if code == JPEG2000:
|
|
256
256
|
kw.setdefault("planar", False)
|
|
257
|
+
if code == JXL:
|
|
258
|
+
from .._jxl_codec import jxl_level_as_quality
|
|
259
|
+
kw = jxl_level_as_quality(kw)
|
|
257
260
|
if code in (ZSTD, JPEG2000, JXL):
|
|
258
261
|
from .pipeline import native_workers, in_worker
|
|
259
262
|
# Zstandard counts background workers: zero means inline serial.
|
|
@@ -292,6 +295,9 @@ def bind_segment_encoder(codec: str | int, *, level=None, owned_output=False,
|
|
|
292
295
|
options.setdefault("level", level)
|
|
293
296
|
if code == JPEG2000:
|
|
294
297
|
options.setdefault("planar", False)
|
|
298
|
+
if code == JXL:
|
|
299
|
+
from .._jxl_codec import jxl_level_as_quality
|
|
300
|
+
options = jxl_level_as_quality(options)
|
|
295
301
|
eager = partial(fn, **options)
|
|
296
302
|
if code not in (ZSTD, JPEG2000, JXL):
|
|
297
303
|
return eager
|