You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, overlayColor = "rgba(15, 15, 15, 0.9)", accentColor = "#1DB954") {
const width = originalImg.naturalWidth || originalImg.width || 800;
const height = originalImg.naturalHeight || originalImg.height || 600;
// Create a container to return instantly while background tasks run
const container = document.createElement('div');
container.style.position = 'relative';
container.style.display = 'inline-block';
container.style.width = `${width}px`;
container.style.height = `${height}px`;
container.style.maxWidth = '100%';
container.style.overflow = 'hidden';
container.style.borderRadius = '8px';
container.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.style.width = '100%';
canvas.style.height = '100%';
canvas.style.display = 'block';
const ctx = canvas.getContext('2d', { willReadFrequently: true });
ctx.drawImage(originalImg, 0, 0, width, height);
container.appendChild(canvas);
// Create Loading Status Element
const statusEl = document.createElement('div');
statusEl.style.position = 'absolute';
statusEl.style.top = '50%';
statusEl.style.left = '50%';
statusEl.style.transform = 'translate(-50%, -50%)';
statusEl.style.color = accentColor;
statusEl.style.backgroundColor = 'rgba(0,0,0,0.85)';
statusEl.style.padding = '15px 25px';
statusEl.style.borderRadius = '8px';
statusEl.style.fontFamily = 'Arial, sans-serif';
statusEl.style.fontSize = '18px';
statusEl.style.fontWeight = 'bold';
statusEl.style.zIndex = '10';
statusEl.style.textAlign = 'center';
statusEl.style.boxShadow = '0 4px 6px rgba(0,0,0,0.3)';
statusEl.innerText = 'Initializing Scanner...';
container.appendChild(statusEl);
// Helper to dynamically inject scripts without conflicts
function loadScript(src, globalVar) {
return new Promise((resolve, reject) => {
if (window[globalVar]) {
resolve();
} else {
const script = document.createElement('script');
script.src = src;
script.crossOrigin = "anonymous";
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load ${src}`));
document.head.appendChild(script);
}
});
}
// Background scanning process (QR/Barcode -> OCR)
(async () => {
let identifiedText = "";
try {
statusEl.innerText = "Scanning for Codes...";
// Try identifying standard music sharing QR codes/barcodes
await loadScript('https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js', 'jsQR');
const imageData = ctx.getImageData(0, 0, width, height);
const code = window.jsQR(imageData.data, imageData.width, imageData.height);
if (code && code.data) {
identifiedText = "Track/Code Identified: " + code.data;
} else {
statusEl.innerText = "Analyzing Text & Metadata...";
// Fallback to OCR to read album artist/track names from the image
await loadScript('https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js', 'Tesseract');
const result = await window.Tesseract.recognize(canvas, 'eng+rus', {
logger: m => {
if (m.status === 'recognizing text') {
const progress = Math.round(m.progress * 100);
statusEl.innerText = `Analyzing image data... ${progress}%`;
} else if (m.status === 'loading tesseract core') {
statusEl.innerText = `Loading scanner engine...`;
} else if (m.status === 'loading language traineddata') {
statusEl.innerText = `Loading language models...`;
}
}
});
const text = result.data.text.trim();
if (text && text.length > 3) {
const cleaned = text.replace(/\n+/g, ' - ').replace(/\s+/g, ' ');
identifiedText = "Album/Track Details: " + cleaned;
} else {
identifiedText = "No musical codes or recognizable text found.";
}
}
} catch (e) {
console.error(e);
identifiedText = "Scanner Error: " + (e.message || "Could not complete scan.");
}
// Clean up UI indicator
if (container.contains(statusEl)) {
container.removeChild(statusEl);
}
// --- Render final Scanner Interface visualization on canvas ---
ctx.restore(); // Ensure valid state
// 1. Draw glowing scanner grid over the image
ctx.strokeStyle = accentColor;
ctx.globalAlpha = 0.15;
ctx.lineWidth = 1;
for (let i = 0; i < width; i += 50) {
ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, height); ctx.stroke();
}
for (let j = 0; j < height; j += 50) {
ctx.beginPath(); ctx.moveTo(0, j); ctx.lineTo(width, j); ctx.stroke();
}
ctx.globalAlpha = 1.0;
// 2. Draw mock tracking scan-line
const lineGrad = ctx.createLinearGradient(0, height * 0.4, width, height * 0.4);
lineGrad.addColorStop(0, 'rgba(29, 185, 84, 0)');
lineGrad.addColorStop(0.5, accentColor);
lineGrad.addColorStop(1, 'rgba(29, 185, 84, 0)');
ctx.fillStyle = lineGrad;
ctx.fillRect(0, height * 0.4 - 2, width, 4);
// 3. Setup bottom info overlay banner
const titleFontSize = Math.max(14, Math.min(24, Math.floor(height * 0.05)));
const textFontSize = Math.max(12, Math.min(16, Math.floor(height * 0.04)));
const lineSpacing = textFontSize + 8;
let overlayHeight = titleFontSize + (lineSpacing * 4) + 30; // Approx enough space for 3 lines of text
if (overlayHeight > height / 2) overlayHeight = height / 2;
ctx.fillStyle = overlayColor;
ctx.fillRect(0, height - overlayHeight, width, overlayHeight);
// Bold top edge line of the results panel
ctx.fillStyle = accentColor;
ctx.fillRect(0, height - overlayHeight, width, 4);
// 4. Fill text inside overlay
ctx.fillStyle = accentColor;
ctx.font = `bold ${titleFontSize}px Arial, sans-serif`;
ctx.fillText('Music Scanner Identification Result', 20, height - overlayHeight + titleFontSize + 15);
ctx.fillStyle = '#ffffff';
ctx.font = `${textFontSize}px Arial, sans-serif`;
// Multi-line word-wrapping
const words = identifiedText.split(' ');
let line = '';
let y = height - overlayHeight + titleFontSize + textFontSize + 25;
const maxWidth = width - 40;
for (let n = 0; n < words.length; n++) {
const testLine = line + words[n] + ' ';
const metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && n > 0) {
ctx.fillText(line, 20, y);
line = words[n] + ' ';
y += lineSpacing;
} else {
line = testLine;
}
// Stop wrapping if we run out of vertical bounds and truncate
if (y > height - 10 && n < words.length - 1) {
line += "...";
break;
}
}
ctx.fillText(line, 20, y);
})();
return container;
}
Apply Changes