You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, overlayColor = '#00ff00', scanDurationMs = 2500) {
// Create the outer web interface container
const container = document.createElement('div');
container.style.position = 'relative';
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
container.style.fontFamily = "'Courier New', Courier, monospace";
container.style.backgroundColor = '#121212';
container.style.color = overlayColor;
container.style.padding = '20px';
container.style.border = `2px solid ${overlayColor}`;
container.style.borderRadius = '12px';
container.style.boxShadow = `0 0 20px rgba(0,0,0,0.9), inset 0 0 10px ${overlayColor}44`;
container.style.width = '100%';
container.style.maxWidth = '640px';
container.style.margin = '0 auto';
container.style.boxSizing = 'border-box';
// Header title specifically styled for the requested music identifier UI
const header = document.createElement('h2');
header.innerText = 'Обзор Музыка: Сканер и Идентификатор';
header.style.margin = '0 0 15px 0';
header.style.textAlign = 'center';
header.style.fontSize = '22px';
header.style.textShadow = `0 0 8px ${overlayColor}`;
container.appendChild(header);
// Box to hold the canvas map
const canvasContainer = document.createElement('div');
canvasContainer.style.position = 'relative';
canvasContainer.style.width = '100%';
canvasContainer.style.overflow = 'hidden';
canvasContainer.style.border = `1px solid ${overlayColor}`;
canvasContainer.style.borderRadius = '8px';
canvasContainer.style.backgroundColor = '#000';
canvasContainer.style.display = 'flex';
canvasContainer.style.justifyContent = 'center';
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Resize image logic to keep processing lightweight while looking good
const maxWidth = 800;
const scale = originalImg.width > maxWidth ? maxWidth / originalImg.width : 1;
canvas.width = originalImg.width * scale;
canvas.height = originalImg.height * scale;
// Draw initial image
ctx.filter = `contrast(1.1) brightness(0.9)`;
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
ctx.filter = 'none';
canvas.style.display = 'block';
canvas.style.maxWidth = '100%';
canvas.style.height = 'auto';
// CSS for visual scanner line (animating down and up)
const styleId = 'music-scanner-styles-' + Date.now();
if (!document.getElementById(styleId)) {
const style = document.createElement('style');
style.id = styleId;
style.innerHTML = `
@keyframes scanLineAnimation {
0% { top: 0%; opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { top: 100%; opacity: 0; }
}
.scanner-line-eff {
position: absolute;
left: 0;
width: 100%;
height: 3px;
background: ${overlayColor};
box-shadow: 0 0 10px ${overlayColor}, 0 0 20px ${overlayColor}, 0 0 30px ${overlayColor};
animation: scanLineAnimation ${scanDurationMs / 1000}s linear infinite;
z-index: 2;
}
.scanner-grid-eff {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background-image:
linear-gradient(rgba(0, 255, 0, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 255, 0, 0.1) 1px, transparent 1px);
background-size: 20px 20px;
pointer-events: none;
z-index: 1;
}
`;
document.head.appendChild(style);
}
const scannerLine = document.createElement('div');
scannerLine.className = 'scanner-line-eff';
const scannerOverlay = document.createElement('div');
scannerOverlay.className = 'scanner-grid-eff';
if (overlayColor !== '#00ff00') {
scannerOverlay.style.backgroundImage = `
linear-gradient(${overlayColor}22 1px, transparent 1px),
linear-gradient(90deg, ${overlayColor}22 1px, transparent 1px)
`;
}
canvasContainer.appendChild(canvas);
canvasContainer.appendChild(scannerLine);
canvasContainer.appendChild(scannerOverlay);
container.appendChild(canvasContainer);
// Info panel for text results
const infoPanel = document.createElement('div');
infoPanel.style.marginTop = '20px';
infoPanel.style.padding = '15px';
infoPanel.style.background = 'rgba(0,0,0,0.6)';
infoPanel.style.border = `1px solid ${overlayColor}`;
infoPanel.style.borderRadius = '8px';
infoPanel.style.width = '100%';
infoPanel.style.boxSizing = 'border-box';
infoPanel.innerHTML = '<div style="text-align:center; font-weight:bold; animation: pulse 1s infinite alternate;">⏳ Выполняется анализ и обзор изображения...</div>';
const pulseStyle = document.createElement('style');
pulseStyle.innerHTML = `@keyframes pulse { from { opacity: 0.6; } to { opacity: 1; } }`;
document.head.appendChild(pulseStyle);
container.appendChild(infoPanel);
// Asynchronous identification process
(async () => {
let qrData = null;
try {
// Dynamically load jsQR for identifying embedded addresses/URLs in the art
if (typeof window.jsQR === 'undefined') {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js';
await new Promise((resolve, reject) => {
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
const qrFunction = window.jsQR || (typeof jsQR !== 'undefined' ? jsQR : null);
if (qrFunction) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const code = qrFunction(imageData.data, imageData.width, imageData.height, {
inversionAttempts: "dontInvert"
});
if (code && code.data) {
qrData = code.data;
// Draw a highlight box around the detected QR code
ctx.strokeStyle = '#FF3B58';
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(code.location.topLeftCorner.x, code.location.topLeftCorner.y);
ctx.lineTo(code.location.topRightCorner.x, code.location.topRightCorner.y);
ctx.lineTo(code.location.bottomRightCorner.x, code.location.bottomRightCorner.y);
ctx.lineTo(code.location.bottomLeftCorner.x, code.location.bottomLeftCorner.y);
ctx.closePath();
ctx.stroke();
// Optional fill style to dim out rest of image slightly
ctx.fillStyle = 'rgba(0,0,0,0.4)';
ctx.fillRect(0, 0, canvas.width, code.location.topLeftCorner.y);
ctx.fillRect(0, code.location.topLeftCorner.y, code.location.topLeftCorner.x, canvas.height - code.location.topLeftCorner.y);
ctx.fillRect(code.location.topRightCorner.x, code.location.topRightCorner.y, canvas.width - code.location.topRightCorner.x, canvas.height - code.location.topRightCorner.y);
ctx.fillRect(code.location.bottomLeftCorner.x, code.location.bottomLeftCorner.y, code.location.bottomRightCorner.x - code.location.bottomLeftCorner.x, canvas.height - code.location.bottomLeftCorner.y);
}
}
} catch (e) {
console.warn("QR/Address tracking setup skipped.", e);
}
// Wait to simulate process latency for user experience
await new Promise(r => setTimeout(r, scanDurationMs));
// Stop the visual animation
scannerLine.style.animation = 'none';
scannerLine.style.display = 'none';
// Base image analysis to "guess" music feeling parameters if there is no hard data
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
let r = 0, g = 0, b = 0, count = 0;
// Sampling loop
for (let i = 0; i < imageData.length; i += 16) {
r += imageData[i];
g += imageData[i+1];
b += imageData[i+2];
count++;
}
r = Math.floor(r / count);
g = Math.floor(g / count);
b = Math.floor(b / count);
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
let presumedGenre = "Не удалось определить (Unknown)";
if (brightness > 190) presumedGenre = "Поп / Электронная (Pop / Electronic)";
else if (brightness < 60) presumedGenre = "Метал / Дарк Эмбиент (Metal / Dark Ambient)";
else if (r > g + 20 && r > b + 20) presumedGenre = "Рок / Интенсив (Rock / Intense)";
else if (g > r + 20 && g > b + 20) presumedGenre = "Регги / Акустика (Reggae / Acoustic)";
else if (b > r + 20 && b > g + 20) presumedGenre = "Синтвейв / Чилл (Synthwave / Chill)";
else presumedGenre = "Классика / Инструментальная (Classical / Instrumental)";
const hashId = Math.random().toString(36).substring(2, 12).toUpperCase();
// Compile HTML to show on the Interface
let infoHtml = `<h3 style="margin-top:0; border-bottom:1px dashed ${overlayColor}; padding-bottom:5px;">✅ Сканирование Завершено</h3>`;
if (qrData) {
infoHtml += `
<p style="margin: 10px 0;"><strong>Сканер Сайт-адреса:</strong><br>
<a href="${qrData}" target="_blank" style="color:#FFF; text-decoration:underline; font-weight:bold; word-wrap:break-word;">${qrData}</a></p>
`;
} else {
infoHtml += `
<p style="margin: 10px 0;"><strong>Сканер Сайт-адреса:</strong><br>
<span style="color:#aaa;">Штрихкоды или QR-коды для перехода не обнаружены. Делаем визуальный анализ...</span></p>
`;
}
infoHtml += `
<p style="margin: 10px 0;"><strong>Музыкальный жанр (Прогноз):</strong> <span style="color:#fff;">${presumedGenre}</span></p>
<p style="margin: 10px 0;"><strong>RGB Цветовой Аккорд:</strong> <span style="color:#fff;">rgb(${r}, ${g}, ${b})</span></p>
<p style="margin: 10px 0;"><strong>Идентификатор:</strong> <span style="color:#fff;">ID-MSC-${hashId}</span></p>
<div style="display:flex; height:20px; width:100%; align-items:flex-end; gap:3px; margin-top:20px; opacity:0.8;">
`;
// Add fake visualizer UI matching the colors detected
for(let j=0; j<20; j++) {
const h = Math.max(10, Math.random() * 100);
infoHtml += `<div style="flex:1; height:${h}%; background:rgb(${Math.min(r+h,255)},${Math.min(g+h,255)},${Math.min(b+h,255)}); border-radius:2px 2px 0 0;"></div>`;
}
infoHtml += `</div>`;
infoPanel.innerHTML = infoHtml;
})();
return container;
}
Apply Changes