nodejs-audio-visualizer 4.4.12 → 4.5.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 (48) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +80 -75
  3. package/dist/audio.d.ts +12 -12
  4. package/dist/audio.js +120 -120
  5. package/dist/beats.d.ts +19 -19
  6. package/dist/beats.js +43 -43
  7. package/dist/bpmEncoder.d.ts +14 -14
  8. package/dist/bpmEncoder.js +97 -97
  9. package/dist/config.d.ts +77 -67
  10. package/dist/config.js +369 -356
  11. package/dist/config.js.map +1 -1
  12. package/dist/dsp.d.ts +16 -16
  13. package/dist/dsp.js +76 -76
  14. package/dist/highlight.d.ts +32 -32
  15. package/dist/highlight.js +325 -325
  16. package/dist/image.d.ts +79 -79
  17. package/dist/image.js +458 -458
  18. package/dist/index.d.ts +79 -74
  19. package/dist/index.js +531 -528
  20. package/dist/index.js.map +1 -1
  21. package/dist/subtitleConvert.d.ts +3 -3
  22. package/dist/subtitleConvert.js +61 -61
  23. package/dist/video.d.ts +80 -80
  24. package/dist/video.js +434 -430
  25. package/dist/video.js.map +1 -1
  26. package/dist/waitForEventLoop.d.ts +1 -1
  27. package/dist/waitForEventLoop.js +5 -5
  28. package/package.json +61 -61
  29. package/src/audio.ts +120 -120
  30. package/src/beats.ts +68 -68
  31. package/src/bpmEncoder.ts +97 -97
  32. package/src/config.ts +476 -462
  33. package/src/dsp.ts +95 -95
  34. package/src/highlight.ts +284 -284
  35. package/src/image.ts +602 -602
  36. package/src/index.ts +713 -685
  37. package/src/subtitleConvert.ts +63 -63
  38. package/src/tests/audio.test.ts +96 -96
  39. package/src/tests/config.test.ts +496 -475
  40. package/src/tests/dsp.test.ts +24 -24
  41. package/src/tests/highlight.test.ts +178 -178
  42. package/src/tests/image.test.ts +222 -222
  43. package/src/tests/index.test.ts +112 -112
  44. package/src/tests/subtitleConvert.test.ts +23 -23
  45. package/src/tests/video.test.ts +285 -216
  46. package/src/typings.d.ts +6 -6
  47. package/src/video.ts +550 -547
  48. package/src/waitForEventLoop.ts +2 -2
package/dist/image.js CHANGED
@@ -1,459 +1,459 @@
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
+ 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
+ };
459
459
  //# sourceMappingURL=image.js.map