diff --git a/src/components/SlideViewer.tsx b/src/components/SlideViewer.tsx index 0a7e0a4f..c113ab5c 100644 --- a/src/components/SlideViewer.tsx +++ b/src/components/SlideViewer.tsx @@ -293,6 +293,8 @@ class SlideViewer extends React.Component { selectedPresentationStateUID: this.props.selectedPresentationStateUID, loadingFrames: new Set(), isICCProfilesEnabled: true, + isPaletteDisplayGammaCorrectionEnabled: + volumeViewer.getPaletteDisplayGammaCorrectionEnabled(), isSegmentationInterpolationEnabled: false, isParametricMapInterpolationEnabled: true, customizedSegmentColors: {}, @@ -317,6 +319,7 @@ class SlideViewer extends React.Component { */ private static readonly createSegmentPaletteColorLookupTable = ( segmentColor: number[], + applyDisplayGammaCorrection = true, ): dmv.color.PaletteColorLookupTable => { /** Create a simple palette with the segment color * For binary segments, we typically have 2 values: background (0) and segment (1) */ @@ -328,6 +331,7 @@ class SlideViewer extends React.Component { return dmv.color.buildPaletteColorLookupTable({ data: paletteData, firstValueMapped: 0, + applyDisplayGammaCorrection, }) } @@ -402,6 +406,9 @@ class SlideViewer extends React.Component { }) this.volumeViewer = volumeViewer this.labelViewer = labelViewer + this.volumeViewer.setPaletteDisplayGammaCorrectionEnabled( + this.state.isPaletteDisplayGammaCorrectionEnabled, + ) const activeOpticalPathIdentifiers: Set = new Set() const visibleOpticalPathIdentifiers: Set = new Set() @@ -3016,7 +3023,10 @@ class SlideViewer extends React.Component { } if (styleOptions.color !== undefined) { stylePayload.paletteColorLookupTable = - SlideViewer.createSegmentPaletteColorLookupTable(styleOptions.color) + SlideViewer.createSegmentPaletteColorLookupTable( + styleOptions.color, + this.volumeViewer.getPaletteDisplayGammaCorrectionEnabled(), + ) } this.volumeViewer.setSegmentStyle(segmentUID, stylePayload) @@ -3578,6 +3588,15 @@ class SlideViewer extends React.Component { this.volumeViewer.toggleICCProfiles() } + /** + * Toggle display gamma compensation for palette-based rendering (optical paths, + * segment overlays, parametric maps). + */ + handlePaletteDisplayGammaCorrectionToggle = (checked: boolean): void => { + this.setState({ isPaletteDisplayGammaCorrectionEnabled: checked }) + this.volumeViewer.setPaletteDisplayGammaCorrectionEnabled(checked) + } + /** * Handler that will toggle the segmentation interpolation, i.e., either * enable or disable it, depending on its current state. @@ -4084,6 +4103,7 @@ class SlideViewer extends React.Component { defaultSegmentStyles[segment.uid].color !== undefined ? SlideViewer.createSegmentPaletteColorLookupTable( defaultSegmentStyles[segment.uid].color as number[], + this.volumeViewer.getPaletteDisplayGammaCorrectionEnabled(), ) : undefined, }) @@ -4565,6 +4585,26 @@ class SlideViewer extends React.Component { ) } + private readonly getPaletteDisplayGammaCorrectionMenu = + (): React.ReactNode => { + return ( +
+ Gamma correction + +
+ ) + } + private readonly getSegmentationInterpolationMenu = (): React.ReactNode => { const segments = this.volumeViewer.getAllSegments() return ( @@ -4588,6 +4628,7 @@ class SlideViewer extends React.Component { private readonly getSettingsPanelContent = (menus: { iccProfilesMenu: React.ReactNode + gammaCorrectionMenu: React.ReactNode segmentationInterpolationMenu: React.ReactNode }): React.ReactNode => { const menuItems: React.ReactNode[] = [] @@ -4595,7 +4636,10 @@ class SlideViewer extends React.Component { menuItems.push( -
{menus.iccProfilesMenu}
+
+ {menus.iccProfilesMenu} + {menus.gammaCorrectionMenu} +
, ) @@ -4734,6 +4778,7 @@ class SlideViewer extends React.Component { const cursor = this.getCursor() const selectedRoiInformation = this.getSelectedRoiInformation() const iccProfilesMenu = this.getICCProfilesMenu() + const gammaCorrectionMenu = this.getPaletteDisplayGammaCorrectionMenu() const segmentationInterpolationMenu = this.getSegmentationInterpolationMenu() @@ -4741,6 +4786,7 @@ class SlideViewer extends React.Component { const settingsPanelContent = this.getSettingsPanelContent({ iccProfilesMenu, + gammaCorrectionMenu, segmentationInterpolationMenu, }) diff --git a/src/components/SlideViewer/types.ts b/src/components/SlideViewer/types.ts index d88889d4..d460fcff 100644 --- a/src/components/SlideViewer/types.ts +++ b/src/components/SlideViewer/types.ts @@ -122,6 +122,7 @@ export interface SlideViewerState { } loadingFrames: Set isICCProfilesEnabled: boolean + isPaletteDisplayGammaCorrectionEnabled: boolean isSegmentationInterpolationEnabled: boolean isParametricMapInterpolationEnabled: boolean customizedSegmentColors: { [segmentUID: string]: number[] } diff --git a/types/dicom-microscopy-viewer/index.d.ts b/types/dicom-microscopy-viewer/index.d.ts index 47a29b64..45d93fe8 100644 --- a/types/dicom-microscopy-viewer/index.d.ts +++ b/types/dicom-microscopy-viewer/index.d.ts @@ -18,6 +18,7 @@ declare module 'dicom-microscopy-viewer' { controls: string[] annotationOptions?: object errorInterceptor?: (error: CustomError) => void + paletteDisplayGammaCorrection?: boolean } export interface ROIStyleOptions { @@ -232,6 +233,8 @@ declare module 'dicom-microscopy-viewer' { ): metadata.MicroscopyBulkSimpleAnnotations toggleICCProfiles (): void; getICCProfiles (): any[]; + setPaletteDisplayGammaCorrectionEnabled (enabled: boolean): void; + getPaletteDisplayGammaCorrectionEnabled (): boolean; toggleSegmentationInterpolation (): void; toggleParametricMapInterpolation (): void; } @@ -814,11 +817,13 @@ declare module 'dicom-microscopy-viewer' { redSegmentedData?: Unit8Array|Unit16Array greenSegmentedData?: Unit8Array|Unit16Array blueSegmentedData?: Unit8Array|Unit16Array + applyDisplayGammaCorrection?: boolean } export interface BuildPaletteColorLookupTableOptions { data: number[][] firstValueMapped: number + applyDisplayGammaCorrection?: boolean } export function buildPaletteColorLookupTable (options: BuildPaletteColorLookupTableOptions): PaletteColorLookupTable @@ -828,6 +833,8 @@ declare module 'dicom-microscopy-viewer' { get uid (): string get data (): number[][] get firstValueMapped (): number + get applyDisplayGammaCorrection (): boolean + setApplyDisplayGammaCorrection (enabled: boolean): void } }