mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-15 00:56:16 -08:00
89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
type SamplingSource = HTMLVideoElement | HTMLCanvasElement
|
|
|
|
function isCanvas(source: SamplingSource): source is HTMLCanvasElement {
|
|
return source.nodeName === 'CANVAS'
|
|
}
|
|
|
|
export function createColorSampler(canvas: HTMLCanvasElement, video: SamplingSource, createCanvas: () => HTMLCanvasElement) {
|
|
let context: CanvasRenderingContext2D | null
|
|
try {
|
|
context = canvas.getContext('2d')
|
|
canvas.width = 3
|
|
canvas.height = 3
|
|
}
|
|
catch (error) {
|
|
canvas.width = 0
|
|
canvas.height = 0
|
|
throw error
|
|
}
|
|
let destroyed = false
|
|
let replaceCanvas = false
|
|
|
|
function read(active: () => boolean): string[] | null {
|
|
if (destroyed || !active())
|
|
return null
|
|
// A canvas proxy's output buffer can differ from its forwarded video dimensions.
|
|
const canvasOutput = isCanvas(video)
|
|
const width = canvasOutput ? video.width : video.videoWidth
|
|
const height = canvasOutput ? video.height : video.videoHeight
|
|
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0)
|
|
return null
|
|
const w = width / 3
|
|
const h = height / 3
|
|
const colors: string[] = []
|
|
try {
|
|
if (replaceCanvas) {
|
|
const replacement = createCanvas()
|
|
if (destroyed || !active()) {
|
|
replacement.width = 0
|
|
replacement.height = 0
|
|
return null
|
|
}
|
|
canvas = replacement
|
|
context = null
|
|
context = canvas.getContext('2d')
|
|
if (destroyed || !active()) {
|
|
canvas.width = 0
|
|
canvas.height = 0
|
|
return null
|
|
}
|
|
canvas.width = 3
|
|
canvas.height = 3
|
|
replaceCanvas = false
|
|
}
|
|
if (!context)
|
|
return null
|
|
for (let row = 0; row < 3; row++) {
|
|
for (let column = 0; column < 3; column++) {
|
|
if (destroyed || !active())
|
|
return null
|
|
context.drawImage(video, column * w, row * h, w, h, 0, 0, 1, 1)
|
|
if (destroyed || !active())
|
|
return null
|
|
const [r, g, b] = context.getImageData(0, 0, 1, 1).data
|
|
colors.push(`rgb(${r}, ${g}, ${b})`)
|
|
}
|
|
}
|
|
return colors
|
|
}
|
|
catch {
|
|
// Firefox can retain taint after a size reset; replace on the next eligible sample.
|
|
if (!destroyed) {
|
|
replaceCanvas = true
|
|
canvas.width = 0
|
|
canvas.height = 0
|
|
}
|
|
return null
|
|
}
|
|
}
|
|
|
|
function destroy() {
|
|
if (destroyed)
|
|
return
|
|
destroyed = true
|
|
canvas.width = 0
|
|
canvas.height = 0
|
|
}
|
|
return { read, destroy }
|
|
}
|