Compare commits

..

7 Commits

Author SHA1 Message Date
徐涛
60d1f82e09 调整平均值的显示方式。 2025-01-14 10:08:06 +08:00
徐涛
bd3f6d02ba 增加Tint和Shade的Mix系数反算。 2025-01-14 09:08:43 +08:00
徐涛
67aca6926f 修正shade scale反算。 2025-01-14 09:08:11 +08:00
徐涛
3ad5babacb 更新生成的WASM包。 2025-01-14 06:08:25 +08:00
徐涛
665821700b 更正逆向计算时当颜色分量为零时的处理。 2025-01-14 06:08:01 +08:00
徐涛
2cb39adc8e 生成可用的WASM包。 2025-01-14 06:03:15 +08:00
徐涛
7c91f50173 增加在RGB颜色空间逆向计算颜色混合比例的功能。 2025-01-14 06:02:49 +08:00
10 changed files with 410 additions and 38 deletions

View File

@ -15,6 +15,7 @@ use wasm_bindgen::prelude::*;
mod color_card;
mod color_differ;
mod errors;
mod reversing;
#[wasm_bindgen]
pub fn represent_rgb(color: &str) -> Result<Box<[u8]>, errors::ColorError> {
@ -496,3 +497,37 @@ pub fn differ_in_oklch(
);
Ok(oklch.difference(&other_oklch))
}
#[wasm_bindgen]
pub fn tint_scale(
basic_color: &str,
mixed_color: &str,
) -> Result<reversing::MixReversing, errors::ColorError> {
let basic_color = Srgb::from_str(basic_color)
.map_err(|_| errors::ColorError::UnrecogniazedRGB(basic_color.to_string()))?
.into_format::<f32>();
let mixed_color = Srgb::from_str(mixed_color)
.map_err(|_| errors::ColorError::UnrecogniazedRGB(mixed_color.to_string()))?
.into_format::<f32>();
Ok(reversing::MixReversing::from_tint_rgb(
basic_color,
mixed_color,
))
}
#[wasm_bindgen]
pub fn shade_scale(
basic_color: &str,
mixed_color: &str,
) -> Result<reversing::MixReversing, errors::ColorError> {
let basic_color = Srgb::from_str(basic_color)
.map_err(|_| errors::ColorError::UnrecogniazedRGB(basic_color.to_string()))?
.into_format::<f32>();
let mixed_color = Srgb::from_str(mixed_color)
.map_err(|_| errors::ColorError::UnrecogniazedRGB(mixed_color.to_string()))?
.into_format::<f32>();
Ok(reversing::MixReversing::from_shade_rgb(
basic_color,
mixed_color,
))
}

View File

@ -0,0 +1,66 @@
use palette::rgb::Rgb;
use serde::Serialize;
use wasm_bindgen::prelude::wasm_bindgen;
#[derive(Debug, Clone, Copy, Serialize)]
#[wasm_bindgen]
pub struct MixReversing {
pub r_factor: f32,
pub g_factor: f32,
pub b_factor: f32,
pub average: f32,
}
impl MixReversing {
pub fn from_tint_rgb(basic_color: Rgb, mixed_result: Rgb) -> Self {
let r_factor = if basic_color.red == 1.0 {
0.0
} else {
(mixed_result.red - basic_color.red) / (1.0 - basic_color.red)
};
let g_factor = if basic_color.green == 1.0 {
0.0
} else {
(mixed_result.green - basic_color.green) / (1.0 - basic_color.green)
};
let b_factor = if basic_color.blue == 1.0 {
0.0
} else {
(mixed_result.blue - basic_color.blue) / (1.0 - basic_color.blue)
};
let average = (r_factor + g_factor + b_factor) / 3.0;
MixReversing {
r_factor,
g_factor,
b_factor,
average,
}
}
pub fn from_shade_rgb(basic_color: Rgb, mixed_result: Rgb) -> Self {
let r_factor = if basic_color.red == 0.0 {
0.0
} else {
(mixed_result.red - basic_color.red) / (0.0 - basic_color.red)
};
let g_factor = if basic_color.green == 0.0 {
0.0
} else {
(mixed_result.green - basic_color.green) / (0.0 - basic_color.green)
};
let b_factor = if basic_color.blue == 0.0 {
0.0
} else {
(mixed_result.blue - basic_color.blue) / (0.0 - basic_color.blue)
};
let average = (r_factor + g_factor + b_factor) / 3.0;
MixReversing {
r_factor,
g_factor,
b_factor,
average,
}
}
}

