Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add zarr.js #21

Merged
merged 4 commits into from
Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
target*
__pycache__/
node_modules/
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ z5py: data/reference_image.png
zarr: data/reference_image.png
python generate_data/generate_zarr.py

.PHONY: js
js: data/reference_image.png
bash generate_data/js/generate_data.sh

.PHONY: data
data: n5java pyn5 z5py zarr
data: n5java pyn5 z5py zarr js

.PHONY: test
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dependencies:
- openjdk
- maven
- make
- nodejs
- z5py >= 2.0.8
- python == 3.7.9
- scikit-image
Expand Down
6 changes: 6 additions & 0 deletions generate_data/js/generate_data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# cd to this directory
# https://stackoverflow.com/a/6393573/2700168
cd "${0%/*}"

npm install
npm start
139 changes: 139 additions & 0 deletions generate_data/js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions generate_data/js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"type": "module",
"scripts": {
"start": "node src/index.js"
},
"dependencies": {
"pngjs": "^6.0.0",
"zarr": "^0.4.0"
}
}
37 changes: 37 additions & 0 deletions generate_data/js/src/fsstore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import path from "path";
import { promises as fsp } from "fs";
import fs from "fs";

import { KeyError } from "zarr";

class FSStore {
constructor(root) {
this.root = root;
if (!fs.existsSync(root)) {
fs.mkdirSync(root, { recursive: true });
}
}

getItem(key) {
const fp = path.join(this.root, key);
return fsp.readFile(fp, null).catch((err) => {
if (err.code === "ENOENT") {
throw new KeyError(key);
}
throw err;
});
}

async setItem(key, value) {
const fp = path.join(this.root, key);
await fsp.mkdir(path.dirname(fp), { recursive: true });
await fsp.writeFile(fp, Buffer.from(value), null);
}

containsItem(key) {
const fp = path.join(this.root, key);
return fs.existsSync(fp);
}
}

export default FSStore;
53 changes: 53 additions & 0 deletions generate_data/js/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import fs from "fs";
import p from "path";
import { PNG } from "pngjs";

import { openGroup, NestedArray, slice } from "zarr";
import FSStore from "./fsstore.js";

const CHUNKS = [100, 100, 1];
const STR_TO_COMPRESSOR = {
gzip: { id: "gzip", level: 1 },
blosc: { id: "blosc", cname: "lz4", clevel: 5, blocksize: 0, shuffle: 1 },
zlib: { id: "zlib", level: 1 },
};

// Simple convenience method to init the root for an empty store.
async function open(path) {
const store = new FSStore(path);
const text = JSON.stringify({ zarr_format: 2 });
await store.setItem(".zgroup", Buffer.from(text));
return openGroup(store);
}

function imread(path) {
const buf = fs.readFileSync(path);
const { data, height, width } = PNG.sync.read(buf, { colorType: 2 });
const arr = new NestedArray(new Uint8Array(data), [height, width, 4]);
return arr.get([null, null, slice(3)]); // drop alpha channel
}

function getName(config) {
if (config === null) return "raw";
if (config.cname) return `${config.id}/${config.cname}`;
return config.id;
}

async function generateZarrFormat(codecIds = ["gzip", "blosc", "zlib", null]) {
const path = p.join("..", "..", "data", "js.zr");
const img = imread(p.join("..", "..", "data", "reference_image.png"));

fs.rmSync(path, { recursive: true, force: true });
const grp = await open(path);
for (const id of codecIds) {
const config = id ? STR_TO_COMPRESSOR[id] : null;
const name = getName(config);
grp.createDataset(name, undefined, img, {
compressor: config,
chunks: CHUNKS,
fillValue: 0,
});
}
}

generateZarrFormat();