@aics/vole-app 3.4.2 → 3.4.4

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.
@@ -184,11 +184,21 @@ var useVolume = function useVolume(scenePaths, options) {
184
184
  throw e;
185
185
  }, [onErrorRef]);
186
186
 
187
- // channel indexes, sorted by category
188
- var _useState9 = useState({}),
189
- _useState10 = _slicedToArray(_useState9, 2),
190
- channelGroupedByType = _useState10[0],
191
- setChannelGroupedByType = _useState10[1];
187
+ // channelGroupedByType groups channel indexes by their category.
188
+ // It depends on `viewerChannelSettings` and the channel names in the current image.
189
+ // TODO this can be derived much more easily once `Volume` has events
190
+ var channelNamesKey = channelSettings.map(function (_ref3) {
191
+ var name = _ref3.name;
192
+ return name;
193
+ }).join("\0");
194
+ var channelNames = useMemo(function () {
195
+ return channelNamesKey.split("\0");
196
+ }, [channelNamesKey]);
197
+ var useDefaultViewerChannelSettings = useViewerState(select("useDefaultViewerChannelSettings"));
198
+ var channelGroupedByType = useMemo(function () {
199
+ var viewerChannelSettings = useDefaultViewerChannelSettings ? getDefaultViewerChannelSettings() : options === null || options === void 0 ? void 0 : options.viewerChannelSettings;
200
+ return makeChannelIndexGrouping(channelNames, viewerChannelSettings);
201
+ }, [channelNames, options === null || options === void 0 ? void 0 : options.viewerChannelSettings, useDefaultViewerChannelSettings]);
192
202
  var onChannelDataLoaded = useCallback(function (aimg, channelIndex) {
193
203
  // let the hook caller know that this channel has loaded
194
204
  var isInitialLoad = channelVersionsRef.current[channelIndex] === CHANNEL_INITIAL_LOAD;
@@ -208,8 +218,6 @@ var useVolume = function useVolume(scenePaths, options) {
208
218
  var _useViewerState$getSt = useViewerState.getState(),
209
219
  useDefaultViewerChannelSettings = _useViewerState$getSt.useDefaultViewerChannelSettings;
210
220
  var viewerChannelSettings = useDefaultViewerChannelSettings ? getDefaultViewerChannelSettings() : options === null || options === void 0 ? void 0 : options.viewerChannelSettings;
211
- var grouping = makeChannelIndexGrouping(channelNames, viewerChannelSettings);
212
- setChannelGroupedByType(grouping);
213
221
  return initChannelSettings(channelNames, viewerChannelSettings);
214
222
  }, [initChannelSettings, options === null || options === void 0 ? void 0 : options.viewerChannelSettings]);
215
223
 
@@ -219,7 +227,7 @@ var useVolume = function useVolume(scenePaths, options) {
219
227
  setLoadThrewError(false);
220
228
  inInitialLoadRef.current = true;
221
229
  var openImage = /*#__PURE__*/function () {
222
- var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
230
+ var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
223
231
  var scene, time, loadSpec, aimg, channelNames, newChannelSettings, requiredLoadSpec, requiredChannelsToLoad, _useViewerState$getSt2, useDefaultViewerChannelSettings, viewerChannelSettings, maskChannelName, maskChannelIndex, viewMode, slice;
224
232
  return _regeneratorRuntime().wrap(function _callee$(_context) {
225
233
  while (1) switch (_context.prev = _context.next) {
@@ -292,11 +300,11 @@ var useVolume = function useVolume(scenePaths, options) {
292
300
  }, _callee);
293
301
  }));
294
302
  return function openImage() {
295
- return _ref3.apply(this, arguments);
303
+ return _ref4.apply(this, arguments);
296
304
  };
297
305
  }();
298
306
  openImage();
299
- }, [sceneLoader, onError, onCreateImageRef, onChangeSceneRef, onChannelLoadedRef, channelVersionsRef, setChannelVersions, playControls, setIsLoading, onChannelDataLoaded, changeViewerSetting, initChannelSettings, setChannelStateForNewImage, options === null || options === void 0 ? void 0 : options.viewerChannelSettings]);
307
+ }, [sceneLoader, onError, onCreateImageRef, onChangeSceneRef, onChannelLoadedRef, channelVersionsRef, setChannelVersions, playControls, setIsLoading, onChannelDataLoaded, changeViewerSetting, setChannelStateForNewImage, options === null || options === void 0 ? void 0 : options.viewerChannelSettings]);
300
308
  // of the above dependencies, we expect only `sceneLoader` to change.
