mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-11 16:26:20 +00:00
MozJPEG options updated
This commit is contained in:
@@ -30,15 +30,14 @@ export default class QuantizerOptions extends Component<Props, State> {
|
||||
@bind
|
||||
onChange(event: Event) {
|
||||
const form = (event.currentTarget as HTMLInputElement).closest('form') as HTMLFormElement;
|
||||
const { options } = this.props;
|
||||
|
||||
const options: QuantizeOptions = {
|
||||
zx: form.zx ? inputFieldValueAsNumber(form.zx) : this.props.options.zx,
|
||||
maxNumColors: form.maxNumColors
|
||||
? inputFieldValueAsNumber(form.maxNumColors)
|
||||
: this.props.options.maxNumColors,
|
||||
const newOptions: QuantizeOptions = {
|
||||
zx: inputFieldValueAsNumber(form.zx, options.zx),
|
||||
maxNumColors: inputFieldValueAsNumber(form.maxNumColors, options.maxNumColors),
|
||||
dither: inputFieldValueAsNumber(form.dither),
|
||||
};
|
||||
this.props.onChange(options);
|
||||
this.props.onChange(newOptions);
|
||||
}
|
||||
|
||||
render({ options }: Props, { extendedSettings }: State) {
|
||||
|
||||
@@ -2,158 +2,197 @@ import { h, Component } from 'preact';
|
||||
import { bind } from '../../lib/initial-util';
|
||||
import { inputFieldChecked, inputFieldValueAsNumber } from '../../lib/util';
|
||||
import { EncodeOptions, MozJpegColorSpace } from './encoder-meta';
|
||||
import '../../custom-els/RangeInput';
|
||||
import * as style from '../../components/options/style.scss';
|
||||
import Checkbox from '../../components/checkbox';
|
||||
import Expander from '../../components/expander';
|
||||
import Select from '../../components/select';
|
||||
import Range from '../../components/range';
|
||||
import linkState from 'linkstate';
|
||||
|
||||
type Props = {
|
||||
options: EncodeOptions,
|
||||
onChange(newOptions: EncodeOptions): void,
|
||||
};
|
||||
interface Props {
|
||||
options: EncodeOptions;
|
||||
onChange(newOptions: EncodeOptions): void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
showAdvanced: boolean;
|
||||
}
|
||||
|
||||
export default class MozJPEGEncoderOptions extends Component<Props, State> {
|
||||
state: State = {
|
||||
showAdvanced: false,
|
||||
};
|
||||
|
||||
export default class MozJPEGEncoderOptions extends Component<Props, {}> {
|
||||
@bind
|
||||
onChange(event: Event) {
|
||||
const form = (event.currentTarget as HTMLInputElement).closest('form') as HTMLFormElement;
|
||||
const { options } = this.props;
|
||||
|
||||
const options: EncodeOptions = {
|
||||
const newOptions: EncodeOptions = {
|
||||
// Copy over options the form doesn't currently care about, eg arithmetic
|
||||
...this.props.options,
|
||||
// And now stuff from the form:
|
||||
// .checked
|
||||
baseline: inputFieldChecked(form.baseline),
|
||||
progressive: inputFieldChecked(form.progressive),
|
||||
optimize_coding: inputFieldChecked(form.optimize_coding),
|
||||
trellis_multipass: inputFieldChecked(form.trellis_multipass),
|
||||
trellis_opt_zero: inputFieldChecked(form.trellis_opt_zero),
|
||||
trellis_opt_table: inputFieldChecked(form.trellis_opt_table),
|
||||
baseline: inputFieldChecked(form.baseline, options.baseline),
|
||||
progressive: inputFieldChecked(form.progressive, options.progressive),
|
||||
optimize_coding: inputFieldChecked(form.optimize_coding, options.optimize_coding),
|
||||
trellis_multipass: inputFieldChecked(form.trellis_multipass, options.trellis_multipass),
|
||||
trellis_opt_zero: inputFieldChecked(form.trellis_opt_zero, options.trellis_opt_zero),
|
||||
trellis_opt_table: inputFieldChecked(form.trellis_opt_table, options.trellis_opt_table),
|
||||
// .value
|
||||
quality: inputFieldValueAsNumber(form.quality),
|
||||
smoothing: inputFieldValueAsNumber(form.smoothing),
|
||||
color_space: inputFieldValueAsNumber(form.color_space),
|
||||
quant_table: inputFieldValueAsNumber(form.quant_table),
|
||||
trellis_loops: inputFieldValueAsNumber(form.trellis_loops),
|
||||
quality: inputFieldValueAsNumber(form.quality, options.quality),
|
||||
smoothing: inputFieldValueAsNumber(form.smoothing, options.smoothing),
|
||||
color_space: inputFieldValueAsNumber(form.color_space, options.color_space),
|
||||
quant_table: inputFieldValueAsNumber(form.quant_table, options.quant_table),
|
||||
trellis_loops: inputFieldValueAsNumber(form.trellis_loops, options.trellis_loops),
|
||||
};
|
||||
this.props.onChange(options);
|
||||
this.props.onChange(newOptions);
|
||||
}
|
||||
|
||||
render({ options }: Props) {
|
||||
render({ options }: Props, { showAdvanced }: State) {
|
||||
// I'm rendering both lossy and lossless forms, as it becomes much easier when
|
||||
// gathering the data.
|
||||
return (
|
||||
<form>
|
||||
<label>
|
||||
Quality:
|
||||
<range-input
|
||||
<form class={style.optionsSection}>
|
||||
<div class={style.optionOneCell}>
|
||||
<Range
|
||||
name="quality"
|
||||
min="0"
|
||||
max="100"
|
||||
value={'' + options.quality}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
name="baseline"
|
||||
type="checkbox"
|
||||
checked={options.baseline}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span>Baseline (worse but legacy-compatible)</span>
|
||||
</label>
|
||||
<label style={{ display: options.baseline ? 'none' : '' }}>
|
||||
<input
|
||||
name="progressive"
|
||||
type="checkbox"
|
||||
checked={options.progressive}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span>Progressive multi-pass rendering</span>
|
||||
</label>
|
||||
<label style={{ display: options.baseline ? '' : 'none' }}>
|
||||
<input
|
||||
name="optimize_coding"
|
||||
type="checkbox"
|
||||
checked={options.optimize_coding}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span>Optimize Huffman table</span>
|
||||
</label>
|
||||
<label>
|
||||
Smoothing:
|
||||
<range-input
|
||||
name="smoothing"
|
||||
min="0"
|
||||
max="100"
|
||||
value={'' + options.smoothing}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Output color space:
|
||||
<select
|
||||
name="color_space"
|
||||
value={'' + options.color_space}
|
||||
onChange={this.onChange}
|
||||
value={options.quality}
|
||||
onInput={this.onChange}
|
||||
>
|
||||
<option value={MozJpegColorSpace.GRAYSCALE}>Grayscale</option>
|
||||
<option value={MozJpegColorSpace.RGB}>RGB (sub-optimal)</option>
|
||||
<option value={MozJpegColorSpace.YCbCr}>YCbCr (optimized for color)</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Quantization table:
|
||||
<select
|
||||
name="quant_table"
|
||||
value={'' + options.quant_table}
|
||||
onChange={this.onChange}
|
||||
>
|
||||
<option value="0">JPEG Annex K</option>
|
||||
<option value="1">Flat</option>
|
||||
<option value="2">MSSIM-tuned Kodak</option>
|
||||
<option value="3">ImageMagick</option>
|
||||
<option value="4">PSNR-HVS-M-tuned Kodak</option>
|
||||
<option value="5">Klein et al</option>
|
||||
<option value="6">Watson et al</option>
|
||||
<option value="7">Ahumada et al</option>
|
||||
<option value="8">Peterson et al</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
name="trellis_multipass"
|
||||
type="checkbox"
|
||||
checked={options.trellis_multipass}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span>Consider multiple scans during trellis quantization</span>
|
||||
</label>
|
||||
<label style={{ display: options.trellis_multipass ? '' : 'none' }}>
|
||||
<input
|
||||
name="trellis_opt_zero"
|
||||
type="checkbox"
|
||||
checked={options.trellis_opt_zero}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span>Optimize runs of zero blocks</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
name="trellis_opt_table"
|
||||
type="checkbox"
|
||||
checked={options.trellis_opt_table}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<span>Optimize after trellis quantization</span>
|
||||
</label>
|
||||
<label>
|
||||
Trellis quantization passes:
|
||||
<range-input
|
||||
name="trellis_loops"
|
||||
min="1"
|
||||
max="50"
|
||||
value={'' + options.trellis_loops}
|
||||
onChange={this.onChange}
|
||||
Quality:
|
||||
</Range>
|
||||
</div>
|
||||
<label class={style.optionInputFirst}>
|
||||
<Checkbox
|
||||
checked={showAdvanced}
|
||||
onChange={linkState(this, 'showAdvanced')}
|
||||
/>
|
||||
Show advanced settings
|
||||
</label>
|
||||
<Expander>
|
||||
{showAdvanced ?
|
||||
<div>
|
||||
<label class={style.optionInputFirst}>
|
||||
<Checkbox
|
||||
name="baseline"
|
||||
checked={options.baseline}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
Pointless spec compliance
|
||||
</label>
|
||||
<Expander>
|
||||
{options.baseline ? null :
|
||||
<label class={style.optionInputFirst}>
|
||||
<Checkbox
|
||||
name="progressive"
|
||||
checked={options.progressive}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
Progressive rendering
|
||||
</label>
|
||||
}
|
||||
</Expander>
|
||||
<Expander>
|
||||
{options.baseline ?
|
||||
<label class={style.optionInputFirst}>
|
||||
<Checkbox
|
||||
name="optimize_coding"
|
||||
checked={options.optimize_coding}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
Optimize Huffman table
|
||||
</label>
|
||||
: null
|
||||
}
|
||||
</Expander>
|
||||
<div class={style.optionOneCell}>
|
||||
<Range
|
||||
name="smoothing"
|
||||
min="0"
|
||||
max="100"
|
||||
value={options.smoothing}
|
||||
onInput={this.onChange}
|
||||
>
|
||||
Smoothing:
|
||||
</Range>
|
||||
</div>
|
||||
<label class={style.optionTextFirst}>
|
||||
Channels:
|
||||
<Select
|
||||
name="color_space"
|
||||
value={options.color_space}
|
||||
onChange={this.onChange}
|
||||
>
|
||||
<option value={MozJpegColorSpace.GRAYSCALE}>Grayscale</option>
|
||||
<option value={MozJpegColorSpace.RGB}>RGB</option>
|
||||
<option value={MozJpegColorSpace.YCbCr}>YCbCr</option>
|
||||
</Select>
|
||||
</label>
|
||||
<label class={style.optionTextFirst}>
|
||||
Quantization:
|
||||
<Select
|
||||
name="quant_table"
|
||||
value={options.quant_table}
|
||||
onChange={this.onChange}
|
||||
>
|
||||
<option value="0">JPEG Annex K</option>
|
||||
<option value="1">Flat</option>
|
||||
<option value="2">MSSIM-tuned Kodak</option>
|
||||
<option value="3">ImageMagick</option>
|
||||
<option value="4">PSNR-HVS-M-tuned Kodak</option>
|
||||
<option value="5">Klein et al</option>
|
||||
<option value="6">Watson et al</option>
|
||||
<option value="7">Ahumada et al</option>
|
||||
<option value="8">Peterson et al</option>
|
||||
</Select>
|
||||
</label>
|
||||
<label class={style.optionInputFirst}>
|
||||
<Checkbox
|
||||
name="trellis_multipass"
|
||||
checked={options.trellis_multipass}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
Trellis multipass
|
||||
</label>
|
||||
<Expander>
|
||||
{options.trellis_multipass ?
|
||||
<label class={style.optionInputFirst}>
|
||||
<Checkbox
|
||||
name="trellis_opt_zero"
|
||||
checked={options.trellis_opt_zero}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
Optimize zero block runs
|
||||
</label>
|
||||
: null
|
||||
}
|
||||
</Expander>
|
||||
<label class={style.optionInputFirst}>
|
||||
<Checkbox
|
||||
name="trellis_opt_table"
|
||||
checked={options.trellis_opt_table}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
Optimize after trellis quantization
|
||||
</label>
|
||||
<div class={style.optionOneCell}>
|
||||
<Range
|
||||
name="trellis_loops"
|
||||
min="1"
|
||||
max="50"
|
||||
value={options.trellis_loops}
|
||||
onInput={this.onChange}
|
||||
>
|
||||
Trellis quantization passes:
|
||||
</Range>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</Expander>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { h, Component } from 'preact';
|
||||
import linkState from 'linkstate';
|
||||
import { bind, linkRef } from '../../lib/initial-util';
|
||||
import { inputFieldValueAsNumber } from '../../lib/util';
|
||||
import { inputFieldValueAsNumber, inputFieldValue } from '../../lib/util';
|
||||
import { ResizeOptions } from './processor-meta';
|
||||
import * as style from '../../components/options/style.scss';
|
||||
import Checkbox from '../../components/checkbox';
|
||||
@@ -27,18 +27,21 @@ export default class ResizerOptions extends Component<Props, State> {
|
||||
form?: HTMLFormElement;
|
||||
|
||||
private reportOptions() {
|
||||
const width = this.form!.width as HTMLInputElement;
|
||||
const height = this.form!.height as HTMLInputElement;
|
||||
const form = this.form!;
|
||||
const width = form.width as HTMLInputElement;
|
||||
const height = form.height as HTMLInputElement;
|
||||
const { options } = this.props;
|
||||
|
||||
if (!width.checkValidity() || !height.checkValidity()) return;
|
||||
|
||||
const options: ResizeOptions = {
|
||||
const newOptions: ResizeOptions = {
|
||||
width: inputFieldValueAsNumber(width),
|
||||
height: inputFieldValueAsNumber(height),
|
||||
method: this.form!.resizeMethod.value,
|
||||
fitMethod: this.form!.fitMethod ? this.form!.fitMethod.value : this.props.options.fitMethod,
|
||||
method: form.resizeMethod.value,
|
||||
// Casting, as the formfield only returns the correct values.
|
||||
fitMethod: inputFieldValue(form.fitMethod, options.fitMethod) as ResizeOptions['fitMethod'],
|
||||
};
|
||||
this.props.onChange(options);
|
||||
this.props.onChange(newOptions);
|
||||
}
|
||||
|
||||
@bind
|
||||
|
||||
@@ -192,8 +192,6 @@ export default class Options extends Component<Props, State> {
|
||||
}
|
||||
</section>
|
||||
|
||||
{/*
|
||||
|
||||
{EncoderOptionComponent &&
|
||||
<EncoderOptionComponent
|
||||
options={
|
||||
@@ -205,6 +203,8 @@ export default class Options extends Component<Props, State> {
|
||||
/>
|
||||
}
|
||||
|
||||
{/*
|
||||
|
||||
<div class={style.row}>
|
||||
<button onClick={this.onCopyToOtherClick}>Copy settings to other side</button>
|
||||
</div>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
box-sizing: border-box;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
text-underline-position: under;
|
||||
width: 48px;
|
||||
position: relative;
|
||||
left: 5px;
|
||||
|
||||
@@ -203,25 +203,40 @@ export function nativeResize(
|
||||
|
||||
/**
|
||||
* @param field An HTMLInputElement, but the casting is done here to tidy up onChange.
|
||||
* @param defaultVal Value to return if 'field' doesn't exist.
|
||||
*/
|
||||
export function inputFieldValueAsNumber(field: any): number {
|
||||
return Number((field as HTMLInputElement).value);
|
||||
export function inputFieldValueAsNumber(field: any, defaultVal: number = 0): number {
|
||||
if (!field) return defaultVal;
|
||||
return Number(inputFieldValue(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field An HTMLInputElement, but the casting is done here to tidy up onChange.
|
||||
* @param defaultVal Value to return if 'field' doesn't exist.
|
||||
*/
|
||||
export function inputFieldCheckedAsNumber(field: any): number {
|
||||
export function inputFieldCheckedAsNumber(field: any, defaultVal: number = 0): number {
|
||||
if (!field) return defaultVal;
|
||||
return Number(inputFieldChecked(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field An HTMLInputElement, but the casting is done here to tidy up onChange.
|
||||
* @param defaultVal Value to return if 'field' doesn't exist.
|
||||
*/
|
||||
export function inputFieldChecked(field: any): boolean {
|
||||
export function inputFieldChecked(field: any, defaultVal: boolean = false): boolean {
|
||||
if (!field) return defaultVal;
|
||||
return (field as HTMLInputElement).checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field An HTMLInputElement, but the casting is done here to tidy up onChange.
|
||||
* @param defaultVal Value to return if 'field' doesn't exist.
|
||||
*/
|
||||
export function inputFieldValue(field: any, defaultVal: string = ''): string {
|
||||
if (!field) return defaultVal;
|
||||
return (field as HTMLInputElement).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a promise that resolves when the user types the konami code.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user