Files
Jungfraujoch/frontend/src/components/ImageFormatSettings.tsx
T
leonarski_f 75e401f0e5
Build Packages / Unit tests (push) Successful in 1h31m59s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 8m43s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 10m5s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 9m27s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 8m56s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 9m24s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 10m27s
Build Packages / build:rpm (rocky8) (push) Successful in 9m20s
Build Packages / build:rpm (rocky9) (push) Successful in 10m50s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 9m54s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 8m38s
Build Packages / DIALS test (push) Successful in 12m13s
Build Packages / XDS test (durin plugin) (push) Successful in 7m8s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m8s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m50s
Build Packages / Generate python client (push) Successful in 16s
Build Packages / Build documentation (push) Successful in 50s
Build Packages / Create release (push) Skipped
v1.0.0-rc.153 (#63)
This is an UNSTABLE release. It includes many experimental features, as well as many AI generated fixes. We recommend using rc.152 for production use.

* jfjoch_broker: Add EXPERIMENTAL pixelrefine mode for image processing
* jfjoch_broker: Allow to load user mask from 8-bit and 16-bit TIFF files
* jfjoch_broker: Add ROI calculation in non-FPGA workflow
* jfjoch_broker: Fixes to TCP image pusher
* jfjoch_broker: Remove NUMA bindings
* jfjoch_broker: Improvements to indexing
* jfjoch_broker: For PSI EIGER, trimming energies are taken from the detector configuration (now compulsory) instead of hardcoded values
* jfjoch_writer: Save ROI definitions and the per-pixel ROI bitmap in the master file; azimuthal ROIs support phi (angular) sectors
* jfjoch_viewer: Major redesign with dockable panels and saved layouts, plus on-canvas creation/move/resize of box, circle and azimuthal ROIs
* jfjoch_viewer: Run jfjoch_process reprocessing jobs from inside the GUI and overlay per-run results

Reviewed-on: #63
2026-06-23 20:29:49 +02:00

262 lines
12 KiB
TypeScript

import {ChangeEvent, memo, useEffect, useState} from 'react';
import {Checkbox, FormControlLabel, FormGroup, List, ListItem, Stack, Tooltip} from "@mui/material";
import FormControl from "@mui/material/FormControl";
import InputLabel from "@mui/material/InputLabel";
import Select, {SelectChangeEvent} from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import {image_format_settings} from "../client";
import {putConfigImageFormatMutation} from "../client/@tanstack/react-query.gen";
import NumberTextField from "./NumberTextField";
import _ from "lodash";
import SettingsPanel from "./SettingsPanel";
import {useUpload} from "./useUpload";
type MyProps = {
s?: image_format_settings
}
const default_image_format_settings: image_format_settings = {
summation: true,
geometry_transform: true,
jungfrau_conversion: true,
jungfrau_conversion_factor_keV: undefined,
bit_depth_image: undefined,
signed_output: undefined,
mask_module_edges: true,
mask_chip_edges: true,
jungfrau_mask_pixels_without_g0: true,
apply_mask: false,
jungfrau_pedestal_g0_rms_limit: 100
};
function extractSignForSelection(input: image_format_settings) : string {
if (input.signed_output === undefined)
return 'a';
else if (input.signed_output)
return 's';
else
return 'u';
}
function extractDepthForSelection(input: image_format_settings) : string {
if (input.bit_depth_image === undefined)
return 'a';
else if (input.bit_depth_image === 8)
return '8';
else if (input.bit_depth_image === 16)
return '16';
else if (input.bit_depth_image === 32)
return '32';
else
return "";
}
function ImageFormatSettings({s: serverS}: MyProps) {
const [s, setS] = useState<image_format_settings>(default_image_format_settings);
const [lastDownloadedS, setLastDownloadedS] = useState<image_format_settings>(default_image_format_settings);
const [bitWidthSelection, setBitWidthSelection] = useState("a");
const [signSelection, setSignSelection] = useState("a");
const [jungfrauConversionFactorErr, setJungfrauConversionFactorErr] = useState(false);
const [jungfrauConversionFactorOld, setJungfrauConversionFactorOld] = useState(12.4);
const [downloadCounter, setDownloadCounter] = useState(0);
const { submit, pending, snackbar } = useUpload(putConfigImageFormatMutation());
useEffect(() => {
if ((serverS !== undefined) && !_.isEqual(serverS, lastDownloadedS)) {
setS(serverS);
setLastDownloadedS(serverS);
setJungfrauConversionFactorErr(false);
setDownloadCounter(c => c + 1);
setJungfrauConversionFactorOld(serverS.jungfrau_conversion_factor_keV ?? jungfrauConversionFactorOld);
setBitWidthSelection(extractDepthForSelection(serverS));
setSignSelection(extractSignForSelection(serverS));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [serverS]);
const handleBitWidthChange = (event: SelectChangeEvent) => {
let val: image_format_settings['bit_depth_image'] = undefined;
if (event.target.value === "a")
val = undefined;
else if (event.target.value === "8")
val = 8;
else if (event.target.value === "16")
val = 16;
else if (event.target.value === "32")
val = 32;
setBitWidthSelection(event.target.value);
setS(prev => ({...prev, bit_depth_image: val}));
};
const handleSignChange = (event: SelectChangeEvent) => {
let val: boolean|undefined = undefined;
if (event.target.value === "a")
val = undefined;
else if (event.target.value === "u")
val = false;
else if (event.target.value === "s")
val = true;
setSignSelection(event.target.value);
setS(prev => ({...prev, signed_output: val}));
};
const dirty = !_.isEqual(s, lastDownloadedS);
return (
<SettingsPanel title="Output image format" dirty={dirty}
onUpload={() => submit(s)} uploadDisabled={pending || jungfrauConversionFactorErr} snackbar={snackbar}>
<FormGroup>
<FormControlLabel control={
<Checkbox checked={s.geometry_transform}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setS(prev => ({...prev, geometry_transform: event.target.checked}));
}}/>
} label="Geometry transformation"/>
<FormControlLabel control={
<Checkbox checked={s.summation}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setS(prev => ({...prev, summation: event.target.checked}));
}}/>
} label="Image summation"/>
<FormControlLabel control={
<Checkbox checked={s.mask_chip_edges}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setS(prev => ({...prev, mask_chip_edges: event.target.checked}));
}}/>
} label="Mask chip edges"/>
<FormControlLabel control={
<Checkbox checked={s.mask_module_edges}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setS(prev => ({...prev, mask_module_edges: event.target.checked}));
}}/>
} label="Mask module edges"/>
<FormControlLabel control={
<Checkbox checked={s.apply_mask}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setS(prev => ({...prev, apply_mask: event.target.checked}));
}}/>
} label="Apply pixel masks on images"/>
</FormGroup>
<b>Output pixel value</b>
<Stack spacing={2} direction="row">
<FormControl>
<InputLabel id="demo-simple-select-label">Bit-width</InputLabel>
<Select
sx={{width: 150}}
labelId="demo-simple-select-label"
id="demo-simple-select"
label="Detector"
value={bitWidthSelection}
onChange={handleBitWidthChange}
>
<MenuItem value={"a"}>Auto</MenuItem>
<MenuItem value={"8"}>8-bit</MenuItem>
<MenuItem value={"16"}>16-bit</MenuItem>
<MenuItem value={"32"}>32-bit</MenuItem>
</Select>
</FormControl>
<FormControl>
<InputLabel id="demo-simple-select-label">Sign</InputLabel>
<Select
sx={{width: 150}}
labelId="demo-simple-select-label"
id="demo-simple-select"
label="Sign"
value={signSelection}
onChange={handleSignChange}
>
<MenuItem value={"a"}>Auto</MenuItem>
<MenuItem value={"s"}>Signed</MenuItem>
<MenuItem value={"u"}>Unsigned</MenuItem>
</Select>
</FormControl>
</Stack>
<b>JUNGFRAU specific</b>
<FormGroup>
<FormControlLabel control={
<Checkbox checked={s.jungfrau_mask_pixels_without_g0}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setS(prev => ({...prev, jungfrau_mask_pixels_without_g0: event.target.checked}));
}}/>
} label="Mask pixels not switching to G0"/>
<FormControlLabel control={
<Checkbox checked={s.jungfrau_conversion}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setJungfrauConversionFactorErr(false);
setS(prev => ({
...prev,
jungfrau_conversion: event.target.checked,
jungfrau_conversion_factor_keV: undefined
}));
}}/>
} label="Conversion to photons"/>
</FormGroup>
<List>
<Tooltip
title="JUNGFRAU conversion factor allows to get different unit than 1 photon count. If not provided incident_energy is used.">
<ListItem>
<Checkbox
checked={s.jungfrau_conversion_factor_keV !== undefined}
disabled={!s.jungfrau_conversion}
onChange={
(event: ChangeEvent<HTMLInputElement>) => {
setDownloadCounter(c => c + 1);
setJungfrauConversionFactorErr(false);
if (!event.target.checked)
setS(prev => ({...prev, jungfrau_conversion_factor_keV: undefined}));
else
setS(prev => ({...prev, jungfrau_conversion_factor_keV: jungfrauConversionFactorOld}));
}}
/>
<FormControl fullWidth>
<NumberTextField
start_val={s.jungfrau_conversion_factor_keV}
disabled={s.jungfrau_conversion_factor_keV === undefined}
label={"JUNGFRAU conversion factor"}
units={"keV"}
float={true}
min={0.001}
fullWidth
counter={downloadCounter}
callback={(val: number, err: boolean) => {
if (!err)
setJungfrauConversionFactorOld(val);
setJungfrauConversionFactorErr(err);
setS(prev => ({...prev, jungfrau_conversion_factor_keV: val}));
}}/>
</FormControl>
</ListItem>
</Tooltip>
</List>
<NumberTextField start_val={s.jungfrau_pedestal_g0_rms_limit}
label={"G0 max RMS"}
min={0}
default={100}
counter={downloadCounter}
callback={(val: number, _err: boolean) => {
setS(prev => ({...prev, jungfrau_pedestal_g0_rms_limit: val}));
}}
/>
</SettingsPanel>
);
}
export default memo(ImageFormatSettings);