nodejs-audio-visualizer 5.0.0 → 5.2.0

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 (53) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +3 -2
  3. package/dist/audio.d.ts +13 -12
  4. package/dist/audio.js +128 -120
  5. package/dist/audio.js.map +1 -1
  6. package/dist/beats.d.ts +39 -19
  7. package/dist/beats.js +220 -43
  8. package/dist/beats.js.map +1 -1
  9. package/dist/bpmEncoder.d.ts +14 -14
  10. package/dist/bpmEncoder.js +97 -97
  11. package/dist/config.d.ts +78 -77
  12. package/dist/config.js +377 -369
  13. package/dist/config.js.map +1 -1
  14. package/dist/dsp.d.ts +16 -16
  15. package/dist/dsp.js +76 -76
  16. package/dist/highlight.d.ts +34 -32
  17. package/dist/highlight.js +334 -325
  18. package/dist/highlight.js.map +1 -1
  19. package/dist/image.d.ts +97 -79
  20. package/dist/image.js +545 -458
  21. package/dist/image.js.map +1 -1
  22. package/dist/index.d.ts +87 -79
  23. package/dist/index.js +597 -534
  24. package/dist/index.js.map +1 -1
  25. package/dist/subtitleConvert.d.ts +3 -3
  26. package/dist/subtitleConvert.js +61 -61
  27. package/dist/video.d.ts +150 -80
  28. package/dist/video.js +677 -434
  29. package/dist/video.js.map +1 -1
  30. package/dist/waitForEventLoop.d.ts +1 -1
  31. package/dist/waitForEventLoop.js +5 -5
  32. package/package.json +62 -61
  33. package/src/audio.ts +129 -120
  34. package/src/beats.ts +279 -68
  35. package/src/bpmEncoder.ts +97 -97
  36. package/src/config.ts +487 -476
  37. package/src/dsp.ts +95 -95
  38. package/src/highlight.ts +291 -284
  39. package/src/image.ts +707 -602
  40. package/src/index.ts +124 -31
  41. package/src/subtitleConvert.ts +63 -63
  42. package/src/tests/audio.test.ts +102 -96
  43. package/src/tests/beats.test.ts +134 -0
  44. package/src/tests/config.test.ts +534 -496
  45. package/src/tests/dsp.test.ts +24 -24
  46. package/src/tests/highlight.test.ts +178 -178
  47. package/src/tests/image.test.ts +319 -222
  48. package/src/tests/index.test.ts +180 -180
  49. package/src/tests/subtitleConvert.test.ts +23 -23
  50. package/src/tests/video.test.ts +535 -285
  51. package/src/typings.d.ts +28 -6
  52. package/src/video.ts +856 -550
  53. package/src/waitForEventLoop.ts +2 -2
