You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, identifiedText = "Universal Pictures Fanfare", transcriptionText = "Audio Universal Pictures David Newman Fanfare Universal Pictures Jerry Goldsmith Fanfare", primaryColor = "#1db954", barsCount = 100) {
let width = originalImg.naturalWidth || originalImg.width || 800;
let height = originalImg.naturalHeight || originalImg.height || 600;
// Implement minimum dimensions to ensure the UI elements always look crisp and readable
if (width < 600) {
const ratio = 600 / width;
width = 600;
height = Math.round(height * ratio);
}
// Create rendering canvas
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
// 1. Draw source image as background album art
ctx.drawImage(originalImg, 0, 0, width, height);
// 2. Draw darkening gradient at the bottom to anchor text and visualizations
const gradientHeight = height * 0.7;
const gradient = ctx.createLinearGradient(0, height - gradientHeight, 0, height);
gradient.addColorStop(0, "rgba(0, 0, 0, 0)");
gradient.addColorStop(0.35, "rgba(0, 0, 0, 0.5)");
gradient.addColorStop(0.65, "rgba(0, 0, 0, 0.85)");
gradient.addColorStop(1, "rgba(0, 0, 0, 0.98)");
ctx.fillStyle = gradient;
ctx.fillRect(0, Math.max(0, height - gradientHeight), width, gradientHeight);
// 3. Dynamic Text Layout Setup (Building systematically from bottom -> up)
const transFontSize = Math.max(14, Math.floor(width * 0.024));
const titleFontSize = Math.max(20, Math.floor(width * 0.038));
const lineHeight = transFontSize * 1.5;
const maxWidth = width * 0.85;
ctx.font = `italic 400 ${transFontSize}px "Segoe UI", Roboto, Helvetica, Arial, sans-serif`;
// Wrap Transcription Text
const formattedTranscription = `“${transcriptionText}”`;
const words = formattedTranscription.split(' ');
let line = '';
const lines = [];
for (let n = 0; n < words.length; n++) {
const testLine = line + words[n] + ' ';
const metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && n > 0) {
lines.push(line);
line = words[n] + ' ';
} else {
line = testLine;
}
}
lines.push(line);
// Calculate dynamic anchor positions
const lowerMargin = Math.max(30, height * 0.06);
const transcriptionStartY = height - lowerMargin - ((lines.length - 1) * lineHeight);
const titleY = transcriptionStartY - titleFontSize - 15;
// 4. Waveform Visualizer Extrapolator
const numBars = parseInt(barsCount, 10) || 100;
const maxAmp = height * 0.15;
const waveformLayerY = titleY - (maxAmp / 2) - 25;
// Extract Image Data for pixel-based waveform simulation (if cross-origin permitted)
let imgData = null;
try {
imgData = ctx.getImageData(0, 0, width, height).data;
} catch (e) {
console.warn("Canvas tainted due to CORS constraints; falling back to algorithmic waveform pattern.");
}
const barWidth = width / numBars;
ctx.fillStyle = primaryColor;
for (let i = 0; i < numBars; i++) {
const x = i * barWidth;
const pxX = Math.floor(x + barWidth / 2);
let intensity = 0.5;
// If possible, drive waveform through pixel brightness extraction for authentic "image" audio mapping
if (imgData) {
let sumBrightness = 0;
let samples = 15;
for (let j = 0; j < samples; j++) {
let py = Math.floor(height * (j / samples));
let pIndex = (py * width + pxX) * 4;
let r = imgData[pIndex];
let g = imgData[pIndex + 1];
let b = imgData[pIndex + 2];
sumBrightness += ((0.299 * r + 0.587 * g + 0.114 * b) / 255) || 0;
}
const avgBrightness = sumBrightness / samples;
const waveNoise = Math.abs(Math.sin(i * 0.6) * Math.cos(i * 1.7));
intensity = (avgBrightness * 0.3) + (waveNoise * 0.7);
} else {
intensity = Math.abs(Math.sin(i * 0.6) * Math.cos(i * 1.7)); // Fallback synthesis
}
// Apply a center envelope (Hanning-style window) so waveform smooths at the edges
const envelope = Math.sin((i / numBars) * Math.PI);
intensity = intensity * envelope;
let h = intensity * maxAmp;
h = Math.max(h, maxAmp * 0.05);
const barActualWidth = barWidth * 0.6;
const barX = x + (barWidth * 0.2);
const barY = waveformLayerY - h / 2;
// Plot pill-shaped bar primitives
let radius = barActualWidth / 2;
if (h < 2 * radius) radius = h / 2;
ctx.beginPath();
ctx.moveTo(barX + radius, barY);
ctx.arcTo(barX + barActualWidth, barY, barX + barActualWidth, barY + h, radius);
ctx.arcTo(barX + barActualWidth, barY + h, barX, barY + h, radius);
ctx.arcTo(barX, barY + h, barX, barY, radius);
ctx.arcTo(barX, barY, barX + barActualWidth, barY, radius);
ctx.closePath();
ctx.fill();
}
// 5. Audio Identify Display Tools & Player Element
const playBtnRadius = Math.max(25, width * 0.035);
const playBtnY = waveformLayerY - (maxAmp / 2) - playBtnRadius - 20;
// Master Play Circle
ctx.beginPath();
ctx.arc(width / 2, playBtnY, playBtnRadius, 0, Math.PI * 2);
ctx.fillStyle = primaryColor;
ctx.shadowColor = "rgba(0, 0, 0, 0.4)";
ctx.shadowBlur = 10;
ctx.fill();
// Clear shadow footprint
ctx.shadowColor = "transparent";
ctx.shadowBlur = 0;
// Playback SVG Triangle Anchor
ctx.beginPath();
const triSize = playBtnRadius * 0.45;
ctx.moveTo((width / 2) - triSize * 0.3, playBtnY - triSize * 0.85);
ctx.lineTo((width / 2) + triSize * 0.9, playBtnY);
ctx.lineTo((width / 2) - triSize * 0.3, playBtnY + triSize * 0.85);
ctx.fillStyle = "#ffffff";
ctx.fill();
// 6. Draw Final Textual Analysis Output Overlay
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// Identification Output Matrix Header
const displayTitleText = identifiedText.toLowerCase().startsWith("identified") ? identifiedText : `IDENTIFIED: ${identifiedText}`;
ctx.fillStyle = primaryColor;
ctx.font = `800 ${titleFontSize}px "Segoe UI", Roboto, Helvetica, Arial, sans-serif`;
ctx.fillText(displayTitleText.toUpperCase(), width / 2, titleY);
// Output Machine Transcription Paragraph
ctx.fillStyle = "#ffffff";
ctx.font = `italic 400 ${transFontSize}px "Segoe UI", Roboto, Helvetica, Arial, sans-serif`;
let drawY = transcriptionStartY;
for (let k = 0; k < lines.length; k++) {
ctx.fillText(lines[k].trim(), width / 2, drawY);
drawY += lineHeight;
}
// Return completely rendered tool representation visually
return canvas;
}
Apply Changes