@swf2es/player 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/package.json +7 -7
  2. package/dist/audio.d.ts +0 -22
  3. package/dist/audio.d.ts.map +0 -1
  4. package/dist/audio.js +0 -106
  5. package/dist/audio.js.map +0 -1
  6. package/dist/bitmap-filters.d.ts +0 -29
  7. package/dist/bitmap-filters.d.ts.map +0 -1
  8. package/dist/bitmap-filters.js +0 -906
  9. package/dist/bitmap-filters.js.map +0 -1
  10. package/dist/bitmap-ops.d.ts +0 -113
  11. package/dist/bitmap-ops.d.ts.map +0 -1
  12. package/dist/bitmap-ops.js +0 -725
  13. package/dist/bitmap-ops.js.map +0 -1
  14. package/dist/bitmap.d.ts +0 -98
  15. package/dist/bitmap.d.ts.map +0 -1
  16. package/dist/bitmap.js +0 -314
  17. package/dist/bitmap.js.map +0 -1
  18. package/dist/bounds.d.ts +0 -26
  19. package/dist/bounds.d.ts.map +0 -1
  20. package/dist/bounds.js +0 -300
  21. package/dist/bounds.js.map +0 -1
  22. package/dist/color.d.ts +0 -7
  23. package/dist/color.d.ts.map +0 -1
  24. package/dist/color.js +0 -42
  25. package/dist/color.js.map +0 -1
  26. package/dist/display.d.ts +0 -425
  27. package/dist/display.d.ts.map +0 -1
  28. package/dist/display.js +0 -1274
  29. package/dist/display.js.map +0 -1
  30. package/dist/drawing.d.ts +0 -52
  31. package/dist/drawing.d.ts.map +0 -1
  32. package/dist/drawing.js +0 -204
  33. package/dist/drawing.js.map +0 -1
  34. package/dist/filters.d.ts +0 -54
  35. package/dist/filters.d.ts.map +0 -1
  36. package/dist/filters.js +0 -155
  37. package/dist/filters.js.map +0 -1
  38. package/dist/fonts.d.ts +0 -23
  39. package/dist/fonts.d.ts.map +0 -1
  40. package/dist/fonts.js +0 -91
  41. package/dist/fonts.js.map +0 -1
  42. package/dist/geometry.d.ts +0 -21
  43. package/dist/geometry.d.ts.map +0 -1
  44. package/dist/geometry.js +0 -76
  45. package/dist/geometry.js.map +0 -1
  46. package/dist/gradients.d.ts +0 -29
  47. package/dist/gradients.d.ts.map +0 -1
  48. package/dist/gradients.js +0 -116
  49. package/dist/gradients.js.map +0 -1
  50. package/dist/images.d.ts +0 -22
  51. package/dist/images.d.ts.map +0 -1
  52. package/dist/images.js +0 -147
  53. package/dist/images.js.map +0 -1
  54. package/dist/input.d.ts +0 -79
  55. package/dist/input.d.ts.map +0 -1
  56. package/dist/input.js +0 -366
  57. package/dist/input.js.map +0 -1
  58. package/dist/keyboard.d.ts +0 -97
  59. package/dist/keyboard.d.ts.map +0 -1
  60. package/dist/keyboard.js +0 -583
  61. package/dist/keyboard.js.map +0 -1
  62. package/dist/morph.d.ts +0 -17
  63. package/dist/morph.d.ts.map +0 -1
  64. package/dist/morph.js +0 -218
  65. package/dist/morph.js.map +0 -1
  66. package/dist/pixi-blend.d.ts +0 -7
  67. package/dist/pixi-blend.d.ts.map +0 -1
  68. package/dist/pixi-blend.js +0 -253
  69. package/dist/pixi-blend.js.map +0 -1
  70. package/dist/pixi-color.d.ts +0 -54
  71. package/dist/pixi-color.d.ts.map +0 -1
  72. package/dist/pixi-color.js +0 -336
  73. package/dist/pixi-color.js.map +0 -1
  74. package/dist/pixi-filters.d.ts +0 -40
  75. package/dist/pixi-filters.d.ts.map +0 -1
  76. package/dist/pixi-filters.js +0 -953
  77. package/dist/pixi-filters.js.map +0 -1
  78. package/dist/pixi-resolve.d.ts +0 -4
  79. package/dist/pixi-resolve.d.ts.map +0 -1
  80. package/dist/pixi-resolve.js +0 -76
  81. package/dist/pixi-resolve.js.map +0 -1
  82. package/dist/pixi.d.ts +0 -219
  83. package/dist/pixi.d.ts.map +0 -1
  84. package/dist/pixi.js +0 -2169
  85. package/dist/pixi.js.map +0 -1
  86. package/dist/playerglobal/flash/filters/filters.d.ts +0 -26
  87. package/dist/playerglobal/flash/filters/filters.d.ts.map +0 -1
  88. package/dist/playerglobal/flash/filters/filters.js +0 -287
  89. package/dist/playerglobal/flash/filters/filters.js.map +0 -1
  90. package/dist/playerglobal/flash/system/FSCommand.d.ts +0 -4
  91. package/dist/playerglobal/flash/system/FSCommand.d.ts.map +0 -1
  92. package/dist/playerglobal/flash/system/FSCommand.js +0 -18
  93. package/dist/playerglobal/flash/system/FSCommand.js.map +0 -1
  94. package/dist/playerglobal/natives.d.ts +0 -10
  95. package/dist/playerglobal/natives.d.ts.map +0 -1
  96. package/dist/playerglobal/natives.js +0 -53
  97. package/dist/playerglobal/natives.js.map +0 -1
  98. package/dist/png.d.ts +0 -4
  99. package/dist/png.d.ts.map +0 -1
  100. package/dist/png.js +0 -140
  101. package/dist/png.js.map +0 -1
  102. package/dist/render/art.d.ts +0 -148
  103. package/dist/render/art.d.ts.map +0 -1
  104. package/dist/render/art.js +0 -575
  105. package/dist/render/art.js.map +0 -1
  106. package/dist/render/batchers.d.ts +0 -23
  107. package/dist/render/batchers.d.ts.map +0 -1
  108. package/dist/render/batchers.js +0 -52
  109. package/dist/render/batchers.js.map +0 -1
  110. package/dist/render/bitmaps.d.ts +0 -117
  111. package/dist/render/bitmaps.d.ts.map +0 -1
  112. package/dist/render/bitmaps.js +0 -422
  113. package/dist/render/bitmaps.js.map +0 -1
  114. package/dist/render/blend.d.ts +0 -37
  115. package/dist/render/blend.d.ts.map +0 -1
  116. package/dist/render/blend.js +0 -195
  117. package/dist/render/blend.js.map +0 -1
  118. package/dist/render/color.d.ts +0 -111
  119. package/dist/render/color.d.ts.map +0 -1
  120. package/dist/render/color.js +0 -533
  121. package/dist/render/color.js.map +0 -1
  122. package/dist/render/compositing.d.ts +0 -77
  123. package/dist/render/compositing.d.ts.map +0 -1
  124. package/dist/render/compositing.js +0 -188
  125. package/dist/render/compositing.js.map +0 -1
  126. package/dist/render/filters.d.ts +0 -98
  127. package/dist/render/filters.d.ts.map +0 -1
  128. package/dist/render/filters.js +0 -1326
  129. package/dist/render/filters.js.map +0 -1
  130. package/dist/render/hooks.d.ts +0 -4
  131. package/dist/render/hooks.d.ts.map +0 -1
  132. package/dist/render/hooks.js +0 -48
  133. package/dist/render/hooks.js.map +0 -1
  134. package/dist/render/node.d.ts +0 -139
  135. package/dist/render/node.d.ts.map +0 -1
  136. package/dist/render/node.js +0 -59
  137. package/dist/render/node.js.map +0 -1
  138. package/dist/render/patches.d.ts +0 -54
  139. package/dist/render/patches.d.ts.map +0 -1
  140. package/dist/render/patches.js +0 -154
  141. package/dist/render/patches.js.map +0 -1
  142. package/dist/render/planes.d.ts +0 -74
  143. package/dist/render/planes.d.ts.map +0 -1
  144. package/dist/render/planes.js +0 -267
  145. package/dist/render/planes.js.map +0 -1
  146. package/dist/render/pointer.d.ts +0 -5
  147. package/dist/render/pointer.d.ts.map +0 -1
  148. package/dist/render/pointer.js +0 -279
  149. package/dist/render/pointer.js.map +0 -1
  150. package/dist/render/pools.d.ts +0 -122
  151. package/dist/render/pools.d.ts.map +0 -1
  152. package/dist/render/pools.js +0 -238
  153. package/dist/render/pools.js.map +0 -1
  154. package/dist/render/resolve.d.ts +0 -4
  155. package/dist/render/resolve.d.ts.map +0 -1
  156. package/dist/render/resolve.js +0 -76
  157. package/dist/render/resolve.js.map +0 -1
  158. package/dist/render/saffron.d.ts +0 -135
  159. package/dist/render/saffron.d.ts.map +0 -1
  160. package/dist/render/saffron.js +0 -725
  161. package/dist/render/saffron.js.map +0 -1
  162. package/dist/render/settle.d.ts +0 -60
  163. package/dist/render/settle.d.ts.map +0 -1
  164. package/dist/render/settle.js +0 -128
  165. package/dist/render/settle.js.map +0 -1
  166. package/dist/render/shared.d.ts +0 -25
  167. package/dist/render/shared.d.ts.map +0 -1
  168. package/dist/render/shared.js +0 -33
  169. package/dist/render/shared.js.map +0 -1
  170. package/dist/render/snapshot.d.ts +0 -21
  171. package/dist/render/snapshot.d.ts.map +0 -1
  172. package/dist/render/snapshot.js +0 -91
  173. package/dist/render/snapshot.js.map +0 -1
  174. package/dist/render/spares.d.ts +0 -56
  175. package/dist/render/spares.d.ts.map +0 -1
  176. package/dist/render/spares.js +0 -160
  177. package/dist/render/spares.js.map +0 -1
  178. package/dist/render/strokes.d.ts +0 -107
  179. package/dist/render/strokes.d.ts.map +0 -1
  180. package/dist/render/strokes.js +0 -448
  181. package/dist/render/strokes.js.map +0 -1
  182. package/dist/render/table.d.ts +0 -213
  183. package/dist/render/table.d.ts.map +0 -1
  184. package/dist/render/table.js +0 -795
  185. package/dist/render/table.js.map +0 -1
  186. package/dist/render/tessellate.d.ts +0 -89
  187. package/dist/render/tessellate.d.ts.map +0 -1
  188. package/dist/render/tessellate.js +0 -386
  189. package/dist/render/tessellate.js.map +0 -1
  190. package/dist/render/text.d.ts +0 -40
  191. package/dist/render/text.d.ts.map +0 -1
  192. package/dist/render/text.js +0 -309
  193. package/dist/render/text.js.map +0 -1
  194. package/dist/render/three.d.ts +0 -83
  195. package/dist/render/three.d.ts.map +0 -1
  196. package/dist/render/three.js +0 -511
  197. package/dist/render/three.js.map +0 -1
  198. package/dist/render/triangles.d.ts +0 -28
  199. package/dist/render/triangles.d.ts.map +0 -1
  200. package/dist/render/triangles.js +0 -189
  201. package/dist/render/triangles.js.map +0 -1
  202. package/dist/render/view.d.ts +0 -238
  203. package/dist/render/view.d.ts.map +0 -1
  204. package/dist/render/view.js +0 -1173
  205. package/dist/render/view.js.map +0 -1
  206. package/dist/render/worker/bitmaps.d.ts +0 -43
  207. package/dist/render/worker/bitmaps.d.ts.map +0 -1
  208. package/dist/render/worker/bitmaps.js +0 -151
  209. package/dist/render/worker/bitmaps.js.map +0 -1
  210. package/dist/render/worker/drawing.d.ts +0 -21
  211. package/dist/render/worker/drawing.d.ts.map +0 -1
  212. package/dist/render/worker/drawing.js +0 -356
  213. package/dist/render/worker/drawing.js.map +0 -1
  214. package/dist/render/worker/filters.d.ts +0 -7
  215. package/dist/render/worker/filters.d.ts.map +0 -1
  216. package/dist/render/worker/filters.js +0 -125
  217. package/dist/render/worker/filters.js.map +0 -1
  218. package/dist/render/worker/frames.d.ts +0 -32
  219. package/dist/render/worker/frames.d.ts.map +0 -1
  220. package/dist/render/worker/frames.js +0 -124
  221. package/dist/render/worker/frames.js.map +0 -1
  222. package/dist/render/worker/host.d.ts +0 -60
  223. package/dist/render/worker/host.d.ts.map +0 -1
  224. package/dist/render/worker/host.js +0 -297
  225. package/dist/render/worker/host.js.map +0 -1
  226. package/dist/render/worker/libraries.d.ts +0 -36
  227. package/dist/render/worker/libraries.d.ts.map +0 -1
  228. package/dist/render/worker/libraries.js +0 -153
  229. package/dist/render/worker/libraries.js.map +0 -1
  230. package/dist/render/worker/presentation.d.ts +0 -18
  231. package/dist/render/worker/presentation.d.ts.map +0 -1
  232. package/dist/render/worker/presentation.js +0 -47
  233. package/dist/render/worker/presentation.js.map +0 -1
  234. package/dist/render/worker/renderer.d.ts +0 -4
  235. package/dist/render/worker/renderer.d.ts.map +0 -1
  236. package/dist/render/worker/renderer.js +0 -21
  237. package/dist/render/worker/renderer.js.map +0 -1
  238. package/dist/render/worker/scene.d.ts +0 -32
  239. package/dist/render/worker/scene.d.ts.map +0 -1
  240. package/dist/render/worker/scene.js +0 -611
  241. package/dist/render/worker/scene.js.map +0 -1
  242. package/dist/render/worker/text.d.ts +0 -47
  243. package/dist/render/worker/text.d.ts.map +0 -1
  244. package/dist/render/worker/text.js +0 -261
  245. package/dist/render/worker/text.js.map +0 -1
  246. package/dist/render/worker/thread.d.ts +0 -23
  247. package/dist/render/worker/thread.d.ts.map +0 -1
  248. package/dist/render/worker/thread.js +0 -107
  249. package/dist/render/worker/thread.js.map +0 -1
  250. package/dist/render/worker/values.d.ts +0 -18
  251. package/dist/render/worker/values.d.ts.map +0 -1
  252. package/dist/render/worker/values.js +0 -64
  253. package/dist/render/worker/values.js.map +0 -1
  254. package/dist/sha256.d.ts +0 -5
  255. package/dist/sha256.d.ts.map +0 -1
  256. package/dist/sha256.js +0 -96
  257. package/dist/sha256.js.map +0 -1
  258. package/dist/shapes.d.ts +0 -71
  259. package/dist/shapes.d.ts.map +0 -1
  260. package/dist/shapes.js +0 -340
  261. package/dist/shapes.js.map +0 -1
  262. package/dist/static-text.d.ts +0 -33
  263. package/dist/static-text.d.ts.map +0 -1
  264. package/dist/static-text.js +0 -105
  265. package/dist/static-text.js.map +0 -1
  266. package/dist/text-layout.d.ts +0 -66
  267. package/dist/text-layout.d.ts.map +0 -1
  268. package/dist/text-layout.js +0 -315
  269. package/dist/text-layout.js.map +0 -1
  270. package/dist/text.d.ts +0 -67
  271. package/dist/text.d.ts.map +0 -1
  272. package/dist/text.js +0 -383
  273. package/dist/text.js.map +0 -1
  274. package/dist/timeline.d.ts +0 -150
  275. package/dist/timeline.d.ts.map +0 -1
  276. package/dist/timeline.js +0 -266
  277. package/dist/timeline.js.map +0 -1