301
309
 
302
310
  var setTime = useCallback(function (view3d, time) {
@@ -86,26 +86,15 @@ function parseLutValue(value, histogram) {
86
86
  * "autoij:0" // use Auto-IJ to calculate min and max.
87
87
  * ```
88
88
  */
89
- export function parseLutFromSettings(histogram, initSettings) {
90
- var _initSettings$intensi, _initSettings$intensi2;
91
- // TODO: Consider minimizing the types/classes this function is interacting
92
- // with, since it is only using `initSettings.lut` and the returned Lut is a
93
- // wrapper around the control point array, e.g.
94
- // `parseControlPointsFromLutParam(histogram: Histogram, lutParam: [string,
95
- // string] | undefined): ControlPoint[] | undefined`
96
-
97
- // There are two possible locations for the LUT settings, due to legacy
98
- // reasons. `initSettings.lut` is deprecated in favor of
99
- // `initSettings.intensity.lut`.
100
- var settingsLut = (_initSettings$intensi = (_initSettings$intensi2 = initSettings.intensity) === null || _initSettings$intensi2 === void 0 ? void 0 : _initSettings$intensi2.lut) !== null && _initSettings$intensi !== void 0 ? _initSettings$intensi : initSettings.lut;
101
- if (settingsLut === undefined || settingsLut.length !== 2) {
89
+ export function parseLutSetting(histogram, lutSetting) {
90
+ if (lutSetting === undefined || lutSetting.length !== 2) {
102
91
  return undefined;
103
92
  }
104
93
  var lutValues;
105
- if (settingsLut[0] === "autoij" || settingsLut[1] === "autoij") {
94
+ if (lutSetting[0] === "autoij" || lutSetting[1] === "autoij") {
106
95
  lutValues = histogram.findAutoIJBins();
107
96
  } else {
108
- lutValues = [parseLutValue(settingsLut[0], histogram), parseLutValue(settingsLut[1], histogram)];
97
+ lutValues = [parseLutValue(lutSetting[0], histogram), parseLutValue(lutSetting[1], histogram)];
109
98
  }
110
99
  if (!Number.isFinite(lutValues[0]) || !Number.isFinite(lutValues[1])) {
111
100
  return undefined;
@@ -156,8 +145,12 @@ export function initializeLut(aimg, channelIndex, channelSettings) {
156
145
  // Attempt to load a LUT from the settings, which will be used as a fallback
157
146
  // to initialize the control points and ramp.
158
147
  if (initSettings) {
159
- var _parseLutFromSettings;
160
- lut = (_parseLutFromSettings = parseLutFromSettings(histogram, initSettings)) !== null && _parseLutFromSettings !== void 0 ? _parseLutFromSettings : defaultLut;
148
+ var _initSettings$intensi, _initSettings$intensi2, _parseLutSetting;
149
+ // There are two possible locations for the LUT settings, due to legacy
150
+ // reasons. `initSettings.lut` is deprecated in favor of
151
+ // `initSettings.intensity.lut`.
152
+ var lutSetting = (_initSettings$intensi = (_initSettings$intensi2 = initSettings.intensity) === null || _initSettings$intensi2 === void 0 ? void 0 : _initSettings$intensi2.lut) !== null && _initSettings$intensi !== void 0 ? _initSettings$intensi : initSettings.lut;
153
+ lut = (_parseLutSetting = parseLutSetting(histogram, lutSetting)) !== null && _parseLutSetting !== void 0 ? _parseLutSetting : defaultLut;
161
154
  }
162
155
 
163
156
  // Use raw intensity values for control points or ramp if provided in the
@@ -189,15 +182,6 @@ export function initializeLut(aimg, channelIndex, channelSettings) {
189
182
  });
190
183
  });
191
184
  }
192
-
193
- // Apply whatever lut is currently visible
194
- var visibleLut;
195
- if (initSettings !== null && initSettings !== void 0 && initSettings.controlPointsEnabled) {
196
- visibleLut = new Lut().createFromControlPoints(controlPoints);
197
- } else {
198
- visibleLut = new Lut().createFromControlPoints(ramp);
199
- }
200
- aimg.setLut(channelIndex, visibleLut);
201
185
  return {
202
186
  ramp: ramp,
203
187
  controlPoints: controlPoints
@@ -102,10 +102,12 @@ var SceneStore = /*#__PURE__*/function () {
102
102
  return channelIndex < imageInfo.channelNames.length;
103
103
  }),
104
104
  time: Math.min(spec.time, maxTime)
105
- });
105
+ }); // TODO it's not great that this is the caller's responsibility... fix this more robustly in vole-core
106
+ image.loadSpec = _objectSpread(_objectSpread({}, image.loadSpec), adjustedSpec);
107
+ image.loadSpecRequired = _objectSpread(_objectSpread({}, image.loadSpecRequired), adjustedSpec);
106
108
  options === null || options === void 0 || (_options$onCreateScen = options.onCreateScene) === null || _options$onCreateScen === void 0 || _options$onCreateScen.call(options, image, scene, adjustedSpec);
107
109
  loader.loadVolumeData(image, adjustedSpec, options === null || options === void 0 ? void 0 : options.onChannelLoaded);
108
- case 14:
110
+ case 16:
109
111
  case "end":
110
112
  return _context2.stop();
111
113
  }
@@ -12,6 +12,7 @@ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol
12
12
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
13
13
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
14
14
  import { ImageType, RenderMode, ViewMode } from "../shared/enums";
15
+ import { controlPointsToRamp, parseLutSetting } from "../shared/utils/controlPointsToLut";
15
16
  import { removeUndefinedProperties } from "../shared/utils/datatypes";
16
17
  import { clamp } from "../shared/utils/math";
17
18
  import { CameraTransformKeys, ViewerChannelSettingKeys, ViewerStateKeys } from "./types";
@@ -434,4 +435,98 @@ export function deserializeViewerChannelSetting(channelIndex, jsonState) {
434
435
  }
435
436
  }
