2026-05-21 00:02:12 +07:00
|
|
|
import type { LayerEffect } from "@pien-studio/types";
|
|
|
|
|
import type { EffectRenderer, EffectRenderContext } from "./types";
|
|
|
|
|
import { faceBlurRenderer } from "./face-blur";
|
|
|
|
|
|
|
|
|
|
const renderers: EffectRenderer[] = [faceBlurRenderer];
|
|
|
|
|
|
|
|
|
|
const effectRendererRegistry = new Map<string, EffectRenderer>(
|
|
|
|
|
renderers.map((r) => [r.kind, r]),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export function getEffectRenderer(kind: string): EffectRenderer | undefined {
|
|
|
|
|
return effectRendererRegistry.get(kind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function renderLayerWithEffects(
|
|
|
|
|
ctx: CanvasRenderingContext2D,
|
|
|
|
|
image: HTMLImageElement,
|
|
|
|
|
effects: LayerEffect[],
|
|
|
|
|
targetWidth: number,
|
|
|
|
|
targetHeight: number,
|
|
|
|
|
): void {
|
|
|
|
|
const activeEffects = effects.filter((e) => {
|
|
|
|
|
if (e.enabled === false) return false;
|
|
|
|
|
return effectRendererRegistry.get(e.kind) !== undefined;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (activeEffects.length === 0) {
|
|
|
|
|
ctx.drawImage(image, 0, 0, targetWidth, targetHeight);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-31 03:03:49 +07:00
|
|
|
const context: EffectRenderContext = {
|
|
|
|
|
ctx,
|
|
|
|
|
image,
|
|
|
|
|
targetWidth,
|
|
|
|
|
targetHeight,
|
|
|
|
|
};
|
2026-05-21 00:02:12 +07:00
|
|
|
|
2026-05-31 03:03:49 +07:00
|
|
|
// The first effect owns the base image draw; later effects only overlay their changes.
|
2026-05-21 00:02:12 +07:00
|
|
|
const first = activeEffects[0];
|
|
|
|
|
const firstRenderer = effectRendererRegistry.get(first.kind);
|
2026-05-24 21:05:21 +07:00
|
|
|
firstRenderer?.renderLayer(context, first);
|
2026-05-21 00:02:12 +07:00
|
|
|
|
|
|
|
|
for (let i = 1; i < activeEffects.length; i++) {
|
|
|
|
|
const effect = activeEffects[i];
|
|
|
|
|
const renderer = effectRendererRegistry.get(effect.kind);
|
2026-05-24 21:05:21 +07:00
|
|
|
renderer?.render(context, effect);
|
2026-05-21 00:02:12 +07:00
|
|
|
}
|
|
|
|
|
}
|