You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, theme = "dark", overlayPosition = "bottom") {
// Create the canvas and context
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Get reliable dimensions
const w = originalImg.naturalWidth || originalImg.width;
const h = originalImg.naturalHeight || originalImg.height;
if (!w || !h) {
console.error("Invalid image dimensions.");
return originalImg;
}
canvas.width = w;
canvas.height = h;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, w, h);
// Try to extract pixel data for heuristic image analysis
// Handles potential cross-origin (tainted canvas) restrictions gracefully
let data;
let isTainted = false;
try {
data = ctx.getImageData(0, 0, w, h).data;
} catch (err) {
console.warn("Canvas tainted by cross-origin data. Resorting to fallback dimensional analysis.");
data = new Uint8ClampedArray([0, 0, 0, 0]); // dummy array
isTainted = true;
}
// Analytic variables
let totalSat = 0;
let sepiaScore = 0;
let bwScore = 0;
let sampleCount = 0;
let hash = 0;
// Fast sampling to maintain peak performance (aiming for ~100k samples max)
const step = isTainted ? 4 : 4 * Math.max(1, Math.floor((w * h) / 100000));
for (let i = 0; i < data.length; i += step) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const sat = max - min;
totalSat += sat;
// Black and White threshold
if (sat <= 15) {
bwScore++;
}
// Sepia heuristics: Red dominates Green, Green dominates Blue, muted saturation
else if (r > g + 5 && g > b + 5 && sat < 100) {
sepiaScore++;
}
// Pseudo-random deterministic hash based on pixels for accurate reproducibility on the same image
hash = (hash + (r * 31) + (g * 17) + b) % 100000;
sampleCount++;
}
// Fallback deterministic logic if cross-origin blocked reads
if (isTainted || sampleCount === 0) {
hash = (w * 31 + h * 17) % 100000;
sampleCount = 1; // avoid division by zero
}
// Averages
const avgSat = totalSat / sampleCount;
const bwRatio = bwScore / sampleCount;
const sepiaRatio = sepiaScore / sampleCount;
// Era Heuristic Classification
let estimatedYear;
let eraName;
if (sepiaRatio > 0.25) {
estimatedYear = 1880 + (hash % 40); // 1880 - 1919
eraName = "Early Studio / Sepia Era";
} else if (bwRatio > 0.45) {
estimatedYear = 1920 + (hash % 45); // 1920 - 1964
eraName = "Classic Black & White Era";
} else if (avgSat < 30) {
estimatedYear = 1965 + (hash % 15); // 1965 - 1979
eraName = "Early Color Film Era";
} else if (avgSat < 50) {
estimatedYear = 1980 + (hash % 20); // 1980 - 1999
eraName = "Late 20th Century Film";
} else {
estimatedYear = 2000 + (hash % 25); // 2000 - 2024
eraName = "Modern Digital Era";
}
// --- Render Identification Overlay ---
// Responsive UI sizing based on canvas width, constrained to keep it legible
const baseFontSize = Math.max(14, w * 0.025);
const padding = baseFontSize * 1.5;
// Ensure overlay doesn't cover more than 35% of very tiny images
const barHeight = Math.min(h * 0.35, baseFontSize * 4.5);
const barY = overlayPosition === "top" ? 0 : h - barHeight;
// Overlay Background
if (theme === "light") {
ctx.fillStyle = 'rgba(245, 245, 245, 0.92)';
} else {
ctx.fillStyle = 'rgba(15, 15, 15, 0.88)';
}
ctx.fillRect(0, barY, w, barHeight);
// Tech Accent Indicator Line
ctx.fillStyle = '#0CAFFF'; // Vibrant Identifier Blue
ctx.fillRect(0, overlayPosition === "top" ? barHeight - 4 : barY, w, 4);
// Text settings
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
// 1. Primary Estimate Text
ctx.fillStyle = '#0CAFFF';
ctx.font = `bold ${baseFontSize * 1.4}px "Segoe UI", -apple-system, Roboto, Helvetica, Arial, sans-serif`;
const yearText = `Est. Year: ~${estimatedYear}`;
ctx.fillText(yearText, padding, barY + (barHeight * 0.38));
// Measure to chain next text directly next to it
const yearWidth = ctx.measureText(yearText).width;
// 2. Era Identity Subtitle
ctx.fillStyle = theme === "light" ? '#222222' : '#FFFFFF';
ctx.font = `bold ${baseFontSize * 1.1}px "Segoe UI", -apple-system, Roboto, Helvetica, Arial, sans-serif`;
ctx.fillText(` | ${eraName}`, padding + yearWidth, barY + (barHeight * 0.38));
// 3. Technical Confidence Metrics Details
ctx.fillStyle = theme === "light" ? '#666666' : '#AAAAAA';
ctx.font = `${baseFontSize * 0.8}px "Segoe UI", -apple-system, Roboto, Helvetica, Arial, sans-serif`;
const analysisStatus = isTainted ? "RESTRICTED (CORS)" : "SUCCESS";
const metricsStr = `Analysis Details: Color Saturation ${Math.round(avgSat)} • B&W ${(bwRatio * 100).toFixed(1)}% • Sepia ${(sepiaRatio * 100).toFixed(1)}% [${analysisStatus}]`;
ctx.fillText(metricsStr, padding, barY + (barHeight * 0.72));
return canvas;
}
Apply Changes