package/dist/image.js CHANGED
@@ -1,459 +1,546 @@
1
- "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
- return new (P || (P = Promise))(function (resolve, reject) {
16
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
- step((generator = generator.apply(thisArg, _arguments || [])).next());
20
- });
21
- };
22
- var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
- function verb(n) { return function (v) { return step([n, v]); }; }
26
- function step(op) {
27
- if (f) throw new TypeError("Generator is already executing.");
28
- while (_) try {
29
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
- if (y = 0, t) op = [op[0] & 2, t.value];
31
- switch (op[0]) {
32
- case 0: case 1: t = op; break;
33
- case 4: _.label++; return { value: op[1], done: false };
34
- case 5: _.label++; y = op[1]; op = [0]; continue;
35
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
- default:
37
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
- if (t[2]) _.ops.pop();
42
- _.trys.pop(); continue;
43
- }
44
- op = body.call(thisArg, _);
45
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
- }
48
- };
49
- var __importDefault = (this && this.__importDefault) || function (mod) {
50
- return (mod && mod.__esModule) ? mod : { "default": mod };
51
- };
52
- Object.defineProperty(exports, "__esModule", { value: true });
53
- var bmp_js_1 = require("bmp-js");
54
- var jimp_1 = __importDefault(require("jimp"));
55
- exports.mixValues = function (value1, value1Opacity, value2) {
56
- return Math.round(value2 * (1 - value1Opacity) + value1 * value1Opacity);
57
- };
58
- exports.mixColors = function (_a) {
59
- var color = _a.color, colorOpacity = _a.colorOpacity, backgroundColor = _a.backgroundColor;
60
- return {
61
- red: exports.mixValues(color.red, colorOpacity, backgroundColor.red),
62
- green: exports.mixValues(color.green, colorOpacity, backgroundColor.green),
63
- blue: exports.mixValues(color.blue, colorOpacity, backgroundColor.blue),
64
- };
65
- };
66
- var getRectPixelColor = function (params) {
67
- var imageDstBuffer = params.imageDstBuffer, pixelIndex = params.pixelIndex, color = params.color, opacity = params.opacity;
68
- if (opacity === 1) {
69
- return color;
70
- }
71
- var backgroundPixelColor = {
72
- blue: imageDstBuffer.data[pixelIndex],
73
- green: imageDstBuffer.data[pixelIndex + 1],
74
- red: imageDstBuffer.data[pixelIndex + 2],
75
- };
76
- var resultColor = exports.mixColors({
77
- color: color,
78
- colorOpacity: opacity,
79
- backgroundColor: backgroundPixelColor,
80
- });
81
- return resultColor;
82
- };
83
- exports.drawRect = function (_a) {
84
- var imageDstBuffer = _a.imageDstBuffer, position = _a.position, size = _a.size, color = _a.color, opacity = _a.opacity;
85
- for (var currY = position.y; currY < position.y + size.height; currY++) {
86
- for (var currX = position.x; currX < position.x + size.width; currX++) {
87
- var pixelIndex = imageDstBuffer.shiftPos + currY * imageDstBuffer.rowBytes + currX * 3;
88
- var pixelColor = getRectPixelColor({
89
- imageDstBuffer: imageDstBuffer,
90
- pixelIndex: pixelIndex,
91
- color: color,
92
- opacity: opacity,
93
- });
94
- imageDstBuffer.data[pixelIndex] = pixelColor.blue;
95
- imageDstBuffer.data[pixelIndex + 1] = pixelColor.green;
96
- imageDstBuffer.data[pixelIndex + 2] = pixelColor.red;
97
- }
98
- }
99
- };
100
- var buildQuadEdgeTable = function (points) {
101
- var edges = [];
102
- for (var i = 0; i < points.length; i++) {
103
- var p1 = points[i];
104
- var p2 = points[(i + 1) % points.length];
105
- if (p1.y === p2.y)
106
- continue; // Skip horizontal edges
107
- var yMin = Math.min(p1.y, p2.y);
108
- var yMax = Math.max(p1.y, p2.y);
109
- var x = p1.y < p2.y ? p1.x : p2.x;
110
- var dx = (p2.x - p1.x) / (p2.y - p1.y);
111
- edges.push({ yMin: yMin, yMax: yMax, x: x, dx: dx });
112
- }
113
- return edges.sort(function (a, b) { return a.yMin - b.yMin; });
114
- };
115
- /**
116
- * Fills a quadrilateral (4-sided polygon) using scan-line algorithm
117
- * Only the outer edges are anti-aliased
118
- */
119
- exports.fillRect = function (_a) {
120
- var imageDstBuffer = _a.imageDstBuffer, points = _a.points, color = _a.color, opacity = _a.opacity;
121
- // Build edge table from all 4 vertices
122
- var edgeTable = buildQuadEdgeTable(points);
123
- if (edgeTable.length === 0)
124
- return;
125
- // Find the bounding box
126
- var yMin = Math.min.apply(Math, points.map(function (p) { return p.y; }));
127
- var yMax = Math.max.apply(Math, points.map(function (p) { return p.y; }));
128
- // Active Edge Table for scan line algorithm
129
- var activeEdges = [];
130
- // Scan line algorithm: process each horizontal line
131
- for (var y = Math.floor(yMin); y <= Math.ceil(yMax); y++) {
132
- // Add edges that start at this scanline to AET
133
- for (var _i = 0, edgeTable_1 = edgeTable; _i < edgeTable_1.length; _i++) {
134
- var edge = edgeTable_1[_i];
135
- if (Math.floor(edge.yMin) === y) {
136
- activeEdges.push(__assign({}, edge));
137
- }
138
- }
139
- // Remove edges that end at this scanline from AET
140
- for (var i = activeEdges.length - 1; i >= 0; i--) {
141
- if (Math.ceil(activeEdges[i].yMax) <= y) {
142
- activeEdges.splice(i, 1);
143
- }
144
- }
145
- // Sort active edges by x coordinate
146
- activeEdges.sort(function (a, b) { return a.x - b.x; });
147
- // Fill pixels between pairs of intersections
148
- for (var i = 0; i < activeEdges.length; i += 2) {
149
- if (i + 1 < activeEdges.length) {
150
- var xStart = activeEdges[i].x;
151
- var xEnd = activeEdges[i + 1].x;
152
- // Anti-aliased rendering with sub-pixel precision
153
- var xStartFloor = Math.floor(xStart);
154
- var xEndCeil = Math.ceil(xEnd);
155
- for (var x = xStartFloor; x < xEndCeil; x++) {
156
- var pixelIndex = imageDstBuffer.shiftPos + y * imageDstBuffer.rowBytes + x * 3;
157
- // Calculate coverage for anti-aliasing
158
- var coverage = 1.0;
159
- if (x === xStartFloor) {
160
- // Left edge pixel - calculate fractional coverage
161
- coverage = Math.min(1.0, 1.0 - (xStart - xStartFloor));
162
- }
163
- else if (x === xEndCeil - 1) {
164
- // Right edge pixel - calculate fractional coverage
165
- coverage = Math.min(1.0, xEnd - Math.floor(xEnd));
166
- }
167
- // Apply coverage to opacity for smooth edges
168
- var effectiveOpacity = opacity * coverage;
169
- var pixelColor = getRectPixelColor({
170
- imageDstBuffer: imageDstBuffer,
171
- pixelIndex: pixelIndex,
172
- color: color,
173
- opacity: effectiveOpacity,
174
- });
175
- imageDstBuffer.data[pixelIndex] = pixelColor.blue;
176
- imageDstBuffer.data[pixelIndex + 1] = pixelColor.green;
177
- imageDstBuffer.data[pixelIndex + 2] = pixelColor.red;
178
- }
179
- }
180
- }
181
- // Update x coordinates for next scanline (x' = x + dx)
182
- for (var _b = 0, activeEdges_1 = activeEdges; _b < activeEdges_1.length; _b++) {
183
- var edge = activeEdges_1[_b];
184
- edge.x += edge.dx;
185
- }
186
- }
187
- };
188
- var getRectY = function (rotation, top, height, rectHeight) {
189
- switch (rotation) {
190
- case 'up':
191
- return top + height - rectHeight;
192
- case 'mirror':
193
- return top + Math.trunc((height - rectHeight) / 2);
194
- default:
195
- return top;
196
- }
197
- };
198
- var minRectHeight = 2;
199
- var getRectHeight = function (height, spectrumValue) {
200
- var rectHeight = Math.trunc(height * spectrumValue);
201
- if (rectHeight < minRectHeight) {
202
- return minRectHeight;
203
- }
204
- return rectHeight;
205
- };
206
- var drawSpectrum = function (_a) {
207
- var imageDstBuffer = _a.imageDstBuffer, spectrum = _a.spectrum, size = _a.size, position = _a.position, rotation = _a.rotation, margin = _a.margin, color = _a.color, opacity = _a.opacity;
208
- var busWidth = Math.trunc(size.width / spectrum.length);
209
- var left = Math.trunc(position.x);
210
- var top = Math.trunc(position.y);
211
- var height = Math.trunc(size.height);
212
- for (var spectrumX = 0; spectrumX < spectrum.length; spectrumX++) {
213
- var spectrumValue = spectrum[spectrumX];
214
- if ((spectrumValue > 1) || (spectrumValue < 0)) {
215
- throw new Error('Spectrum values must be in range from 0 to 1');
216
- }
217
- var rectX = left + busWidth * spectrumX;
218
- var rectHeight = getRectHeight(height, spectrumValue);
219
- var rectY = getRectY(rotation, top, height, rectHeight);
220
- exports.drawRect({
221
- imageDstBuffer: imageDstBuffer,
222
- position: { x: rectX + margin, y: rectY },
223
- size: { width: busWidth - margin / 2, height: rectHeight },
224
- color: color,
225
- opacity: opacity,
226
- });
227
- }
228
- };
229
- var calcCirclePoint = function (angleRadians, radius) {
230
- var circleX = radius * Math.cos(angleRadians);
231
- var circleY = radius * Math.sin(angleRadians);
232
- return { x: circleX, y: circleY };
233
- };
234
- var lerp = function (start, end, t) {
235
- return start + (end - start) * t;
236
- };
237
- var drawPolarSpectrum = function (_a) {
238
- var imageDstBuffer = _a.imageDstBuffer, spectrum = _a.spectrum, centerX = _a.centerX, centerY = _a.centerY, innerRadius = _a.innerRadius, maxBarLength = _a.maxBarLength, barWidth = _a.barWidth, color = _a.color, opacity = _a.opacity;
239
- var angleStep = (2 * Math.PI) / spectrum.length;
240
- var innerLength = innerRadius * 2 * Math.PI;
241
- var radiansPerPixel = 2 * Math.PI / innerLength;
242
- var barWidthInRadians = radiansPerPixel * barWidth;
243
- var spectrumAverage = spectrum.reduce(function (a, b) { return a + b; }, 0) / spectrum.length;
244
- var scaleFactor = lerp(0.75, 1, spectrumAverage);
245
- var scaledMaxOuterRadius = (innerRadius + maxBarLength) * scaleFactor;
246
- var scaledInnerRadius = innerRadius * scaleFactor;
247
- for (var i = 0; i < spectrum.length; i++) {
248
- var currentSpectrumValue = spectrum[i] || 0;
249
- var busRadius = lerp(scaledInnerRadius, scaledMaxOuterRadius, currentSpectrumValue);
250
- var angle = i * angleStep;
251
- var angleRadiansStart = angle;
252
- var angleRadiansEnd = angle + barWidthInRadians;
253
- var point1 = calcCirclePoint(angleRadiansStart, scaledInnerRadius);
254
- var point2 = calcCirclePoint(angleRadiansStart, busRadius);
255
- var point3 = calcCirclePoint(angleRadiansEnd, scaledInnerRadius);
256
- var point4 = calcCirclePoint(angleRadiansEnd, busRadius);
257
- exports.fillRect({
258
- imageDstBuffer: imageDstBuffer,
259
- points: [
260
- { x: centerX + Math.round(point1.x), y: centerY + Math.round(point1.y) },
261
- { x: centerX + Math.round(point2.x), y: centerY + Math.round(point2.y) },
262
- { x: centerX + Math.round(point4.x), y: centerY + Math.round(point4.y) },
263
- { x: centerX + Math.round(point3.x), y: centerY + Math.round(point3.y) },
264
- ],
265
- color: color,
266
- opacity: opacity,
267
- });
268
- }
269
- };
270
- exports.createSpectrumVisualizerFrameGenerator = function () {
271
- var prevSpectrum = null;
272
- return function (_a) {
273
- var backgroundImageBuffer = _a.backgroundImageBuffer, spectrum = _a.spectrum, size = _a.size, position = _a.position, rotation = _a.rotation, margin = _a.margin, color = _a.color, opacity = _a.opacity, spectrumEffect = _a.spectrumEffect;
274
- var imageDstBuffer = Object.assign({}, backgroundImageBuffer);
275
- imageDstBuffer.data = Buffer.from(backgroundImageBuffer.data);
276
- var rgbSpectrumColor = (typeof color === 'string') ? hexToRgb(color) : color;
277
- if (spectrumEffect === 'volume') {
278
- drawSpectrum({
279
- imageDstBuffer: imageDstBuffer,
280
- spectrum: spectrum,
281
- size: size,
282
- position: { x: position.x + 2, y: position.y + 2 },
283
- rotation: rotation,
284
- margin: margin,
285
- color: rgbSpectrumColor,
286
- opacity: opacity * 0.5,
287
- });
288
- }
289
- if (spectrumEffect === 'smooth' && prevSpectrum) {
290
- drawSpectrum({
291
- imageDstBuffer: imageDstBuffer,
292
- spectrum: prevSpectrum,
293
- size: size,
294
- position: position,
295
- rotation: rotation,
296
- margin: margin,
297
- color: rgbSpectrumColor,
298
- opacity: opacity * 0.3,
299
- });
300
- }
301
- drawSpectrum({
302
- imageDstBuffer: imageDstBuffer,
303
- spectrum: spectrum,
304
- size: size,
305
- position: position,
306
- rotation: rotation,
307
- margin: margin,
308
- color: rgbSpectrumColor,
309
- opacity: opacity,
310
- });
311
- prevSpectrum = spectrum;
312
- return imageDstBuffer;
313
- };
314
- };
315
- exports.createPolarVisualizerFrameGenerator = function () {
316
- var prevSpectrum = null;
317
- return function (_a) {
318
- var backgroundImageBuffer = _a.backgroundImageBuffer, spectrum = _a.spectrum, centerX = _a.centerX, centerY = _a.centerY, innerRadius = _a.innerRadius, maxBarLength = _a.maxBarLength, barWidth = _a.barWidth, color = _a.color, opacity = _a.opacity, spectrumEffect = _a.spectrumEffect;
319
- var imageDstBuffer = Object.assign({}, backgroundImageBuffer);
320
- imageDstBuffer.data = Buffer.from(backgroundImageBuffer.data);
321
- var rgbSpectrumColor = (typeof color === 'string') ? hexToRgb(color) : color;
322
- if (spectrumEffect === 'volume') {
323
- drawPolarSpectrum({
324
- imageDstBuffer: imageDstBuffer,
325
- spectrum: spectrum,
326
- centerX: centerX + 2,
327
- centerY: centerY + 2,
328
- innerRadius: innerRadius,
329
- maxBarLength: maxBarLength,
330
- barWidth: barWidth,
331
- color: rgbSpectrumColor,
332
- opacity: opacity * 0.5,
333
- });
334
- }
335
- if (spectrumEffect === 'smooth' && prevSpectrum) {
336
- drawPolarSpectrum({
337
- imageDstBuffer: imageDstBuffer,
338
- spectrum: prevSpectrum,
339
- centerX: centerX,
340
- centerY: centerY,
341
- innerRadius: innerRadius,
342
- maxBarLength: maxBarLength,
343
- barWidth: barWidth,
344
- color: rgbSpectrumColor,
345
- opacity: opacity * 0.3,
346
- });
347
- }
348
- drawPolarSpectrum({
349
- imageDstBuffer: imageDstBuffer,
350
- spectrum: spectrum,
351
- centerX: centerX,
352
- centerY: centerY,
353
- innerRadius: innerRadius,
354
- maxBarLength: maxBarLength,
355
- barWidth: barWidth,
356
- color: rgbSpectrumColor,
357
- opacity: opacity,
358
- });
359
- prevSpectrum = spectrum;
360
- return imageDstBuffer;
361
- };
362
- };
363
- exports.convertToBmp = function (filePath, targetWidth, targetHeight) { return __awaiter(void 0, void 0, void 0, function () {
364
- return __generator(this, function (_a) {
365
- return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(void 0, void 0, void 0, function () {
366
- var image, sw, sh, isOrientationMismatch, targetAspect, cropW, cropH, cropX, cropY, _a;
367
- return __generator(this, function (_b) {
368
- switch (_b.label) {
369
- case 0:
370
- _b.trys.push([0, 2, , 3]);
371
- return [4 /*yield*/, jimp_1.default.read(filePath)];
372
- case 1:
373
- image = _b.sent();
374
- if (targetWidth && targetHeight) {
375
- sw = image.getWidth();
376
- sh = image.getHeight();
377
- isOrientationMismatch = (sw > sh && targetWidth < targetHeight) ||
378
- (sw < sh && targetWidth > targetHeight);
379
- if (isOrientationMismatch) {
380
- targetAspect = targetWidth / targetHeight;
381
- cropW = void 0, cropH = void 0, cropX = void 0, cropY = void 0;
382
- if (sw / sh > targetAspect) {
383
- cropW = Math.round(sh * targetAspect);
384
- cropH = sh;
385
- cropX = Math.round((sw - cropW) / 2);
386
- cropY = 0;
387
- }
388
- else {
389
- cropW = sw;
390
- cropH = Math.round(sw / targetAspect);
391
- cropX = 0;
392
- cropY = Math.round((sh - cropH) / 2);
393
- }
394
- image.crop(cropX, cropY, cropW, cropH);
395
- }
396
- image.resize(targetWidth, targetHeight);
397
- }
398
- image.getBuffer("image/bmp", function (err, value) {
399
- if (err) {
400
- reject(err);
401
- }
402
- resolve(value);
403
- });
404
- return [3 /*break*/, 3];
405
- case 2:
406
- _a = _b.sent();
407
- throw new Error("Cannot procces image file from path: " + filePath);
408
- case 3: return [2 /*return*/];
409
- }
410
- });
411
- }); })];
412
- });
413
- }); };
414
- exports.parseImage = function (buffer) { return bmp_js_1.decode(buffer); };
415
- exports.getImageColor = function (image) {
416
- var blueSum = 0;
417
- var greenSum = 0;
418
- var redSum = 0;
419
- for (var currY = 0; currY < image.height; currY++) {
420
- for (var currX = 0; currX < image.width; currX++) {
421
- var idx = (image.width * currY + currX) << 2;
422
- blueSum += image.data[idx + 1];
423
- greenSum += image.data[idx + 2];
424
- redSum += image.data[idx + 3];
425
- }
426
- }
427
- var pixelsCount = image.width * image.height;
428
- return {
429
- red: ~~(redSum / pixelsCount),
430
- green: ~~(greenSum / pixelsCount),
431
- blue: ~~(blueSum / pixelsCount)
432
- };
433
- };
434
- exports.getVideoFrameColor = function (bgrBuffer, width, height) {
435
- var blueSum = 0;
436
- var greenSum = 0;
437
- var redSum = 0;
438
- var pixelsCount = width * height;
439
- for (var i = 0; i < bgrBuffer.length; i += 3) {
440
- blueSum += bgrBuffer[i];
441
- greenSum += bgrBuffer[i + 1];
442
- redSum += bgrBuffer[i + 2];
443
- }
444
- return {
445
- red: ~~(redSum / pixelsCount),
446
- green: ~~(greenSum / pixelsCount),
447
- blue: ~~(blueSum / pixelsCount),
448
- };
449
- };
450
- exports.invertColor = function (color) {
451
- return ({ red: 255 - color.red, green: 255 - color.green, blue: 255 - color.blue });
452
- };
453
- var hexToRgb = function (hex) {
454
- var red = parseInt(hex.substring(1, 3), 16);
455
- var green = parseInt(hex.substring(3, 5), 16);
456
- var blue = parseInt(hex.substring(5, 7), 16);
457
- return { red: red, green: green, blue: blue };
458
- };
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (_) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var bmp_js_1 = require("bmp-js");
54
+ var jimp_1 = __importDefault(require("jimp"));
55
+ exports.mixValues = function (value1, value1Opacity, value2) {
56
+ return Math.round(value2 * (1 - value1Opacity) + value1 * value1Opacity);
57
+ };
58
+ exports.mixColors = function (_a) {
59
+ var color = _a.color, colorOpacity = _a.colorOpacity, backgroundColor = _a.backgroundColor;
60
+ return {
61
+ red: exports.mixValues(color.red, colorOpacity, backgroundColor.red),
62
+ green: exports.mixValues(color.green, colorOpacity, backgroundColor.green),
63
+ blue: exports.mixValues(color.blue, colorOpacity, backgroundColor.blue),
64
+ };
65
+ };
66
+ var getRectPixelColor = function (params) {
67
+ var imageDstBuffer = params.imageDstBuffer, pixelIndex = params.pixelIndex, color = params.color, opacity = params.opacity;
68
+ if (opacity === 1) {
69
+ return color;
70
+ }
71
+ var backgroundPixelColor = {
72
+ blue: imageDstBuffer.data[pixelIndex],
73
+ green: imageDstBuffer.data[pixelIndex + 1],
74
+ red: imageDstBuffer.data[pixelIndex + 2],
75
+ };
76
+ var resultColor = exports.mixColors({
77
+ color: color,
78
+ colorOpacity: opacity,
79
+ backgroundColor: backgroundPixelColor,
80
+ });
81
+ return resultColor;
82
+ };
83
+ exports.drawRect = function (_a) {
84
+ var imageDstBuffer = _a.imageDstBuffer, position = _a.position, size = _a.size, color = _a.color, opacity = _a.opacity;
85
+ for (var currY = position.y; currY < position.y + size.height; currY++) {
86
+ for (var currX = position.x; currX < position.x + size.width; currX++) {
87
+ var pixelIndex = imageDstBuffer.shiftPos + currY * imageDstBuffer.rowBytes + currX * 3;
88
+ var pixelColor = getRectPixelColor({
89
+ imageDstBuffer: imageDstBuffer,
90
+ pixelIndex: pixelIndex,
91
+ color: color,
92
+ opacity: opacity,
93
+ });
94
+ imageDstBuffer.data[pixelIndex] = pixelColor.blue;
95
+ imageDstBuffer.data[pixelIndex + 1] = pixelColor.green;
96
+ imageDstBuffer.data[pixelIndex + 2] = pixelColor.red;
97
+ }
98
+ }
99
+ };
100
+ var buildQuadEdgeTable = function (points) {
101
+ var edges = [];
102
+ for (var i = 0; i < points.length; i++) {
103
+ var p1 = points[i];
104
+ var p2 = points[(i + 1) % points.length];
105
+ if (p1.y === p2.y)
106
+ continue; // Skip horizontal edges
107
+ var yMin = Math.min(p1.y, p2.y);
108
+ var yMax = Math.max(p1.y, p2.y);
109
+ var x = p1.y < p2.y ? p1.x : p2.x;
110
+ var dx = (p2.x - p1.x) / (p2.y - p1.y);
111
+ edges.push({ yMin: yMin, yMax: yMax, x: x, dx: dx });
112
+ }
113
+ return edges.sort(function (a, b) { return a.yMin - b.yMin; });
114
+ };
115
+ /**
116
+ * Fills a quadrilateral (4-sided polygon) using scan-line algorithm
117
+ * Only the outer edges are anti-aliased
118
+ */
119
+ exports.fillRect = function (_a) {
120
+ var imageDstBuffer = _a.imageDstBuffer, points = _a.points, color = _a.color, opacity = _a.opacity;
121
+ // Build edge table from all 4 vertices
122
+ var edgeTable = buildQuadEdgeTable(points);
123
+ if (edgeTable.length === 0)
124
+ return;
125
+ // Find the bounding box
126
+ var yMin = Math.min.apply(Math, points.map(function (p) { return p.y; }));
127
+ var yMax = Math.max.apply(Math, points.map(function (p) { return p.y; }));
128
+ // Active Edge Table for scan line algorithm
129
+ var activeEdges = [];
130
+ // Scan line algorithm: process each horizontal line
131
+ for (var y = Math.floor(yMin); y <= Math.ceil(yMax); y++) {
132
+ // Add edges that start at this scanline to AET
133
+ for (var _i = 0, edgeTable_1 = edgeTable; _i < edgeTable_1.length; _i++) {
134
+ var edge = edgeTable_1[_i];
135
+ if (Math.floor(edge.yMin) === y) {
136
+ activeEdges.push(__assign({}, edge));
137
+ }
138
+ }
139
+ // Remove edges that end at this scanline from AET
140
+ for (var i = activeEdges.length - 1; i >= 0; i--) {
141
+ if (Math.ceil(activeEdges[i].yMax) <= y) {
142
+ activeEdges.splice(i, 1);
143
+ }
144
+ }
145
+ // Sort active edges by x coordinate
146
+ activeEdges.sort(function (a, b) { return a.x - b.x; });
147
+ // Fill pixels between pairs of intersections
148
+ for (var i = 0; i < activeEdges.length; i += 2) {
149
+ if (i + 1 < activeEdges.length) {
150
+ var xStart = activeEdges[i].x;
151
+ var xEnd = activeEdges[i + 1].x;
152
+ // Anti-aliased rendering with sub-pixel precision
153
+ var xStartFloor = Math.floor(xStart);
154
+ var xEndCeil = Math.ceil(xEnd);
155
+ for (var x = xStartFloor; x < xEndCeil; x++) {
156
+ var pixelIndex = imageDstBuffer.shiftPos + y * imageDstBuffer.rowBytes + x * 3;
157
+ // Calculate coverage for anti-aliasing
158
+ var coverage = 1.0;
159
+ if (x === xStartFloor) {
160
+ // Left edge pixel - calculate fractional coverage
161
+ coverage = Math.min(1.0, 1.0 - (xStart - xStartFloor));
162
+ }
163
+ else if (x === xEndCeil - 1) {
164
+ // Right edge pixel - calculate fractional coverage
165
+ coverage = Math.min(1.0, xEnd - Math.floor(xEnd));
166
+ }
167
+ // Apply coverage to opacity for smooth edges
168
+ var effectiveOpacity = opacity * coverage;
169
+ var pixelColor = getRectPixelColor({
170
+ imageDstBuffer: imageDstBuffer,
171
+ pixelIndex: pixelIndex,
172
+ color: color,
173
+ opacity: effectiveOpacity,
174
+ });
175
+ imageDstBuffer.data[pixelIndex] = pixelColor.blue;
176
+ imageDstBuffer.data[pixelIndex + 1] = pixelColor.green;
177
+ imageDstBuffer.data[pixelIndex + 2] = pixelColor.red;
178
+ }
179
+ }
180
+ }
181
+ // Update x coordinates for next scanline (x' = x + dx)
182
+ for (var _b = 0, activeEdges_1 = activeEdges; _b < activeEdges_1.length; _b++) {
183
+ var edge = activeEdges_1[_b];
184
+ edge.x += edge.dx;
185
+ }
186
+ }
187
+ };
188
+ var getRectY = function (rotation, top, height, rectHeight) {
189
+ switch (rotation) {
190
+ case 'up':
191
+ return top + height - rectHeight;
192
+ case 'mirror':
193
+ return top + Math.trunc((height - rectHeight) / 2);
194
+ default:
195
+ return top;
196
+ }
197
+ };
198
+ var minRectHeight = 2;
199
+ var getRectHeight = function (height, spectrumValue) {
200
+ var rectHeight = Math.trunc(height * spectrumValue);
201
+ if (rectHeight < minRectHeight) {
202
+ return minRectHeight;
203
+ }
204
+ return rectHeight;
205
+ };
206
+ var drawSpectrum = function (_a) {
207
+ var imageDstBuffer = _a.imageDstBuffer, spectrum = _a.spectrum, size = _a.size, position = _a.position, rotation = _a.rotation, margin = _a.margin, color = _a.color, opacity = _a.opacity;
208
+ var busWidth = Math.trunc(size.width / spectrum.length);
209
+ var left = Math.trunc(position.x);
210
+ var top = Math.trunc(position.y);
211
+ var height = Math.trunc(size.height);
212
+ for (var spectrumX = 0; spectrumX < spectrum.length; spectrumX++) {
213
+ var spectrumValue = spectrum[spectrumX];
214
+ if ((spectrumValue > 1) || (spectrumValue < 0)) {
215
+ throw new Error('Spectrum values must be in range from 0 to 1');
216
+ }
217
+ var rectX = left + busWidth * spectrumX;
218
+ var rectHeight = getRectHeight(height, spectrumValue);
219
+ var rectY = getRectY(rotation, top, height, rectHeight);
220
+ exports.drawRect({
221
+ imageDstBuffer: imageDstBuffer,
222
+ position: { x: rectX + margin, y: rectY },
223
+ size: { width: busWidth - margin / 2, height: rectHeight },
224
+ color: color,
225
+ opacity: opacity,
226
+ });
227
+ }
228
+ };
229
+ var calcCirclePoint = function (angleRadians, radius) {
230
+ var circleX = radius * Math.cos(angleRadians);
231
+ var circleY = radius * Math.sin(angleRadians);
232
+ return { x: circleX, y: circleY };
233
+ };
234
+ var lerp = function (start, end, t) {
235
+ return start + (end - start) * t;
236
+ };
237
+ var drawPolarSpectrum = function (_a) {
238
+ var imageDstBuffer = _a.imageDstBuffer, spectrum = _a.spectrum, centerX = _a.centerX, centerY = _a.centerY, innerRadius = _a.innerRadius, maxBarLength = _a.maxBarLength, barWidth = _a.barWidth, color = _a.color, opacity = _a.opacity;
239
+ var angleStep = (2 * Math.PI) / spectrum.length;
240
+ var innerLength = innerRadius * 2 * Math.PI;
241
+ var radiansPerPixel = 2 * Math.PI / innerLength;
242
+ var barWidthInRadians = radiansPerPixel * barWidth;
243
+ var spectrumAverage = spectrum.reduce(function (a, b) { return a + b; }, 0) / spectrum.length;
244
+ var scaleFactor = lerp(0.75, 1, spectrumAverage);
245
+ var scaledMaxOuterRadius = (innerRadius + maxBarLength) * scaleFactor;
246
+ var scaledInnerRadius = innerRadius * scaleFactor;
247
+ for (var i = 0; i < spectrum.length; i++) {
248
+ var currentSpectrumValue = spectrum[i] || 0;
249
+ var busRadius = lerp(scaledInnerRadius, scaledMaxOuterRadius, currentSpectrumValue);
250
+ var angle = i * angleStep;
251
+ var angleRadiansStart = angle;
252
+ var angleRadiansEnd = angle + barWidthInRadians;
253
+ var point1 = calcCirclePoint(angleRadiansStart, scaledInnerRadius);
254
+ var point2 = calcCirclePoint(angleRadiansStart, busRadius);
255
+ var point3 = calcCirclePoint(angleRadiansEnd, scaledInnerRadius);
256
+ var point4 = calcCirclePoint(angleRadiansEnd, busRadius);
257
+ exports.fillRect({
258
+ imageDstBuffer: imageDstBuffer,
259
+ points: [
260
+ { x: centerX + Math.round(point1.x), y: centerY + Math.round(point1.y) },
261
+ { x: centerX + Math.round(point2.x), y: centerY + Math.round(point2.y) },
262
+ { x: centerX + Math.round(point4.x), y: centerY + Math.round(point4.y) },
263
+ { x: centerX + Math.round(point3.x), y: centerY + Math.round(point3.y) },
264
+ ],
265
+ color: color,
266
+ opacity: opacity,
267
+ });
268
+ }
269
+ };
270
+ exports.createSpectrumVisualizerFrameGenerator = function () {
271
+ var prevSpectrum = null;
272
+ return function (_a) {
273
+ var backgroundImageBuffer = _a.backgroundImageBuffer, spectrum = _a.spectrum, size = _a.size, position = _a.position, rotation = _a.rotation, margin = _a.margin, color = _a.color, opacity = _a.opacity, spectrumEffect = _a.spectrumEffect;
274
+ var imageDstBuffer = Object.assign({}, backgroundImageBuffer);
275
+ imageDstBuffer.data = Buffer.from(backgroundImageBuffer.data);
276
+ var rgbSpectrumColor = (typeof color === 'string') ? hexToRgb(color) : color;
277
+ if (spectrumEffect === 'volume') {
278
+ drawSpectrum({
279
+ imageDstBuffer: imageDstBuffer,
280
+ spectrum: spectrum,
281
+ size: size,
282
+ position: { x: position.x + 2, y: position.y + 2 },
283
+ rotation: rotation,
284
+ margin: margin,
285
+ color: rgbSpectrumColor,
286
+ opacity: opacity * 0.5,
287
+ });
288
+ }
289
+ if (spectrumEffect === 'smooth' && prevSpectrum) {
290
+ drawSpectrum({
291
+ imageDstBuffer: imageDstBuffer,
292
+ spectrum: prevSpectrum,
293
+ size: size,
294
+ position: position,
295
+ rotation: rotation,
296
+ margin: margin,
297
+ color: rgbSpectrumColor,
298
+ opacity: opacity * 0.3,
299
+ });
300
+ }
301
+ drawSpectrum({
302
+ imageDstBuffer: imageDstBuffer,
303
+ spectrum: spectrum,
304
+ size: size,
305
+ position: position,
306
+ rotation: rotation,
307
+ margin: margin,
308
+ color: rgbSpectrumColor,
309
+ opacity: opacity,
310
+ });
311
+ prevSpectrum = spectrum;
312
+ return imageDstBuffer;
313
+ };
314
+ };
315
+ exports.createPolarVisualizerFrameGenerator = function () {
316
+ var prevSpectrum = null;
317
+ return function (_a) {
318
+ var backgroundImageBuffer = _a.backgroundImageBuffer, spectrum = _a.spectrum, centerX = _a.centerX, centerY = _a.centerY, innerRadius = _a.innerRadius, maxBarLength = _a.maxBarLength, barWidth = _a.barWidth, color = _a.color, opacity = _a.opacity, spectrumEffect = _a.spectrumEffect;
319
+ var imageDstBuffer = Object.assign({}, backgroundImageBuffer);
320
+ imageDstBuffer.data = Buffer.from(backgroundImageBuffer.data);
321
+ var rgbSpectrumColor = (typeof color === 'string') ? hexToRgb(color) : color;
322
+ if (spectrumEffect === 'volume') {
323
+ drawPolarSpectrum({
324
+ imageDstBuffer: imageDstBuffer,
325
+ spectrum: spectrum,
326
+ centerX: centerX + 2,
327
+ centerY: centerY + 2,
328
+ innerRadius: innerRadius,
329
+ maxBarLength: maxBarLength,
330
+ barWidth: barWidth,
331
+ color: rgbSpectrumColor,
332
+ opacity: opacity * 0.5,
333
+ });
334
+ }
335
+ if (spectrumEffect === 'smooth' && prevSpectrum) {
336
+ drawPolarSpectrum({
337
+ imageDstBuffer: imageDstBuffer,
338
+ spectrum: prevSpectrum,
339
+ centerX: centerX,
340
+ centerY: centerY,
341
+ innerRadius: innerRadius,
342
+ maxBarLength: maxBarLength,
343
+ barWidth: barWidth,
344
+ color: rgbSpectrumColor,
345
+ opacity: opacity * 0.3,
346
+ });
347
+ }
348
+ drawPolarSpectrum({
349
+ imageDstBuffer: imageDstBuffer,
350
+ spectrum: spectrum,
351
+ centerX: centerX,
352
+ centerY: centerY,
353
+ innerRadius: innerRadius,
354
+ maxBarLength: maxBarLength,
355
+ barWidth: barWidth,
356
+ color: rgbSpectrumColor,
357
+ opacity: opacity,
358
+ });
359
+ prevSpectrum = spectrum;
360
+ return imageDstBuffer;
361
+ };
362
+ };
363
+ exports.convertToBmp = function (filePath, targetWidth, targetHeight) { return __awaiter(void 0, void 0, void 0, function () {
364
+ return __generator(this, function (_a) {
365
+ return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(void 0, void 0, void 0, function () {
366
+ var image, sw, sh, isOrientationMismatch, targetAspect, cropW, cropH, cropX, cropY, _a;
367
+ return __generator(this, function (_b) {
368
+ switch (_b.label) {
369
+ case 0:
370
+ _b.trys.push([0, 2, , 3]);
371
+ return [4 /*yield*/, jimp_1.default.read(filePath)];
372
+ case 1:
373
+ image = _b.sent();
374
+ if (targetWidth && targetHeight) {
375
+ sw = image.getWidth();
376
+ sh = image.getHeight();
377
+ isOrientationMismatch = (sw > sh && targetWidth < targetHeight) ||
378
+ (sw < sh && targetWidth > targetHeight);
379
+ if (isOrientationMismatch) {
380
+ targetAspect = targetWidth / targetHeight;
381
+ cropW = void 0, cropH = void 0, cropX = void 0, cropY = void 0;
382
+ if (sw / sh > targetAspect) {
383
+ cropW = Math.round(sh * targetAspect);
384
+ cropH = sh;
385
+ cropX = Math.round((sw - cropW) / 2);
386
+ cropY = 0;
387
+ }
388
+ else {
389
+ cropW = sw;
390
+ cropH = Math.round(sw / targetAspect);
391
+ cropX = 0;
392
+ cropY = Math.round((sh - cropH) / 2);
393
+ }
394
+ image.crop(cropX, cropY, cropW, cropH);
395
+ }
396
+ image.resize(targetWidth, targetHeight);
397
+ }
398
+ image.getBuffer("image/bmp", function (err, value) {
399
+ if (err) {
400
+ reject(err);
401
+ }
402
+ resolve(value);
403
+ });
404
+ return [3 /*break*/, 3];
405
+ case 2:
406
+ _a = _b.sent();
407
+ throw new Error("Cannot procces image file from path: " + filePath);
408
+ case 3: return [2 /*return*/];
409
+ }
410
+ });
411
+ }); })];
412
+ });
413
+ }); };
414
+ exports.parseImage = function (buffer) { return bmp_js_1.decode(buffer); };
415
+ exports.getImageColor = function (image) {
416
+ var blueSum = 0;
417
+ var greenSum = 0;
418
+ var redSum = 0;
419
+ for (var currY = 0; currY < image.height; currY++) {
420
+ for (var currX = 0; currX < image.width; currX++) {
421
+ var idx = (image.width * currY + currX) << 2;
422
+ blueSum += image.data[idx + 1];
423
+ greenSum += image.data[idx + 2];
424
+ redSum += image.data[idx + 3];
425
+ }
426
+ }
427
+ var pixelsCount = image.width * image.height;
428
+ return {
429
+ red: ~~(redSum / pixelsCount),
430
+ green: ~~(greenSum / pixelsCount),
431
+ blue: ~~(blueSum / pixelsCount)
432
+ };
433
+ };
434
+ exports.getVideoFrameColor = function (bgrBuffer, width, height) {
435
+ var blueSum = 0;
436
+ var greenSum = 0;
437
+ var redSum = 0;
438
+ var pixelsCount = width * height;
439
+ for (var i = 0; i < bgrBuffer.length; i += 3) {
440
+ blueSum += bgrBuffer[i];
441
+ greenSum += bgrBuffer[i + 1];
442
+ redSum += bgrBuffer[i + 2];
443
+ }
444
+ return {
445
+ red: ~~(redSum / pixelsCount),
446
+ green: ~~(greenSum / pixelsCount),
447
+ blue: ~~(blueSum / pixelsCount),
448
+ };
449
+ };
450
+ exports.invertColor = function (color) {
451
+ return ({ red: 255 - color.red, green: 255 - color.green, blue: 255 - color.blue });
452
+ };
453
+ /** Pixel shift strength for the cut frame and the frames after it. */
454
+ exports.CUT_SHAKE_AMPLITUDE_BY_OFFSET = [14, 9, 5, 3, 1];
455
+ exports.CUT_SHAKE_PEAK_AMPLITUDE = 14;
456
+ exports.MIN_CUT_SHAKE_FRAMES = 3;
457
+ exports.SHAKE_DURATION_BEAT_FRACTION = 1 / 3;
458
+ /** Camera shake starts this many seconds after the cut instead of on the cut frame. */
459
+ exports.CAMERA_SHAKE_DELAY_SECONDS = 0.1;
460
+ /**
461
+ * When auto-edit produces no cuts (e.g. a single continuous-shot video with no detected
462
+ * scene changes), camera shake falls back to every Nth beat of the tempo grid instead.
463
+ */
464
+ exports.CAMERA_SHAKE_EVERY_BEATS = 2;
465
+ exports.buildCutShakeAmplitudes = function (periodFrames) {
466
+ if (!(periodFrames > 0)) {
467
+ return Array.from(exports.CUT_SHAKE_AMPLITUDE_BY_OFFSET);
468
+ }
469
+ var frameCount = Math.max(exports.MIN_CUT_SHAKE_FRAMES, Math.round(periodFrames * exports.SHAKE_DURATION_BEAT_FRACTION));
470
+ if (frameCount === 1) {
471
+ return [exports.CUT_SHAKE_PEAK_AMPLITUDE];
472
+ }
473
+ var decayTo = 1 / exports.CUT_SHAKE_PEAK_AMPLITUDE;
474
+ var amplitudes = [];
475
+ for (var i = 0; i < frameCount; i++) {
476
+ var t = i / (frameCount - 1);
477
+ amplitudes.push(Math.max(1, Math.round(exports.CUT_SHAKE_PEAK_AMPLITUDE * Math.pow(decayTo, t))));
478
+ }
479
+ return amplitudes;
480
+ };
481
+ var clampInt = function (value, min, max) {
482
+ if (value < min) {
483
+ return min;
484
+ }
485
+ if (value > max) {
486
+ return max;
487
+ }
488
+ return value;
489
+ };
490
+ exports.getCutShakeOffset = function (frameIndex, cutFrames, amplitudes, delayFrames) {
491
+ if (amplitudes === void 0) { amplitudes = exports.CUT_SHAKE_AMPLITUDE_BY_OFFSET; }
492
+ if (delayFrames === void 0) { delayFrames = 0; }
493
+ if (amplitudes.length === 0) {
494
+ return { x: 0, y: 0 };
495
+ }
496
+ var delayedFrameIndex = frameIndex - delayFrames;
497
+ var framesAfterCut = -1;
498
+ var originCut = -1;
499
+ for (var offset = 0; offset < amplitudes.length; offset++) {
500
+ var cut = delayedFrameIndex - offset;
501
+ if (cutFrames.has(cut) && (framesAfterCut === -1 || offset < framesAfterCut)) {
502
+ framesAfterCut = offset;
503
+ originCut = cut;
504
+ }
505
+ }
506
+ if (framesAfterCut === -1) {
507
+ return { x: 0, y: 0 };
508
+ }
509
+ var amplitude = amplitudes[framesAfterCut];
510
+ var angle = originCut * 2.399 + framesAfterCut * 2.1;
511
+ return {
512
+ x: Math.round(Math.cos(angle) * amplitude),
513
+ y: Math.round(Math.sin(angle) * amplitude),
514
+ };
515
+ };
516
+ exports.applyCameraShake = function (imageDstBuffer, width, height, offsetX, offsetY) {
517
+ var ox = Math.round(offsetX);
518
+ var oy = Math.round(offsetY);
519
+ if (ox === 0 && oy === 0) {
520
+ return;
521
+ }
522
+ var shiftPos = imageDstBuffer.shiftPos, rowBytes = imageDstBuffer.rowBytes, data = imageDstBuffer.data;
523
+ var pixelBytes = height * rowBytes;
524
+ var sourcePixels = Buffer.allocUnsafe(pixelBytes);
525
+ data.copy(sourcePixels, 0, shiftPos, shiftPos + pixelBytes);
526
+ for (var y = 0; y < height; y++) {
527
+ var srcY = clampInt(y - oy, 0, height - 1);
528
+ var dstRow = shiftPos + y * rowBytes;
529
+ var srcRow = srcY * rowBytes;
530
+ for (var x = 0; x < width; x++) {
531
+ var srcX = clampInt(x - ox, 0, width - 1);
532
+ var dstIndex = dstRow + x * 3;
533
+ var srcIndex = srcRow + srcX * 3;
534
+ data[dstIndex] = sourcePixels[srcIndex];
535
+ data[dstIndex + 1] = sourcePixels[srcIndex + 1];
536
+ data[dstIndex + 2] = sourcePixels[srcIndex + 2];
537
+ }
538
+ }
539
+ };
540
+ var hexToRgb = function (hex) {
541
+ var red = parseInt(hex.substring(1, 3), 16);
542
+ var green = parseInt(hex.substring(3, 5), 16);
543
+ var blue = parseInt(hex.substring(5, 7), 16);
544
+ return { red: red, green: green, blue: blue };
545
+ };
459
546
  //# sourceMappingURL=image.js.map