Skip to content

Commit

Permalink
Only use nested(store) for correct version of OME-Zarr
Browse files Browse the repository at this point in the history
  • Loading branch information
will-moore committed Mar 31, 2021
1 parent 01a051a commit ddee2e9
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 25 deletions.
35 changes: 32 additions & 3 deletions src/ome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,28 @@ import { ZarrPixelSource } from '@hms-dbmi/viv';
import pMap from 'p-map';
import { Group as ZarrGroup, HTTPStore, openGroup, ZarrArray } from 'zarr';
import type { ImageLayerConfig, SourceData } from './state';
import { join, loadMultiscales, guessTileSize, range, parseMatrix } from './utils';
import {
guessTileSize,
join,
loadMultiscales,
nested,
parseMatrix,
range
} from './utils';

export async function loadWell(config: ImageLayerConfig, grp: ZarrGroup, wellAttrs: Ome.Well): Promise<SourceData> {
// OME-Zarr uses nested chunks since version 0.2
function isNested(version: String | undefined) : boolean {
return version != undefined && version !== "0.1";
}

export async function loadWell(
config: ImageLayerConfig,
grp: ZarrGroup,
wellAttrs: Ome.Well
): Promise<SourceData> {
if (isNested(wellAttrs.version)) {
grp.store = nested(grp.store);
}
// Can filter Well fields by URL query ?acquisition=ID
const acquisitionId: number | undefined = config.acquisition ? parseInt(config.acquisition) : undefined;
let acquisitions: Ome.Acquisition[] = [];
Expand Down Expand Up @@ -104,7 +123,14 @@ export async function loadWell(config: ImageLayerConfig, grp: ZarrGroup, wellAtt
return sourceData;
}

export async function loadPlate(config: ImageLayerConfig, grp: ZarrGroup, plateAttrs: Ome.Plate): Promise<SourceData> {
export async function loadPlate(
config: ImageLayerConfig,
grp: ZarrGroup,
plateAttrs: Ome.Plate
): Promise<SourceData> {
if (isNested(plateAttrs.version)) {
grp.store = nested(grp.store);
}
if (!('columns' in plateAttrs) || !('rows' in plateAttrs)) {
throw Error(`Plate .zattrs missing columns or rows`);
}
Expand Down Expand Up @@ -193,6 +219,9 @@ export async function loadOmeroMultiscales(
grp: ZarrGroup,
attrs: { multiscales: Ome.Multiscale[]; omero: Ome.Omero }
): Promise<SourceData> {
if (isNested(attrs.multiscales[0]?.version)) {
grp.store = nested(grp.store);
}
const { name, opacity = 1, colormap = '' } = config;
const data = await loadMultiscales(grp, attrs.multiscales);
const meta = parseOmeroMeta(attrs.omero);
Expand Down
51 changes: 29 additions & 22 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,9 @@ async function normalizeStore(source: string | ZarrArray['store']) {

export async function open(source: string | ZarrArray['store']) {
const { store, path } = await normalizeStore(source);

function nested(store) {
const get = (target, key) => {
if (key === 'getItem' || key === 'setItem' || key === 'containsItem') {
return (path, ...args) => {
if (path.endsWith('.zarray') || path.endsWith('.zattrs') || path.endsWith('.zgroup')) {
return target[key](path, ...args);
}
const prefix = path.split('/');
const chunkKey = prefix.pop();
const newPath = [...prefix, chunkKey.replaceAll('.', '/')].join('/');
return target[key](newPath, ...args);
}
}
return Reflect.get(target, key);
};
return new Proxy(store, { get });
}
const nested_store = nested(store);

return openGroup(nested_store, path).catch((err) => {
return openGroup(store, path).catch((err) => {
if (err instanceof ContainsArrayError) {
return openArray({ nested_store, path });
return openArray({ store, path });
}
throw err;
});
Expand All @@ -70,6 +50,33 @@ export async function loadMultiscales(grp: ZarrGroup, multiscales: Ome.Multiscal
throw Error('Multiscales metadata included a path to a group.');
}

export function nested(store: ZarrArray['store']) {
const get = (target: ZarrArray['store'], key: string | number | symbol) => {
if (key === 'getItem' || key === 'containsItem' || key === 'setItem') {
return (path: string, ...args: any[]) => {
if (path.endsWith('.zarray') || path.endsWith('.zattrs') || path.endsWith('.zgroup')) {
if (key === 'setItem') {
// TypeScript: setItem() needs 'value'
return target[key](path, args[0]);
} else {
return target[key](path, ...args);
}
}
const prefix = path.split('/');
const chunkKey = prefix.pop() as string;
const newPath = [...prefix, chunkKey.replaceAll('.', '/')].join('/');
if (key === 'setItem') {
return target[key](newPath, args[0]);
} else {
return target[key](newPath, ...args);
}
}
}
return Reflect.get(target, key);
};
return new Proxy(store, { get });
}

export function hexToRGB(hex: string): number[] {
if (hex.startsWith('#')) hex = hex.slice(1);
const r = parseInt(hex.slice(0, 2), 16);
Expand Down

0 comments on commit ddee2e9

Please sign in to comment.