436
437
  return result;
438
+ }
439
+
440
+ /**
441
+ * Parses a `ViewerChannelStateParams` object into a partial `ChannelState`.
442
+ *
443
+ * This is used to convert raw URL params into internal channel state fields,
444
+ * leaving absent or invalid values undefined.
445
+ *
446
+ * This function optionally accepts the target channel's `Histogram`. This
447
+ * argument is required to parse the following params correctly:
448
+ *
449
+ * - `lut`, which contains instructions for how to set the channel's
450
+ * intensities *relative to its intensity distribution*.
451
+ * - `rmp`, the legacy ramp parameter represented as histogram bin indices
452
+ * - `cps`, the legacy control points parameter where `x` values are
453
+ * represented as histogram bin indices
454
+ *
455
+ * If `histogram` is left undefined, e.g. because the channel has not yet been
456
+ * loaded, these params are ignored.
457
+ */
458
+ export function deserializeChannelState(jsonState, histogram) {
459
+ var result = {
460
+ volumeEnabled: parseStringBoolean(jsonState[ViewerChannelSettingKeys.VolumeEnabled]),
461
+ isosurfaceEnabled: parseStringBoolean(jsonState[ViewerChannelSettingKeys.SurfaceEnabled]),
462
+ isovalue: parseStringFloat(jsonState[ViewerChannelSettingKeys.IsosurfaceValue], -Infinity, Infinity),
463
+ keepIntensityRange: parseStringBoolean(jsonState[ViewerChannelSettingKeys.KeepRange]),
464
+ opacity: parseStringFloat(jsonState[ViewerChannelSettingKeys.IsosurfaceAlpha], 0, 1),
465
+ colorizeEnabled: parseStringBoolean(jsonState[ViewerChannelSettingKeys.Colorize]),
466
+ colorizeAlpha: parseStringFloat(jsonState[ViewerChannelSettingKeys.ColorizeAlpha], 0, 1),
467
+ useControlPoints: parseStringBoolean(jsonState[ViewerChannelSettingKeys.ControlPointsEnabled]),
468
+ color: parseHexColorAsColorArray(jsonState[ViewerChannelSettingKeys.Color])
469
+ };
470
+ var lutSerialized = jsonState[ViewerChannelSettingKeys.Lut];
471
+ var pointsFromLut = undefined;
472
+ if (histogram !== undefined && lutSerialized !== undefined && LUT_REGEX.test(lutSerialized)) {
473
+ var _lutSerialized$split = lutSerialized.split(":"),
474
+ _lutSerialized$split2 = _slicedToArray(_lutSerialized$split, 2),
475
+ min = _lutSerialized$split2[0],
476
+ max = _lutSerialized$split2[1];
477
+ var lut = parseLutSetting(histogram, [min.trim(), max.trim()]);
478
+ pointsFromLut = lut === null || lut === void 0 ? void 0 : lut.controlPoints.map(function (point) {
479
+ return _objectSpread(_objectSpread({}, point), {}, {
480
+ x: histogram.getValueFromBinIndex(point.x)
481
+ });
482
+ });
483
+ }
484
+ if (jsonState[ViewerChannelSettingKeys.Ramp]) {
485
+ if (RAMP_REGEX.test(jsonState[ViewerChannelSettingKeys.Ramp])) {
486
+ var _jsonState$ViewerChan7 = jsonState[ViewerChannelSettingKeys.Ramp].split(":"),
487
+ _jsonState$ViewerChan8 = _slicedToArray(_jsonState$ViewerChan7, 2),
488
+ _min3 = _jsonState$ViewerChan8[0],
489
+ _max3 = _jsonState$ViewerChan8[1];
490
+ result.ramp = [Number.parseFloat(_min3), Number.parseFloat(_max3)];
491
+ }
492
+ } else if (jsonState[ViewerChannelSettingKeys.RampLegacy]) {
493
+ if (histogram !== undefined) {
494
+ if (RAMP_REGEX.test(jsonState[ViewerChannelSettingKeys.RampLegacy])) {
495
+ var _jsonState$ViewerChan9 = jsonState[ViewerChannelSettingKeys.RampLegacy].split(":"),
496
+ _jsonState$ViewerChan10 = _slicedToArray(_jsonState$ViewerChan9, 2),
497
+ rawMin = _jsonState$ViewerChan10[0],
498
+ rawMax = _jsonState$ViewerChan10[1];
499
+ var _min4 = histogram.getValueFromBinIndex(Number.parseFloat(rawMin));
500
+ var _max4 = histogram.getValueFromBinIndex(Number.parseFloat(rawMax));
501
+ result.ramp = [_min4, _max4];
502
+ }
503
+ }
504
+ } else if (pointsFromLut !== undefined) {
505
+ result.ramp = controlPointsToRamp(pointsFromLut);
506
+ }
507
+ if (jsonState[ViewerChannelSettingKeys.ControlPoints]) {
508
+ var parsedResult = parseControlPoints(jsonState[ViewerChannelSettingKeys.ControlPoints]);
509
+ if (parsedResult) {
510
+ result.controlPoints = parsedResult;
511
+ }
512
+ } else if (jsonState[ViewerChannelSettingKeys.ControlPointsLegacy]) {
513
+ if (histogram !== undefined) {
514
+ var _parsedResult2 = parseControlPoints(jsonState[ViewerChannelSettingKeys.ControlPointsLegacy]);
515
+ if (_parsedResult2) {
516
+ result.controlPoints = _parsedResult2.map(function (_ref) {
517
+ var opacity = _ref.opacity,
518
+ color = _ref.color,
519
+ x = _ref.x;
520
+ return {
521
+ opacity: opacity,
522
+ color: color,
523
+ x: histogram.getValueFromBinIndex(x)
524
+ };
525
+ });
526
+ }
527
+ }
528
+ } else if (pointsFromLut !== undefined) {
529
+ result.controlPoints = pointsFromLut;
530
+ }
531
+ return removeUndefinedProperties(result);
437
532
  }
