@niivue/niivue 0.43.0 → 0.43.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/index.d.ts CHANGED
@@ -215,11 +215,12 @@ type ImageFromUrlOptions = {
215
215
  ignoreZeroVoxels?: boolean;
216
216
  imageType?: ImageType;
217
217
  frame4D?: number;
218
- colormapLabel?: string[];
218
+ colormapLabel?: LUT | null;
219
219
  pairedImgData?: null;
220
220
  limitFrames4D?: number;
221
221
  isManifest?: boolean;
222
222
  urlImgData?: string;
223
+ buffer?: ArrayBuffer;
223
224
  };
224
225
  type ImageFromFileOptions = {
225
226
  file: File | File[];
@@ -248,6 +249,14 @@ type ImageFromBase64 = {
248
249
  trustCalMinMax?: boolean;
249
250
  percentileFrac?: number;
250
251
  ignoreZeroVoxels?: boolean;
252
+ useQFormNotSForm?: boolean;
253
+ colormapNegative?: string;
254
+ frame4D?: number;
255
+ imageType?: ImageType;
256
+ cal_minNeg?: number;
257
+ cal_maxNeg?: number;
258
+ colorbarVisible?: boolean;
259
+ colormapLabel?: LUT | null;
251
260
  };
252
261
  type ImageMetadata = {
253
262
  id: string;
@@ -262,7 +271,7 @@ type ImageMetadata = {
262
271
  dt: number;
263
272
  bpv: number;
264
273
  };
265
- declare const NVImageFromUrlOptions: (url: string, urlImageData?: string, name?: string, colormap?: string, opacity?: number, cal_min?: number, cal_max?: number, trustCalMinMax?: boolean, percentileFrac?: number, ignoreZeroVoxels?: boolean, useQFormNotSForm?: boolean, colormapNegative?: string, frame4D?: number, imageType?: ImageType, cal_minNeg?: number, cal_maxNeg?: number, colorbarVisible?: boolean, alphaThreshold?: boolean, colormapLabel?: string[]) => ImageFromUrlOptions;
274
+ declare const NVImageFromUrlOptions: (url: string, urlImageData?: string, name?: string, colormap?: string, opacity?: number, cal_min?: number, cal_max?: number, trustCalMinMax?: boolean, percentileFrac?: number, ignoreZeroVoxels?: boolean, useQFormNotSForm?: boolean, colormapNegative?: string, frame4D?: number, imageType?: ImageType, cal_minNeg?: number, cal_maxNeg?: number, colorbarVisible?: boolean, alphaThreshold?: boolean, colormapLabel?: null) => ImageFromUrlOptions;
266
275
 
267
276
  type TypedVoxelArray = Float32Array | Uint8Array | Int16Array | Float64Array | Uint16Array;
268
277
  /**
@@ -397,7 +406,7 @@ declare class NVImage {
397
406
  * factory function to load and return a new NVImage instance from a given URL
398
407
  * @returns NVImage instance
399
408
  */
400
- static loadFromUrl({ url, urlImgData, headers, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, isManifest, limitFrames4D, imageType, colorbarVisible }?: Partial<Omit<ImageFromUrlOptions, 'url'>> & {
409
+ static loadFromUrl({ url, urlImgData, headers, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, isManifest, limitFrames4D, imageType, colorbarVisible, buffer }?: Partial<Omit<ImageFromUrlOptions, 'url'>> & {
401
410
  url?: string | Uint8Array | ArrayBuffer;
402
411
  }): Promise<NVImage>;
403
412
  static readFileAsync(file: File, bytesToLoad?: number): Promise<ArrayBuffer>;
@@ -440,7 +449,7 @@ declare class NVImage {
440
449
  * @example
441
450
  * myImage = NVImage.loadFromBase64('SomeBase64String')
442
451
  */
443
- static loadFromBase64({ base64, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels }: ImageFromBase64): NVImage;
452
+ static loadFromBase64({ base64, name, colormap, opacity, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, imageType, cal_minNeg, cal_maxNeg, colorbarVisible, colormapLabel }: ImageFromBase64): NVImage;
444
453
  /**
445
454
  * make a clone of a NVImage instance and return a new NVImage
446
455
  * @returns NVImage instance
@@ -989,26 +998,38 @@ type NVMeshLayer = {
989
998
  headers?: Record<string, string>;
990
999
  opacity: number;
991
1000
  colormap: string;
992
- colormapNegative: string;
993
- colormapInvert: boolean;
1001
+ colormapNegative?: string;
1002
+ colormapInvert?: boolean;
994
1003
  colormapLabel?: ColorMap | LUT;
995
- useNegativeCmap: boolean;
996
- global_min: number;
997
- global_max: number;
1004
+ useNegativeCmap?: boolean;
1005
+ global_min?: number;
1006
+ global_max?: number;
998
1007
  cal_min: number;
999
1008
  cal_max: number;
1000
1009
  cal_minNeg: number;
1001
1010
  cal_maxNeg: number;
1002
- isAdditiveBlend: boolean;
1011
+ isAdditiveBlend?: boolean;
1003
1012
  frame4D: number;
1004
1013
  nFrame4D: number;
1005
- values: number[];
1014
+ values: AnyNumberArray;
1006
1015
  outlineBorder?: number;
1007
1016
  isTransparentBelowCalMin?: boolean;
1008
- alphaThreshold: boolean;
1017
+ alphaThreshold?: boolean;
1009
1018
  base64?: string;
1010
1019
  colorbarVisible?: boolean;
1011
1020
  };
1021
+ declare const NVMeshLayerDefaults: {
1022
+ colormap: string;
1023
+ opacity: number;
1024
+ nFrame4D: number;
1025
+ frame4D: number;
1026
+ outlineBorder: number;
1027
+ cal_min: number;
1028
+ cal_max: number;
1029
+ cal_minNeg: number;
1030
+ cal_maxNeg: number;
1031
+ values: number[];
1032
+ };
1012
1033
  declare class NVMeshFromUrlOptions {
1013
1034
  url: string;
1014
1035
  gl: WebGL2RenderingContext | null;
@@ -1031,6 +1052,7 @@ type BaseLoadParams = {
1031
1052
  type LoadFromUrlParams = Partial<BaseLoadParams> & {
1032
1053
  url: string;
1033
1054
  headers?: Record<string, string>;
1055
+ buffer?: ArrayBuffer;
1034
1056
  };
1035
1057
  type LoadFromFileParams = BaseLoadParams & {
1036
1058
  file: Blob;
@@ -1126,7 +1148,7 @@ declare class NVMesh {
1126
1148
  /**
1127
1149
  * factory function to load and return a new NVMesh instance from a given URL
1128
1150
  */
1129
- static loadFromUrl({ url, headers, gl, name, opacity, rgba255, visible, layers }?: Partial<LoadFromUrlParams>): Promise<NVMesh>;
1151
+ static loadFromUrl({ url, headers, gl, name, opacity, rgba255, visible, layers, buffer }?: Partial<LoadFromUrlParams>): Promise<NVMesh>;
1130
1152
  static readFileAsync(file: Blob): Promise<ArrayBuffer>;
1131
1153
  /**
1132
1154
  * factory function to load and return a new NVMesh instance from a file in the browser
@@ -1422,7 +1444,7 @@ declare class NVMeshLoaders {
1422
1444
  static readTCK(buffer: ArrayBuffer): TCK;
1423
1445
  static readTRK(buffer: ArrayBuffer): TRK;
1424
1446
  static readTxtVTK(buffer: ArrayBuffer): VTK;
1425
- static readLayer(name: string | undefined, buffer: ArrayBuffer, nvmesh: NVMesh, opacity?: number, colormap?: string, colormapNegative?: string, useNegativeCmap?: boolean, cal_min?: number | null, cal_max?: number | null, outlineBorder?: number): void;
1447
+ static readLayer(name: string | undefined, buffer: ArrayBuffer, nvmesh: NVMesh, opacity?: number, colormap?: string, colormapNegative?: string, useNegativeCmap?: boolean, cal_min?: number | null, cal_max?: number | null, outlineBorder?: number): NVMeshLayer | undefined;
1426
1448
  static readSMP(buffer: ArrayBuffer, n_vert: number): Float32Array;
1427
1449
  static readSTC(buffer: ArrayBuffer, n_vert: number): Float32Array;
1428
1450
  static readCURV(buffer: ArrayBuffer, n_vert: number): Float32Array;
@@ -1991,6 +2013,18 @@ declare class Niivue {
1991
2013
  * @param url - filename
1992
2014
  */
1993
2015
  isMeshExt(url: string): boolean;
2016
+ /**
2017
+ * Load an image or mesh from an array buffer
2018
+ * @param buffer - ArrayBuffer with the entire contents of a mesh or volume
2019
+ * @param name - string of filename, extension used to infer type (NIfTI, MGH, MZ3, etc)
2020
+ * @see {@link http://192.168.0.150:8080/features/draganddrop.html | live demo usage}
2021
+ */
2022
+ loadFromArrayBuffer(buffer: ArrayBuffer, name: string): Promise<void>;
2023
+ /**
2024
+ * Load a mesh or image from a file object
2025
+ * @param file - File object
2026
+ */
2027
+ loadFromFile(file: File): Promise<void>;
1994
2028
  dropListener(e: DragEvent): void;
1995
2029
  /**
1996
2030
  * insert a gap between slices of a mutliplanar view.
@@ -2703,9 +2737,10 @@ declare class Niivue {
2703
2737
  * @param toRAS - reslice to row, column slices to right-anterior-superior not left-inferior-anterior (default false).
2704
2738
  * @param isLinear - reslice with linear rather than nearest-neighbor interpolation (default true).
2705
2739
  * @param asFloat32 - use Float32 datatype rather than Uint8 (default false).
2740
+ * @param isRobustMinMax - clamp intensity with robust min max (~2%..98%) instead of FreeSurfer (0%..99.99%) (default false).
2706
2741
  * @see {@link https://niivue.github.io/niivue/features/torso.html | live demo usage}
2707
2742
  */
2708
- conform(volume: NVImage, toRAS?: boolean, isLinear?: boolean, asFloat32?: boolean): Promise<NVImage>;
2743
+ conform(volume: NVImage, toRAS?: boolean, isLinear?: boolean, asFloat32?: boolean, isRobustMinMax?: boolean): Promise<NVImage>;
2709
2744
  /**
2710
2745
  * darken crevices and brighten corners when 3D rendering drawings.
2711
2746
  * @param amount - amount of ambient occlusion (default 0.4)
@@ -2882,4 +2917,4 @@ declare class Niivue {
2882
2917
  set gl(gl: WebGL2RenderingContext | null);
2883
2918
  }
2884
2919
 
2885
- export { type Connectome, type ConnectomeOptions, DEFAULT_OPTIONS, DRAG_MODE, type DocumentData, type DragReleaseParams, type ExportDocumentData, INITIAL_SCENE_DATA, LabelLineTerminator, LabelTextAlignment, type LegacyConnectome, type LegacyNodes, MULTIPLANAR_TYPE, type NVConfigOptions, type NVConnectomeEdge, type NVConnectomeNode, NVController, NVDocument, NVImage, NVImageFromUrlOptions, NVLabel3D, NVLabel3DStyle, NVMesh, NVMeshFromUrlOptions, NVMeshLoaders, NVUtilities, type NiftiHeader, Niivue, type Point, SLICE_TYPE, type Scene, type Volume, cmapper, ColorTables as colortables };
2920
+ export { type Connectome, type ConnectomeOptions, DEFAULT_OPTIONS, DRAG_MODE, type DocumentData, type DragReleaseParams, type ExportDocumentData, INITIAL_SCENE_DATA, LabelLineTerminator, LabelTextAlignment, type LegacyConnectome, type LegacyNodes, MULTIPLANAR_TYPE, type NVConfigOptions, type NVConnectomeEdge, type NVConnectomeNode, NVController, NVDocument, NVImage, NVImageFromUrlOptions, NVLabel3D, NVLabel3DStyle, NVMesh, NVMeshFromUrlOptions, NVMeshLayerDefaults, NVMeshLoaders, NVUtilities, type NiftiHeader, Niivue, type Point, SLICE_TYPE, type Scene, type Volume, cmapper, ColorTables as colortables };
package/build/index.js CHANGED
@@ -13,7 +13,7 @@ var __publicField = (obj, key, value) => {
13
13
  import { mat4 as mat46, vec2, vec3 as vec311, vec4 as vec48 } from "gl-matrix";
14
14
 
15
15
  // package.json
16
- var version = "0.43.0";
16
+ var version = "0.43.2";
17
17
 
18
18
  // src/logger.ts
19
19
  var _Log = class _Log {
@@ -12269,6 +12269,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
12269
12269
  // read mesh overlay to influence vertex colors
12270
12270
  static readLayer(name = "", buffer, nvmesh, opacity = 0.5, colormap = "warm", colormapNegative = "winter", useNegativeCmap = false, cal_min = null, cal_max = null, outlineBorder = 0) {
12271
12271
  const layer = {
12272
+ ...NVMeshLayerDefaults,
12272
12273
  colormapInvert: false,
12273
12274
  alphaThreshold: false,
12274
12275
  isTransparentBelowCalMin: true,
@@ -12311,9 +12312,10 @@ var NVMeshLoaders = class _NVMeshLoaders {
12311
12312
  cal_min: mn2,
12312
12313
  cal_max: mx2
12313
12314
  });
12314
- return;
12315
+ return layer;
12315
12316
  }
12316
12317
  if (n_vert < 3) {
12318
+ log.error("n_vert < 3 in layer");
12317
12319
  return;
12318
12320
  }
12319
12321
  if (ext === "MZ3") {
@@ -12357,9 +12359,10 @@ var NVMeshLoaders = class _NVMeshLoaders {
12357
12359
  layer.values = _NVMeshLoaders.readSTC(buffer, n_vert);
12358
12360
  } else {
12359
12361
  log.warn("Unknown layer overlay format " + name);
12360
- return;
12362
+ return layer;
12361
12363
  }
12362
12364
  if (!layer.values) {
12365
+ log.error("no values in layer");
12363
12366
  return;
12364
12367
  }
12365
12368
  layer.nFrame4D = layer.values.length / n_vert;
@@ -12373,11 +12376,11 @@ var NVMeshLoaders = class _NVMeshLoaders {
12373
12376
  }
12374
12377
  layer.global_min = mn;
12375
12378
  layer.global_max = mx;
12376
- layer.cal_min = cal_min;
12379
+ layer.cal_min = cal_min || 0;
12377
12380
  if (!cal_min) {
12378
12381
  layer.cal_min = mn;
12379
12382
  }
12380
- layer.cal_max = cal_max;
12383
+ layer.cal_max = cal_max || 0;
12381
12384
  if (!cal_max) {
12382
12385
  layer.cal_max = mx;
12383
12386
  }
@@ -12387,7 +12390,7 @@ var NVMeshLoaders = class _NVMeshLoaders {
12387
12390
  layer.colormap = colormap;
12388
12391
  layer.colormapNegative = colormapNegative;
12389
12392
  layer.useNegativeCmap = useNegativeCmap;
12390
- nvmesh.layers.push(layer);
12393
+ return layer;
12391
12394
  }
12392
12395
  // readLayer()
12393
12396
  // read brainvoyager smp format file
@@ -14802,6 +14805,18 @@ var NVMeshLoaders = class _NVMeshLoaders {
14802
14805
  };
14803
14806
 
14804
14807
  // src/nvmesh.ts
14808
+ var NVMeshLayerDefaults = {
14809
+ colormap: "gray",
14810
+ opacity: 0,
14811
+ nFrame4D: 0,
14812
+ frame4D: 0,
14813
+ outlineBorder: 0,
14814
+ cal_min: 0,
14815
+ cal_max: 0,
14816
+ cal_minNeg: 0,
14817
+ cal_maxNeg: 0,
14818
+ values: new Array()
14819
+ };
14805
14820
  var NVMeshFromUrlOptions = class {
14806
14821
  constructor(url = "", gl = null, name = "", opacity = 1, rgba255 = new Uint8Array([255, 255, 255, 255]), visible = true, layers = [], colorbarVisible = true) {
14807
14822
  __publicField(this, "url");
@@ -14822,7 +14837,7 @@ var NVMeshFromUrlOptions = class {
14822
14837
  this.colorbarVisible = colorbarVisible;
14823
14838
  }
14824
14839
  };
14825
- var NVMesh = class _NVMesh {
14840
+ var NVMesh2 = class _NVMesh {
14826
14841
  /**
14827
14842
  * @param pts - a 3xN array of vertex positions (X,Y,Z coordinates).
14828
14843
  * @param tris - a 3xN array of triangle indices (I,J,K; indexed from zero). Each triangle generated from three vertices.
@@ -14938,6 +14953,7 @@ var NVMesh = class _NVMesh {
14938
14953
  this.pts = pts;
14939
14954
  this.layers = [];
14940
14955
  this.type = "mesh" /* MESH */;
14956
+ this.tris = tris;
14941
14957
  if (rgba255[3] < 1) {
14942
14958
  this.rgba255 = rgba255;
14943
14959
  this.fiberLength = 2;
@@ -14979,7 +14995,6 @@ var NVMesh = class _NVMesh {
14979
14995
  }
14980
14996
  }
14981
14997
  this.rgba255 = rgba255;
14982
- this.tris = tris;
14983
14998
  this.updateMesh(gl);
14984
14999
  }
14985
15000
  initValuesArray(va) {
@@ -15992,7 +16007,7 @@ var NVMesh = class _NVMesh {
15992
16007
  if ("cal_max" in layer) {
15993
16008
  cal_max = layer.cal_max;
15994
16009
  }
15995
- NVMeshLoaders.readLayer(
16010
+ const newLayer = NVMeshLoaders.readLayer(
15996
16011
  layerName,
15997
16012
  buffer,
15998
16013
  nvmesh,
@@ -16003,6 +16018,9 @@ var NVMesh = class _NVMesh {
16003
16018
  cal_min,
16004
16019
  cal_max
16005
16020
  );
16021
+ if (newLayer) {
16022
+ nvmesh.layers.push(newLayer);
16023
+ }
16006
16024
  }
16007
16025
  /**
16008
16026
  * factory function to load and return a new NVMesh instance from a given URL
@@ -16015,7 +16033,8 @@ var NVMesh = class _NVMesh {
16015
16033
  opacity = 1,
16016
16034
  rgba255 = [255, 255, 255, 255],
16017
16035
  visible = true,
16018
- layers = []
16036
+ layers = [],
16037
+ buffer = new ArrayBuffer(0)
16019
16038
  } = {}) {
16020
16039
  let urlParts = url.split("/");
16021
16040
  if (name === "") {
@@ -16035,17 +16054,22 @@ var NVMesh = class _NVMesh {
16035
16054
  if (!gl) {
16036
16055
  throw Error("gl context is null");
16037
16056
  }
16038
- const response = await fetch(url, { headers });
16039
- if (!response.ok) {
16040
- throw Error(response.statusText);
16057
+ let buff;
16058
+ if (buffer.byteLength > 0) {
16059
+ buff = buffer;
16060
+ } else {
16061
+ const response = await fetch(url, { headers });
16062
+ if (!response.ok) {
16063
+ throw Error(response.statusText);
16064
+ }
16065
+ buff = await response.arrayBuffer();
16041
16066
  }
16042
- const buffer = await response.arrayBuffer();
16043
- const nvmesh = await this.readMesh(buffer, name, gl, opacity, new Uint8Array(rgba255), visible);
16067
+ const nvmesh = await this.readMesh(buff, name, gl, opacity, new Uint8Array(rgba255), visible);
16044
16068
  if (!layers || layers.length < 1) {
16045
16069
  return nvmesh;
16046
16070
  }
16047
16071
  for (let i = 0; i < layers.length; i++) {
16048
- await this.loadLayer(layers[i], nvmesh);
16072
+ await _NVMesh.loadLayer(layers[i], nvmesh);
16049
16073
  }
16050
16074
  nvmesh.updateMesh(gl);
16051
16075
  return nvmesh;
@@ -17952,7 +17976,7 @@ var NVIMAGE_TYPE = Object.freeze({
17952
17976
  return imageType;
17953
17977
  }
17954
17978
  });
17955
- var NVImageFromUrlOptions = (url, urlImageData = "", name = "", colormap = "gray", opacity = 1, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false, useQFormNotSForm = false, colormapNegative = "", frame4D = 0, imageType = NVIMAGE_TYPE.UNKNOWN, cal_minNeg = NaN, cal_maxNeg = NaN, colorbarVisible = true, alphaThreshold = false, colormapLabel = []) => {
17979
+ var NVImageFromUrlOptions = (url, urlImageData = "", name = "", colormap = "gray", opacity = 1, cal_min = NaN, cal_max = NaN, trustCalMinMax = true, percentileFrac = 0.02, ignoreZeroVoxels = false, useQFormNotSForm = false, colormapNegative = "", frame4D = 0, imageType = NVIMAGE_TYPE.UNKNOWN, cal_minNeg = NaN, cal_maxNeg = NaN, colorbarVisible = true, alphaThreshold = false, colormapLabel = null) => {
17956
17980
  return {
17957
17981
  url,
17958
17982
  urlImageData,
@@ -20600,7 +20624,8 @@ var NVImage = class _NVImage {
20600
20624
  isManifest = false,
20601
20625
  limitFrames4D = NaN,
20602
20626
  imageType = NVIMAGE_TYPE.UNKNOWN,
20603
- colorbarVisible = true
20627
+ colorbarVisible = true,
20628
+ buffer = new ArrayBuffer(0)
20604
20629
  } = {}) {
20605
20630
  if (url === "") {
20606
20631
  throw Error("url must not be empty");
@@ -20610,12 +20635,19 @@ var NVImage = class _NVImage {
20610
20635
  if (url instanceof Uint8Array) {
20611
20636
  url = url.buffer;
20612
20637
  }
20638
+ if (buffer.byteLength > 0) {
20639
+ url = buffer;
20640
+ }
20613
20641
  if (url instanceof ArrayBuffer) {
20614
20642
  dataBuffer = url;
20615
- url = "array.nii";
20616
- const bytes = new Uint8Array(dataBuffer);
20617
- if (bytes[0] === 31 && bytes[1] === 139) {
20618
- url = "array.nii.gz";
20643
+ if (name !== "") {
20644
+ url = name;
20645
+ } else {
20646
+ url = "array.nii";
20647
+ const bytes = new Uint8Array(dataBuffer);
20648
+ if (bytes[0] === 31 && bytes[1] === 139) {
20649
+ url = "array.nii.gz";
20650
+ }
20619
20651
  }
20620
20652
  }
20621
20653
  if (!isNaN(limitFrames4D)) {
@@ -21067,7 +21099,15 @@ var NVImage = class _NVImage {
21067
21099
  cal_max = NaN,
21068
21100
  trustCalMinMax = true,
21069
21101
  percentileFrac = 0.02,
21070
- ignoreZeroVoxels = false
21102
+ ignoreZeroVoxels = false,
21103
+ useQFormNotSForm = false,
21104
+ colormapNegative = "",
21105
+ frame4D = 0,
21106
+ imageType = NVIMAGE_TYPE.UNKNOWN,
21107
+ cal_minNeg = NaN,
21108
+ cal_maxNeg = NaN,
21109
+ colorbarVisible = true,
21110
+ colormapLabel = null
21071
21111
  }) {
21072
21112
  function base64ToArrayBuffer(base642) {
21073
21113
  const binary_string = window.atob(base642);
@@ -21092,7 +21132,15 @@ var NVImage = class _NVImage {
21092
21132
  cal_max,
21093
21133
  trustCalMinMax,
21094
21134
  percentileFrac,
21095
- ignoreZeroVoxels
21135
+ ignoreZeroVoxels,
21136
+ useQFormNotSForm,
21137
+ colormapNegative,
21138
+ frame4D,
21139
+ imageType,
21140
+ cal_minNeg,
21141
+ cal_maxNeg,
21142
+ colorbarVisible,
21143
+ colormapLabel
21096
21144
  );
21097
21145
  } catch (err) {
21098
21146
  log.debug(err);
@@ -21845,7 +21893,7 @@ var NVDocument = class _NVDocument {
21845
21893
  ignoreZeroVoxels: false,
21846
21894
  useQFormNotSForm: false,
21847
21895
  colormapNegative: "",
21848
- colormapLabel: [],
21896
+ colormapLabel: null,
21849
21897
  imageType: NVIMAGE_TYPE.NII,
21850
21898
  frame4D: 0,
21851
21899
  limitFrames4D: NaN,
@@ -21890,7 +21938,7 @@ var NVDocument = class _NVDocument {
21890
21938
  ignoreZeroVoxels: false,
21891
21939
  useQFormNotSForm: false,
21892
21940
  colormapNegative: "",
21893
- colormapLabel: [],
21941
+ colormapLabel: null,
21894
21942
  imageType: NVIMAGE_TYPE.NII,
21895
21943
  frame4D: 0,
21896
21944
  limitFrames4D: NaN,
@@ -21908,6 +21956,7 @@ var NVDocument = class _NVDocument {
21908
21956
  }
21909
21957
  }
21910
21958
  imageOptions2.colormap = volume.colormap;
21959
+ imageOptions2.colormapLabel = volume.colormapLabel;
21911
21960
  imageOptions2.opacity = volume.opacity;
21912
21961
  imageOptions2.cal_max = volume.cal_max || NaN;
21913
21962
  imageOptions2.cal_min = volume.cal_min || NaN;
@@ -22019,6 +22068,10 @@ var NVDocument = class _NVDocument {
22019
22068
  const utf8decoder = new TextDecoder();
22020
22069
  const dataString = utf8decoder.decode(arrayBuffer);
22021
22070
  document2.data = JSON.parse(dataString);
22071
+ if (document2.data.opts.meshThicknessOn2D === "infinity") {
22072
+ document2.data.opts.meshThicknessOn2D = Infinity;
22073
+ }
22074
+ document2.scene.sceneData = { ...INITIAL_SCENE_DATA, ...document2.data.sceneData };
22022
22075
  _NVDocument.deserializeMeshDataObjects(document2);
22023
22076
  return document2;
22024
22077
  }
@@ -22031,7 +22084,7 @@ var NVDocument = class _NVDocument {
22031
22084
  if (document2.data.opts.meshThicknessOn2D === "infinity") {
22032
22085
  document2.data.opts.meshThicknessOn2D = Infinity;
22033
22086
  }
22034
- document2.scene.sceneData = data.sceneData;
22087
+ document2.scene.sceneData = { ...INITIAL_SCENE_DATA, ...data.sceneData };
22035
22088
  _NVDocument.deserializeMeshDataObjects(document2);
22036
22089
  return document2;
22037
22090
  }
@@ -22113,7 +22166,7 @@ var defaultOptions = {
22113
22166
  edgeScale: 1,
22114
22167
  legendLineThickness: 0
22115
22168
  };
22116
- var NVConnectome = class _NVConnectome extends NVMesh {
22169
+ var NVConnectome = class _NVConnectome extends NVMesh2 {
22117
22170
  constructor(gl, connectome) {
22118
22171
  super(new Float32Array([]), new Uint32Array([]), connectome.name, new Uint8Array([]), 1, true, gl, connectome);
22119
22172
  __publicField(this, "gl");
@@ -22935,7 +22988,7 @@ var NVController = class {
22935
22988
  case 9 /* MESH_FROM_URL_ADDED */:
22936
22989
  if (!this.niivue.getMediaByUrl(msg.meshOptions.url)) {
22937
22990
  msg.meshOptions.gl = this.niivue.gl;
22938
- NVMesh.loadFromUrl(msg.meshOptions).then((mesh) => {
22991
+ NVMesh2.loadFromUrl(msg.meshOptions).then((mesh) => {
22939
22992
  this.addMesh(mesh, msg.meshOptions.url);
22940
22993
  }).catch((e) => {
22941
22994
  if (e) {
@@ -24590,6 +24643,42 @@ var Niivue = class _Niivue {
24590
24643
  log.debug(ext);
24591
24644
  return MESH_EXTENSIONS.includes(ext);
24592
24645
  }
24646
+ /**
24647
+ * Load an image or mesh from an array buffer
24648
+ * @param buffer - ArrayBuffer with the entire contents of a mesh or volume
24649
+ * @param name - string of filename, extension used to infer type (NIfTI, MGH, MZ3, etc)
24650
+ * @see {@link http://192.168.0.150:8080/features/draganddrop.html | live demo usage}
24651
+ */
24652
+ async loadFromArrayBuffer(buffer, name) {
24653
+ const ext = this.getFileExt(name);
24654
+ if (MESH_EXTENSIONS.includes(ext)) {
24655
+ await this.addMeshFromUrl({ url: name, buffer });
24656
+ return;
24657
+ }
24658
+ const imageOptions = NVImageFromUrlOptions(name);
24659
+ imageOptions.buffer = buffer;
24660
+ imageOptions.name = name;
24661
+ await this.addVolumeFromUrl(imageOptions);
24662
+ }
24663
+ /**
24664
+ * Load a mesh or image from a file object
24665
+ * @param file - File object
24666
+ */
24667
+ async loadFromFile(file) {
24668
+ const ext = this.getFileExt(file.name);
24669
+ if (MESH_EXTENSIONS.includes(ext)) {
24670
+ await NVMesh2.loadFromFile({ file, gl: this.gl, name: file.name }).then((mesh) => {
24671
+ this.addMesh(mesh);
24672
+ });
24673
+ return;
24674
+ }
24675
+ await NVImage.loadFromFile({
24676
+ file,
24677
+ name: file.name
24678
+ }).then((volume) => {
24679
+ this.addVolume(volume);
24680
+ });
24681
+ }
24593
24682
  // not included in public docs
24594
24683
  dropListener(e) {
24595
24684
  e.stopPropagation();
@@ -24668,7 +24757,7 @@ var Niivue = class _Niivue {
24668
24757
  if (MESH_EXTENSIONS.includes(ext)) {
24669
24758
  ;
24670
24759
  entry.file((file) => {
24671
- NVMesh.loadFromFile({
24760
+ NVMesh2.loadFromFile({
24672
24761
  file,
24673
24762
  gl: this.gl,
24674
24763
  name: file.name
@@ -25963,6 +26052,7 @@ var Niivue = class _Niivue {
25963
26052
  const opts = { ...DEFAULT_OPTIONS, ...document2.opts };
25964
26053
  this.scene.pan2Dxyzmm = document2.scene.pan2Dxyzmm ? document2.scene.pan2Dxyzmm : [0, 0, 0, 1];
25965
26054
  this.document.opts = opts;
26055
+ this.setClipPlane(this.scene.clipPlaneDepthAziElev);
25966
26056
  log.debug("load document", document2);
25967
26057
  this.mediaUrlMap.clear();
25968
26058
  this.createEmptyDrawing();
@@ -25977,7 +26067,6 @@ var Niivue = class _Niivue {
25977
26067
  const image = NVImage.loadFromBase64({ base64: base642, ...imageOptions });
25978
26068
  if (image) {
25979
26069
  this.addVolume(image);
25980
- document2.addImageOptions(image, imageOptions);
25981
26070
  }
25982
26071
  }
25983
26072
  }
@@ -25995,7 +26084,7 @@ var Niivue = class _Niivue {
25995
26084
  for (const meshDataObject of document2.meshDataObjects ?? []) {
25996
26085
  const meshInit = { gl: this.gl, ...meshDataObject };
25997
26086
  log.debug(meshInit);
25998
- const meshToAdd = new NVMesh(
26087
+ const meshToAdd = new NVMesh2(
25999
26088
  meshInit.pts,
26000
26089
  meshInit.tris,
26001
26090
  meshInit.name,
@@ -26017,7 +26106,9 @@ var Niivue = class _Niivue {
26017
26106
  if (document2.data.connectomes) {
26018
26107
  for (const connectomeString of document2.data.connectomes) {
26019
26108
  const connectome = JSON.parse(connectomeString);
26020
- this.loadConnectome(connectome);
26109
+ const meshToAdd = this.loadConnectomeAsMesh(connectome);
26110
+ meshToAdd.updateMesh(this.gl);
26111
+ this.addMesh(meshToAdd);
26021
26112
  }
26022
26113
  }
26023
26114
  this.updateGLVolume();
@@ -26164,7 +26255,6 @@ var Niivue = class _Niivue {
26164
26255
  this.drawScene();
26165
26256
  this.document.previewImageDataURL = this.canvas.toDataURL();
26166
26257
  const json = this.document.json();
26167
- json.sceneData = { ...this.scene };
26168
26258
  return json;
26169
26259
  }
26170
26260
  /**
@@ -26175,12 +26265,12 @@ var Niivue = class _Niivue {
26175
26265
  * @see {@link https://niivue.github.io/niivue/features/document.3d.html | live demo usage}
26176
26266
  */
26177
26267
  async saveDocument(fileName = "untitled.nvd") {
26178
- this.document.opts = this.opts;
26179
- this.document.scene = this.scene;
26180
26268
  this.document.title = fileName;
26181
26269
  log.debug("saveDocument", this.volumes[0]);
26182
26270
  this.drawScene();
26183
26271
  this.document.previewImageDataURL = this.canvas.toDataURL();
26272
+ this.document.volumes = this.volumes;
26273
+ this.document.meshes = this.meshes;
26184
26274
  this.document.download(fileName);
26185
26275
  }
26186
26276
  /**
@@ -26241,7 +26331,7 @@ var Niivue = class _Niivue {
26241
26331
  this.addMesh(mesh2);
26242
26332
  return mesh2;
26243
26333
  }
26244
- const mesh = await NVMesh.loadFromUrl({ ...meshOptions, gl: this.gl });
26334
+ const mesh = await NVMesh2.loadFromUrl({ ...meshOptions, gl: this.gl });
26245
26335
  this.mediaUrlMap.set(mesh, meshOptions.url);
26246
26336
  this.onMeshAddedFromUrl(meshOptions, mesh);
26247
26337
  this.addMesh(mesh);
@@ -26271,6 +26361,7 @@ var Niivue = class _Niivue {
26271
26361
  for (let i = 0; i < meshList.length; i++) {
26272
26362
  await this.addMeshFromUrl(meshList[i]);
26273
26363
  }
26364
+ this.updateGLVolume();
26274
26365
  this.drawScene();
26275
26366
  return this;
26276
26367
  }
@@ -28497,6 +28588,16 @@ var Niivue = class _Niivue {
28497
28588
  if (volume.hdr.datatypeCode === 2 /* DT_UINT8 */) {
28498
28589
  return [src_min, 1];
28499
28590
  }
28591
+ if (!isFinite(f_low) || !isFinite(f_high)) {
28592
+ if (isFinite(volume.cal_min) && isFinite(volume.cal_max) && volume.cal_max > volume.cal_min) {
28593
+ src_min = volume.cal_min;
28594
+ src_max = volume.cal_max;
28595
+ const scale2 = (dst_max - dst_min) / (src_max - src_min);
28596
+ log.info(" Robust Rescale: min: " + src_min + " max: " + src_max + " scale: " + scale2);
28597
+ console.log("Robust Rescale: min: " + src_min + " max: " + src_max + " scale: " + scale2);
28598
+ return [src_min, scale2];
28599
+ }
28600
+ }
28500
28601
  const img = volume.img;
28501
28602
  const voxnum = volume.hdr.dims[1] * volume.hdr.dims[2] * volume.hdr.dims[3];
28502
28603
  if (volume.hdr.scl_slope !== 1 || volume.hdr.scl_inter !== 0) {
@@ -28637,9 +28738,10 @@ var Niivue = class _Niivue {
28637
28738
  * @param toRAS - reslice to row, column slices to right-anterior-superior not left-inferior-anterior (default false).
28638
28739
  * @param isLinear - reslice with linear rather than nearest-neighbor interpolation (default true).
28639
28740
  * @param asFloat32 - use Float32 datatype rather than Uint8 (default false).
28741
+ * @param isRobustMinMax - clamp intensity with robust min max (~2%..98%) instead of FreeSurfer (0%..99.99%) (default false).
28640
28742
  * @see {@link https://niivue.github.io/niivue/features/torso.html | live demo usage}
28641
28743
  */
28642
- async conform(volume, toRAS = false, isLinear = true, asFloat32 = false) {
28744
+ async conform(volume, toRAS = false, isLinear = true, asFloat32 = false, isRobustMinMax = false) {
28643
28745
  const outDim = 256;
28644
28746
  const outMM = 1;
28645
28747
  const obj = this.conformVox2Vox(volume.hdr.dims, volume.hdr.affine.flat(), outDim, outMM, toRAS);
@@ -28732,9 +28834,13 @@ var Niivue = class _Niivue {
28732
28834
  }
28733
28835
  const src_min = 0;
28734
28836
  const scale = 0;
28837
+ let f_low = 0;
28838
+ if (isRobustMinMax) {
28839
+ f_low = NaN;
28840
+ }
28735
28841
  let bytes = new Uint8Array();
28736
28842
  if (asFloat32) {
28737
- const gs = await this.getScale(volume, 0, 1);
28843
+ const gs = await this.getScale(volume, 0, 1, f_low);
28738
28844
  const out_img32 = await this.scalecropFloat32(out_img, 0, 1, gs[0], gs[1]);
28739
28845
  bytes = await this.createNiftiArray(
28740
28846
  [outDim, outDim, outDim],
@@ -28744,7 +28850,7 @@ var Niivue = class _Niivue {
28744
28850
  new Uint8Array(out_img32.buffer)
28745
28851
  );
28746
28852
  } else {
28747
- const gs = await this.getScale(volume, 0, 255);
28853
+ const gs = await this.getScale(volume, 0, 255, f_low);
28748
28854
  const out_img8 = await this.scalecropUint8(out_img, 0, 255, gs[0], gs[1]);
28749
28855
  bytes = await this.createNiftiArray(
28750
28856
  [outDim, outDim, outDim],
@@ -31945,8 +32051,9 @@ export {
31945
32051
  NVImageFromUrlOptions,
31946
32052
  NVLabel3D,
31947
32053
  NVLabel3DStyle,
31948
- NVMesh,
32054
+ NVMesh2 as NVMesh,
31949
32055
  NVMeshFromUrlOptions,
32056
+ NVMeshLayerDefaults,
31950
32057
  NVMeshLoaders,
31951
32058
  NVUtilities,
31952
32059
  Niivue,