0fcb77b991
CI Build & Deploy Pipeline / Staging E2E Tests (push) Failing after 2m50s
CI Build & Deploy Pipeline / Production Browser E2E (push) Failing after 1437h19m24s
CI Build & Deploy Pipeline / Build Production Web Image (push) Failing after 1437h19m26s
CI Build & Deploy Pipeline / Deploy Production (push) Failing after 1437h19m25s
CI Build & Deploy Pipeline / Build Production API Image (push) Failing after 1437h19m26s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 1437h21m16s
CI Build & Deploy Pipeline / Build Staging API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Failing after 1437h51m29s
CI/CD Pipeline / Validate Code Quality And Tests (push) Has been skipped
CI/CD Pipeline / Unit Tests (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
201 lines
6.1 KiB
TypeScript
201 lines
6.1 KiB
TypeScript
/**
|
|
* 绿幕抠像配置面板
|
|
* 5 种颜色预设 + 自定义颜色 + 相似度/边缘平滑/溢色抑制
|
|
*/
|
|
import React, { useCallback } from "react"
|
|
import { Drawer, Switch } from "antd"
|
|
import type { ChromaKeyConfig, ChromaKeyColorPreset } from "../types"
|
|
import {
|
|
DEFAULT_CHROMA_KEY_CONFIG,
|
|
CHROMA_KEY_PRESET_LABELS,
|
|
CHROMA_KEY_PRESET_COLORS,
|
|
} from "../types"
|
|
|
|
interface GreenScreenPanelProps {
|
|
open: boolean
|
|
onClose: () => void
|
|
config: ChromaKeyConfig
|
|
onChange: (config: ChromaKeyConfig) => void
|
|
}
|
|
|
|
/** 预设列表 */
|
|
const PRESET_LIST: ChromaKeyColorPreset[] = ["green", "blue", "red", "pure_green", "soft_green"]
|
|
|
|
const GreenScreenPanel: React.FC<GreenScreenPanelProps> = ({ open, onClose, config, onChange }) => {
|
|
const update = useCallback(
|
|
(partial: Partial<ChromaKeyConfig>) => {
|
|
onChange({ ...config, ...partial })
|
|
},
|
|
[config, onChange],
|
|
)
|
|
|
|
const handleReset = useCallback(() => {
|
|
onChange({ ...DEFAULT_CHROMA_KEY_CONFIG, enabled: config.enabled })
|
|
}, [config.enabled, onChange])
|
|
|
|
/** 选择颜色预设时同步更新 color 字段 */
|
|
const handlePresetSelect = useCallback(
|
|
(preset: ChromaKeyColorPreset) => {
|
|
update({
|
|
color_preset: preset,
|
|
color: CHROMA_KEY_PRESET_COLORS[preset],
|
|
})
|
|
},
|
|
[update],
|
|
)
|
|
|
|
/** 自定义颜色变化时清除预设标记 */
|
|
const handleColorChange = useCallback(
|
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
update({ color: e.target.value })
|
|
},
|
|
[update],
|
|
)
|
|
|
|
return (
|
|
<Drawer
|
|
title="绿幕抠像"
|
|
placement="right"
|
|
width={420}
|
|
open={open}
|
|
onClose={onClose}
|
|
className="green-screen-panel-drawer"
|
|
>
|
|
{/* 顶部开关 */}
|
|
<div className="green-header">
|
|
<span className="green-header-label">启用绿幕抠像</span>
|
|
<Switch
|
|
size="small"
|
|
checked={config.enabled}
|
|
onChange={(checked) => update({ enabled: checked })}
|
|
/>
|
|
</div>
|
|
|
|
{/* 颜色预设 */}
|
|
<div className="green-section">
|
|
<div className="green-section-title">颜色预设</div>
|
|
<div className="green-presets">
|
|
{PRESET_LIST.map((p) => (
|
|
<button
|
|
key={p}
|
|
className={`green-preset-btn${config.color_preset === p ? " active" : ""}`}
|
|
onClick={() => handlePresetSelect(p)}
|
|
>
|
|
<span
|
|
className="green-preset-dot"
|
|
style={{ background: CHROMA_KEY_PRESET_COLORS[p] }}
|
|
/>
|
|
<span className="green-preset-label">{CHROMA_KEY_PRESET_LABELS[p]}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 自定义颜色 */}
|
|
<div className="green-section">
|
|
<div className="green-section-title">自定义颜色</div>
|
|
<div className="green-color-row">
|
|
<input
|
|
type="color"
|
|
className="green-color-picker"
|
|
value={config.color}
|
|
onChange={handleColorChange}
|
|
/>
|
|
<input
|
|
type="text"
|
|
className="green-color-hex"
|
|
value={config.color}
|
|
onChange={handleColorChange}
|
|
placeholder="#00FF00"
|
|
/>
|
|
<div className="green-color-swatch" style={{ background: config.color }} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* 参数调节 */}
|
|
<div className="green-section">
|
|
<div className="green-section-title">参数调节</div>
|
|
|
|
{/* 相似度 */}
|
|
<div className="green-slider-row">
|
|
<div className="green-slider-header">
|
|
<span className="green-slider-label">相似度</span>
|
|
<span className="green-slider-value">{config.similarity}%</span>
|
|
</div>
|
|
<input
|
|
type="range"
|
|
className="green-slider"
|
|
min={0}
|
|
max={100}
|
|
value={config.similarity}
|
|
onChange={(e) => update({ similarity: Number(e.target.value) })}
|
|
/>
|
|
<div className="green-slider-desc">越大容忍的色差范围越广</div>
|
|
</div>
|
|
|
|
{/* 边缘平滑 */}
|
|
<div className="green-slider-row">
|
|
<div className="green-slider-header">
|
|
<span className="green-slider-label">边缘平滑</span>
|
|
<span className="green-slider-value">{config.blend}%</span>
|
|
</div>
|
|
<input
|
|
type="range"
|
|
className="green-slider"
|
|
min={0}
|
|
max={100}
|
|
value={config.blend}
|
|
onChange={(e) => update({ blend: Number(e.target.value) })}
|
|
/>
|
|
<div className="green-slider-desc">越大边缘越柔和自然</div>
|
|
</div>
|
|
|
|
{/* 溢色抑制 */}
|
|
<div className="green-slider-row">
|
|
<div className="green-slider-header">
|
|
<span className="green-slider-label">溢色抑制</span>
|
|
<span className="green-slider-value">{config.spill}%</span>
|
|
</div>
|
|
<input
|
|
type="range"
|
|
className="green-slider"
|
|
min={0}
|
|
max={100}
|
|
value={config.spill}
|
|
onChange={(e) => update({ spill: Number(e.target.value) })}
|
|
/>
|
|
<div className="green-slider-desc">去除边缘颜色溢出</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 预览 */}
|
|
<div className="green-section">
|
|
<div className="green-section-title">效果预览</div>
|
|
<div className="green-preview-box">
|
|
<div className="green-preview-bg" style={{ background: config.color, opacity: 0.3 }} />
|
|
<div className="green-preview-subject">
|
|
<div className="green-preview-circle" />
|
|
<div className="green-preview-text">主体</div>
|
|
</div>
|
|
<div
|
|
className="green-preview-edge"
|
|
style={{
|
|
borderColor: config.color,
|
|
filter: `blur(${config.blend / 10}px)`,
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 底部重置 */}
|
|
<div className="green-footer">
|
|
<button className="green-reset-btn" onClick={handleReset}>
|
|
重置参数
|
|
</button>
|
|
</div>
|
|
</Drawer>
|
|
)
|
|
}
|
|
|
|
export default GreenScreenPanel
|