UNPKG

imagerot

Version:

A lightweight, cross-environment image library for applying unique effects via raw image buffers.

69 lines (68 loc) 3.91 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.macroblock = void 0; const macroblock = (_a, ...args_1) => __awaiter(void 0, [_a, ...args_1], void 0, function* ({ data, width, height }, options = {}) { var _b, _c, _d, _e; if (data.length === 0) return data; const lineThickness = (_b = options.lineThickness) !== null && _b !== void 0 ? _b : 2; const interferenceIntensity = (_c = options.interferenceIntensity) !== null && _c !== void 0 ? _c : 0.3; const noiseIntensity = (_d = options.noiseIntensity) !== null && _d !== void 0 ? _d : 0.1; const colorBleed = (_e = options.colorBleed) !== null && _e !== void 0 ? _e : 0.2; const tempData = new Uint8Array(data); // Copy for shifts and bleeding // Apply scanlines: Darken every other set of rows for (let y = 0; y < height; y++) { const isScanline = (y % (lineThickness * 2)) < lineThickness; // Alternate bands const darkenFactor = isScanline ? 0.85 : 1.0; // Slight darken for VHS lines for (let x = 0; x < width; x++) { const idx = (y * width + x) * 4; // Darken for scanlines data[idx] = Math.floor(tempData[idx] * darkenFactor); data[idx + 1] = Math.floor(tempData[idx + 1] * darkenFactor); data[idx + 2] = Math.floor(tempData[idx + 2] * darkenFactor); // Add noise: Random perturbation if (Math.random() < noiseIntensity) { const noise = Math.floor(Math.random() * 50 - 25); // -25 to 25 shift data[idx] = Math.max(0, Math.min(255, data[idx] + noise)); data[idx + 1] = Math.max(0, Math.min(255, data[idx + 1] + noise)); data[idx + 2] = Math.max(0, Math.min(255, data[idx + 2] + noise)); } } // Interference: Random row shifts for glitchy tracking if (Math.random() < interferenceIntensity) { const shift = Math.floor(Math.random() * 10 - 5); // -5 to 5 pixel horizontal shift for (let x = 0; x < width; x++) { const srcX = Math.max(0, Math.min(width - 1, x + shift)); const idx = (y * width + x) * 4; const srcIdx = (y * width + srcX) * 4; data[idx] = tempData[srcIdx]; data[idx + 1] = tempData[srcIdx + 1]; data[idx + 2] = tempData[srcIdx + 2]; } } } // Add color bleed: Slight RGB channel shifts for VHS chromatic aberration for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const idx = (y * width + x) * 4; // Shift red slightly left, blue right (simple bleed) const redShift = Math.floor(colorBleed * 5); // e.g., 1 pixel if colorBleed=0.2 const blueShift = -redShift; const rSrcX = Math.max(0, Math.min(width - 1, x + redShift)); const bSrcX = Math.max(0, Math.min(width - 1, x + blueShift)); data[idx] = tempData[(y * width + rSrcX) * 4]; // Red from shifted data[idx + 2] = tempData[(y * width + bSrcX) * 4 + 2]; // Blue from shifted } } return data; }); exports.macroblock = macroblock;