@@ -1,906 +0,0 @@
1
- // BitmapData.applyFilter and generateFilterRect, on the CPU, as adl
2
- // computes them (docs/architecture.md, "Filters"): the source filtered, past
3
- // the source rect too, and the filter's rect written whole into the
4
- // destination; a blur's runs truncated to 8 bits each, a glow's alpha from
5
- // the blur so truncated times strength, a bevel's from the difference of two
6
- // reads of it, a colour matrix of straight colour, rounded, a convolution of
7
- // straight colour, truncated.
8
- import { over, premultiply, unmultiply } from "./bitmap.js";
9
- import { ramp } from "./gradients.js";
10
- /** The filters this filters: the others' rects and pixels are still to come. */
11
- export const filtersDrawn = new Set([
12
- "blur",
13
- "glow",
14
- "dropShadow",
15
- "colorMatrix",
16
- "convolution",
17
- "bevel",
18
- "gradientGlow",
19
- "gradientBevel",
20
- "displacementMap",
21
- ]);
22
- /**
23
- * How far adl's rect for a blur of `quality` passes reaches, a blur below
24
- * 1 counting as 1: the passes' spread, which grows slower than their
25
- * number, as a float, times the blur; for a blur that rounded up from a
26
- * quarter, for the others half to even from a half, as x87 rounds.
27
- */
28
- const PASS_SPREADS = [
29
- 1.0, 2.1, 2.7, 3.1, 3.5, 3.8, 4.0, 4.2, 4.4, 4.6, 5.0, 6.0, 6.0, 7.0, 7.0,
30
- ].map((spread) => Math.fround(spread) / 2);
31
- function spreadOf(blur, quality, kind) {
32
- if (quality < 1) {
33
- return 0;
34
- }
35
- const x = Math.max(blur || 0, 1) * PASS_SPREADS[Math.min(quality, 15) - 1];
36
- if (kind === "blur") {
37
- return Math.floor(x + 0.75);
38
- }
39
- const v = x + 0.5;
40
- const whole = Math.floor(v);
41
- return v - whole === 0.5 ? whole + (whole % 2) : Math.round(v);
42
- }
43
- /** How far a filter's rect reaches past what it filters, each way, before any offset: [x, y], whole pixels. */
44
- function reach(f) {
45
- if (f.kind === "convolution") {
46
- return [f.matrixX >> 1, f.matrixY >> 1];
47
- }
48
- if (f.kind === "colorMatrix") {
49
- return [0, 0];
50
- }
51
- // A displacement map's reach, by its scale, as adl reckons it: a quarter of it, whole; none with no map.
52
- if (f.kind === "displacementMap") {
53
- return f.mapBitmap
54
- ? [Math.floor(Math.abs(f.scaleX) / 4) || 0, Math.floor(Math.abs(f.scaleY) / 4) || 0]
55
- : [0, 0];
56
- }
57
- return [spreadOf(f.blurX, f.quality, f.kind), spreadOf(f.blurY, f.quality, f.kind)];
58
- }
59
- /**
60
- * A shadow's or a bevel's offset in whole pixels, down: [x, y]. adl has it
61
- * in 256ths, to the nearest, so the cosine of 90° is 0, not just under it,
62
- * and 6 × sin 30° is 3, not just under.
63
- */
64
- function offsetOf(f) {
65
- const radians = ((f.angle || 0) * Math.PI) / 180;
66
- const whole = (v) => Math.floor(Math.round(v * 256) / 256);
67
- return [
68
- whole((f.distance || 0) * Math.cos(radians)),
69
- whole((f.distance || 0) * Math.sin(radians)),
70
- ];
71
- }
72
- /**
73
- * The rect a filter makes of `rect`, as generateFilterRect gives it: grown
74
- * by its reach; a shadow's, inner too, by its offset where it moves and
75
- * less it on the other side, never inward; a bevel's by the offset's size
76
- * both ways.
77
- */
78
- export function filterRect(rect, f) {
79
- const [rx, ry] = reach(f);
80
- let [left, right, top, bottom] = [rx, rx, ry, ry];
81
- if (f.kind === "dropShadow" || f.kind === "gradientGlow") {
82
- const [ox, oy] = offsetOf(f);
83
- left = Math.max(0, rx - ox);
84
- right = Math.max(0, rx + ox);
85
- top = Math.max(0, ry - oy);
86
- bottom = Math.max(0, ry + oy);
87
- }
88
- else if (f.kind === "bevel" || f.kind === "gradientBevel") {
89
- const [ox, oy] = offsetOf(f);
90
- left = right = rx + Math.abs(ox);
91
- top = bottom = ry + Math.abs(oy);
92
- }
93
- return {
94
- x: rect.x - left,
95
- y: rect.y - top,
96
- width: rect.width + left + right,
97
- height: rect.height + top + bottom,
98
- };
99
- }
100
- /**
101
- * One run of a box `width` pixels wide over `planes` (each w × h), along x
102
- * or y, each value truncated to 8 bits. Its taps from the pixel out are
103
- * whole while they lie within half the width, and the next one weighs the
104
- * part of it the box covers: the whole ones a running sum of integers,
105
- * exact, the two partial ones added to it. Along y the sums run down
106
- * whole rows at once, which the planes keep together.
107
- */
108
- function run(planes, w, h, width, alongX) {
109
- if (width <= 1) {
110
- return;
111
- }
112
- const half = width / 2;
113
- // The whole taps reach `full` each way; the partial one past them weighs `part`.
114
- const full = Math.floor(half - 0.5);
115
- const part = Math.min(1, Math.max(0, half - full - 0.5));
116
- const scale = 1 / width;
117
- if (alongX) {
118
- // The line between zeros, as far as the taps reach past its ends.
119
- const pad = full + 1;
120
- const line = new Int32Array(w + 2 * pad + 1);
121
- for (const plane of planes) {
122
- for (let row = 0; row < h * w; row += w) {
123
- line.set(plane.subarray(row, row + w), pad);
124
- let sum = 0;
125
- for (let i = pad - full; i <= pad + full; i++) {
126
- sum += line[i];
127
- }
128
- for (let i = 0; i < w; i++) {
129
- const at = i + pad;
130
- // A hair over, so that a value the sum hits exactly stays.
131
- plane[row + i] =
132
- ((sum + part * (line[at - full - 1] + line[at + full + 1])) * scale + 1e-7) | 0;
133
- sum += line[at + full + 1] - line[at - full];
134
- }
135
- }
136
- }
137
- return;
138
- }
139
- // Along y, rows past the plane's ends are zeros.
140
- const zeros = new Int32Array(w);
141
- const rowOf = (plane, y) => y >= 0 && y < h ? plane.subarray(y * w, y * w + w) : zeros;
142
- const sums = new Int32Array(w);
143
- const out = new Int32Array(w * h);
144
- for (const plane of planes) {
145
- sums.fill(0);
146
- for (let j = -full; j <= full; j++) {
147
- const r = rowOf(plane, j);
148
- for (let x = 0; x < w; x++) {
149
- sums[x] += r[x];
150
- }
151
- }
152
- for (let y = 0; y < h; y++) {
153
- const lo = rowOf(plane, y - full - 1);
154
- const hi = rowOf(plane, y + full + 1);
155
- const leaving = rowOf(plane, y - full);
156
- const o = y * w;
157
- for (let x = 0; x < w; x++) {
158
- out[o + x] = ((sums[x] + part * (lo[x] + hi[x])) * scale + 1e-7) | 0;
159
- // The rows entering and leaving the whole taps, for the next.
160
- sums[x] += hi[x] - leaving[x];
161
- }
162
- }
163
- plane.set(out);
164
- }
165
- }
166
- /** The blur's runs: each quality's run along x, then along y. */
167
- function blur(planes, w, h, f) {
168
- for (let q = 0; q < f.quality; q++) {
169
- run(planes, w, h, f.blurX || 0, true);
170
- run(planes, w, h, f.blurY || 0, false);
171
- }
172
- }
173
- /**
174
- * Filter `rect` of `source` into `dest` at (dx, dy), as applyFilter does:
175
- * the filter's rect, moved there and clipped, written whole. True where the
176
- * filter is one this draws; the others leave `dest` as it was.
177
- */
178
- export function applyFilter(dest, source, rect, dx, dy, f, map = null) {
179
- if (!filtersDrawn.has(f.kind)) {
180
- return false;
181
- }
182
- const out = filterRect(rect, f);
183
- // What the destination shows of the filter's rect, in the filter's
184
- // coordinates, and the work: that and as far round it as the filter
185
- // reaches into it, so that a rect far past the destination costs nothing.
186
- const mx = dx - rect.x;
187
- const my = dy - rect.y;
188
- // A displacement map writes the rect alone: what adl writes past it is a quirk of its own.
189
- const written = f.kind === "displacementMap" ? rect : out;
190
- const shown = intersect(written, { x: -mx, y: -my, width: dest.width, height: dest.height });
191
- if (!shown) {
192
- return true;
193
- }
194
- if (f.kind === "displacementMap") {
195
- write(dest, displace(source, rect, shown, f, map), shown, shown, mx, my);
196
- return true;
197
- }
198
- if (f.kind === "convolution" && (f.matrixX === 0 || f.matrixY === 0)) {
199
- copyEmpty(dest, source, rect, out, shown, mx, my);
200
- return true;
201
- }
202
- if (f.kind === "convolution") {
203
- write(dest, convolve(source, shown, f, dest.transparent), shown, shown, mx, my);
204
- return true;
205
- }
206
- // The work: what is shown and as far round it as the filter reaches into
207
- // it, which may be past the rect, whose edge cuts what is written alone.
208
- const [hx, hy] = halo(f);
209
- const work = {
210
- x: shown.x - hx,
211
- y: shown.y - hy,
212
- width: shown.width + 2 * hx,
213
- height: shown.height + 2 * hy,
214
- };
215
- const w = work.width;
216
- const h = work.height;
217
- // The source's premultiplied channels over the work, past `rect` too, as
218
- // far as the bitmap goes.
219
- const pixels = source.pixels;
220
- const sw = source.width;
221
- const a = new Int32Array(w * h);
222
- const r = new Int32Array(w * h);
223
- const g = new Int32Array(w * h);
224
- const b = new Int32Array(w * h);
225
- const from = intersect(work, { x: 0, y: 0, width: sw, height: source.height });
226
- if (from) {
227
- for (let sy = from.y; sy < from.y + from.height; sy++) {
228
- let i = (sy - work.y) * w + from.x - work.x;
229
- for (let sx = from.x; sx < from.x + from.width; sx++, i++) {
230
- const p = pixels[sy * sw + sx];
231
- a[i] = p >>> 24;
232
- r[i] = (p >>> 16) & 0xff;
233
- g[i] = (p >>> 8) & 0xff;
234
- b[i] = p & 0xff;
235
- }
236
- }
237
- }
238
- const result = new Uint32Array(w * h);
239
- if (f.kind === "blur") {
240
- blur([a, r, g, b], w, h, f);
241
- for (let i = 0; i < result.length; i++) {
242
- result[i] = ((a[i] << 24) | (r[i] << 16) | (g[i] << 8) | b[i]) >>> 0;
243
- }
244
- }
245
- else if (f.kind === "colorMatrix") {
246
- colorMatrix(dest, result, [a, r, g, b], work, contentOf(source, rect), f.matrix);
247
- }
248
- else if (f.kind === "bevel") {
249
- bevel(result, [a, r, g, b], w, h, f);
250
- }
251
- else if (f.kind === "gradientGlow") {
252
- gradientGlow(result, [a, r, g, b], w, h, f);
253
- }
254
- else if (f.kind === "gradientBevel") {
255
- gradientBevel(result, [a, r, g, b], w, h, f);
256
- }
257
- else {
258
- glow(result, [a, r, g, b], w, h, f);
259
- }
260
- write(dest, result, work, shown, mx, my);
261
- return true;
262
- }
263
- function intersect(p, q) {
264
- const x0 = Math.max(p.x, q.x);
265
- const y0 = Math.max(p.y, q.y);
266
- const x1 = Math.min(p.x + p.width, q.x + q.width);
267
- const y1 = Math.min(p.y + p.height, q.y + q.height);
268
- return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;
269
- }
270
- /**
271
- * How far a pixel's result reaches for the source, each way: a blur's
272
- * `quality` runs each reach half its box, whole taps; a shadow's offset,
273
- * and the next pixel it samples between, beyond that.
274
- */
275
- function halo(f) {
276
- if (f.kind === "colorMatrix") {
277
- return [0, 0];
278
- }
279
- let hx = f.quality * Math.ceil((f.blurX || 0) / 2);
280
- let hy = f.quality * Math.ceil((f.blurY || 0) / 2);
281
- if (f.kind !== "blur" && f.kind !== "glow") {
282
- const radians = ((f.angle || 0) * Math.PI) / 180;
283
- hx += Math.ceil(Math.abs((f.distance || 0) * Math.cos(radians))) + 1;
284
- hy += Math.ceil(Math.abs((f.distance || 0) * Math.sin(radians))) + 1;
285
- }
286
- return [hx, hy];
287
- }
288
- /** The bounds of the pixels of `rect` of the source that are not transparent: null for none. */
289
- function contentOf(source, rect) {
290
- const area = intersect(rect, { x: 0, y: 0, width: source.width, height: source.height });
291
- if (!area) {
292
- return null;
293
- }
294
- const pixels = source.pixels;
295
- let x0 = Number.POSITIVE_INFINITY;
296
- let y0 = Number.POSITIVE_INFINITY;
297
- let x1 = -1;
298
- let y1 = -1;
299
- for (let y = area.y; y < area.y + area.height; y++) {
300
- for (let x = area.x; x < area.x + area.width; x++) {
301
- if (pixels[y * source.width + x] >>> 24) {
302
- x0 = Math.min(x0, x);
303
- y0 = Math.min(y0, y);
304
- x1 = Math.max(x1, x);
305
- y1 = Math.max(y1, y);
306
- }
307
- }
308
- }
309
- return x1 < 0 ? null : { x: x0, y: y0, width: x1 - x0 + 1, height: y1 - y0 + 1 };
310
- }
311
- /**
312
- * A colour matrix of each pixel's straight colour, rounded. adl maps the
313
- * pixels about what the source has, its bounds and one more each way, one
314
- * by one, their colour premultiplied by the new alpha and truncated; the
315
- * rest of the rect it fills with the map of a transparent pixel, written as
316
- * the store premultiplies it.
317
- */
318
- function colorMatrix(dest, result, [a, r, g, b], work, content, m) {
319
- // The map of straight (r, g, b, a) into `mapped`, each clamped and rounded.
320
- const mapped = [0, 0, 0, 0];
321
- const map = (cr, cg, cb, ca) => {
322
- for (let row = 0; row < 4; row++) {
323
- const v = m[row * 5] * cr +
324
- m[row * 5 + 1] * cg +
325
- m[row * 5 + 2] * cb +
326
- m[row * 5 + 3] * ca +
327
- m[row * 5 + 4];
328
- mapped[row] = Math.max(0, Math.min(255, Math.round(Number.isNaN(v) ? 0 : v)));
329
- }
330
- return mapped;
331
- };
332
- const empty = [...map(0, 0, 0, 0)];
333
- result.fill(dest.premultiplied(((empty[3] << 24) | (empty[0] << 16) | (empty[1] << 8) | empty[2]) >>> 0));
334
- if (!content) {
335
- return;
336
- }
337
- // What the source has, and one more each way, as far as the work goes.
338
- const near = intersect({ x: content.x - 1, y: content.y - 1, width: content.width + 2, height: content.height + 2 }, work);
339
- if (!near) {
340
- return;
341
- }
342
- for (let y = near.y; y < near.y + near.height; y++) {
343
- for (let x = near.x; x < near.x + near.width; x++) {
344
- const i = (y - work.y) * work.width + (x - work.x);
345
- const s = a[i] > 0 ? 255 / a[i] : 0;
346
- const [nr, ng, nb, na] = map(r[i] * s, g[i] * s, b[i] * s, a[i]);
347
- result[i] =
348
- ((na << 24) |
349
- (Math.floor((nr * na) / 255) << 16) |
350
- (Math.floor((ng * na) / 255) << 8) |
351
- Math.floor((nb * na) / 255)) >>>
352
- 0;
353
- }
354
- }
355
- }
356
- /** The channel of an unmultiplied pixel a displacement reads: red 1, green 2, blue 4, alpha 8; any other none, 128. */
357
- function channelOf(pixel, component) {
358
- switch (component) {
359
- case 1:
360
- return (pixel >>> 16) & 0xff;
361
- case 2:
362
- return (pixel >>> 8) & 0xff;
363
- case 4:
364
- return pixel & 0xff;
365
- case 8:
366
- return pixel >>> 24;
367
- default:
368
- return 128;
369
- }
370
- }
371
- /**
372
- * A displacement map over `area` of the source: each pixel takes the
373
- * source's at itself moved by the map's channels there, (c − 128) × scale
374
- * / 256, between pixels linearly with weights in 256ths; past the source
375
- * rect as the mode says: wrapped, clamped, the pixel's own (ignore) or the
376
- * filter's colour. Where the map is not, it keeps its own.
377
- */
378
- function displace(source, rect, area, f, map) {
379
- const pixels = source.pixels;
380
- const sw = source.width;
381
- const own = (x, y) => x >= 0 && y >= 0 && x < sw && y < source.height ? pixels[y * sw + x] : 0;
382
- const a = Math.floor(f.alpha * 255);
383
- const colour = premultiply(((a << 24) | (f.color & 0xffffff)) >>> 0);
384
- const result = new Uint32Array(area.width * area.height);
385
- for (let y = 0; y < area.height; y++) {
386
- const sy = area.y + y;
387
- for (let x = 0; x < area.width; x++) {
388
- const sx = area.x + x;
389
- const mx = sx - rect.x - f.mapPoint[0];
390
- const my = sy - rect.y - f.mapPoint[1];
391
- if (!map || mx < 0 || my < 0 || mx >= map.width || my >= map.height) {
392
- result[y * area.width + x] = own(sx, sy);
393
- continue;
394
- }
395
- const m = unmultiply(map.pixels[my * map.width + mx]);
396
- // Where to read, in 256ths, the offset truncated toward 0 as adl's fixed point has it.
397
- const px = sx * 256 + Math.trunc((channelOf(m, f.componentX) - 128) * f.scaleX);
398
- const py = sy * 256 + Math.trunc((channelOf(m, f.componentY) - 128) * f.scaleY);
399
- let x0 = px >> 8;
400
- let y0 = py >> 8;
401
- const fx = px & 255;
402
- const fy = py & 255;
403
- const left = rect.x;
404
- const top = rect.y;
405
- const right = rect.x + rect.width - 1;
406
- const bottom = rect.y + rect.height - 1;
407
- // Ignoring, a place past the rect takes the pixel's own, its fraction kept.
408
- if (f.mode === "ignore") {
409
- x0 = x0 < left || x0 > right ? sx : x0;
410
- y0 = y0 < top || y0 > bottom ? sy : y0;
411
- }
412
- const at = (cx, cy) => {
413
- let ix = cx - rect.x;
414
- let iy = cy - rect.y;
415
- if (ix >= 0 && iy >= 0 && ix < rect.width && iy < rect.height) {
416
- return own(cx, cy);
417
- }
418
- if (f.mode === "wrap") {
419
- ix = ((ix % rect.width) + rect.width) % rect.width;
420
- iy = ((iy % rect.height) + rect.height) % rect.height;
421
- }
422
- else if (f.mode === "color") {
423
- return colour;
424
- }
425
- else {
426
- ix = Math.max(0, Math.min(rect.width - 1, ix));
427
- iy = Math.max(0, Math.min(rect.height - 1, iy));
428
- }
429
- return own(rect.x + ix, rect.y + iy);
430
- };
431
- // The corners' weights in 256ths, each truncated, as adl's fixed point has them.
432
- const w00 = ((256 - fx) * (256 - fy)) >> 8;
433
- const w10 = (fx * (256 - fy)) >> 8;
434
- const w01 = ((256 - fx) * fy) >> 8;
435
- const w11 = (fx * fy) >> 8;
436
- const c00 = at(x0, y0);
437
- const c10 = at(x0 + 1, y0);
438
- const c01 = at(x0, y0 + 1);
439
- const c11 = at(x0 + 1, y0 + 1);
440
- let out = 0;
441
- for (const shift of [24, 16, 8, 0]) {
442
- const v = ((c00 >>> shift) & 0xff) * w00 +
443
- ((c10 >>> shift) & 0xff) * w10 +
444
- ((c01 >>> shift) & 0xff) * w01 +
445
- ((c11 >>> shift) & 0xff) * w11;
446
- out |= (v >> 8) << shift;
447
- }
448
- result[y * area.width + x] = out >>> 0;
449
- }
450
- }
451
- return result;
452
- }
453
- /**
454
- * What adl makes of a convolution with no taps: a copy, of as much of the
455
- * source as the filter's rect is big (the other size of the matrix still
456
- * grows it) from the source rect's corner, to that rect's corner; over
457
- * what an opaque destination has, into a transparent one as it is; what
458
- * lies past the source left as it was, and in place the source as it was
459
- * before. `shown` is what the destination shows of `out`, and (mx, my)
460
- * moves both there.
461
- */
462
- function copyEmpty(dest, source, rect, out, shown, mx, my) {
463
- const target = dest.pixels;
464
- const pixels = source === dest ? source.pixels.slice() : source.pixels;
465
- for (let y = shown.y; y < shown.y + shown.height; y++) {
466
- const sy = rect.y + y - out.y;
467
- if (sy < 0 || sy >= source.height) {
468
- continue;
469
- }
470
- for (let x = shown.x; x < shown.x + shown.width; x++) {
471
- const sx = rect.x + x - out.x;
472
- if (sx >= 0 && sx < source.width) {
473
- const p = pixels[sy * source.width + sx];
474
- const at = (y + my) * dest.width + x + mx;
475
- target[at] = dest.transparent ? p : over(p, target[at]);
476
- }
477
- }
478
- }
479
- dest.changed();
480
- }
481
- /**
482
- * A convolution over `area` of the source, as adl computes it: each tap
483
- * reads the source's straight colour, past the rect too, and past the
484
- * bitmap the nearest edge's or the filter's colour; the sum divided (0
485
- * counting as 1), the bias added, clamped and truncated, the alpha the
486
- * source's where the filter keeps it; the colour premultiplied by that alpha,
487
- * or kept straight for an opaque destination.
488
- */
489
- function convolve(source, area, f, transparent) {
490
- const cols = f.matrixX;
491
- const rows = f.matrixY;
492
- const hx = cols >> 1;
493
- const hy = rows >> 1;
494
- const divisor = f.divisor || 1;
495
- const matrix = Array.from({ length: cols * rows }, (_, k) => f.matrix[k] || 0);
496
- const weights = matrix.map((m) => m / divisor);
497
- const integer = integerKernel(matrix, divisor);
498
- const sw = source.width;
499
- const sh = source.height;
500
- const preserveAlpha = f.preserveAlpha;
501
- // The straight colour of the pixels the taps reach, clamped to the bitmap,
502
- // a plane a channel, and after each the filter's colour.
503
- const clampX = (x) => Math.max(0, Math.min(sw - 1, x));
504
- const clampY = (y) => Math.max(0, Math.min(sh - 1, y));
505
- const x0 = clampX(area.x - hx);
506
- const y0 = clampY(area.y - hy);
507
- const nw = clampX(area.x + area.width + cols - hx - 2) - x0 + 1;
508
- const nh = clampY(area.y + area.height + rows - hy - 2) - y0 + 1;
509
- const colour = nw * nh;
510
- const planes = [0, 1, 2, 3].map(() => new Int32Array(colour + 1));
511
- const [pr, pg, pb, pa] = planes;
512
- const pixels = source.pixels;
513
- for (let y = 0; y < nh; y++) {
514
- for (let x = 0; x < nw; x++) {
515
- const stored = pixels[(y0 + y) * sw + x0 + x];
516
- // Opaque pixels, most of a picture's, are straight already.
517
- const p = stored >>> 24 === 255 ? stored : unmultiply(stored);
518
- const i = y * nw + x;
519
- pr[i] = (p >>> 16) & 0xff;
520
- pg[i] = (p >>> 8) & 0xff;
521
- pb[i] = p & 0xff;
522
- pa[i] = source.transparent ? p >>> 24 : 255;
523
- }
524
- }
525
- pr[colour] = (f.color >> 16) & 0xff;
526
- pg[colour] = (f.color >> 8) & 0xff;
527
- pb[colour] = f.color & 0xff;
528
- pa[colour] = Math.floor(f.alpha * 255);
529
- const at = (x, y) => !f.clamp && (x < 0 || x >= sw || y < 0 || y >= sh)
530
- ? colour
531
- : (clampY(y) - y0) * nw + clampX(x) - x0;
532
- // The taps that weigh anything: where each reads from the pixel, and its
533
- // place in the planes from the pixel's where it lies in the bitmap.
534
- const tapsOf = (ws, centreLast) => {
535
- const dx = [];
536
- const dy = [];
537
- const w = [];
538
- for (let k = 0; k < ws.length; k++) {
539
- if (ws[k] !== 0) {
540
- const last = centreLast && k === ws.length - 1;
541
- dx.push(last ? 0 : (k % cols) - hx);
542
- dy.push(last ? 0 : Math.floor(k / cols) - hy);
543
- w.push(ws[k]);
544
- }
545
- }
546
- return { dx, dy, w, at: dx.map((x, k) => dy[k] * nw + x) };
547
- };
548
- const general = tapsOf(weights, false);
549
- const fixedTaps = tapsOf(matrix, true);
550
- const bias = f.bias;
551
- // A channel's sum biased, clamped and truncated: a hair over, so that a
552
- // value the sum hits exactly stays; NaN, from a NaN bias, 0.
553
- const straight = (v) => {
554
- const c = v + bias;
555
- return c >= 255 ? 255 : c > 0 ? Math.floor(c + 1e-7) : 0;
556
- };
557
- const scale = integer === null ? 0 : integer / 65536;
558
- const sums = [0, 1, 2, 3].map(() => new Float64Array(area.width));
559
- const [sr, sg, sb, sa] = sums;
560
- const result = new Uint32Array(area.width * area.height);
561
- for (let y = 0; y < area.height; y++) {
562
- const sy = area.y + y;
563
- for (const sum of sums) {
564
- sum.fill(0);
565
- }
566
- // The pixels whose taps all lie in the bitmap, x from `x1` to before `x2`,
567
- // sum a tap at a time along the row; the rest a pixel at a time.
568
- const rowInside = sy >= hy && sy <= sh - rows + hy;
569
- const x1 = rowInside ? Math.min(area.width, Math.max(0, hx - area.x)) : 0;
570
- const x2 = rowInside ? Math.max(x1, Math.min(area.width, sw - cols + hx + 1 - area.x)) : 0;
571
- const fixedRow = integer !== null && sy >= 1 && sy < sh - 1;
572
- if (x2 > x1) {
573
- // The fixed-point way, where it is taken, is inside these too (its taps are 3 × 3).
574
- const taps = fixedRow ? fixedTaps : general;
575
- const base = (sy - y0) * nw + area.x + x1 - x0;
576
- for (let k = 0; k < taps.w.length; k++) {
577
- const w = taps.w[k];
578
- let i = base + taps.at[k];
579
- for (let x = x1; x < x2; x++, i++) {
580
- sr[x] += pr[i] * w;
581
- sg[x] += pg[i] * w;
582
- sb[x] += pb[i] * w;
583
- sa[x] += pa[i] * w;
584
- }
585
- }
586
- }
587
- for (let x = 0; x < area.width; x++) {
588
- const sx = area.x + x;
589
- const fixed = fixedRow && sx >= 1 && sx < sw - 1;
590
- if (x < x1 || x >= x2) {
591
- const taps = fixed ? fixedTaps : general;
592
- for (let k = 0; k < taps.w.length; k++) {
593
- const i = at(sx + taps.dx[k], sy + taps.dy[k]);
594
- const w = taps.w[k];
595
- sr[x] += pr[i] * w;
596
- sg[x] += pg[i] * w;
597
- sb[x] += pb[i] * w;
598
- sa[x] += pa[i] * w;
599
- }
600
- }
601
- let r = sr[x];
602
- let g = sg[x];
603
- let b = sb[x];
604
- let a = sa[x];
605
- if (fixed) {
606
- r = Math.floor(r * scale);
607
- g = Math.floor(g * scale);
608
- b = Math.floor(b * scale);
609
- a = Math.floor(a * scale);
610
- }
611
- const alpha = preserveAlpha ? pa[at(sx, sy)] : straight(a);
612
- const by = transparent ? alpha : 255;
613
- r = straight(r) * by;
614
- g = straight(g) * by;
615
- b = straight(b) * by;
616
- // The fixed-point way premultiplies truncating, the other as the store does.
617
- result[y * area.width + x] = fixed
618
- ? ((alpha << 24) |
619
- (Math.floor(r / 255) << 16) |
620
- (Math.floor(g / 255) << 8) |
621
- Math.floor(b / 255)) >>>
622
- 0
623
- : ((alpha << 24) |
624
- (((r + 127) / 255) << 16) |
625
- (((g + 127) / 255) << 8) |
626
- ((b + 127) / 255)) >>>
627
- 0;
628
- }
629
- }
630
- return result;
631
- }
632
- /**
633
- * The reciprocal adl divides a 3 × 3 kernel by in fixed point, where it
634
- * takes that way, which it does inside the bitmap for whole weights whose
635
- * positive and negative sums each stay within 127 and a divisor from 1.1,
636
- * or past 2.0001 with a negative weight: 65536 / divisor, truncated, plus
637
- * one, wrapped to a short. That way also reads the centre for the last tap.
638
- * Null where it takes the other.
639
- */
640
- export function integerKernel(matrix, divisor) {
641
- if (matrix.length !== 9 || !matrix.every(Number.isInteger)) {
642
- return null;
643
- }
644
- const positive = matrix.reduce((s, m) => s + Math.max(0, m), 0);
645
- const negative = matrix.reduce((s, m) => s + Math.min(0, m), 0);
646
- const enough = negative < 0 ? divisor > Math.fround(2.0001) : divisor >= Math.fround(1.1);
647
- if (positive > 127 || negative < -127 || !enough) {
648
- return null;
649
- }
650
- return ((Math.floor(65536 / divisor) + 1) << 16) >> 16;
651
- }
652
- /**
653
- * The plane (w × h) read at every pixel moved by (ox, oy), between pixels
654
- * linearly, with weights in 256ths, truncated, as adl's fixed point has
655
- * them; `outside` past it. Each column's and row's whole part and weight
656
- * are computed once.
657
- */
658
- function shifted(plane, w, h, ox, oy, outside) {
659
- const xs = new Int32Array(w);
660
- const fxs = new Float64Array(w);
661
- for (let x = 0; x < w; x++) {
662
- const at = x + ox;
663
- xs[x] = Math.floor(at);
664
- fxs[x] = Math.floor((at - xs[x]) * 256) / 256;
665
- }
666
- const out = new Int32Array(w * h);
667
- const value = (x, y) => x >= 0 && x < w && y >= 0 && y < h ? plane[y * w + x] : outside;
668
- for (let y = 0; y < h; y++) {
669
- const at = y + oy;
670
- const y0 = Math.floor(at);
671
- const fy = Math.floor((at - y0) * 256) / 256;
672
- for (let x = 0; x < w; x++) {
673
- const x0 = xs[x];
674
- const fx = fxs[x];
675
- if (fx === 0 && fy === 0) {
676
- out[y * w + x] = value(x0, y0);
677
- continue;
678
- }
679
- const top = value(x0, y0) * (1 - fx) + value(x0 + 1, y0) * fx;
680
- const bottom = value(x0, y0 + 1) * (1 - fx) + value(x0 + 1, y0 + 1) * fx;
681
- out[y * w + x] = Math.floor(top * (1 - fy) + bottom * fy + 1e-7);
682
- }
683
- }
684
- return out;
685
- }
686
- /**
687
- * A bevel: the source's alpha blurred, truncated, read from the offset
688
- * forward and back; their difference, times strength (to 255) and the
689
- * colour's alpha, rounded, the highlight where forward is more and the
690
- * shadow where it is less. Inner, it lies atop the source, which keeps its
691
- * alpha; outer, behind it; full, over it; knocked out, alone, masked to
692
- * where the source is (inner) or is not (outer). Each over another as the
693
- * store draws, truncated.
694
- */
695
- function bevel(result, [a, r, g, b], w, h, f) {
696
- const blurred = new Int32Array(a);
697
- blur([blurred], w, h, f);
698
- const radians = ((f.angle || 0) * Math.PI) / 180;
699
- // As a shadow's. Off the axes adl reads about a 256th further out, which
700
- // this does not: within 2 a channel there.
701
- const ox = (f.distance || 0) * Math.cos(radians);
702
- const oy = (f.distance || 0) * Math.sin(radians);
703
- const on = shifted(blurred, w, h, ox, oy, 0);
704
- const back = shifted(blurred, w, h, -ox, -oy, 0);
705
- const channels = (c) => [(c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff];
706
- const [hr, hg, hb] = channels(f.highlightColor);
707
- const [sr, sg, sb] = channels(f.shadowColor);
708
- const highlightAlpha = f.highlightAlpha;
709
- const shadowAlpha = f.shadowAlpha;
710
- const strength = f.strength;
711
- const place = placer(f);
712
- for (let i = 0; i < w * h; i++) {
713
- const d = on[i] - back[i];
714
- const lit = d > 0;
715
- // Its alpha rounds, where a glow's truncates.
716
- const la = Math.round(Math.min(255, Math.floor(Math.abs(d) * strength)) * (lit ? highlightAlpha : shadowAlpha));
717
- result[i] = place(a[i], r[i], g[i], b[i], la, Math.floor(((lit ? hr : sr) * la) / 255), Math.floor(((lit ? hg : sg) * la) / 255), Math.floor(((lit ? hb : sb) * la) / 255));
718
- }
719
- }
720
- /**
721
- * How a bevel or a gradient filter places its layer (premultiplied, alpha
722
- * la) on the source's pixel: masked, rounding, to where the source is
723
- * (inner) or, knocked out, is not (outer); inner atop the source, which keeps its
724
- * alpha, outer behind it, full over it, knocked out alone; each over
725
- * another as the store draws, top + bottom × (256 − top's alpha) / 256,
726
- * truncated.
727
- */
728
- function placer(f) {
729
- const inner = f.type === "inner";
730
- const outer = f.type === "outer";
731
- const knockout = f.knockout;
732
- const over = (top, ta, bottom) => Math.min(255, top + ((bottom * (256 - ta)) >> 8));
733
- return (sa, sr, sg, sb, la, lr, lg, lb) => {
734
- const m = inner ? sa : outer && knockout ? 255 - sa : 255;
735
- const mA = Math.floor((la * m + 127) / 255);
736
- const mr = Math.floor((lr * m + 127) / 255);
737
- const mg = Math.floor((lg * m + 127) / 255);
738
- const mb = Math.floor((lb * m + 127) / 255);
739
- let oa;
740
- let or;
741
- let og;
742
- let ob;
743
- if (knockout) {
744
- oa = mA;
745
- or = mr;
746
- og = mg;
747
- ob = mb;
748
- }
749
- else if (outer) {
750
- oa = over(sa, sa, mA);
751
- or = over(sr, sa, mr);
752
- og = over(sg, sa, mg);
753
- ob = over(sb, sa, mb);
754
- }
755
- else {
756
- // What is left shows through, by the layer's own alpha atop, by its masked one over.
757
- const ta = inner ? la : mA;
758
- oa = over(mA, ta, sa);
759
- or = over(mr, ta, sr);
760
- og = over(mg, ta, sg);
761
- ob = over(mb, ta, sb);
762
- }
763
- return (((oa << 24) | (Math.min(or, oa) << 16) | (Math.min(og, oa) << 8) | Math.min(ob, oa)) >>> 0);
764
- };
765
- }
766
- /** A gradient filter's 256 colours, premultiplied, from its stops, as a gradient fill's ramp; with none, none. */
767
- export function gradientTable(f) {
768
- if (f.colors.length === 0) {
769
- return new Uint32Array(256);
770
- }
771
- const stops = f.colors.map((c, k) => ({
772
- ratio: f.ratios[k],
773
- color: ((Math.round((f.alphas[k] ?? 1) * 255) << 24) | (c & 0xffffff)) >>> 0,
774
- }));
775
- return ramp(stops, false);
776
- }
777
- /**
778
- * A gradient glow: the source's alpha blurred, truncated, from its offset
779
- * back as a shadow's, times strength to 255, picking its colour and alpha
780
- * from the gradient; placed as a bevel's layer is.
781
- */
782
- function gradientGlow(result, [a, r, g, b], w, h, f) {
783
- const blurred = new Int32Array(a);
784
- blur([blurred], w, h, f);
785
- const radians = ((f.angle || 0) * Math.PI) / 180;
786
- const ox = (f.distance || 0) * Math.cos(radians);
787
- const oy = (f.distance || 0) * Math.sin(radians);
788
- const moved = shifted(blurred, w, h, -ox, -oy, 0);
789
- const table = gradientTable(f);
790
- const place = placer(f);
791
- for (let i = 0; i < w * h; i++) {
792
- const c = table[Math.min(255, Math.floor(moved[i] * f.strength))];
793
- result[i] = place(a[i], r[i], g[i], b[i], c >>> 24, (c >>> 16) & 0xff, (c >>> 8) & 0xff, c & 0xff);
794
- }
795
- }
796
- /**
797
- * A gradient bevel: a bevel's difference, the source's alpha blurred and
798
- * read on and back by its offset, picking its colour and alpha from the
799
- * gradient, the middle where they agree; placed as a bevel's layer is.
800
- */
801
- function gradientBevel(result, [a, r, g, b], w, h, f) {
802
- const blurred = new Int32Array(a);
803
- blur([blurred], w, h, f);
804
- const radians = ((f.angle || 0) * Math.PI) / 180;
805
- const ox = (f.distance || 0) * Math.cos(radians);
806
- const oy = (f.distance || 0) * Math.sin(radians);
807
- const on = shifted(blurred, w, h, ox, oy, 0);
808
- const back = shifted(blurred, w, h, -ox, -oy, 0);
809
- const table = gradientTable(f);
810
- const place = placer(f);
811
- for (let i = 0; i < w * h; i++) {
812
- const d = Math.max(-255, Math.min(255, Math.floor((on[i] - back[i]) * f.strength)));
813
- const c = table[Math.floor((d + 256) / 2)];
814
- result[i] = place(a[i], r[i], g[i], b[i], c >>> 24, (c >>> 16) & 0xff, (c >>> 8) & 0xff, c & 0xff);
815
- }
816
- }
817
- /**
818
- * A glow or a shadow: the source's alpha blurred, truncated, times strength
819
- * (to 255) and alpha, in its colour, from the offset back for a shadow;
820
- * behind the source, or inside it for an inner one, or alone.
821
- */
822
- function glow(result, [a, r, g, b], w, h, f) {
823
- // An inner one blurs what the source leaves, 255 less its alpha, as adl does.
824
- const blurred = f.inner ? a.map((v) => 255 - v) : new Int32Array(a);
825
- blur([blurred], w, h, f);
826
- const radians = ((f.angle || 0) * Math.PI) / 180;
827
- const shadow = f.kind === "dropShadow";
828
- // A shadow's offset, which adl samples the blurred alpha at between pixels, linearly.
829
- const ox = shadow ? (f.distance || 0) * Math.cos(radians) : 0;
830
- const oy = shadow ? (f.distance || 0) * Math.sin(radians) : 0;
831
- const moved = shifted(blurred, w, h, -ox, -oy, f.inner ? 255 : 0);
832
- const cr = (f.color >> 16) & 0xff;
833
- const cg = (f.color >> 8) & 0xff;
834
- const cb = f.color & 0xff;
835
- const hide = shadow && f.hideObject;
836
- const round = (v) => Math.max(0, Math.min(255, Math.round(v)));
837
- for (let y = 0; y < h; y++) {
838
- for (let x = 0; x < w; x++) {
839
- const i = y * w + x;
840
- const blurA = moved[i];
841
- const sa = a[i];
842
- let ga = Math.floor(Math.min(255, Math.floor(blurA * f.strength)) * f.alpha);
843
- if (f.inner) {
844
- ga = Math.floor((ga * sa) / 255);
845
- }
846
- const gr = (cr * ga) / 255;
847
- const gg = (cg * ga) / 255;
848
- const gb = (cb * ga) / 255;
849
- let oa;
850
- let or;
851
- let og;
852
- let ob;
853
- if (f.knockout && !f.inner) {
854
- oa = (ga * (255 - sa)) / 255;
855
- or = (gr * (255 - sa)) / 255;
856
- og = (gg * (255 - sa)) / 255;
857
- ob = (gb * (255 - sa)) / 255;
858
- }
859
- else if (f.inner && !f.knockout) {
860
- const keep = (255 - ga) / 255;
861
- oa = ga + sa * keep;
862
- or = gr + r[i] * keep;
863
- og = gg + g[i] * keep;
864
- ob = gb + b[i] * keep;
865
- }
866
- else if (f.knockout || hide) {
867
- // Knocked out inside, or a shadow drawn alone: the glow by itself.
868
- oa = ga;
869
- or = gr;
870
- og = gg;
871
- ob = gb;
872
- }
873
- else {
874
- const behind = (255 - sa) / 255;
875
- oa = sa + ga * behind;
876
- or = r[i] + gr * behind;
877
- og = g[i] + gg * behind;
878
- ob = b[i] + gb * behind;
879
- }
880
- const ka = round(oa);
881
- result[i] =
882
- ((ka << 24) |
883
- (Math.min(round(or), ka) << 16) |
884
- (Math.min(round(og), ka) << 8) |
885
- Math.min(round(ob), ka)) >>>
886
- 0;
887
- }
888
- }
889
- }
890
- /** `part` of `pixels`, which cover `rect`, into `dest`, moved by (mx, my), clipped; an opaque store keeps its alpha. */
891
- function write(dest, pixels, rect, part, mx, my) {
892
- const target = dest.pixels;
893
- const to = intersect({ x: part.x + mx, y: part.y + my, width: part.width, height: part.height }, { x: 0, y: 0, width: dest.width, height: dest.height });
894
- if (to) {
895
- const opaque = dest.transparent ? 0 : 0xff000000;
896
- for (let ty = to.y; ty < to.y + to.height; ty++) {
897
- let i = (ty - my - rect.y) * rect.width + to.x - mx - rect.x;
898
- let t = ty * dest.width + to.x;
899
- for (let n = 0; n < to.width; n++) {
900
- target[t++] = (pixels[i++] | opaque) >>> 0;
901
- }
902
- }
903
- }
904
- dest.changed();
905
- }
906
- //# sourceMappingURL=bitmap-filters.js.map