You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, gridCount = "1", colorGroups = "8", apply2012Filter = "true") {
// Parse parameters
const grid = parseInt(gridCount, 10);
const validGrid = isNaN(grid) || grid < 1 ? 1 : grid;
const numColorLevels = parseInt(colorGroups, 10);
const validColorGroups = isNaN(numColorLevels) || numColorLevels < 2 ? 8 : numColorLevels;
const do2012Filter = String(apply2012Filter).toLowerCase() === "true" || apply2012Filter === "1";
// Setup canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = originalImg.width;
const height = originalImg.height;
canvas.width = width;
canvas.height = height;
// Step 1: Physical "Group" Arraying - creating a grid of the original image
const tileW = width / validGrid;
const tileH = height / validGrid;
for (let row = 0; row < validGrid; row++) {
for (let col = 0; col < validGrid; col++) {
ctx.drawImage(originalImg, col * tileW, row * tileH, tileW, tileH);
}
}
// Step 2: Pixel Data Modification (Color grouping and 2012 styling)
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
// Factor used to force colors into "groups" (Posterization limit)
const factor = 255 / (validColorGroups - 1);
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// Apply a "2012 Vintage Photo App" stylistic color manipulation
if (do2012Filter) {
// Warm sepia tones commonly seen in 2012-era filters
let tr = (r * 0.393) + (g * 0.769) + (b * 0.189);
let tg = (r * 0.349) + (g * 0.686) + (b * 0.168);
let tb = (r * 0.272) + (g * 0.534) + (b * 0.131);
// Enhance contrast significantly (popular 2012 stylistic choice)
r = ((tr / 255 - 0.5) * 1.2 + 0.5) * 255;
g = ((tg / 255 - 0.5) * 1.2 + 0.5) * 255;
b = ((tb / 255 - 0.5) * 1.2 + 0.5) * 255;
}
// Color Space Grouping (quantizing into distinct bands)
r = Math.round(r / factor) * factor;
g = Math.round(g / factor) * factor;
b = Math.round(b / factor) * factor;
// Clamp values to valid 0-255 range and update pixel data
data[i] = Math.min(255, Math.max(0, r));
data[i + 1] = Math.min(255, Math.max(0, g));
data[i + 2] = Math.min(255, Math.max(0, b));
}
// Push manipulated pixels back onto the canvas
ctx.putImageData(imageData, 0, 0);
// Step 3: Draw 2012 specific lighting / vignette overlays
if (do2012Filter) {
const cx = width / 2;
const cy = height / 2;
const maxRadius = Math.sqrt(cx * cx + cy * cy);
// 1. Dark Vignette border (Heavy corners were a signature of group shared photos in 2012)
const vignette = ctx.createRadialGradient(cx, cy, maxRadius * 0.4, cx, cy, maxRadius);
vignette.addColorStop(0, 'rgba(0, 0, 0, 0)');
vignette.addColorStop(1, 'rgba(0, 0, 0, 0.7)');
ctx.fillStyle = vignette;
ctx.fillRect(0, 0, width, height);
// 2. Light leak / Sun flare overlay mask
const flare = ctx.createRadialGradient(cx * 0.5, cy * 0.3, 0, cx * 0.5, cy * 0.3, maxRadius * 0.8);
flare.addColorStop(0, 'rgba(255, 200, 150, 0.25)');
flare.addColorStop(1, 'rgba(255, 200, 150, 0)');
ctx.globalCompositeOperation = 'screen';
ctx.fillStyle = flare;
ctx.fillRect(0, 0, width, height);
// Restore default composite operation context
ctx.globalCompositeOperation = 'source-over';
}
return canvas;
}
Apply Changes