mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-30 12:01:20 -08:00
refactor(mask): [PKG-MASK-04] migrate strict types and preserve public consumers
This commit is contained in:
1 parent
aba125262a
commit
aca4bc1cd2
30 files changed
+1848
-72
No files matched your search
@@ -0,0 +1,68 @@
|
||||
import type { BodySegmenter } from '@tensorflow-models/body-segmentation'
|
||||
import type { Active, MaskConfig, MaskOutput } from './types'
|
||||
import { drawMask, toBinaryMask } from './sdk'
|
||||
|
||||
export function makeWhiteTransparent(imageData: ImageData): ImageData {
|
||||
const data = imageData.data
|
||||
// Native ImageData stores complete four-byte RGBA pixels.
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
if (data[i]! > 250 && data[i + 1]! > 250 && data[i + 2]! > 250)
|
||||
data[i + 3] = 0
|
||||
}
|
||||
return imageData
|
||||
}
|
||||
|
||||
export function createOutput(layer: HTMLElement): MaskOutput {
|
||||
const canvas = document.createElement('canvas')
|
||||
try {
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (!ctx)
|
||||
throw new Error('Danmuku mask requires a 2D canvas context')
|
||||
Object.assign(layer.style, {
|
||||
maskMode: 'alpha',
|
||||
maskSize: 'contain',
|
||||
maskRepeat: 'no-repeat',
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
})
|
||||
return { canvas, ctx }
|
||||
}
|
||||
catch (error) {
|
||||
canvas.width = 0
|
||||
canvas.height = 0
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function renderMask(output: MaskOutput, video: HTMLVideoElement, layer: HTMLElement, segmenter: BodySegmenter, config: MaskConfig, active: Active): Promise<void> {
|
||||
const { canvas, ctx } = output
|
||||
canvas.width = video.videoWidth
|
||||
canvas.height = video.videoHeight
|
||||
const segmentation = await segmenter.segmentPeople(video)
|
||||
if (!active() || !segmentation || !segmentation.length)
|
||||
return
|
||||
const mask = await toBinaryMask(
|
||||
segmentation,
|
||||
{ r: 255, g: 255, b: 255, a: 255 },
|
||||
{ r: 0, g: 0, b: 0, a: 255 },
|
||||
config.drawContour,
|
||||
config.foregroundThreshold,
|
||||
)
|
||||
if (!active())
|
||||
return
|
||||
await drawMask(canvas, video, mask, config.opacity, config.maskBlurAmount)
|
||||
if (!active())
|
||||
return
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
||||
ctx.putImageData(makeWhiteTransparent(imageData), 0, 0)
|
||||
const url = canvas.toDataURL()
|
||||
if (active())
|
||||
layer.style.maskImage = `url(${url})`
|
||||
}
|
||||
|
||||
export function releaseOutput(output: MaskOutput | null): void {
|
||||
if (output) {
|
||||
output.canvas.width = 0
|
||||
output.canvas.height = 0
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user