@niivue/niivue 0.67.1-dev.1 → 0.67.1-dev.2
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/build/drawing/index.d.ts +1 -1
- package/build/drawing/index.js.map +1 -1
- package/build/index.min.js +1 -1
- package/build/metafile-esm.json +1 -1
- package/build/niivue/index.d.ts +2 -2
- package/build/niivue/index.js +89 -20
- package/build/niivue/index.js.map +1 -1
- package/build/{nvdocument-B64_4nuJ.d.ts → nvdocument-DrX6RoEG.d.ts} +14 -1
- package/build/utils/index.d.ts +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +89 -20
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/niivue.umd.js +20 -20
- package/package.json +109 -109
- package/src/niivue/index.ts +18 -1
- package/src/nvimage/index.ts +10 -2
- package/src/nvimage/utils.ts +2 -0
- package/src/nvimage/zarr/NVZarrHelper.ts +77 -19
|
@@ -448,6 +448,8 @@ type ImageFromUrlOptions = {
|
|
|
448
448
|
zarrChannel?: number;
|
|
449
449
|
/** Convert OME spatial units to millimeters for NIfTI compatibility (default: true) */
|
|
450
450
|
zarrConvertUnits?: boolean;
|
|
451
|
+
/** World-space center [x, y, z] in mm where the zarr volume center should be positioned */
|
|
452
|
+
zarrCenterMM?: [number, number, number];
|
|
451
453
|
};
|
|
452
454
|
type ImageFromFileOptions = {
|
|
453
455
|
file: File | File[];
|
|
@@ -747,6 +749,7 @@ declare class NVZarrHelper {
|
|
|
747
749
|
private voxelTranslations;
|
|
748
750
|
private hasTranslations;
|
|
749
751
|
private convertUnitsToMm;
|
|
752
|
+
private worldOffsetMM;
|
|
750
753
|
private centerX;
|
|
751
754
|
private centerY;
|
|
752
755
|
private centerZ;
|
|
@@ -757,6 +760,7 @@ declare class NVZarrHelper {
|
|
|
757
760
|
private currentAbortController;
|
|
758
761
|
private runningMin;
|
|
759
762
|
private runningMax;
|
|
763
|
+
private calibrationDone;
|
|
760
764
|
private updateDebounceTimer;
|
|
761
765
|
private readonly UPDATE_DEBOUNCE_MS;
|
|
762
766
|
private pendingChunkCount;
|
|
@@ -814,6 +818,13 @@ declare class NVZarrHelper {
|
|
|
814
818
|
height: number;
|
|
815
819
|
depth: number;
|
|
816
820
|
};
|
|
821
|
+
getWorldOffset(): [number, number, number];
|
|
822
|
+
/**
|
|
823
|
+
* Set the world-space offset so the full level's center maps to targetMM in world space.
|
|
824
|
+
* Computes the native physical center of the zarr level, then sets worldOffsetMM
|
|
825
|
+
* so that center aligns with targetMM. Also centers the viewport on the level center.
|
|
826
|
+
*/
|
|
827
|
+
setWorldCenter(targetMM: [number, number, number]): void;
|
|
817
828
|
/**
|
|
818
829
|
* Convert physical (mm) coordinates back to real zarr level pixel coordinates.
|
|
819
830
|
* Inverts the affine: levelPixel = (mm - OME_translation) / scale
|
|
@@ -953,6 +964,7 @@ declare class NVImage {
|
|
|
953
964
|
onColormapChange: (img: NVImage) => void;
|
|
954
965
|
onOpacityChange: (img: NVImage) => void;
|
|
955
966
|
zarrHelper: NVZarrHelper | null;
|
|
967
|
+
_hasExplicitZarrCenter: boolean;
|
|
956
968
|
mm000?: vec3;
|
|
957
969
|
mm100?: vec3;
|
|
958
970
|
mm010?: vec3;
|
|
@@ -1056,7 +1068,7 @@ declare class NVImage {
|
|
|
1056
1068
|
/**
|
|
1057
1069
|
* factory function to load and return a new NVImage instance from a given URL
|
|
1058
1070
|
*/
|
|
1059
|
-
static loadFromUrl({ url, urlImgData, headers, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, isManifest, limitFrames4D, imageType, colorbarVisible, buffer, zarrLevel, zarrMaxVolumeSize, zarrChannel, zarrConvertUnits }?: Partial<Omit<ImageFromUrlOptions, 'url'>> & {
|
|
1071
|
+
static loadFromUrl({ url, urlImgData, headers, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, isManifest, limitFrames4D, imageType, colorbarVisible, buffer, zarrLevel, zarrMaxVolumeSize, zarrChannel, zarrConvertUnits, zarrCenterMM }?: Partial<Omit<ImageFromUrlOptions, 'url'>> & {
|
|
1060
1072
|
url?: string | Uint8Array | ArrayBuffer;
|
|
1061
1073
|
}): Promise<NVImage>;
|
|
1062
1074
|
/**
|
|
@@ -1071,6 +1083,7 @@ declare class NVImage {
|
|
|
1071
1083
|
convertUnitsToMm?: boolean;
|
|
1072
1084
|
colormap?: string;
|
|
1073
1085
|
opacity?: number;
|
|
1086
|
+
zarrCenterMM?: [number, number, number];
|
|
1074
1087
|
}): Promise<NVImage>;
|
|
1075
1088
|
static readFileAsync(file: File, bytesToLoad?: number): Promise<ArrayBuffer>;
|
|
1076
1089
|
/**
|
package/build/utils/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -245,6 +245,8 @@ type ImageFromUrlOptions = {
|
|
|
245
245
|
zarrChannel?: number;
|
|
246
246
|
/** Convert OME spatial units to millimeters for NIfTI compatibility (default: true) */
|
|
247
247
|
zarrConvertUnits?: boolean;
|
|
248
|
+
/** World-space center [x, y, z] in mm where the zarr volume center should be positioned */
|
|
249
|
+
zarrCenterMM?: [number, number, number];
|
|
248
250
|
};
|
|
249
251
|
type ImageFromFileOptions = {
|
|
250
252
|
file: File | File[];
|
|
@@ -544,6 +546,7 @@ declare class NVZarrHelper {
|
|
|
544
546
|
private voxelTranslations;
|
|
545
547
|
private hasTranslations;
|
|
546
548
|
private convertUnitsToMm;
|
|
549
|
+
private worldOffsetMM;
|
|
547
550
|
private centerX;
|
|
548
551
|
private centerY;
|
|
549
552
|
private centerZ;
|
|
@@ -554,6 +557,7 @@ declare class NVZarrHelper {
|
|
|
554
557
|
private currentAbortController;
|
|
555
558
|
private runningMin;
|
|
556
559
|
private runningMax;
|
|
560
|
+
private calibrationDone;
|
|
557
561
|
private updateDebounceTimer;
|
|
558
562
|
private readonly UPDATE_DEBOUNCE_MS;
|
|
559
563
|
private pendingChunkCount;
|
|
@@ -611,6 +615,13 @@ declare class NVZarrHelper {
|
|
|
611
615
|
height: number;
|
|
612
616
|
depth: number;
|
|
613
617
|
};
|
|
618
|
+
getWorldOffset(): [number, number, number];
|
|
619
|
+
/**
|
|
620
|
+
* Set the world-space offset so the full level's center maps to targetMM in world space.
|
|
621
|
+
* Computes the native physical center of the zarr level, then sets worldOffsetMM
|
|
622
|
+
* so that center aligns with targetMM. Also centers the viewport on the level center.
|
|
623
|
+
*/
|
|
624
|
+
setWorldCenter(targetMM: [number, number, number]): void;
|
|
614
625
|
/**
|
|
615
626
|
* Convert physical (mm) coordinates back to real zarr level pixel coordinates.
|
|
616
627
|
* Inverts the affine: levelPixel = (mm - OME_translation) / scale
|
|
@@ -750,6 +761,7 @@ declare class NVImage {
|
|
|
750
761
|
onColormapChange: (img: NVImage) => void;
|
|
751
762
|
onOpacityChange: (img: NVImage) => void;
|
|
752
763
|
zarrHelper: NVZarrHelper | null;
|
|
764
|
+
_hasExplicitZarrCenter: boolean;
|
|
753
765
|
mm000?: vec3;
|
|
754
766
|
mm100?: vec3;
|
|
755
767
|
mm010?: vec3;
|
|
@@ -853,7 +865,7 @@ declare class NVImage {
|
|
|
853
865
|
/**
|
|
854
866
|
* factory function to load and return a new NVImage instance from a given URL
|
|
855
867
|
*/
|
|
856
|
-
static loadFromUrl({ url, urlImgData, headers, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, isManifest, limitFrames4D, imageType, colorbarVisible, buffer, zarrLevel, zarrMaxVolumeSize, zarrChannel, zarrConvertUnits }?: Partial<Omit<ImageFromUrlOptions, 'url'>> & {
|
|
868
|
+
static loadFromUrl({ url, urlImgData, headers, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, isManifest, limitFrames4D, imageType, colorbarVisible, buffer, zarrLevel, zarrMaxVolumeSize, zarrChannel, zarrConvertUnits, zarrCenterMM }?: Partial<Omit<ImageFromUrlOptions, 'url'>> & {
|
|
857
869
|
url?: string | Uint8Array | ArrayBuffer;
|
|
858
870
|
}): Promise<NVImage>;
|
|
859
871
|
/**
|
|
@@ -868,6 +880,7 @@ declare class NVImage {
|
|
|
868
880
|
convertUnitsToMm?: boolean;
|
|
869
881
|
colormap?: string;
|
|
870
882
|
opacity?: number;
|
|
883
|
+
zarrCenterMM?: [number, number, number];
|
|
871
884
|
}): Promise<NVImage>;
|
|
872
885
|
static readFileAsync(file: File, bytesToLoad?: number): Promise<ArrayBuffer>;
|
|
873
886
|
/**
|
package/dist/index.js
CHANGED
|
@@ -5249,7 +5249,7 @@ var forEach3 = (function() {
|
|
|
5249
5249
|
// package.json
|
|
5250
5250
|
var package_default = {
|
|
5251
5251
|
name: "@niivue/niivue",
|
|
5252
|
-
version: "0.67.1-dev.
|
|
5252
|
+
version: "0.67.1-dev.2",
|
|
5253
5253
|
description: "minimal webgl2 nifti image viewer",
|
|
5254
5254
|
types: "./build/niivue/index.d.ts",
|
|
5255
5255
|
main: "./build/niivue/index.js",
|
|
@@ -31283,6 +31283,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31283
31283
|
__publicField(this, "voxelTranslations");
|
|
31284
31284
|
__publicField(this, "hasTranslations");
|
|
31285
31285
|
__publicField(this, "convertUnitsToMm");
|
|
31286
|
+
__publicField(this, "worldOffsetMM", [0, 0, 0]);
|
|
31286
31287
|
__publicField(this, "centerX");
|
|
31287
31288
|
__publicField(this, "centerY");
|
|
31288
31289
|
__publicField(this, "centerZ");
|
|
@@ -31293,6 +31294,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31293
31294
|
__publicField(this, "currentAbortController", null);
|
|
31294
31295
|
__publicField(this, "runningMin", Infinity);
|
|
31295
31296
|
__publicField(this, "runningMax", -Infinity);
|
|
31297
|
+
__publicField(this, "calibrationDone", false);
|
|
31296
31298
|
// Debounce state for batching chunk updates
|
|
31297
31299
|
__publicField(this, "updateDebounceTimer", null);
|
|
31298
31300
|
__publicField(this, "UPDATE_DEBOUNCE_MS", 50);
|
|
@@ -31355,9 +31357,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31355
31357
|
const level = Math.max(0, Math.min(options.level, helper.pyramidInfo.levels.length - 1));
|
|
31356
31358
|
helper.pyramidLevel = level;
|
|
31357
31359
|
helper.updateLevelInfo();
|
|
31358
|
-
helper.centerX = helper.
|
|
31359
|
-
helper.centerY = helper.
|
|
31360
|
-
helper.centerZ = helper.
|
|
31360
|
+
helper.centerX = helper.levelDims.width / 2;
|
|
31361
|
+
helper.centerY = helper.levelDims.height / 2;
|
|
31362
|
+
helper.centerZ = helper.levelDims.depth / 2;
|
|
31361
31363
|
helper.configureHostImage();
|
|
31362
31364
|
return helper;
|
|
31363
31365
|
}
|
|
@@ -31520,6 +31522,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31520
31522
|
affine[row][col] = niftiCols[col].scale;
|
|
31521
31523
|
affine[row][3] = niftiCols[col].trans;
|
|
31522
31524
|
}
|
|
31525
|
+
affine[0][3] += this.worldOffsetMM[0];
|
|
31526
|
+
affine[1][3] += this.worldOffsetMM[1];
|
|
31527
|
+
affine[2][3] += this.worldOffsetMM[2];
|
|
31523
31528
|
hdr.affine = affine;
|
|
31524
31529
|
} else {
|
|
31525
31530
|
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
@@ -31543,12 +31548,15 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31543
31548
|
affine[row][col] = niftiCols[col].scale;
|
|
31544
31549
|
affine[row][3] = niftiCols[col].trans;
|
|
31545
31550
|
}
|
|
31551
|
+
affine[0][3] += this.worldOffsetMM[0];
|
|
31552
|
+
affine[1][3] += this.worldOffsetMM[1];
|
|
31553
|
+
affine[2][3] += this.worldOffsetMM[2];
|
|
31546
31554
|
hdr.affine = affine;
|
|
31547
31555
|
} else {
|
|
31548
31556
|
hdr.affine = [
|
|
31549
|
-
[scaleW, 0, 0, volStartW * scaleW],
|
|
31550
|
-
[0, -scaleH, 0, volStartH * scaleH],
|
|
31551
|
-
[0, 0, -scaleD, volStartD * scaleD],
|
|
31557
|
+
[scaleW, 0, 0, volStartW * scaleW + this.worldOffsetMM[0]],
|
|
31558
|
+
[0, -scaleH, 0, volStartH * scaleH + this.worldOffsetMM[1]],
|
|
31559
|
+
[0, 0, -scaleD, volStartD * scaleD + this.worldOffsetMM[2]],
|
|
31552
31560
|
[0, 0, 0, 1]
|
|
31553
31561
|
];
|
|
31554
31562
|
}
|
|
@@ -31622,11 +31630,46 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31622
31630
|
getVolumeDims() {
|
|
31623
31631
|
return { ...this.volumeDims };
|
|
31624
31632
|
}
|
|
31633
|
+
getWorldOffset() {
|
|
31634
|
+
return [...this.worldOffsetMM];
|
|
31635
|
+
}
|
|
31636
|
+
/**
|
|
31637
|
+
* Set the world-space offset so the full level's center maps to targetMM in world space.
|
|
31638
|
+
* Computes the native physical center of the zarr level, then sets worldOffsetMM
|
|
31639
|
+
* so that center aligns with targetMM. Also centers the viewport on the level center.
|
|
31640
|
+
*/
|
|
31641
|
+
setWorldCenter(targetMM) {
|
|
31642
|
+
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
31643
|
+
const { transW, transH, transD } = this.getConvertedTranslations();
|
|
31644
|
+
const axisNames = this.pyramidInfo.axisMapping.spatialAxisNames;
|
|
31645
|
+
const physW = this.levelDims.width / 2 * scaleW + transW;
|
|
31646
|
+
const physH = this.levelDims.height / 2 * scaleH + transH;
|
|
31647
|
+
const physD = this.levelDims.depth / 2 * scaleD + transD;
|
|
31648
|
+
const nativeCenter = [0, 0, 0];
|
|
31649
|
+
const dims = [
|
|
31650
|
+
{ name: axisNames[axisNames.length - 1], phys: physW },
|
|
31651
|
+
{ name: axisNames[axisNames.length - 2], phys: physH },
|
|
31652
|
+
{ name: axisNames.length >= 3 ? axisNames[axisNames.length - 3] : "z", phys: physD }
|
|
31653
|
+
];
|
|
31654
|
+
for (const d of dims) {
|
|
31655
|
+
const row = d.name === "x" ? 0 : d.name === "y" ? 1 : 2;
|
|
31656
|
+
nativeCenter[row] = d.phys;
|
|
31657
|
+
}
|
|
31658
|
+
this.worldOffsetMM = [targetMM[0] - nativeCenter[0], targetMM[1] - nativeCenter[1], targetMM[2] - nativeCenter[2]];
|
|
31659
|
+
this.centerX = this.levelDims.width / 2;
|
|
31660
|
+
this.centerY = this.levelDims.height / 2;
|
|
31661
|
+
this.centerZ = this.levelDims.depth / 2;
|
|
31662
|
+
this.clampCenter();
|
|
31663
|
+
this.updateAffine();
|
|
31664
|
+
}
|
|
31625
31665
|
/**
|
|
31626
31666
|
* Convert physical (mm) coordinates back to real zarr level pixel coordinates.
|
|
31627
31667
|
* Inverts the affine: levelPixel = (mm - OME_translation) / scale
|
|
31628
31668
|
*/
|
|
31629
31669
|
mmToLevelCoords(mmX, mmY, mmZ) {
|
|
31670
|
+
mmX -= this.worldOffsetMM[0];
|
|
31671
|
+
mmY -= this.worldOffsetMM[1];
|
|
31672
|
+
mmZ -= this.worldOffsetMM[2];
|
|
31630
31673
|
const { scaleW, scaleH, scaleD } = this.getConvertedScales();
|
|
31631
31674
|
const axisNames = this.pyramidInfo.axisMapping.spatialAxisNames;
|
|
31632
31675
|
const mmByAxis = { x: mmX, y: mmY, z: mmZ };
|
|
@@ -31738,8 +31781,6 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31738
31781
|
this.currentAbortController?.abort();
|
|
31739
31782
|
const abortController = new AbortController();
|
|
31740
31783
|
this.currentAbortController = abortController;
|
|
31741
|
-
this.runningMin = Infinity;
|
|
31742
|
-
this.runningMax = -Infinity;
|
|
31743
31784
|
await new Promise((resolve2) => {
|
|
31744
31785
|
requestAnimationFrame(() => resolve2());
|
|
31745
31786
|
});
|
|
@@ -31852,14 +31893,16 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31852
31893
|
if (actualChunkW <= 0 || actualChunkH <= 0 || actualChunkD <= 0) {
|
|
31853
31894
|
return;
|
|
31854
31895
|
}
|
|
31855
|
-
|
|
31856
|
-
|
|
31857
|
-
|
|
31858
|
-
|
|
31859
|
-
this.runningMin
|
|
31860
|
-
|
|
31861
|
-
|
|
31862
|
-
this.runningMax
|
|
31896
|
+
if (!this.calibrationDone) {
|
|
31897
|
+
const step = Math.max(1, Math.floor(data.length / 2e3));
|
|
31898
|
+
for (let i = 0; i < data.length; i += step) {
|
|
31899
|
+
const val = data[i];
|
|
31900
|
+
if (val < this.runningMin) {
|
|
31901
|
+
this.runningMin = val;
|
|
31902
|
+
}
|
|
31903
|
+
if (val > this.runningMax) {
|
|
31904
|
+
this.runningMax = val;
|
|
31905
|
+
}
|
|
31863
31906
|
}
|
|
31864
31907
|
}
|
|
31865
31908
|
const fullChunkVol = this.chunkSize.width * this.chunkSize.height * this.chunkSize.depth;
|
|
@@ -31890,6 +31933,9 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31890
31933
|
}
|
|
31891
31934
|
}
|
|
31892
31935
|
updateCalibration() {
|
|
31936
|
+
if (this.calibrationDone) {
|
|
31937
|
+
return;
|
|
31938
|
+
}
|
|
31893
31939
|
if (this.runningMin < Infinity && this.runningMax > -Infinity) {
|
|
31894
31940
|
this.hostImage.cal_min = this.runningMin;
|
|
31895
31941
|
this.hostImage.cal_max = this.runningMax;
|
|
@@ -31897,6 +31943,7 @@ var NVZarrHelper = class _NVZarrHelper {
|
|
|
31897
31943
|
this.hostImage.robust_max = this.runningMax;
|
|
31898
31944
|
this.hostImage.global_min = this.runningMin;
|
|
31899
31945
|
this.hostImage.global_max = this.runningMax;
|
|
31946
|
+
this.calibrationDone = true;
|
|
31900
31947
|
}
|
|
31901
31948
|
}
|
|
31902
31949
|
/**
|
|
@@ -31990,6 +32037,7 @@ var NVImage = class _NVImage {
|
|
|
31990
32037
|
__publicField(this, "onOpacityChange", () => {
|
|
31991
32038
|
});
|
|
31992
32039
|
__publicField(this, "zarrHelper", null);
|
|
32040
|
+
__publicField(this, "_hasExplicitZarrCenter", false);
|
|
31993
32041
|
__publicField(this, "mm000");
|
|
31994
32042
|
__publicField(this, "mm100");
|
|
31995
32043
|
__publicField(this, "mm010");
|
|
@@ -32626,7 +32674,8 @@ var NVImage = class _NVImage {
|
|
|
32626
32674
|
zarrLevel,
|
|
32627
32675
|
zarrMaxVolumeSize,
|
|
32628
32676
|
zarrChannel,
|
|
32629
|
-
zarrConvertUnits
|
|
32677
|
+
zarrConvertUnits,
|
|
32678
|
+
zarrCenterMM
|
|
32630
32679
|
} = {}) {
|
|
32631
32680
|
if (url === "") {
|
|
32632
32681
|
throw Error("url must not be empty");
|
|
@@ -32679,7 +32728,8 @@ var NVImage = class _NVImage {
|
|
|
32679
32728
|
channel: zarrChannel,
|
|
32680
32729
|
convertUnitsToMm: zarrConvertUnits,
|
|
32681
32730
|
colormap,
|
|
32682
|
-
opacity
|
|
32731
|
+
opacity,
|
|
32732
|
+
zarrCenterMM
|
|
32683
32733
|
});
|
|
32684
32734
|
}
|
|
32685
32735
|
const zarrResult = await loadZarrData(url);
|
|
@@ -32758,6 +32808,10 @@ var NVImage = class _NVImage {
|
|
|
32758
32808
|
cacheSize: options.cacheSize,
|
|
32759
32809
|
convertUnitsToMm: options.convertUnitsToMm
|
|
32760
32810
|
});
|
|
32811
|
+
if (options.zarrCenterMM) {
|
|
32812
|
+
nvimage.zarrHelper.setWorldCenter(options.zarrCenterMM);
|
|
32813
|
+
nvimage._hasExplicitZarrCenter = true;
|
|
32814
|
+
}
|
|
32761
32815
|
if (options.colormap) {
|
|
32762
32816
|
nvimage._colormap = options.colormap;
|
|
32763
32817
|
}
|
|
@@ -45355,7 +45409,8 @@ var Niivue = class {
|
|
|
45355
45409
|
zarrLevel: imageItem.zarrLevel,
|
|
45356
45410
|
zarrMaxVolumeSize: imageItem.zarrMaxVolumeSize,
|
|
45357
45411
|
zarrChannel: imageItem.zarrChannel,
|
|
45358
|
-
zarrConvertUnits: imageItem.zarrConvertUnits
|
|
45412
|
+
zarrConvertUnits: imageItem.zarrConvertUnits,
|
|
45413
|
+
zarrCenterMM: imageItem.zarrCenterMM
|
|
45359
45414
|
};
|
|
45360
45415
|
const volume = await NVImage.loadFromUrl(imageOptions);
|
|
45361
45416
|
this.document.addImageOptions(volume, imageOptions);
|
|
@@ -45935,6 +45990,20 @@ var Niivue = class {
|
|
|
45935
45990
|
this.setVolume(volume, result.index);
|
|
45936
45991
|
this.onImageLoaded(volume);
|
|
45937
45992
|
if (volume.zarrHelper) {
|
|
45993
|
+
if (!volume._hasExplicitZarrCenter && this.back && this.back !== volume && this.back.hdr?.dims) {
|
|
45994
|
+
const bg = this.back;
|
|
45995
|
+
const dims = bg.hdr.dims;
|
|
45996
|
+
const affine = bg.hdr.affine;
|
|
45997
|
+
const ci = (dims[1] - 1) / 2;
|
|
45998
|
+
const cj = (dims[2] - 1) / 2;
|
|
45999
|
+
const ck = (dims[3] - 1) / 2;
|
|
46000
|
+
const bgCenter = [
|
|
46001
|
+
affine[0][0] * ci + affine[0][1] * cj + affine[0][2] * ck + affine[0][3],
|
|
46002
|
+
affine[1][0] * ci + affine[1][1] * cj + affine[1][2] * ck + affine[1][3],
|
|
46003
|
+
affine[2][0] * ci + affine[2][1] * cj + affine[2][2] * ck + affine[2][3]
|
|
46004
|
+
];
|
|
46005
|
+
volume.zarrHelper.setWorldCenter(bgCenter);
|
|
46006
|
+
}
|
|
45938
46007
|
volume.zarrHelper.onChunksUpdated = () => {
|
|
45939
46008
|
this.updateGLVolume();
|
|
45940
46009
|
this._skipDragInDraw = true;
|