1import Konva from "konva"
2
3import type { EffectParams } from "./presets"
4
5/* Satu-satunya tempat preset efek dipetakan ke filter Konva (ARCHITECTURE §3:
6 filter bawaan Konva supaya hasil sama antar browser).
7 Konva menyimpan hasil filter di kanvas cache yang ukurannya dihitung di ruang
8 induk node (tidak terpengaruh skala panggung), jadi rasio piksel 1 berarti
9 cache sudah setara 1:1 dengan ruang strip 600 x 1800 dan tetap tajam saat
10 ekspor. */
11
12const CACHE_PIXEL_RATIO = 1
13
14interface FilterSpec {
15 filters: Konva.Filter[]
16 attrs: Record<string, number>
17}
18
19function specFor(params: EffectParams): FilterSpec | null {
20 switch (params.kind) {
21 case "none":
22 return null
23 case "grayscale":
24 return { filters: [Konva.Filters.Grayscale], attrs: {} }
25 case "sepia":
26 return { filters: [Konva.Filters.Sepia], attrs: {} }
27 case "pop":
28 return {
29 filters: [Konva.Filters.HSV, Konva.Filters.Contrast],
30 attrs: { saturation: 1.6, contrast: 1.15 },
31 }
32 case "pixelate":
33 return {
34 filters: [Konva.Filters.Pixelate],
35 attrs: { pixelSize: params.size },
36 }
37 case "invert":
38 return { filters: [Konva.Filters.Invert], attrs: {} }
39 case "soften":
40 return {
41 filters: [Konva.Filters.Blur, Konva.Filters.Brighten],
42 attrs: { blurRadius: 1.2, brightness: 0.08 },
43 }
44 }
45}
46
47export function applyEffect(node: Konva.Image, params: EffectParams): void {
48 const spec = specFor(params)
49 if (spec === null) {
50 node.filters([])
51 node.clearCache()
52 return
53 }
54
55 for (const [name, value] of Object.entries(spec.attrs)) {
56 node.setAttr(name, value)
57 }
58 node.filters(spec.filters)
59 node.cache({ pixelRatio: CACHE_PIXEL_RATIO })
60}
61