| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | import invariant from 'invariant'; |
| | import {Group} from 'pts'; |
| | import {EffectFrameContext} from './Effect'; |
| |
|
| | export type MaskCanvas = { |
| | maskCanvas: OffscreenCanvas; |
| | bounds: number[][]; |
| | scaleX: number; |
| | scaleY: number; |
| | }; |
| |
|
| | import {Effects} from '@/common/components/video/effects/Effects'; |
| | import type {CarbonIconType} from '@carbon/icons-react'; |
| | import { |
| | AppleDash, |
| | Asterisk, |
| | Barcode, |
| | CenterCircle, |
| | ColorPalette, |
| | ColorSwitch, |
| | Development, |
| | Erase, |
| | FaceWink, |
| | Humidity, |
| | Image, |
| | Overlay, |
| | TextFont, |
| | } from '@carbon/icons-react'; |
| |
|
| | export type DemoEffect = { |
| | title: string; |
| | Icon: CarbonIconType; |
| | effectName: keyof Effects; |
| | }; |
| |
|
| | export const backgroundEffects: DemoEffect[] = [ |
| | {title: 'Original', Icon: Image, effectName: 'Original'}, |
| | {title: 'Erase', Icon: Erase, effectName: 'EraseBackground'}, |
| | { |
| | title: 'Gradient', |
| | Icon: ColorPalette, |
| | effectName: 'Gradient', |
| | }, |
| | { |
| | title: 'Pixelate', |
| | Icon: Development, |
| | effectName: 'Pixelate', |
| | }, |
| | {title: 'Desaturate', Icon: ColorSwitch, effectName: 'Desaturate'}, |
| | {title: 'Text', Icon: TextFont, effectName: 'BackgroundText'}, |
| | {title: 'Blur', Icon: Humidity, effectName: 'BackgroundBlur'}, |
| | {title: 'Outline', Icon: AppleDash, effectName: 'Sobel'}, |
| | ]; |
| |
|
| | export const highlightEffects: DemoEffect[] = [ |
| | {title: 'Original', Icon: Image, effectName: 'Cutout'}, |
| | {title: 'Erase', Icon: Erase, effectName: 'EraseForeground'}, |
| | {title: 'Gradient', Icon: ColorPalette, effectName: 'VibrantMask'}, |
| | {title: 'Pixelate', Icon: Development, effectName: 'PixelateMask'}, |
| | { |
| | title: 'Overlay', |
| | Icon: Overlay, |
| | effectName: 'Overlay', |
| | }, |
| | {title: 'Emoji', Icon: FaceWink, effectName: 'Replace'}, |
| | {title: 'Burst', Icon: Asterisk, effectName: 'Burst'}, |
| | {title: 'Spotlight', Icon: CenterCircle, effectName: 'Scope'}, |
| | ]; |
| |
|
| | export const moreEffects: DemoEffect[] = [ |
| | {title: 'Noisy', Icon: Barcode, effectName: 'NoisyMask'}, |
| | ]; |
| |
|
| | |
| | |
| | export function copyCanvasContent( |
| | ctx: CanvasRenderingContext2D, |
| | effectContext: EffectFrameContext, |
| | ): OffscreenCanvas { |
| | const {width, height} = effectContext; |
| | const previousContent = ctx.getImageData(0, 0, width, height); |
| | const tempCanvas = new OffscreenCanvas(width, height); |
| | const tempCtx = tempCanvas.getContext('2d'); |
| | tempCtx?.putImageData(previousContent, 0, 0); |
| | return tempCanvas; |
| | } |
| |
|
| | export function isInvalidMask(bound: number[][] | Group) { |
| | return ( |
| | bound[0].length < 2 || |
| | bound[1].length < 2 || |
| | bound[1][0] - bound[0][0] < 1 || |
| | bound[1][1] - bound[0][1] < 1 |
| | ); |
| | } |
| |
|
| | export type MaskRenderingData = { |
| | canvas: OffscreenCanvas; |
| | scale: number[]; |
| | bounds: number[][]; |
| | }; |
| |
|
| | export class EffectLayer { |
| | canvas: OffscreenCanvas; |
| | ctx: OffscreenCanvasRenderingContext2D; |
| | width: number; |
| | height: number; |
| |
|
| | constructor(context: EffectFrameContext) { |
| | this.canvas = new OffscreenCanvas(context.width, context.height); |
| | const ctx = this.canvas.getContext('2d'); |
| | invariant(ctx !== null, 'context cannot be null'); |
| | this.ctx = ctx; |
| | this.width = context.width; |
| | this.height = context.height; |
| | } |
| |
|
| | image(source: CanvasImageSourceWebCodecs) { |
| | this.ctx.drawImage(source, 0, 0); |
| | } |
| |
|
| | filter(filterString: string) { |
| | this.ctx.filter = filterString; |
| | } |
| |
|
| | composite(blend: GlobalCompositeOperation) { |
| | this.ctx.globalCompositeOperation = blend; |
| | } |
| |
|
| | fill(color: string) { |
| | this.ctx.fillStyle = color; |
| | this.ctx.fillRect(0, 0, this.width, this.height); |
| | } |
| |
|
| | clear() { |
| | this.ctx.clearRect(0, 0, this.width, this.height); |
| | } |
| | } |
| |
|