(color: string)
| 25 | const colorProbeCtx = colorProbeCanvas.getContext('2d', { willReadFrequently: true }) |
| 26 | |
| 27 | function parseCssColorToRgba(color: string): RgbaColor | null { |
| 28 | if (!colorProbeCtx) return null |
| 29 | |
| 30 | const ctx = colorProbeCtx |
| 31 | ctx.clearRect(0, 0, 1, 1) |
| 32 | |
| 33 | // 先写入完全透明作为基底,确保读取到 alpha 信息。 |
| 34 | ctx.fillStyle = 'rgba(0, 0, 0, 0)' |
| 35 | ctx.fillRect(0, 0, 1, 1) |
| 36 | |
| 37 | try { |
| 38 | ctx.fillStyle = color |
| 39 | } catch { |
| 40 | return null |
| 41 | } |
| 42 | |
| 43 | ctx.fillRect(0, 0, 1, 1) |
| 44 | const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data |
| 45 | if (a === 0) return null |
| 46 | |
| 47 | return { |
| 48 | r, |
| 49 | g, |
| 50 | b, |
| 51 | a: a / 255, |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | function compositeOver(top: RgbaColor, bottom: RgbaColor): RgbaColor { |
| 56 | const alpha = top.a + bottom.a * (1 - top.a) |
no outgoing calls
no test coverage detected