@aics/vole-core 3.15.6 → 3.15.7
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.
- package/es/ContourPass.js +2 -2
- package/es/Line3d.js +4 -4
- package/es/loaders/TiffLoader.js +29 -12
- package/es/loaders/index.js +2 -1
- package/es/types/ContourPass.d.ts +1 -1
- package/es/types/Line3d.d.ts +1 -1
- package/es/types/loaders/TiffLoader.d.ts +2 -2
- package/es/workers/VolumeLoaderContext.js +3 -1
- package/package.json +1 -1
package/es/ContourPass.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Color, DataTexture, FloatType, RedIntegerFormat, RGBAFormat, Uniform, UnsignedIntType } from "three";
|
|
2
|
-
import
|
|
2
|
+
import { clamp } from "three/src/math/MathUtils.js";
|
|
3
|
+
import RenderToBuffer, { RenderPassType } from "./RenderToBuffer.js";
|
|
3
4
|
/* babel-plugin-inline-import './constants/shaders/contour.frag' */
|
|
4
5
|
const contourFragShader = "precision highp float;\nprecision highp int;\nprecision highp usampler2D;\nprecision highp sampler3D;\n\n/**\n * LUT mapping from the segmentation ID (raw pixel value) to the\n * global ID (index in data buffers like `featureData` and `outlierData`).\n * \n * For a given local pixel ID `localId`, the global ID is given by:\n * `localIdToGlobalId[localId - localIdOffset] - 1`.\n*/\nuniform usampler2D localIdToGlobalId;\nuniform uint localIdOffset;\nuniform bool useGlobalIdLookup;\n/* Pick buffer. Used to determine IDs. */\nuniform sampler2D pickBuffer;\n\nuniform int highlightedId;\nuniform int outlineThickness;\nuniform float outlineAlpha;\nuniform vec3 outlineColor;\nuniform float devicePixelRatio;\n\nconst uint BACKGROUND_ID = 0u;\nconst uint MISSING_DATA_ID = 0xFFFFFFFFu;\nconst int ID_OFFSET = 1;\n\nuvec4 getUintFromTex(usampler2D tex, int index) {\n int width = textureSize(tex, 0).x;\n ivec2 featurePos = ivec2(index % width, index / width);\n return uvec4(texelFetch(tex, featurePos, 0));\n}\n\nuint getId(ivec2 uv) {\n float rawId = texelFetch(pickBuffer, uv, 0).g;\n if (rawId == 0.0) {\n return BACKGROUND_ID;\n }\n int localId = int(rawId) - int(localIdOffset);\n if (!useGlobalIdLookup) {\n return uint(localId + ID_OFFSET);\n }\n uvec4 c = getUintFromTex(localIdToGlobalId, localId);\n // Note: IDs are offset by `ID_OFFSET` (`=1`) to reserve `0` for local IDs\n // that don't have associated data in the global lookup. `ID_OFFSET` MUST be\n // subtracted from the ID when accessing data buffers.\n uint globalId = c.r;\n if (globalId == 0u) {\n return MISSING_DATA_ID;\n }\n return globalId;\n}\n\nbool isEdge(ivec2 uv, int id, int thickness) {\n float wStep = 1.0;\n float hStep = 1.0;\n float thicknessFloat = float(thickness);\n // sample around the pixel to see if we are on an edge\n int R = int(getId(uv + ivec2(thicknessFloat * wStep, 0))) - ID_OFFSET;\n int L = int(getId(uv + ivec2(-thicknessFloat * wStep, 0))) - ID_OFFSET;\n int T = int(getId(uv + ivec2(0, thicknessFloat * hStep))) - ID_OFFSET;\n int B = int(getId(uv + ivec2(0, -thicknessFloat * hStep))) - ID_OFFSET;\n // if any neighbors are not id then this is an edge\n return id != -1 && (R != id || L != id || T != id || B != id);\n}\n\nvoid main(void) {\n ivec2 vUv = ivec2(int(gl_FragCoord.x / devicePixelRatio), int(gl_FragCoord.y / devicePixelRatio));\n\n uint rawId = getId(vUv);\n int id = int(rawId) - ID_OFFSET;\n\n if (id == highlightedId && isEdge(vUv, id, outlineThickness)) {\n gl_FragColor = vec4(outlineColor, outlineAlpha);\n } else {\n gl_FragColor = vec4(0, 0, 0, 0.0);\n }\n}";
|
|
5
|
-
import { clamp } from "three/src/math/MathUtils";
|
|
6
6
|
const makeDefaultUniforms = () => {
|
|
7
7
|
const pickBufferTex = new DataTexture(new Float32Array([1, 0, 0, 0]), 1, 1, RGBAFormat, FloatType);
|
|
8
8
|
const localIdToGlobalId = new DataTexture(new Uint32Array([0]), 1, 1, RedIntegerFormat, UnsignedIntType);
|
package/es/Line3d.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Group, Vector3 } from "three";
|
|
2
|
-
import { LineMaterial } from "three/addons/lines/LineMaterial";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { LineMaterial } from "three/addons/lines/LineMaterial.js";
|
|
3
|
+
import { LineSegments2 } from "three/addons/lines/LineSegments2.js";
|
|
4
|
+
import { LineSegmentsGeometry } from "three/addons/lines/LineSegmentsGeometry.js";
|
|
5
|
+
import { MESH_NO_PICK_OCCLUSION_LAYER, OVERLAY_LAYER } from "./ThreeJsPanel.js";
|
|
6
6
|
const DEFAULT_VERTEX_BUFFER_SIZE = 1020;
|
|
7
7
|
|
|
8
8
|
/**
|
package/es/loaders/TiffLoader.js
CHANGED
|
@@ -11,15 +11,16 @@ function prepareXML(xml) {
|
|
|
11
11
|
return xml.trim().replace(expr, "").trim();
|
|
12
12
|
}
|
|
13
13
|
function getOME(xml) {
|
|
14
|
+
if (xml === undefined) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const prepared = prepareXML(xml);
|
|
14
18
|
const parser = new DOMParser();
|
|
15
19
|
try {
|
|
16
|
-
const xmlDoc = parser.parseFromString(
|
|
20
|
+
const xmlDoc = parser.parseFromString(prepared, "text/xml");
|
|
17
21
|
return xmlDoc.getElementsByTagName("OME")[0];
|
|
18
22
|
} catch (e) {
|
|
19
|
-
|
|
20
|
-
type: VolumeLoadErrorType.INVALID_METADATA,
|
|
21
|
-
cause: e
|
|
22
|
-
});
|
|
23
|
+
return undefined;
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
class OMEDims {
|
|
@@ -85,6 +86,7 @@ function getOMEDims(imageEl) {
|
|
|
85
86
|
return dims;
|
|
86
87
|
}
|
|
87
88
|
const getBytesPerSample = type => type === "uint8" ? 1 : type === "uint16" ? 2 : 4;
|
|
89
|
+
const getPixelType = pxSize => pxSize === 1 ? "uint8" : pxSize === 2 ? "uint16" : "uint32";
|
|
88
90
|
|
|
89
91
|
// Despite the class `TiffLoader` extends, this loader is not threadable, since geotiff internally uses features that
|
|
90
92
|
// aren't available on workers. It uses its own specialized workers anyways.
|
|
@@ -95,17 +97,32 @@ class TiffLoader extends ThreadableVolumeLoader {
|
|
|
95
97
|
}
|
|
96
98
|
async loadOmeDims() {
|
|
97
99
|
if (!this.dims) {
|
|
98
|
-
const tiff = await fromUrl(this.url, {
|
|
100
|
+
const tiff = await fromUrl(this.url[0], {
|
|
99
101
|
allowFullFile: true
|
|
100
|
-
}).catch(wrapVolumeLoadError(`Could not open TIFF file at ${this.url}`, VolumeLoadErrorType.NOT_FOUND));
|
|
102
|
+
}).catch(wrapVolumeLoadError(`Could not open TIFF file at ${this.url[0]}`, VolumeLoadErrorType.NOT_FOUND));
|
|
101
103
|
// DO NOT DO THIS, ITS SLOW
|
|
102
104
|
// const imagecount = await tiff.getImageCount();
|
|
103
105
|
// read the FIRST image
|
|
104
106
|
const image = await tiff.getImage().catch(wrapVolumeLoadError("Failed to open TIFF image", VolumeLoadErrorType.NOT_FOUND));
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
const omeEl = getOME(image.getFileDirectory().ImageDescription);
|
|
108
|
+
if (omeEl !== undefined) {
|
|
109
|
+
const image0El = omeEl.getElementsByTagName("Image")[0];
|
|
110
|
+
this.dims = getOMEDims(image0El);
|
|
111
|
+
} else {
|
|
112
|
+
console.warn("Could not read OME-TIFF metadata from file. Doing our best with base TIFF metadata.");
|
|
113
|
+
this.dims = new OMEDims();
|
|
114
|
+
this.dims.sizex = image.getWidth();
|
|
115
|
+
this.dims.sizey = image.getHeight();
|
|
116
|
+
// TODO this is a big hack/assumption about only loading multi-source tiffs that are not OMETIFF.
|
|
117
|
+
// We really have to check each url in the array for sizec to get the total number of channels
|
|
118
|
+
// See combinedNumChannels in ImageInfo below.
|
|
119
|
+
// Also compare with how OMEZarrLoader does this.
|
|
120
|
+
this.dims.sizec = this.url.length > 1 ? this.url.length : 1; // if multiple urls, assume one channel per url
|
|
121
|
+
this.dims.pixeltype = getPixelType(image.getBytesPerPixel());
|
|
122
|
+
this.dims.channelnames = Array.from({
|
|
123
|
+
length: this.dims.sizec
|
|
124
|
+
}, (_, i) => "Channel" + i);
|
|
125
|
+
}
|
|
109
126
|
}
|
|
110
127
|
return this.dims;
|
|
111
128
|
}
|
|
@@ -189,7 +206,7 @@ class TiffLoader extends ThreadableVolumeLoader {
|
|
|
189
206
|
sizez: volumeSize.z,
|
|
190
207
|
dimensionOrder: dims.dimensionorder,
|
|
191
208
|
bytesPerSample: getBytesPerSample(dims.pixeltype),
|
|
192
|
-
url: this.url
|
|
209
|
+
url: this.url.length > 1 ? this.url[channel] : this.url[0] // if multiple urls, use the channel index to select the right one
|
|
193
210
|
};
|
|
194
211
|
const worker = new Worker(new URL("../workers/FetchTiffWorker", import.meta.url), {
|
|
195
212
|
type: "module"
|
package/es/loaders/index.js
CHANGED
|
@@ -24,13 +24,14 @@ export function pathToFileType(path) {
|
|
|
24
24
|
export async function createVolumeLoader(path, options) {
|
|
25
25
|
const pathString = Array.isArray(path) ? path[0] : path;
|
|
26
26
|
const fileType = options?.fileType || pathToFileType(pathString);
|
|
27
|
+
const pathArrayForTiffLoader = Array.isArray(path) ? path : [path];
|
|
27
28
|
switch (fileType) {
|
|
28
29
|
case VolumeFileFormat.ZARR:
|
|
29
30
|
return await OMEZarrLoader.createLoader(path, options?.scene, options?.cache, options?.queue, options?.fetchOptions);
|
|
30
31
|
case VolumeFileFormat.JSON:
|
|
31
32
|
return new JsonImageInfoLoader(path, options?.cache);
|
|
32
33
|
case VolumeFileFormat.TIFF:
|
|
33
|
-
return new TiffLoader(
|
|
34
|
+
return new TiffLoader(pathArrayForTiffLoader);
|
|
34
35
|
case VolumeFileFormat.DATA:
|
|
35
36
|
if (!options?.rawArrayOptions) {
|
|
36
37
|
throw new Error("Must provide RawArrayOptions for RawArrayLoader");
|
package/es/types/Line3d.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Color, Euler, Group, Vector3 } from "three";
|
|
2
|
-
import { IDrawableObject } from "./types";
|
|
2
|
+
import { IDrawableObject } from "./types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Simple wrapper for a 3D line segments object, with controls for vertex data,
|
|
5
5
|
* color, width, and segments visible.
|
|
@@ -34,9 +34,9 @@ export type TiffLoadResult = {
|
|
|
34
34
|
range: [number, number];
|
|
35
35
|
};
|
|
36
36
|
declare class TiffLoader extends ThreadableVolumeLoader {
|
|
37
|
-
url: string;
|
|
37
|
+
url: string[];
|
|
38
38
|
dims?: OMEDims;
|
|
39
|
-
constructor(url: string);
|
|
39
|
+
constructor(url: string[]);
|
|
40
40
|
private loadOmeDims;
|
|
41
41
|
loadDims(_loadSpec: LoadSpec): Promise<VolumeDims[]>;
|
|
42
42
|
createImageInfo(_loadSpec: LoadSpec): Promise<LoadedVolumeInfo>;
|
|
@@ -164,7 +164,9 @@ class VolumeLoaderContext {
|
|
|
164
164
|
const pathString = Array.isArray(path) ? path[0] : path;
|
|
165
165
|
const fileType = options?.fileType || pathToFileType(pathString);
|
|
166
166
|
if (fileType === VolumeFileFormat.TIFF) {
|
|
167
|
-
|
|
167
|
+
// tiff loader accepts array of paths for separate channel sources
|
|
168
|
+
const pathArray = Array.isArray(path) ? path : [path];
|
|
169
|
+
return new TiffLoader(pathArray);
|
|
168
170
|
} else if (fileType === VolumeFileFormat.DATA) {
|
|
169
171
|
if (!options?.rawArrayOptions) {
|
|
170
172
|
throw new Error("Failed to create loader: Must provide RawArrayOptions for RawArrayLoader");
|