Repository navigation
Configurable per-channel rendering settings (release v0.6.0) - #15
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #15 +/- ##
==========================
==========================
☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🟡 Changes recommended
Multiple unresolved moderate issues remain in rendering, caching, validation, and URL handling.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Prepares the v0.6.0 release with configurable per-channel rendering, shared OME-Zarr loading, raw tile conversion, and updated documentation.
Changes:
- Adds channel arrays and rendering settings.
- Refactors tile loading, caching, and converters.
- Updates exports, demo parameters, documentation, and release metadata.
File summaries
| File | Description |
|---|---|
src/utils.ts |
URL and data-range utilities |
src/OMEZarrTileSourceOptions.ts |
Expanded configuration options |
src/OMEZarrTileSource.ts |
Loading, rendering, validation, caching, and tile handling |
src/OMEZarrTileData.ts |
Raw multi-channel tile data contract |
src/OMEZarr.ts |
Shared loaded OME-Zarr data |
src/main.ts |
Public API exports |
README.md |
Updated API and usage documentation |
package.json |
Version bumped to 0.6.0 |
index.html |
Query-parameter-driven demo configuration |
CHANGELOG.md |
v0.6.0 release notes |
Review details
Suppressed comments (8)
src/OMEZarrTileSource.ts:674
- The channel range check has the same gap:
c: [NaN]or a fractional channel index passes and is sent togetSlicesas an invalid selection. Add an integer/non-negative condition so every explicit channel index is validated before it is used.
if (this._c !== undefined && this._c.some((c) => c < 0 || c >= sizeC)) {
src/OMEZarrTileSource.ts:827
- This stores the LUT/color-map objects returned by the metadata/configuration directly in cached tile data.
renderonly shallow-copies LUT arrays immediately before rendering, so mutating a loaded channel LUT, map, or its color entries after download changes tiles that are already cached, contrary to the documented snapshot behavior. Clone the LUT/map and nested color arrays when constructingOMEZarrTileData.
lutsOrColorMaps: chunks.map((_, i) => lutsOrColorMaps?.[i]),
src/OMEZarrTileSource.ts:268
- Unlike the array form,
instanceof Mapaccepts any keys and values, so malformed maps (for examplenew Map([['x', 'y']])) pass constructor validation and later reach the sort/render path, where they can produce invalid data or errors. Validate finite numeric keys and RGB/RGBA array values before accepting a color map.
(lutOrColorMap) =>
lutOrColorMap instanceof Map ||
(Array.isArray(lutOrColorMap) &&
lutOrColorMap.length > 0 &&
lutOrColorMap.every(
src/OMEZarrTileSource.ts:796
- The cache identity uses only a 32-bit FNV-1a hash for all rendering settings. Two different user-provided settings can collide, making
equalsand this cache key identical and causing one rendering to reuse another rendering's raw tile data. Include a collision-free canonical representation in the key, or use a sufficiently collision-resistant identity rather than relying solely on this 32-bit hash.
url.searchParams.append("render", this._renderSettingsHash.toString(16));
src/OMEZarrTileSource.ts:927
- When
cis omitted for an image without omero metadata,channelsisundefinedeven thoughloadChunksreturns every channel. A scalarrange,color, LUT, orinvertedvalue therefore remains a one-entry array here anddownloadTileStartapplies it only tochunks[0]; the other channels silently use defaults, contrary to the option contract. Repeat these settings using the loaded c-axis size (or expand them when building the tile data).
if (values === undefined) {
return channels?.map(() => undefined);
}
if (values.length === 1 && channels !== undefined) {
return channels.map(() => values[0]);
src/OMEZarrTileSource.ts:547
- When
tileisundefined, this method never validateslevel; an out-of-range level is then indexed througharraysand fails with an incidental TypeError instead of the documentedlevel out of boundserror. Validate the level before the tile branch so both whole-plane and tile loads follow the same contract.
const indices: { [k: string]: number | [number, number] | undefined } = {
t: this.t, // undefined = middle plane
z: this.z, // undefined = middle plane
};
src/OMEZarrTileSource.ts:307
- Assigning the supplied
loadedobject here makesloadedand all metadata-resolved getters visible immediately, beforegetImageInfohas validated the object or raisedready; invalid preloaded data can therefore be observed as ready. Keep the constructor argument in a separate pending field and assign_loadedonly after validation succeeds so the documented ready-only contract is preserved.
this._loaded = loaded;
src/utils.ts:53
- The fallback does not strip query strings or fragments, so in a runtime without
document(for example SSR or Node),isOZX("image.ozx?download=1")returnsfalseeven though the documented path suffix is.ozxandresolveUrlhas already failed only because no base URL exists. Apply the same query/fragment stripping in the fallback.
return url.toString().endsWith(".ozx"); // not a URL (e.g. an unrelated tile source)
- Files reviewed: 10/10 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Prepares the v0.6.0 release.
Highlights
range,color,lutOrColorMapandinverted, as a single value for all rendered channels or one value per channel, overriding the omero metadatacnow accepts an array of channel indices composited in the given orderloaded,t,z,cs,channels,ranges,colors,lutsOrColorMaps,inverteds, plusgetWidth(level)/getHeight(level)ome-zarrdata and rendered by the registered converter;OMEZarrTileDataholds one chunk per rendered channel (chunks) together with the fully resolved rendering settings for that tile, instead of a single chunk and channel. ThedataTypeoption is goneOMEZarrTileSource.loadOMEZarrloads metadata and arrays once for sharing across tile sources; the constructor andopentake the resultingOMEZarrinstead of anNgffImagegetNumTilesis derived from the actual array shape of each resolution level instead of the width-based scale, and tile requests outside a level are rejectedequalsandgetTileHashKeynow cover the same components (URL,zip, resolvedt/z/csand a hash of the configured rendering settings), so tile sources rendering the same image identically share cached tiles and differently rendered ones no longer doreverse()in ome-zarr.jsrenderChunksno longer corrupts the LUT of an inverted channelBreaking changes and the full list are in the changelog.
Release
package.jsonbumped to0.6.0, changelog rolled over to[0.6.0] - 2026-09-17v0.6.0still needs to be pushed after merging to trigger the publish workflowChecks
pnpm run lint,fmt:check,test(no test files) andbuild:libpass.