@@ -12,7 +12,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
12
12
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
13
13
  import { describe, expect, it } from "@jest/globals";
14
14
  import { RenderMode, ViewMode } from "../../shared/enums";
15
- import { CONTROL_POINTS_REGEX, deserializeViewerChannelSetting, deserializeViewerState, LEGACY_CONTROL_POINTS_REGEX, parseHexColorAsColorArray, parseKeyValueList, parseStringEnum, parseStringFloat, parseStringInt } from "../deserialize";
15
+ import { CONTROL_POINTS_REGEX, deserializeChannelState, deserializeViewerChannelSetting, deserializeViewerState, LEGACY_CONTROL_POINTS_REGEX, parseHexColorAsColorArray, parseKeyValueList, parseStringEnum, parseStringFloat, parseStringInt } from "../deserialize";
16
16
  import { serializeViewerState } from "../serialize";
17
17
  import { CUSTOM_TEST_VIEWER_STATE, DEFAULT_TEST_VIEWER_CHANNEL_SETTING, DEFAULT_TEST_VIEWER_STATE, SERIALIZED_CUSTOM_TEST_VIEWER_STATE, SERIALIZED_DEFAULT_TEST_VIEWER_STATE } from "./test_data";
18
18
 
@@ -306,6 +306,57 @@ describe("deserializeViewerChannelSetting", function () {
306
306
  expect(result.isovalue).toBeUndefined();
307
307
  });
