UNPKG

@niivue/niivue

Version:

minimal webgl2 nifti image viewer

1,496 lines (1,481 loc) 120 kB
import { mat4, vec3, vec4, vec2 } from 'gl-matrix'; import * as nifti from 'nifti-reader-js'; import { WebSocketSubject } from 'rxjs/webSocket'; type ColorMap = { R: number[]; G: number[]; B: number[]; A: number[]; I: number[]; min?: number; max?: number; labels?: string[]; }; type LUT = { lut: Uint8ClampedArray; min?: number; max?: number; labels?: string[]; }; declare class ColorTables { gamma: number; version: number; cluts: Record<string, ColorMap>; /** * Sets cluts to alphabetically sorted cmaps */ constructor(); addColormap(key: string, cmap: ColorMap): void; colormaps(): Array<keyof typeof this.cluts>; colorMaps(): Array<keyof typeof this.cluts>; colormapFromKey(name: string): ColorMap; colormap(key?: string, isInvert?: boolean): Uint8ClampedArray; makeLabelLut(cm: ColorMap, alphaFill?: number): LUT; makeLabelLutFromUrl(name: string): Promise<LUT>; makeDrawLut(name: string | ColorMap): LUT; makeLut(Rsi: number[], Gsi: number[], Bsi: number[], Asi: number[], Isi: number[], isInvert: boolean): Uint8ClampedArray; } declare const cmapper: ColorTables; declare class Shader { program: WebGLProgram; uniforms: Record<string, WebGLUniformLocation | null>; isMatcap?: boolean; constructor(gl: WebGL2RenderingContext, vertexSrc: string, fragmentSrc: string); use(gl: WebGL2RenderingContext): void; } type Geometry = { vertexBuffer: WebGLBuffer; indexBuffer: WebGLBuffer; indexCount: number; vao: WebGLVertexArrayObject | null; }; /** * Object rendered with WebGL **/ declare class NiivueObject3D { static BLEND: number; static CULL_FACE: number; static CULL_FRONT: number; static CULL_BACK: number; static ENABLE_DEPTH_TEST: number; sphereIdx: number[]; sphereVtx: number[]; renderShaders: number[]; isVisible: boolean; isPickable: boolean; vertexBuffer: WebGLVertexArrayObject; indexCount: number; indexBuffer: WebGLVertexArrayObject | null; vao: WebGLVertexArrayObject | null; mode: number; glFlags: number; id: number; colorId: [number, number, number, number]; modelMatrix: mat4; scale: number[]; position: number[]; rotation: number[]; rotationRadians: number; extentsMin: number[]; extentsMax: number[]; furthestVertexFromOrigin?: number; originNegate?: vec3; fieldOfViewDeObliqueMM?: vec3; mm?: vec4; constructor(id: number, vertexBuffer: WebGLBuffer, mode: number, indexCount: number, indexBuffer?: WebGLVertexArrayObject | null, vao?: WebGLVertexArrayObject | null); static generateCrosshairs: (gl: WebGL2RenderingContext, id: number, xyzMM: vec4, xyzMin: vec3, xyzMax: vec3, radius: number, sides?: number, gap?: number) => NiivueObject3D; static generateCrosshairsGeometry: (gl: WebGL2RenderingContext, xyzMM: vec4, xyzMin: vec3, xyzMax: vec3, radius: number, sides?: number, gap?: number) => Geometry; static getFirstPerpVector: (v1: vec3) => vec3; static subdivide: (verts: number[], faces: number[]) => void; static weldVertices: (verts: number[], faces: number[]) => number[]; static makeSphere: (vertices: number[], indices: number[], radius: number, origin?: vec3 | vec4) => void; static makeCylinder: (vertices: number[], indices: number[], start: vec3, dest: vec3, radius: number, sides?: number, endcaps?: boolean) => void; static makeColoredCylinder: (vertices: number[], indices: number[], colors: number[], start: vec3, dest: vec3, radius: number, rgba255?: number[], sides?: number, endcaps?: boolean) => void; static makeColoredSphere: (vertices: number[], indices: number[], colors: number[], radius: number, origin?: vec3 | vec4, rgba255?: number[]) => void; } declare enum LabelTextAlignment { LEFT = "left", RIGHT = "right", CENTER = "center" } declare enum LabelLineTerminator { NONE = "none", CIRCLE = "circle", RING = "ring" } declare enum LabelAnchorPoint { NONE = 0, TOPLEFT = 9, TOPCENTER = 10, TOPRIGHT = 12, MIDDLELEFT = 17, MIDDLECENTER = 18, MIDDLERIGHT = 20, BOTTOMLEFT = 33, BOTTOMCENTER = 34, BOTTOMRIGHT = 36 } /** * Class representing label style. * @ignore */ declare class NVLabel3DStyle { textColor: number[]; textScale: number; textAlignment?: LabelTextAlignment; lineWidth: number; lineColor: number[]; lineTerminator: LabelLineTerminator; bulletScale?: number; bulletColor?: number[]; backgroundColor?: number[]; /** * @param textColor - Color of text * @param textScale - Text Size (0.0..1.0) * @param lineWidth - Line width * @param lineColor - Line color * @param bulletScale - Bullet size respective of text * @param bulletColor - Bullet color * @param backgroundColor - Background color of label */ constructor(textColor?: number[], textScale?: number, textAlignment?: LabelTextAlignment, lineWidth?: number, lineColor?: number[], lineTerminator?: LabelLineTerminator, bulletScale?: number, bulletColor?: number[], backgroundColor?: number[]); } /** * Label class * @ignore */ declare class NVLabel3D { text: string; style: NVLabel3DStyle; points?: number[] | number[][]; anchor: LabelAnchorPoint; onClick?: (label: NVLabel3D) => void; /** * @param text - The text of the label * @param style - The style of the label * @param points - An array of points label for label lines */ constructor(text: string, style: NVLabel3DStyle, points?: number[] | number[][], anchor?: LabelAnchorPoint, onClick?: (label: NVLabel3D) => void); } /** * Enum for NIfTI datatype codes * // https://nifti.nimh.nih.gov/pub/dist/src/niftilib/nifti1.h */ declare enum NiiDataType { DT_NONE = 0, DT_BINARY = 1, DT_UINT8 = 2, DT_INT16 = 4, DT_INT32 = 8, DT_FLOAT32 = 16, DT_COMPLEX64 = 32, DT_FLOAT64 = 64, DT_RGB24 = 128, DT_INT8 = 256, DT_UINT16 = 512, DT_UINT32 = 768, DT_INT64 = 1024, DT_UINT64 = 1280, DT_FLOAT128 = 1536, DT_COMPLEX128 = 1792, DT_COMPLEX256 = 2048, DT_RGBA32 = 2304 } /** * Enum for supported image types (e.g. NII, NRRD, DICOM) */ declare enum ImageType { UNKNOWN = 0, NII = 1, DCM = 2, DCM_MANIFEST = 3, MIH = 4, MIF = 5, NHDR = 6, NRRD = 7, MHD = 8, MHA = 9, MGH = 10, MGZ = 11, V = 12, V16 = 13, VMR = 14, HEAD = 15, DCM_FOLDER = 16, SRC = 17, FIB = 18 } type ImageFromUrlOptions = { url: string; urlImageData?: string; headers?: Record<string, string>; name?: string; colorMap?: string; colormap?: string; opacity?: number; cal_min?: number; cal_max?: number; trustCalMinMax?: boolean; percentileFrac?: number; useQFormNotSForm?: boolean; alphaThreshold?: boolean; colormapNegative?: string; colorMapNegative?: string; cal_minNeg?: number; cal_maxNeg?: number; colorbarVisible?: boolean; ignoreZeroVoxels?: boolean; imageType?: ImageType; frame4D?: number; colormapLabel?: LUT | null; pairedImgData?: null; limitFrames4D?: number; isManifest?: boolean; urlImgData?: string; buffer?: ArrayBuffer; }; type ImageFromFileOptions = { file: File | File[]; name?: string; colormap?: string; opacity?: number; urlImgData?: File | null | FileSystemEntry; cal_min?: number; cal_max?: number; trustCalMinMax?: boolean; percentileFrac?: number; ignoreZeroVoxels?: boolean; useQFormNotSForm?: boolean; colormapNegative?: string; imageType?: ImageType; frame4D?: number; limitFrames4D?: number; }; type ImageFromBase64 = { base64: 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; colormapLabel?: LUT | null; }; type ImageMetadata = { id: string; datatypeCode: number; nx: number; ny: number; nz: number; nt: number; dx: number; dy: number; dz: number; dt: number; bpv: number; }; 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?: any) => ImageFromUrlOptions; type TypedVoxelArray = Float32Array | Uint8Array | Int16Array | Float64Array | Uint16Array; /** * a NVImage encapsulates some images data and provides methods to query and operate on images */ declare class NVImage { name: string; id: string; url?: string; headers?: Record<string, string>; _colormap: string; _opacity: number; percentileFrac: number; ignoreZeroVoxels: boolean; trustCalMinMax: boolean; colormapNegative: string; colormapLabel: LUT | null; colormapInvert?: boolean; nFrame4D?: number; frame4D: number; nTotalFrame4D?: number; cal_minNeg: number; cal_maxNeg: number; colorbarVisible: boolean; modulationImage: number | null; modulateAlpha: number; series: any; nVox3D?: number; oblique_angle?: number; maxShearDeg?: number; useQFormNotSForm: boolean; alphaThreshold?: number; pixDims?: number[]; matRAS?: mat4; pixDimsRAS?: number[]; obliqueRAS?: mat4; dimsRAS?: number[]; permRAS?: number[]; img2RASstep?: number[]; img2RASstart?: number[]; toRAS?: mat4; toRASvox?: mat4; frac2mm?: mat4; frac2mmOrtho?: mat4; extentsMinOrtho?: number[]; extentsMaxOrtho?: number[]; mm2ortho?: mat4; hdr: nifti.NIFTI1 | nifti.NIFTI2 | null; imageType?: ImageType; img?: TypedVoxelArray; imaginary?: Float32Array; v1?: Float32Array; fileObject?: File | File[]; dims?: number[]; onColormapChange: (img: NVImage) => void; onOpacityChange: (img: NVImage) => void; mm000?: vec3; mm100?: vec3; mm010?: vec3; mm001?: vec3; cal_min?: number; cal_max?: number; robust_min?: number; robust_max?: number; global_min?: number; global_max?: number; urlImgData?: string; isManifest?: boolean; limitFrames4D?: number; /** * * @param dataBuffer - an array buffer of image data to load (there are also methods that abstract this more. See loadFromUrl, and loadFromFile) * @param name - a name for this image. Default is an empty string * @param colormap - a color map to use. default is gray * @param opacity - the opacity for this image. default is 1 * @param pairedImgData - Allows loading formats where header and image are separate files (e.g. nifti.hdr, nifti.img) * @param cal_min - minimum intensity for color brightness/contrast * @param cal_max - maximum intensity for color brightness/contrast * @param trustCalMinMax - whether or not to trust cal_min and cal_max from the nifti header (trusting results in faster loading) * @param percentileFrac - the percentile to use for setting the robust range of the display values (smart intensity setting for images with large ranges) * @param ignoreZeroVoxels - whether or not to ignore zero voxels in setting the robust range of display values * @param useQFormNotSForm - give precedence to QForm (Quaternion) or SForm (Matrix) * @param colormapNegative - a color map to use for symmetrical negative intensities * @param frame4D - volume displayed, 0 indexed, must be less than nFrame4D * * FIXME the following params are documented but not included in the actual constructor * @param onColormapChange - callback for color map change * @param onOpacityChange -callback for color map change * * TODO the following parameters were not documented * @param imageType - TODO * @param cal_minNeg - TODO * @param cal_maxNeg - TODO * @param colorbarVisible - TODO * @param colormapLabel - TODO */ constructor(dataBuffer?: ArrayBuffer | ArrayBuffer[] | null, name?: string, colormap?: string, opacity?: number, pairedImgData?: ArrayBuffer | null, 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, colormapLabel?: LUT | null); computeObliqueAngle(mtx44: mat4): number; float32V1asRGBA(inImg: Float32Array): Uint8Array; loadImgV1(isFlipX?: boolean, isFlipY?: boolean, isFlipZ?: boolean): boolean; calculateOblique(): void; THD_daxes_to_NIFTI(xyzDelta: number[], xyzOrigin: number[], orientSpecific: number[]): void; SetPixDimFromSForm(): void; readDICOM(buf: ArrayBuffer | ArrayBuffer[]): ArrayBuffer; readECAT(buffer: ArrayBuffer): ArrayBuffer; readV16(buffer: ArrayBuffer): ArrayBuffer; readVMR(buffer: ArrayBuffer): ArrayBuffer; readMGH(buffer: ArrayBuffer): ArrayBuffer; readFIB(buffer: ArrayBuffer): [ArrayBuffer, Float32Array]; readSRC(buffer: ArrayBuffer): ArrayBuffer; readHEAD(dataBuffer: ArrayBuffer, pairedImgData: ArrayBuffer | null): ArrayBuffer; readMHA(buffer: ArrayBuffer, pairedImgData: ArrayBuffer | null): ArrayBuffer; readMIF(buffer: ArrayBuffer, pairedImgData: ArrayBuffer | null): ArrayBuffer; readNRRD(dataBuffer: ArrayBuffer, pairedImgData: ArrayBuffer | null): ArrayBuffer; calculateRAS(): void; img2RAS(): TypedVoxelArray; vox2mm(XYZ: number[], mtx: mat4): vec3; mm2vox(mm: number[], frac?: boolean): Float32Array | vec3; arrayEquals(a: unknown[], b: unknown[]): boolean; setColormap(cm: string): void; setColormapLabel(cm: ColorMap): void; setColormapLabelFromUrl(url: string): Promise<void>; get colormap(): string; get colorMap(): string; set colormap(cm: string); set colorMap(cm: string); get opacity(): number; set opacity(opacity: number); calMinMax(): number[]; intensityRaw2Scaled(raw: number): number; intensityScaled2Raw(scaled: number): number; saveToUint8Array(fnm: string, drawing8?: Uint8Array | null): Uint8Array; saveToDisk(fnm?: string, drawing8?: Uint8Array | null): Uint8Array; static fetchDicomData(url: string, headers?: Record<string, string>): Promise<ArrayBuffer[]>; static fetchPartial(url: string, bytesToLoad: number, headers?: Record<string, string>): Promise<Response>; /** * factory function to load and return a new NVImage instance from a given URL * @returns NVImage instance */ 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'>> & { url?: string | Uint8Array | ArrayBuffer; }): Promise<NVImage>; static readFileAsync(file: File, bytesToLoad?: number): Promise<ArrayBuffer>; /** * factory function to load and return a new NVImage instance from a file in the browser */ static loadFromFile({ file, // file can be an array of file objects or a single file object name, colormap, opacity, urlImgData, cal_min, cal_max, trustCalMinMax, percentileFrac, ignoreZeroVoxels, useQFormNotSForm, colormapNegative, frame4D, limitFrames4D, imageType }: ImageFromFileOptions): Promise<NVImage>; /** * factory function to load and return a new NVImage instance from a base64 encoded string * * @returns NVImage instance * @example * myImage = NVImage.loadFromBase64('SomeBase64String') */ static createNiftiArray(dims?: number[], pixDims?: number[], affine?: number[], datatypeCode?: number, // DT_UINT8 img?: Uint8Array): Uint8Array; static createNiftiHeader(dims?: number[], pixDims?: number[], affine?: number[], datatypeCode?: number): nifti.NIFTI1; /** * read a 3D slab of voxels from a volume * @param voxStart - first row, column and slice (RAS order) for selection * @param voxEnd - final row, column and slice (RAS order) for selection * @param dataType - array data type. Options: 'same' (default), 'uint8', 'float32', 'scaled', 'normalized', 'windowed' * @returns the an array where ret[0] is the voxel values and ret[1] is dimension of selection * @see {@link https://niivue.github.io/niivue/features/slab_selection.html | live demo usage} */ getVolumeData(voxStart?: number[], voxEnd?: number[], dataType?: string): [TypedVoxelArray, number[]]; /** * write a 3D slab of voxels from a volume * @param voxStart - first row, column and slice (RAS order) for selection * @param voxEnd - final row, column and slice (RAS order) for selection * @param img - array of voxel values to insert (RAS order) * @see {@link https://niivue.github.io/niivue/features/slab_selection.html | live demo usage} */ setVolumeData(voxStart?: number[], voxEnd?: number[], img?: TypedVoxelArray): void; /** * factory function to load and return a new NVImage instance from a base64 encoded string * * @returns NVImage instance * @example * myImage = NVImage.loadFromBase64('SomeBase64String') */ 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; /** * make a clone of a NVImage instance and return a new NVImage * @returns NVImage instance * @example * myImage = NVImage.loadFromFile(SomeFileObject) // files can be from dialogs or drag and drop * clonedImage = myImage.clone() */ clone(): NVImage; /** * fill a NVImage instance with zeros for the image data * @example * myImage = NVImage.loadFromFile(SomeFileObject) // files can be from dialogs or drag and drop * clonedImageWithZeros = myImage.clone().zeroImage() */ zeroImage(): void; /** * get nifti specific metadata about the image */ getImageMetadata(): ImageMetadata; /** * a factory function to make a zero filled image given a NVImage as a reference * @param nvImage - an existing NVImage as a reference * @param dataType - the output data type. Options: 'same', 'uint8' * @returns new NVImage filled with zeros for the image data * @example * myImage = NVImage.loadFromFile(SomeFileObject) // files can be from dialogs or drag and drop * newZeroImage = NVImage.zerosLike(myImage) */ static zerosLike(nvImage: NVImage, dataType?: string): NVImage; getValue(x: number, y: number, z: number, frame4D?: number, isReadImaginary?: boolean): number; /** * @param id - id of 3D Object (is this the base volume or an overlay?) * @param gl - WebGL rendering context * @returns new 3D object in model space */ toNiivueObject3D(id: number, gl: WebGL2RenderingContext): NiivueObject3D; /** * Update options for image */ applyOptionsUpdate(options: ImageFromUrlOptions): void; getImageOptions(): ImageFromUrlOptions; /** * Converts NVImage to NIfTI compliant byte array */ toUint8Array(drawingBytes?: Uint8Array | null): Uint8Array; convertVox2Frac(vox: vec3): vec3; convertFrac2Vox(frac: vec3): vec3; convertFrac2MM(frac: vec3, isForceSliceMM?: boolean): vec4; convertMM2Frac(mm: vec3 | vec4, isForceSliceMM?: boolean): vec3; } type FreeSurferConnectome = { data_type: string; points: Array<{ comments?: Array<{ text: string; }>; coordinates: { x: number; y: number; z: number; }; }>; }; /** * Represents a connectome */ declare class NVConnectome extends NVMesh { gl: WebGL2RenderingContext; nodesChanged: EventTarget; constructor(gl: WebGL2RenderingContext, connectome: LegacyConnectome); static convertLegacyConnectome(json: LegacyConnectome): Connectome; static convertFreeSurferConnectome(json: FreeSurferConnectome, colormap?: string): Connectome; updateLabels(): void; addConnectomeNode(node: NVConnectomeNode): void; deleteConnectomeNode(node: NVConnectomeNode): void; updateConnectomeNodeByIndex(index: number, updatedNode: NVConnectomeNode): void; updateConnectomeNodeByPoint(point: [number, number, number], updatedNode: NVConnectomeNode): void; addConnectomeEdge(first: number, second: number, colorValue: number): NVConnectomeEdge; deleteConnectomeEdge(first: number, second: number): NVConnectomeEdge; findClosestConnectomeNode(point: number[], distance: number): NVConnectomeNode | null; updateConnectome(gl: WebGL2RenderingContext): void; updateMesh(gl: WebGL2RenderingContext): void; json(): Connectome; /** * Factory method to create connectome from options */ static loadConnectomeFromUrl(gl: WebGL2RenderingContext, url: string): Promise<NVConnectome>; } /** * Slice Type * @ignore */ declare enum SLICE_TYPE { AXIAL = 0, CORONAL = 1, SAGITTAL = 2, MULTIPLANAR = 3, RENDER = 4 } declare enum SHOW_RENDER { NEVER = 0, ALWAYS = 1, AUTO = 2 } /** * Multi-planar layout * @ignore */ declare enum MULTIPLANAR_TYPE { AUTO = 0, COLUMN = 1, GRID = 2, ROW = 3 } /** * Drag mode * @ignore */ declare enum DRAG_MODE { none = 0, contrast = 1, measurement = 2, pan = 3, slicer3D = 4, callbackOnly = 5 } /** * NVConfigOptions */ type NVConfigOptions = { textHeight: number; colorbarHeight: number; crosshairWidth: number; crosshairGap: number; rulerWidth: number; show3Dcrosshair: boolean; backColor: number[]; crosshairColor: number[]; fontColor: Float32List; selectionBoxColor: number[]; clipPlaneColor: number[]; clipThick: number; clipVolumeLow: number[]; clipVolumeHigh: number[]; rulerColor: number[]; colorbarMargin: number; trustCalMinMax: boolean; clipPlaneHotKey: string; viewModeHotKey: string; doubleTouchTimeout: number; longTouchTimeout: number; keyDebounceTime: number; isNearestInterpolation: boolean; atlasOutline: number; isRuler: boolean; isColorbar: boolean; isOrientCube: boolean; multiplanarPadPixels: number; multiplanarForceRender: boolean; multiplanarEqualSize: boolean; multiplanarShowRender: SHOW_RENDER; isRadiologicalConvention: boolean; meshThicknessOn2D: number | string; dragMode: DRAG_MODE; yoke3Dto2DZoom: boolean; isDepthPickMesh: boolean; isCornerOrientationText: boolean; sagittalNoseLeft: boolean; isSliceMM: boolean; isV1SliceShader: boolean; isHighResolutionCapable: boolean; logLevel: 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'silent'; loadingText: string; isForceMouseClickToVoxelCenters: boolean; dragAndDropEnabled: boolean; drawingEnabled: boolean; penValue: number; floodFillNeighbors: number; isFilledPen: boolean; thumbnail: string; maxDrawUndoBitmaps: number; sliceType: SLICE_TYPE; isAntiAlias: boolean | null; isAdditiveBlend: boolean; isResizeCanvas: boolean; meshXRay: number; limitFrames4D: number; showLegend: boolean; legendBackgroundColor: number[]; legendTextColor: number[]; multiplanarLayout: MULTIPLANAR_TYPE; renderOverlayBlend: number; sliceMosaicString: string; centerMosaic: boolean; clickToSegment: boolean; clickToSegmentRadius: number; clickToSegmentSteps: number; clickToSegmentBright: boolean; }; declare const DEFAULT_OPTIONS: NVConfigOptions; type SceneData = { gamma: number; azimuth: number; elevation: number; crosshairPos: vec3; clipPlane: number[]; clipPlaneDepthAziElev: number[]; volScaleMultiplier: number; pan2Dxyzmm: vec4; clipThick: number; clipVolumeLow: number[]; clipVolumeHigh: number[]; }; declare const INITIAL_SCENE_DATA: { gamma: number; azimuth: number; elevation: number; crosshairPos: vec3; clipPlane: number[]; clipPlaneDepthAziElev: number[]; volScaleMultiplier: number; pan2Dxyzmm: vec4; clipThick: number; clipVolumeLow: number[]; clipVolumeHigh: number[]; }; type Scene = { onAzimuthElevationChange: (azimuth: number, elevation: number) => void; onZoom3DChange: (scale: number) => void; sceneData: SceneData; renderAzimuth: number; renderElevation: number; volScaleMultiplier: number; crosshairPos: vec3; clipPlane: number[]; clipPlaneDepthAziElev: number[]; pan2Dxyzmm: vec4; _elevation?: number; _azimuth?: number; gamma?: number; }; type DocumentData = { title: string; imageOptionsArray: ImageFromUrlOptions[]; meshOptionsArray: unknown[]; opts: NVConfigOptions; previewImageDataURL: string; labels: NVLabel3D[]; encodedImageBlobs: string[]; encodedDrawingBlob: string; meshesString?: string; sceneData?: SceneData; connectomes?: string[]; customData?: string; }; type ExportDocumentData = { encodedImageBlobs: string[]; encodedDrawingBlob: string; previewImageDataURL: string; imageOptionsMap: Map<string, number>; imageOptionsArray: ImageFromUrlOptions[]; sceneData: Partial<SceneData>; opts: NVConfigOptions; meshesString: string; labels: NVLabel3D[]; connectomes: string[]; customData: string; }; /** * Creates and instance of NVDocument * @ignore */ declare class NVDocument { data: DocumentData; scene: Scene; volumes: NVImage[]; meshDataObjects?: Array<NVMesh | NVConnectome>; meshes: Array<NVMesh | NVConnectome>; drawBitmap: Uint8Array | null; imageOptionsMap: Map<any, any>; meshOptionsMap: Map<any, any>; constructor(); /** * Title of the document */ get title(): string; /** * Gets preview image blob * @returns dataURL of preview image */ get previewImageDataURL(): string; /** * Sets preview image blob * @param dataURL - encoded preview image */ set previewImageDataURL(dataURL: string); /** * @param title - title of document */ set title(title: string); get imageOptionsArray(): ImageFromUrlOptions[]; /** * Gets the base 64 encoded blobs of associated images */ get encodedImageBlobs(): string[]; /** * Gets the base 64 encoded blob of the associated drawing * TODO the return type was marked as string[] here, was that an error? */ get encodedDrawingBlob(): string; /** * Gets the options of the {@link Niivue} instance */ get opts(): NVConfigOptions; /** * Sets the options of the {@link Niivue} instance */ set opts(opts: NVConfigOptions); /** * Gets the 3D labels of the {@link Niivue} instance */ get labels(): NVLabel3D[]; /** * Sets the 3D labels of the {@link Niivue} instance */ set labels(labels: NVLabel3D[]); get customData(): string | undefined; set customData(data: string); /** * Checks if document has an image by id */ hasImage(image: NVImage): boolean; /** * Checks if document has an image by url */ hasImageFromUrl(url: string): boolean; /** * Adds an image and the options an image was created with */ addImageOptions(image: NVImage, imageOptions: ImageFromUrlOptions): void; /** * Removes image from the document as well as its options */ removeImage(image: NVImage): void; /** * Returns the options for the image if it was added by url */ getImageOptions(image: NVImage): ImageFromUrlOptions | null; /** * Converts NVDocument to JSON */ json(): ExportDocumentData; /** * Downloads a JSON file with options, scene, images, meshes and drawing of {@link Niivue} instance */ download(fileName: string, compress: boolean): Promise<void>; /** * Deserialize mesh data objects */ static deserializeMeshDataObjects(document: NVDocument): void; /** * Factory method to return an instance of NVDocument from a URL */ static loadFromUrl(url: string): Promise<NVDocument>; /** * Factory method to return an instance of NVDocument from a File object */ static loadFromFile(file: Blob): Promise<NVDocument>; /** * Factory method to return an instance of NVDocument from JSON */ static loadFromJSON(data: DocumentData): NVDocument; } type NiftiHeader = { littleEndian: boolean; dim_info: number; dims: number[]; pixDims: number[]; intent_p1: number; intent_p2: number; intent_p3: number; intent_code: number; datatypeCode: number; numBitsPerVoxel: number; slice_start: number; vox_offset: number; scl_slope: number; scl_inter: number; slice_end: number; slice_code: number; xyzt_units: number; cal_max: number; cal_min: number; slice_duration: number; toffset: number; description: string; aux_file: string; qform_code: number; sform_code: number; quatern_b: number; quatern_c: number; quatern_d: number; qoffset_x: number; qoffset_y: number; qoffset_z: number; affine: number[][]; intent_name: string; magic: string; }; type Volume = Record<string, any>; type Point = { comments: Array<{ text: string; prefilled?: string; }>; coordinates: { x: number; y: number; z: number; }; }; /** * Representes the vertices of a connectome * @ignore */ type NVConnectomeNode = { name: string; x: number; y: number; z: number; colorValue: number; sizeValue: number; label?: NVLabel3D; }; /** * Represents edges between connectome nodes * @ignore */ type NVConnectomeEdge = { first: number; second: number; colorValue: number; }; type ConnectomeOptions = { name: string; nodeColormap: string; nodeColormapNegative: string; nodeMinColor: number; nodeMaxColor: number; nodeScale: number; edgeColormap: string; edgeColormapNegative: string; edgeMin: number; edgeMax: number; edgeScale: number; legendLineThickness?: number; }; type Connectome = ConnectomeOptions & { nodes: NVConnectomeNode[]; edges: NVConnectomeEdge[]; }; type LegacyNodes = { names: string[]; prefilled: unknown[]; X: number[]; Y: number[]; Z: number[]; Color: number[]; Size: number[]; }; type LegacyConnectome = Partial<ConnectomeOptions> & { nodes: LegacyNodes; edges: number[]; }; type DragReleaseParams = { fracStart: vec3; fracEnd: vec3; voxStart: vec3; voxEnd: vec3; mmStart: vec4; mmEnd: vec4; mmLength: number; tileIdx: number; axCorSag: SLICE_TYPE; }; type NiiVueLocationValue = { id: string; mm: vec4; name: string; value: number; vox: vec3; }; type NiiVueLocation = { axCorSag: number; frac: vec3; mm: vec4; string: string; values: NiiVueLocationValue[]; vox: vec3; xy: [number, number]; }; type ValuesArray = Array<{ id: string; vals: Float32Array; global_min?: number; global_max?: number; cal_min?: number; cal_max?: number; }>; type AnyNumberArray = number[] | Float64Array | Float32Array | Uint32Array | Uint16Array | Uint8Array | Int32Array | Int16Array | Int8Array; type DefaultMeshType = { positions: Float32Array; indices: Uint32Array; colors?: Float32Array; }; type TRACT = { pts: Float32Array; offsetPt0: Uint32Array; dps: ValuesArray; }; type TT = { pts: Float32Array; offsetPt0: Uint32Array; }; type TRX = { pts: Float32Array; offsetPt0: Uint32Array; dpg: ValuesArray; dps: ValuesArray; dpv: ValuesArray; header: unknown; }; type TRK = { pts: Float32Array; offsetPt0: Uint32Array; dps: ValuesArray; dpv: ValuesArray; }; type TCK = { pts: Float32Array; offsetPt0: Uint32Array; }; type VTK = DefaultMeshType | { pts: Float32Array; offsetPt0: Uint32Array; }; type ANNOT = Uint32Array | { scalars: Float32Array; colormapLabel: LUT; }; type MZ3 = Float32Array | { positions: Float32Array | null; indices: Uint32Array | null; scalars: Float32Array; colors: Float32Array | null; }; type GII = { scalars: Float32Array; positions?: Float32Array; indices?: Uint32Array; colormapLabel?: LUT; anatomicalStructurePrimary: string; }; type MGH = AnyNumberArray | { scalars: AnyNumberArray; colormapLabel: LUT; }; type X3D = { positions: Float32Array; indices: Uint32Array; rgba255: Uint8Array; }; /** Enum for text alignment */ declare enum MeshType { MESH = "mesh", CONNECTOME = "connectome", FIBER = "fiber" } type NVMeshLayer = { name?: string; key?: string; url?: string; headers?: Record<string, string>; opacity: number; colormap: string; colormapNegative?: string; colormapInvert?: boolean; colormapLabel?: ColorMap | LUT; useNegativeCmap?: boolean; global_min?: number; global_max?: number; cal_min: number; cal_max: number; cal_minNeg: number; cal_maxNeg: number; isAdditiveBlend?: boolean; frame4D: number; nFrame4D: number; values: AnyNumberArray; outlineBorder?: number; isTransparentBelowCalMin?: boolean; alphaThreshold?: boolean; base64?: string; colorbarVisible?: boolean; }; declare const NVMeshLayerDefaults: { colormap: string; opacity: number; nFrame4D: number; frame4D: number; outlineBorder: number; cal_min: number; cal_max: number; cal_minNeg: number; cal_maxNeg: number; values: number[]; }; declare class NVMeshFromUrlOptions { url: string; gl: WebGL2RenderingContext | null; name: string; opacity: number; rgba255: Uint8Array; visible: boolean; layers: NVMeshLayer[]; colorbarVisible: boolean; constructor(url?: string, gl?: any, name?: string, opacity?: number, rgba255?: Uint8Array, visible?: boolean, layers?: any[], colorbarVisible?: boolean); } type BaseLoadParams = { gl: WebGL2RenderingContext; name: string; opacity: number; rgba255: number[] | Uint8Array; visible: boolean; layers: NVMeshLayer[]; }; type LoadFromUrlParams = Partial<BaseLoadParams> & { url: string; headers?: Record<string, string>; buffer?: ArrayBuffer; }; type LoadFromFileParams = BaseLoadParams & { file: Blob; }; type LoadFromBase64Params = BaseLoadParams & { base64: string; }; /** * a NVMesh encapsulates some mesh data and provides methods to query and operate on meshes */ declare class NVMesh { id: string; name: string; anatomicalStructurePrimary: string; colorbarVisible: boolean; furthestVertexFromOrigin: number; extentsMin: number | number[]; extentsMax: number | number[]; opacity: number; visible: boolean; meshShaderIndex: number; offsetPt0: Uint32Array | null; colormapInvert: boolean; fiberGroupColormap: ColorMap | null; indexBuffer: WebGLBuffer; vertexBuffer: WebGLBuffer; vao: WebGLVertexArrayObject; vaoFiber: WebGLVertexArrayObject; pts: Float32Array; tris?: Uint32Array; layers: NVMeshLayer[]; type: MeshType; data_type?: string; rgba255: Uint8Array; fiberLength?: number; fiberLengths?: Uint32Array; fiberDensity?: Float32Array; fiberDither: number; fiberColor: string; fiberDecimationStride: number; fiberSides: number; fiberRadius: number; fiberOcclusion: number; f32PerVertex: number; fiberMask?: unknown[]; colormap?: ColorMap | LegacyConnectome | string | null; dpg?: ValuesArray | null; dps?: ValuesArray | null; dpv?: ValuesArray | null; hasConnectome: boolean; connectome?: LegacyConnectome | string; indexCount?: number; vertexCount: number; nodeScale: number; edgeScale: number; legendLineThickness: number; nodeColormap: string; edgeColormap: string; nodeColormapNegative?: string; edgeColormapNegative?: string; nodeMinColor?: number; nodeMaxColor?: number; edgeMin?: number; edgeMax?: number; nodes?: LegacyNodes | NVConnectomeNode[]; edges?: number[] | NVConnectomeEdge[]; points?: Point[]; /** * @param pts - a 3xN array of vertex positions (X,Y,Z coordinates). * @param tris - a 3xN array of triangle indices (I,J,K; indexed from zero). Each triangle generated from three vertices. * @param name - a name for this image. Default is an empty string * @param rgba255 - the base color of the mesh. RGBA values from 0 to 255. Default is white * @param opacity - the opacity for this mesh. default is 1 * @param visible - whether or not this image is to be visible * @param gl - WebGL rendering context * @param connectome - specify connectome edges and nodes. Default is null (not a connectome). * @param dpg - Data per group for tractography, see TRK format. Default is null (not tractograpgy) * @param dps - Data per streamline for tractography, see TRK format. Default is null (not tractograpgy) * @param dpv - Data per vertex for tractography, see TRK format. Default is null (not tractograpgy) * @param colorbarVisible - does this mesh display a colorbar * @param anatomicalStructurePrimary - region for mesh. Default is an empty string */ constructor(pts: Float32Array, tris: Uint32Array, name: string, rgba255: Uint8Array, opacity: number, visible: boolean, gl: WebGL2RenderingContext, connectome?: LegacyConnectome | string | null, dpg?: ValuesArray | null, dps?: ValuesArray | null, dpv?: ValuesArray | null, colorbarVisible?: boolean, anatomicalStructurePrimary?: string); initValuesArray(va: ValuesArray): ValuesArray; linesToCylinders(gl: WebGL2RenderingContext, posClrF32: Float32Array, indices: number[]): void; createFiberDensityMap(): void; updateFibers(gl: WebGL2RenderingContext): void; indexNearestXYZmm(Xmm: number, Ymm: number, Zmm: number): number[]; unloadMesh(gl: WebGL2RenderingContext): void; updateMesh(gl: WebGL2RenderingContext): void; reverseFaces(gl: WebGL2RenderingContext): void; hierarchicalOrder(): number; decimateFaces(n: number, ntarget: number): void; decimateHierarchicalMesh(gl: WebGL2RenderingContext, order?: number): boolean; setLayerProperty(id: number, key: keyof NVMeshLayer, val: number | string | boolean, gl: WebGL2RenderingContext): void; setProperty(key: keyof this, val: unknown, gl: WebGL2RenderingContext): void; generatePosNormClr(pts: Float32Array, tris: Uint32Array, rgba255: Uint8Array): Float32Array; static readMesh(buffer: ArrayBuffer, name: string, gl: WebGL2RenderingContext, opacity?: number, rgba255?: Uint8Array, visible?: boolean): NVMesh; static loadLayer(layer: NVMeshLayer, nvmesh: NVMesh): Promise<void>; /** * factory function to load and return a new NVMesh instance from a given URL */ static loadFromUrl({ url, headers, gl, name, opacity, rgba255, visible, layers, buffer }?: Partial<LoadFromUrlParams>): Promise<NVMesh>; static readFileAsync(file: Blob): Promise<ArrayBuffer>; /** * factory function to load and return a new NVMesh instance from a file in the browser * * @returns NVMesh instance */ static loadFromFile({ file, gl, name, opacity, rgba255, visible, layers }?: Partial<LoadFromFileParams>): Promise<NVMesh>; /** * load and return a new NVMesh instance from a base64 encoded string */ loadFromBase64({ base64, gl, name, opacity, rgba255, visible, layers }?: Partial<LoadFromBase64Params>): Promise<NVMesh>; static readGII(buffer: ArrayBuffer): GII; static readX3D(buffer: ArrayBuffer): X3D; static readNII(buffer: ArrayBuffer, n_vert?: number): Uint8Array | Float32Array | Int32Array | Int16Array; static readNII2(buffer: ArrayBuffer, n_vert?: number): Uint8Array | Float32Array | Int32Array | Int16Array; static readMGH(buffer: ArrayBuffer): MGH; static readSTL(buffer: ArrayBuffer): DefaultMeshType; static readTxtSTL(buffer: ArrayBuffer): DefaultMeshType; static readSRF(buffer: ArrayBuffer): DefaultMeshType; static readFreeSurfer(buffer: ArrayBuffer): DefaultMeshType; static readOBJ(buffer: ArrayBuffer): DefaultMeshType; static readOFF(buffer: ArrayBuffer): DefaultMeshType; static readGEO(buffer: ArrayBuffer, isFlipWinding?: boolean): DefaultMeshType; static readICO(buffer: ArrayBuffer): DefaultMeshType; static readPLY(buffer: ArrayBuffer): DefaultMeshType; static readMZ3(buffer: ArrayBuffer, n_vert?: number): MZ3; static readVTK(buffer: ArrayBuffer): VTK; static readASC(buffer: ArrayBuffer): DefaultMeshType; static readNV(buffer: ArrayBuffer): DefaultMeshType; static readANNOT(buffer: ArrayBuffer, n_vert: number, isReadColortables?: boolean): ANNOT; static readCURV(buffer: ArrayBuffer, n_vert: number): Float32Array; static readSTC(buffer: ArrayBuffer, n_vert: number): Float32Array; static readSMP(buffer: ArrayBuffer, n_vert: number): Float32Array; static readTxtVTK(buffer: ArrayBuffer): VTK; static readTRK(buffer: ArrayBuffer): TRK; static readTCK(buffer: ArrayBuffer): TCK; static readTSF(buffer: ArrayBuffer): Float32Array; static readTT(buffer: ArrayBuffer): TT; static readTRX(buffer: ArrayBuffer): TRX; static readTRACT(buffer: ArrayBuffer): TRACT; } /** * Enum for sync operations */ declare enum NVMESSAGE { ZOOM = 1,// "zoom", CLIP_PLANE = 2,// "clipPlane", AZIMUTH_ELEVATION = 3,// "ae", FRAME_CHANGED = 4,// "frame changed", VOLUME_ADDED_FROM_URL = 5,// "volume added from url", VOLUME_WITH_URL_REMOVED = 6,// "volume with url removed", COLORMAP_CHANGED = 7,// "color map has changed", OPACITY_CHANGED = 8,// "opacity has changed", MESH_FROM_URL_ADDED = 9,// "mesh added from url", MESH_WITH_URL_REMOVED = 10,// "mesh with url removed", CUSTOM_SHADER_ADDED = 11,// "custom shader added", SHADER_CHANGED = 12,// "mesh shader changed", MESH_PROPERTY_CHANGED = 13,// "mesh property changed", USER_JOINED = "user joined",// TODO this breaks the scheme a bit -- see session-bus::localStorageEventListener CREATE = "create",// TODO same as above VOLUME_LOADED_FROM_URL = "volume with url added" } type Message = { userKey?: string; from?: string; } & ({ op: NVMESSAGE.ZOOM; zoom: number; } | { op: NVMESSAGE.CLIP_PLANE; clipPlane: number[]; } | { op: NVMESSAGE.AZIMUTH_ELEVATION; elevation: number; azimuth: number; } | { op: NVMESSAGE.FRAME_CHANGED; url: string; index: number; } | { op: NVMESSAGE.VOLUME_ADDED_FROM_URL; imageOptions: any; } | { op: NVMESSAGE.VOLUME_LOADED_FROM_URL; url: string; } | { op: NVMESSAGE.VOLUME_WITH_URL_REMOVED; url: string; } | { op: NVMESSAGE.COLORMAP_CHANGED; url: string; colormap: string; } | { op: NVMESSAGE.OPACITY_CHANGED; url: string; opacity: number; } | { op: NVMESSAGE.MESH_FROM_URL_ADDED; meshOptions: LoadFromUrlParams; } | { op: NVMESSAGE.MESH_WITH_URL_REMOVED; url: string; } | { op: NVMESSAGE.CUSTOM_SHADER_ADDED; fragmentShaderText: string; name: string; } | { op: NVMESSAGE.SHADER_CHANGED; meshIndex: number; shaderIndex: number; } | { op: NVMESSAGE.MESH_PROPERTY_CHANGED; meshIndex: number; key: string; val: unknown; } | { op: NVMESSAGE.USER_JOINED; user: SessionUser; } | { op: NVMESSAGE.CREATE; key: string; }); /** * SessionUser specifies display name, user id and user key * @param userKey - Used to protect user properties */ declare class SessionUser { id: string; displayName: string; key: string; properties: Map<string, string>; constructor(displayName?: string, userId?: string, userKey?: string, userProperties?: Map<string, string>); } /** * SessionBus is for synchronizing both remote and local instances */ declare class SessionBus { userList: SessionUser[]; user: SessionUser; userQueueName?: string; userListName?: string; onMessageCallback: (newMessage: Message) => void; isConnectedToServer: boolean; isController: boolean; sessionScene: {}; sessionKey: string; sessionName: string; sessionSceneName: string; serverConnection$: WebSocketSubject<Message> | null; constructor(name: string, user: SessionUser, onMessageCallback: (newMessage: Message) => void, serverURL?: string, sessionKey?: string); sendSessionMessage(message: Message): void; connectToServer(serverURL: string, sessionName: string): void; subscribeToServer(): void; sendLocalMessage(message: Message): void; localStorageEventListener(e: StorageEvent): void; } /** * NVController is for synchronizing both remote and local instances of Niivue * @ignore */ declare class NVController { niivue: Niivue; mediaUrlMap: Map<string, unknown>; isInSession: boolean; user?: SessionUser; sessionBus?: SessionBus; onFrameChange: (_volume: NVImage, _index: number) => void; /** * @param niivue - niivue object to control */ constructor(niivue: Niivue); onLocationChangeHandler(location: unknown): void; addVolume(volume: NVImage, url: string): void; addMesh(mesh: NVMesh, url: string): void; onNewMessage(msg: Message): void; /** * Connects to existing session or creates new session */ connectToSession(sessionName: string, user?: SessionUser, serverBaseUrl?: string, sessionKey?: string): void; /** * Zoom level has changed */ onZoom3DChangeHandler(zoom: number): void; /** * Azimuth and/or elevation has changed */ onAzimuthElevationChangeHandler(azimuth: number, elevation: number): void; /** * Clip plane has changed */ onClipPlaneChangeHandler(clipPlane: number[]): void; /** * Add an image and notify subscribers */ onVolumeAddedFromUrlHandler(imageOptions: ImageFromUrlOptions, volume: NVImage): void; /** * A volume has been added */ onImageLoadedHandler(volume: NVImage): void; /** * Notifies other users that a volume has been removed */ onVolumeWithUrlRemovedHandler(url: string): void; /** * Notifies that a mesh has been loaded by URL */ onMeshAddedFromUrlHandler(meshOptions: LoadFromUrlParams): void; /** * Notifies that a mesh has been added */ onMeshLoadedHandler(mesh: NVMesh): void; onMeshWithUrlRemovedHandler(url: string): void; /** * * @param volume - volume that has changed color maps */ onColormapChangeHandler(volume: NVImage): void; /** * @param volume - volume that has changed opacity */ onOpacityChangeHandler(volume: NVImage): void; /** * Frame for 4D image has changed */ onFrameChangeHandler(volume: NVImage, index: number): void; /** * Custom mesh shader has been added * @param fragmentShaderText - shader code to be compiled * @param name - name of shader, can be used as index */ onCustomMeshShaderAddedHandler(fragmentShaderText: string, name: string): void; /** * Mesh shader has changed * @param meshIndex - index of mesh * @param shaderIndex - index of shader */ onMeshShaderChanged(meshIndex: number, shaderIndex: number): void; /** * Mesh property has been changed * @param meshIndex - index of mesh * @param key - property index * @param val - property value */ onMeshPropertyChanged(meshIndex: number, key: string, val: unknown): void; } type TypedNumberArray = Float64Array | Float32Array | Uint32Array | Uint16Array | Uint8Array | Int32Array | Int16Array | Int8Array; /** * Namespace for utility functions * @ignore */ declare class NVUtilities { static arrayBufferToBase64(arrayBuffer: ArrayBuffer): string; static readMatV4(buffer: ArrayBuffer): Record<string, TypedNumberArray>; static uint8tob64(bytes: Uint8Array): string; static download(content: string | ArrayBuffer, fileName: string, contentType: string): void; static readFileAsync(file: Blob): Promise<ArrayBuffer>; static blobToBase64(blob: Blob): Promise<string>; static decompressBase64String(base64: string): Promise<string>; static compressToBase64String(string: string): Promise<string>; static compressStringToArrayBuffer(input: string): Promise<ArrayBuffer>; static isArrayBufferCompressed(buffer: ArrayBuffer): boolean; static decompressArrayBuffer(buffer: ArrayBuffer): Promise<string>; static arraysAreEqual(a: unknown[], b: unknown[]): boolean; /** * Generate a pre-filled number array. * * @param start - start value * @param stop - stop value * @param step - step