View File

@ -34,6 +34,8 @@ export function differ_in_rgb(color: string, other: string): RGBDifference;
export function differ_in_hsl(color: string, other: string): HSLDifference;
export function differ_in_hct(color: string, other: string): HctDiffference;
export function differ_in_oklch(color: string, other: string): OklchDifference;
export function tint_scale(basic_color: string, mixed_color: string): MixReversing;
export function shade_scale(basic_color: string, mixed_color: string): MixReversing;
export class Differ {
private constructor();
free(): void;
@ -54,6 +56,14 @@ export class HctDiffference {
chroma: Differ;
lightness: Differ;
}
export class MixReversing {
private constructor();
free(): void;
r_factor: number;
g_factor: number;
b_factor: number;
average: number;
}
export class OklchDifference {
private constructor();
free(): void;
@ -107,25 +117,17 @@ export interface InitOutput {
readonly differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_oklchdifference_free: (a: number, b: number) => void;
readonly __wbg_get_oklchdifference_hue: (a: number) => number;
readonly __wbg_set_oklchdifference_hue: (a: number, b: number) => void;
readonly __wbg_get_oklchdifference_chroma: (a: number) => number;
readonly __wbg_set_oklchdifference_chroma: (a: number, b: number) => void;
readonly __wbg_get_oklchdifference_lightness: (a: number) => number;
readonly __wbg_set_oklchdifference_lightness: (a: number, b: number) => void;
readonly __wbg_differ_free: (a: number, b: number) => void;
readonly __wbg_get_differ_delta: (a: number) => number;
readonly __wbg_set_differ_delta: (a: number, b: number) => void;
readonly __wbg_get_differ_percent: (a: number) => number;
readonly __wbg_set_differ_percent: (a: number, b: number) => void;
readonly __wbg_hctdiffference_free: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_hue: (a: number) => number;
readonly __wbg_set_hctdiffference_hue: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_chroma: (a: number) => number;
readonly __wbg_set_hctdiffference_chroma: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_lightness: (a: number) => number;
readonly __wbg_set_hctdiffference_lightness: (a: number, b: number) => void;
readonly tint_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly shade_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_mixreversing_free: (a: number, b: number) => void;
readonly __wbg_get_mixreversing_r_factor: (a: number) => number;
readonly __wbg_set_mixreversing_r_factor: (a: number, b: number) => void;
readonly __wbg_get_mixreversing_g_factor: (a: number) => number;
readonly __wbg_set_mixreversing_g_factor: (a: number, b: number) => void;
readonly __wbg_get_mixreversing_b_factor: (a: number) => number;
readonly __wbg_set_mixreversing_b_factor: (a: number, b: number) => void;
readonly __wbg_get_mixreversing_average: (a: number) => number;
readonly __wbg_set_mixreversing_average: (a: number, b: number) => void;
readonly __wbg_rgbdifference_free: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_r: (a: number) => number;
readonly __wbg_set_rgbdifference_r: (a: number, b: number) => void;
@ -133,6 +135,25 @@ export interface InitOutput {
readonly __wbg_set_rgbdifference_g: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_b: (a: number) => number;
readonly __wbg_set_rgbdifference_b: (a: number, b: number) => void;
readonly __wbg_differ_free: (a: number, b: number) => void;
readonly __wbg_get_differ_delta: (a: number) => number;
readonly __wbg_set_differ_delta: (a: number, b: number) => void;
readonly __wbg_get_differ_percent: (a: number) => number;
readonly __wbg_set_differ_percent: (a: number, b: number) => void;
readonly __wbg_oklchdifference_free: (a: number, b: number) => void;
readonly __wbg_get_oklchdifference_hue: (a: number) => number;
readonly __wbg_set_oklchdifference_hue: (a: number, b: number) => void;
readonly __wbg_get_oklchdifference_chroma: (a: number) => number;
readonly __wbg_set_oklchdifference_chroma: (a: number, b: number) => void;
readonly __wbg_get_oklchdifference_lightness: (a: number) => number;
readonly __wbg_set_oklchdifference_lightness: (a: number, b: number) => void;
readonly __wbg_hctdiffference_free: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_hue: (a: number) => number;
readonly __wbg_set_hctdiffference_hue: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_chroma: (a: number) => number;
readonly __wbg_set_hctdiffference_chroma: (a: number, b: number) => void;
readonly __wbg_get_hctdiffference_lightness: (a: number) => number;
readonly __wbg_set_hctdiffference_lightness: (a: number, b: number) => void;
readonly __wbg_hsldifference_free: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_hue: (a: number) => number;
readonly __wbg_set_hsldifference_hue: (a: number, b: number) => void;

View File

@ -807,6 +807,40 @@ export function differ_in_oklch(color, other) {
return OklchDifference.__wrap(ret[0]);
}
/**
* @param {string} basic_color
* @param {string} mixed_color
* @returns {MixReversing}
*/
export function tint_scale(basic_color, mixed_color) {
const ptr0 = passStringToWasm0(basic_color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(mixed_color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.tint_scale(ptr0, len0, ptr1, len1);
if (ret[2]) {
throw takeFromExternrefTable0(ret[1]);
}
return MixReversing.__wrap(ret[0]);
}
/**
* @param {string} basic_color
* @param {string} mixed_color
* @returns {MixReversing}
*/
export function shade_scale(basic_color, mixed_color) {
const ptr0 = passStringToWasm0(basic_color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ptr1 = passStringToWasm0(mixed_color, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
const ret = wasm.shade_scale(ptr0, len0, ptr1, len1);
if (ret[2]) {
throw takeFromExternrefTable0(ret[1]);
}
return MixReversing.__wrap(ret[0]);
}
function _assertClass(instance, klass) {
if (!(instance instanceof klass)) {
throw new Error(`expected instance of ${klass.name}`);
@ -1010,6 +1044,85 @@ export class HctDiffference {
}
}
const MixReversingFinalization = (typeof FinalizationRegistry === 'undefined')
? { register: () => {}, unregister: () => {} }
: new FinalizationRegistry(ptr => wasm.__wbg_mixreversing_free(ptr >>> 0, 1));
export class MixReversing {
static __wrap(ptr) {
ptr = ptr >>> 0;
const obj = Object.create(MixReversing.prototype);
obj.__wbg_ptr = ptr;
MixReversingFinalization.register(obj, obj.__wbg_ptr, obj);
return obj;
}
__destroy_into_raw() {
const ptr = this.__wbg_ptr;
this.__wbg_ptr = 0;
MixReversingFinalization.unregister(this);
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_mixreversing_free(ptr, 0);
}
/**
* @returns {number}
*/
get r_factor() {
const ret = wasm.__wbg_get_mixreversing_r_factor(this.__wbg_ptr);
return ret;
}
/**
* @param {number} arg0
*/
set r_factor(arg0) {
wasm.__wbg_set_mixreversing_r_factor(this.__wbg_ptr, arg0);
}
/**
* @returns {number}
*/
get g_factor() {
const ret = wasm.__wbg_get_mixreversing_g_factor(this.__wbg_ptr);
return ret;
}
/**
* @param {number} arg0
*/
set g_factor(arg0) {
wasm.__wbg_set_mixreversing_g_factor(this.__wbg_ptr, arg0);
}
/**
* @returns {number}
*/
get b_factor() {
const ret = wasm.__wbg_get_mixreversing_b_factor(this.__wbg_ptr);
return ret;
}
/**
* @param {number} arg0
*/
set b_factor(arg0) {
wasm.__wbg_set_mixreversing_b_factor(this.__wbg_ptr, arg0);
}
/**
* @returns {number}
*/
get average() {
const ret = wasm.__wbg_get_mixreversing_average(this.__wbg_ptr);
return ret;
}
/**
* @param {number} arg0
*/
set average(arg0) {
wasm.__wbg_set_mixreversing_average(this.__wbg_ptr, arg0);
}
}
const OklchDifferenceFinalization = (typeof FinalizationRegistry === 'undefined')
? { register: () => {}, unregister: () => {} }
: new FinalizationRegistry(ptr => wasm.__wbg_oklchdifference_free(ptr >>> 0, 1));

View File

@ -35,25 +35,17 @@ export const differ_in_rgb: (a: number, b: number, c: number, d: number) => [num
export const differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_hct: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_oklch: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_oklchdifference_free: (a: number, b: number) => void;
export const __wbg_get_oklchdifference_hue: (a: number) => number;
export const __wbg_set_oklchdifference_hue: (a: number, b: number) => void;
export const __wbg_get_oklchdifference_chroma: (a: number) => number;
export const __wbg_set_oklchdifference_chroma: (a: number, b: number) => void;
export const __wbg_get_oklchdifference_lightness: (a: number) => number;
export const __wbg_set_oklchdifference_lightness: (a: number, b: number) => void;
export const __wbg_differ_free: (a: number, b: number) => void;
export const __wbg_get_differ_delta: (a: number) => number;
export const __wbg_set_differ_delta: (a: number, b: number) => void;
export const __wbg_get_differ_percent: (a: number) => number;
export const __wbg_set_differ_percent: (a: number, b: number) => void;
export const __wbg_hctdiffference_free: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_hue: (a: number) => number;
export const __wbg_set_hctdiffference_hue: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_chroma: (a: number) => number;
export const __wbg_set_hctdiffference_chroma: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_lightness: (a: number) => number;
export const __wbg_set_hctdiffference_lightness: (a: number, b: number) => void;
export const tint_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
export const shade_scale: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_mixreversing_free: (a: number, b: number) => void;
export const __wbg_get_mixreversing_r_factor: (a: number) => number;
export const __wbg_set_mixreversing_r_factor: (a: number, b: number) => void;
export const __wbg_get_mixreversing_g_factor: (a: number) => number;
export const __wbg_set_mixreversing_g_factor: (a: number, b: number) => void;
export const __wbg_get_mixreversing_b_factor: (a: number) => number;
export const __wbg_set_mixreversing_b_factor: (a: number, b: number) => void;
export const __wbg_get_mixreversing_average: (a: number) => number;
export const __wbg_set_mixreversing_average: (a: number, b: number) => void;
export const __wbg_rgbdifference_free: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_r: (a: number) => number;
export const __wbg_set_rgbdifference_r: (a: number, b: number) => void;
@ -61,6 +53,25 @@ export const __wbg_get_rgbdifference_g: (a: number) => number;
export const __wbg_set_rgbdifference_g: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_b: (a: number) => number;
export const __wbg_set_rgbdifference_b: (a: number, b: number) => void;
export const __wbg_differ_free: (a: number, b: number) => void;
export const __wbg_get_differ_delta: (a: number) => number;
export const __wbg_set_differ_delta: (a: number, b: number) => void;
export const __wbg_get_differ_percent: (a: number) => number;
export const __wbg_set_differ_percent: (a: number, b: number) => void;
export const __wbg_oklchdifference_free: (a: number, b: number) => void;
export const __wbg_get_oklchdifference_hue: (a: number) => number;
export const __wbg_set_oklchdifference_hue: (a: number, b: number) => void;
export const __wbg_get_oklchdifference_chroma: (a: number) => number;
export const __wbg_set_oklchdifference_chroma: (a: number, b: number) => void;
export const __wbg_get_oklchdifference_lightness: (a: number) => number;
export const __wbg_set_oklchdifference_lightness: (a: number, b: number) => void;
export const __wbg_hctdiffference_free: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_hue: (a: number) => number;
export const __wbg_set_hctdiffference_hue: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_chroma: (a: number) => number;
export const __wbg_set_hctdiffference_chroma: (a: number, b: number) => void;
export const __wbg_get_hctdiffference_lightness: (a: number) => number;
export const __wbg_set_hctdiffference_lightness: (a: number, b: number) => void;
export const __wbg_hsldifference_free: (a: number, b: number) => void;
export const __wbg_get_hsldifference_hue: (a: number) => number;
export const __wbg_set_hsldifference_hue: (a: number, b: number) => void;

View File

@ -4,6 +4,9 @@
flex-direction: row;
align-items: stretch;
gap: var(--spacing-m);
&:not(:first-of-type) {
margin-top: var(--spacing-s);
}
.element {
display: flex;
flex-direction: row;
@ -12,6 +15,10 @@
.element_name {
font-size: var(--font-size-xxl);
font-weight: bold;
&.mean {
border-top: 2px solid var(--color-fg);
padding-top: var(--spacing-xxs);
}
}
.element_values {
display: flex;
@ -20,6 +27,11 @@
font-size: var(--font-size-xs);
line-height: var(--font-size-xs);
}
.element_value {
align-self: flex-end;
font-size: var(--font-size-s);
line-height: var(--font-size-s);
}
}
}
}

View File

@ -0,0 +1,55 @@
import cx from 'clsx';
import { useMemo } from 'react';
import { MixReversing } from '../../color_functions/color_module';
import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props';
const defaultMixResult: MixReversing = {
r_factor: 0,
g_factor: 0,
b_factor: 0,
average: 0,
};
export function ShadeScale({ basic = '000000', compare = '000000' }: CompareMethodProps) {
const { colorFn } = useColorFunction();
const mixFactors = useMemo(() => {
if (!colorFn) {
return defaultMixResult;
}
try {
const factor = colorFn.shade_scale(basic, compare);
return factor;
} catch (e) {
console.error('[Reversing Tint]', e);
}
return defaultMixResult;
}, [basic, compare]);
return (
<div>
<h6>Compare in RGB Shade.</h6>
<div className={styles.elements}>
<div className={styles.element}>
<div className={styles.element_name}>R</div>
<div className={styles.element_value}>{(mixFactors.r_factor * 100).toFixed(2)}%</div>
</div>
<div className={styles.element}>
<div className={styles.element_name}>G</div>
<div className={styles.element_value}>{(mixFactors.g_factor * 100).toFixed(2)}%</div>
</div>
<div className={styles.element}>
<div className={styles.element_name}>B</div>
<div className={styles.element_value}>{(mixFactors.b_factor * 100).toFixed(2)}%</div>
</div>
</div>
<div className={styles.elements}>
<div className={styles.element}>
<div className={cx(styles.element_name, styles.mean)}>F</div>
<div className={styles.element_value}>{(mixFactors.average * 100).toFixed(2)}%</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,55 @@
import cx from 'clsx';
import { useMemo } from 'react';
import { MixReversing } from '../../color_functions/color_module';
import { useColorFunction } from '../../ColorFunctionContext';
import styles from './CompareLayout.module.css';
import { CompareMethodProps } from './share-props';
const defaultMixResult: MixReversing = {
r_factor: 0,
g_factor: 0,
b_factor: 0,
average: 0,
};
export function TintScale({ basic = '000000', compare = '000000' }: CompareMethodProps) {
const { colorFn } = useColorFunction();
const mixFactors = useMemo(() => {
if (!colorFn) {
return defaultMixResult;
}
try {
const factor = colorFn.tint_scale(basic, compare);
return factor;
} catch (e) {
console.error('[Reversing Tint]', e);
}
return defaultMixResult;
}, [basic, compare]);
return (
<div>
<h6>Compare in RGB Tint.</h6>
<div className={styles.elements}>
<div className={styles.element}>
<div className={styles.element_name}>R</div>
<div className={styles.element_value}>{(mixFactors.r_factor * 100).toFixed(2)}%</div>
</div>
<div className={styles.element}>
<div className={styles.element_name}>G</div>
<div className={styles.element_value}>{(mixFactors.g_factor * 100).toFixed(2)}%</div>
</div>
<div className={styles.element}>
<div className={styles.element_name}>B</div>
<div className={styles.element_value}>{(mixFactors.b_factor * 100).toFixed(2)}%</div>
</div>
</div>
<div className={styles.elements}>
<div className={styles.element}>
<div className={cx(styles.element_name, styles.mean)}>F</div>
<div className={styles.element_value}>{(mixFactors.average * 100).toFixed(2)}%</div>
</div>
</div>
</div>
);
}

View File

@ -6,6 +6,8 @@ import { HCTCompare } from '../page-components/color-compare/HCTCompare';
import { HSLCompare } from '../page-components/color-compare/HSLCompare';
import { OklchCompare } from '../page-components/color-compare/OKLCHCompare';
import { RGBCompare } from '../page-components/color-compare/RGBCompare';
import { ShadeScale } from '../page-components/color-compare/ShadeScale';
import { TintScale } from '../page-components/color-compare/TintScale';
import styles from './Compare.module.css';
export function ColorCompare() {
@ -36,6 +38,8 @@ export function ColorCompare() {
<HSLCompare basic={basicColor} compare={compareColor} />
<HCTCompare basic={basicColor} compare={compareColor} />
<OklchCompare basic={basicColor} compare={compareColor} />
<TintScale basic={basicColor} compare={compareColor} />
<ShadeScale basic={basicColor} compare={compareColor} />
</div>
</div>
</ScrollArea>