308
308
  });
309
+ describe("deserializeChannelState", function () {
310
+ it("returns an empty object for empty input", function () {
311
+ expect(deserializeChannelState({})).toEqual({});
312
+ });
313
+ it("parses channel state fields", function () {
314
+ var data = {
315
+ col: "ff0000",
316
+ clz: "1",
317
+ cza: "0.5",
318
+ isa: "0.75",
319
+ ven: "1",
320
+ sen: "1",
321
+ isv: "128",
322
+ ram: "0:255",
323
+ cpe: "1",
324
+ pin: "1"
325
+ };
326
+ expect(deserializeChannelState(data)).toEqual({
327
+ color: [255, 0, 0],
328
+ colorizeEnabled: true,
329
+ colorizeAlpha: 0.5,
330
+ opacity: 0.75,
331
+ volumeEnabled: true,
332
+ isosurfaceEnabled: true,
333
+ isovalue: 128,
334
+ ramp: [0, 255],
335
+ useControlPoints: true,
336
+ keepIntensityRange: true
337
+ });
338
+ });
339
+ it("prefers new control points and ramp fields over legacy fields", function () {
340
+ var data = {
341
+ cpt: "0:0:000000:255:1:ffffff",
342
+ cps: "0:0:ff0000:255:1:00ff00",
343
+ ram: "1:2",
344
+ rmp: "3:4"
345
+ };
346
+ expect(deserializeChannelState(data)).toEqual({
347
+ controlPoints: [{
348
+ x: 0,
349
+ opacity: 0,
350
+ color: [0, 0, 0]
351
+ }, {
352
+ x: 255,
353
+ opacity: 1,
354
+ color: [255, 255, 255]
355
+ }],
356
+ ramp: [1, 2]
357
+ });
358
+ });
359
+ });
309
360
  describe("deserializeViewerState", function () {
310
361
  it("returns an empty object for empty input", function () {
311
362
  expect(deserializeViewerState({})).toEqual({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aics/vole-app",
3
- "version": "3.4.2",
3
+ "version": "3.4.4",
4
4
  "description": "web view of cell volume images",
5
5
  "main": "es/index.js",
6
6
  "module": "es/index.js",
@@ -43,7 +43,7 @@
43
43
  "deploy": "gh-pages -d imageviewer -t true",
44
44
  "checks": "npm run lint && npm run typeCheck && npm run test"
45
45
  },
46
- "author": "Megan Riel-Mehan",
46
+ "author": "Allen Institute, Cell Science",
47
47
  "license": "BSD-3-Clause",
48
48
  "dependencies": {
49
49
  "@aics/vole-core": "^4.9.2",
@@ -60,6 +60,7 @@
60
60
  "react-color": "^2.19.3",
61
61
  "react-router-dom": "^6.26.2",
62
62
  "styled-components": "^6.1.13",
63
+ "three": "0.184.0",
63
64
  "usehooks-ts": "^3.1.0",
64
65
  "uuid": "^13.0.0",
65
66
  "zustand": "^5.0.6"
@@ -85,7 +86,7 @@
85
86
  "@types/react": "^18.x",
86
87
  "@types/react-color": "^3.0.12",
87
88
  "@types/react-dom": "^18.x",
88
- "@types/three": "^0.171.0",
89
+ "@types/three": "0.184.0",
89
90
  "@typescript-eslint/eslint-plugin": "^8.46.2",
90
91
  "@typescript-eslint/parser": "^8.46.2",
91
92
  "antd": "^5.16.2",
@@ -1,5 +1,5 @@
1
1
  import { type ControlPoint, type Histogram, Lut, type Volume } from "@aics/vole-core";
2
- import { type ViewerChannelSetting, type ViewerChannelSettings } from "./viewerChannelSettings";
2
+ import { type ViewerChannelSettings } from "./viewerChannelSettings";
3
3
  /**
4
4
  * @param {Object[]} controlPoints - array of `{x:number, opacity:number,
5
5
  * color:string}`, where `x` is a histogram bin index.
@@ -35,7 +35,7 @@ export declare function getDefaultLut(histogram: Histogram): Lut;
35
35
  * "autoij:0" // use Auto-IJ to calculate min and max.
36
36
  * ```
37
37
  */
38
- export declare function parseLutFromSettings(histogram: Histogram, initSettings: ViewerChannelSetting): Lut | undefined;
38
+ export declare function parseLutSetting(histogram: Histogram, lutSetting: [string, string] | undefined): Lut | undefined;
39
39
  /**
40
40
  * Initializes the lookup table (LUT) that maps from volume intensity values to color + opacity and applies the LUT to the volume.
41
41
  *
@@ -1,6 +1,7 @@
1
+ import type { Histogram } from "@aics/vole-core";
1
2
  import type { ColorArray } from "../shared/utils/colorRepresentations";
2
3
  import type { ViewerChannelSetting } from "../shared/utils/viewerChannelSettings";
3
- import { type ViewerChannelStateParams, type ViewerState, type ViewerStateParams } from "./types";
4
+ import { type ChannelState, type ViewerChannelStateParams, type ViewerState, type ViewerStateParams } from "./types";
4
5
  /**
5
6
  * LEGACY: Matches a COMMA-separated list of control points, where each control point is represented
6
7
  * by a triplet of `{x}:{opacity}:{hex color}`.
@@ -68,3 +69,22 @@ export declare function deserializeViewerState(params: ViewerStateParams): Parti
68
69
  * @returns A ViewerChannelSetting object.
69
70
  */
70
71
  export declare function deserializeViewerChannelSetting(channelIndex: number, jsonState: ViewerChannelStateParams): ViewerChannelSetting;
72
+ /**
73
+ * Parses a `ViewerChannelStateParams` object into a partial `ChannelState`.
74
+ *
75
+ * This is used to convert raw URL params into internal channel state fields,
76
+ * leaving absent or invalid values undefined.
77
+ *
78
+ * This function optionally accepts the target channel's `Histogram`. This
79
+ * argument is required to parse the following params correctly:
80
+ *
81
+ * - `lut`, which contains instructions for how to set the channel's
82
+ * intensities *relative to its intensity distribution*.
83
+ * - `rmp`, the legacy ramp parameter represented as histogram bin indices
84
+ * - `cps`, the legacy control points parameter where `x` values are
85
+ * represented as histogram bin indices
86
+ *
87
+ * If `histogram` is left undefined, e.g. because the channel has not yet been
88
+ * loaded, these params are ignored.
89
+ */
90
+ export declare function deserializeChannelState(jsonState: ViewerChannelStateParams, histogram?: Histogram): Partial<ChannelState>;