mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-14 01:37:26 +00:00
215 lines
7.2 KiB
TypeScript
215 lines
7.2 KiB
TypeScript
import { EncodeOptions, defaultOptions } from '../shared/meta';
|
||
import type WorkerBridge from 'client/lazy-app/worker-bridge';
|
||
import { h, Component, Fragment } from 'preact';
|
||
import {
|
||
inputFieldChecked,
|
||
inputFieldValueAsNumber,
|
||
preventDefault,
|
||
clamp,
|
||
} from 'client/lazy-app/util';
|
||
import * as style from 'client/lazy-app/Compress/Options/style.css';
|
||
import linkState from 'linkstate';
|
||
import Range from 'client/lazy-app/Compress/Options/Range';
|
||
import Checkbox from 'client/lazy-app/Compress/Options/Checkbox';
|
||
import Expander from 'client/lazy-app/Compress/Options/Expander';
|
||
import Select from 'client/lazy-app/Compress/Options/Select';
|
||
import Revealer from 'client/lazy-app/Compress/Options/Revealer';
|
||
|
||
export function encode(
|
||
signal: AbortSignal,
|
||
workerBridge: WorkerBridge,
|
||
imageData: ImageData,
|
||
options: EncodeOptions,
|
||
) {
|
||
return workerBridge.basisEncode(signal, imageData, options);
|
||
}
|
||
|
||
interface Props {
|
||
options: EncodeOptions;
|
||
onChange(newOptions: EncodeOptions): void;
|
||
}
|
||
|
||
interface State {
|
||
showAdvanced: boolean;
|
||
}
|
||
|
||
export class Options extends Component<Props, State> {
|
||
state: State = {
|
||
showAdvanced: false,
|
||
};
|
||
|
||
onChange = (event: Event) => {
|
||
const form = (event.currentTarget as HTMLInputElement).closest(
|
||
'form',
|
||
) as HTMLFormElement;
|
||
const { options } = this.props;
|
||
|
||
const uastc = form.mode.value === '1';
|
||
let quality = inputFieldValueAsNumber(form.quality, options.quality);
|
||
if (uastc) {
|
||
quality = clamp(0, quality, 4);
|
||
} else {
|
||
quality = Math.floor(clamp(0, quality, 255));
|
||
}
|
||
|
||
const newOptions: EncodeOptions = {
|
||
...this.props.options,
|
||
uastc,
|
||
quality,
|
||
y_flip: inputFieldChecked(form.y_flip, options.y_flip),
|
||
perceptual: inputFieldChecked(form.perceptual, options.perceptual),
|
||
mipmap: inputFieldChecked(form.mipmap, options.mipmap),
|
||
srgb_mipmap: inputFieldChecked(form.srgb_mipmap, options.srgb_mipmap),
|
||
mipmap_filter: form.mipmap_filter?.value ?? defaultOptions.mipmap_filter,
|
||
// FIXME: We really should support range remapping
|
||
// in the range-slider component. For now I’ll
|
||
// shoe-horn it into the state management.
|
||
mipmap_min_dimension:
|
||
2 **
|
||
inputFieldValueAsNumber(
|
||
form.mipmap_min_dimension,
|
||
Math.floor(Math.log2(options.mipmap_min_dimension)),
|
||
),
|
||
compression: inputFieldValueAsNumber(
|
||
form.compression,
|
||
options.compression,
|
||
),
|
||
};
|
||
this.props.onChange(newOptions);
|
||
};
|
||
|
||
render({ options }: Props, { showAdvanced }: State) {
|
||
return (
|
||
<form class={style.optionsSection} onSubmit={preventDefault}>
|
||
<label class={style.optionTextFirst}>
|
||
Mode:
|
||
<Select
|
||
name="mode"
|
||
value={options.uastc ? '1' : '0'}
|
||
onChange={this.onChange}
|
||
>
|
||
<option value="0">Compression (ETC1S)</option>
|
||
<option value="1">Quality (UASTC)</option>
|
||
</Select>
|
||
</label>
|
||
<div class={style.optionOneCell}>
|
||
<Range
|
||
name="quality"
|
||
min={options.uastc ? '0' : '1'}
|
||
max={options.uastc ? '4' : '255'}
|
||
step={options.uastc ? '0.1' : '1'}
|
||
value={options.quality}
|
||
onInput={this.onChange}
|
||
>
|
||
Quality:
|
||
</Range>
|
||
</div>
|
||
<div class={style.optionOneCell}>
|
||
<Range
|
||
name="compression"
|
||
min="0"
|
||
max="4"
|
||
value={options.compression}
|
||
onInput={this.onChange}
|
||
>
|
||
Compression:
|
||
</Range>
|
||
</div>
|
||
<label class={style.optionToggle}>
|
||
Flip Y Axis
|
||
<Checkbox
|
||
name="y_flip"
|
||
checked={options.y_flip}
|
||
onChange={this.onChange}
|
||
/>
|
||
</label>
|
||
<label class={style.optionReveal}>
|
||
<Revealer
|
||
checked={showAdvanced}
|
||
onChange={linkState(this, 'showAdvanced')}
|
||
/>
|
||
Advanced settings
|
||
</label>
|
||
<Expander>
|
||
{showAdvanced ? (
|
||
<div>
|
||
<label class={style.optionToggle}>
|
||
Perceptual distance metric
|
||
<Checkbox
|
||
name="perceptual"
|
||
checked={options.perceptual}
|
||
onChange={this.onChange}
|
||
/>
|
||
</label>
|
||
<label class={style.optionToggle}>
|
||
Embed Mipmaps
|
||
<Checkbox
|
||
name="mipmap"
|
||
checked={options.mipmap}
|
||
onChange={this.onChange}
|
||
/>
|
||
</label>
|
||
<Expander>
|
||
{options.mipmap ? (
|
||
<Fragment>
|
||
<div class={style.optionOneCell}>
|
||
<Range
|
||
min="0"
|
||
max="10"
|
||
name="mipmap_min_dimension"
|
||
value={Math.floor(
|
||
Math.log2(options.mipmap_min_dimension),
|
||
)}
|
||
onInput={this.onChange}
|
||
>
|
||
Log2 of smallest mipmap:
|
||
</Range>
|
||
</div>
|
||
<label class={style.optionTextFirst}>
|
||
Resampling filter:
|
||
<Select
|
||
name="mipmap_filter"
|
||
value={options.mipmap_filter}
|
||
onChange={this.onChange}
|
||
>
|
||
<option value="box">Box</option>
|
||
<option value="tent">Tent</option>
|
||
<option value="bell">Bell</option>
|
||
<option value="b-spline">B-Spline</option>
|
||
<option value="mitchell">Mitchell</option>
|
||
<option value="blackman">Blackman</option>
|
||
<option value="lanczos3">Lanczos3</option>
|
||
<option value="lanczos4">Lanczos4</option>
|
||
<option value="lanczos6">Lanczos6</option>
|
||
<option value="lanczos12">Lanczos12</option>
|
||
<option value="kaiser">Kaiser</option>
|
||
<option value="gaussian">Gaussian</option>
|
||
<option value="catmullrom">Catmullrom</option>
|
||
<option value="quadratic_interp">
|
||
Quadratic Interpolation
|
||
</option>
|
||
<option value="quadratic_approx">
|
||
Quadratic Approx
|
||
</option>
|
||
<option value="quadratic_mix">Quadratic Mix</option>
|
||
</Select>
|
||
</label>
|
||
<label class={style.optionToggle}>
|
||
sRGB Mipmapping
|
||
<Checkbox
|
||
name="srgb_mipmap"
|
||
checked={options.srgb_mipmap}
|
||
onChange={this.onChange}
|
||
/>
|
||
</label>
|
||
</Fragment>
|
||
) : null}
|
||
</Expander>
|
||
</div>
|
||
) : null}
|
||
</Expander>
|
||
</form>
|
||
);
|
||
}
|
||
}
|