You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, maxPredictions = 5) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Ensure maxPredictions is treated as a number
maxPredictions = Number(maxPredictions) || 5;
// Determine dimensions and scaling (limit max width for performance and UI layout)
const MAX_WIDTH = 800;
let scale = 1;
if (originalImg.width > MAX_WIDTH) {
scale = MAX_WIDTH / originalImg.width;
}
const imgW = originalImg.width * scale;
const imgH = originalImg.height * scale;
// Canvas dimensions - ensure minimum width for the panel text
canvas.width = Math.max(imgW, 600);
canvas.height = imgH + 110 + (maxPredictions * 40);
// Initial sync layout rendering function
const drawBaseUI = () => {
// Draw the image area with deep slate background
ctx.fillStyle = '#0f172a';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(originalImg, (canvas.width - imgW) / 2, 0, imgW, imgH);
// Draw bottom panel area
ctx.fillStyle = '#1e293b';
ctx.fillRect(0, imgH, canvas.width, canvas.height - imgH);
// draw Title
ctx.fillStyle = '#f8fafc';
ctx.font = 'bold 22px sans-serif';
ctx.fillText('Image Description & Identifier Scanner', 20, imgH + 40);
// Image Metadata
ctx.fillStyle = '#94a3b8';
ctx.font = '14px sans-serif';
ctx.textAlign = 'right';
ctx.fillText(`Original: ${originalImg.width} x ${originalImg.height}px`, canvas.width - 20, imgH + 40);
ctx.textAlign = 'left';
// Divider Line
ctx.strokeStyle = '#334155';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(20, imgH + 55);
ctx.lineTo(canvas.width - 20, imgH + 55);
ctx.stroke();
};
drawBaseUI();
// Helper to draw messages in the panel dynamically
const drawMessage = (msg, color = '#38bdf8') => {
ctx.fillStyle = '#1e293b'; // clear previous panel area below line
ctx.fillRect(0, imgH + 58, canvas.width, canvas.height - imgH - 58);
ctx.fillStyle = color;
ctx.font = 'italic 16px sans-serif';
ctx.fillText(msg, 20, imgH + 90);
};
drawMessage('Loading TensorFlow.js and AI Models... (may take a moment)');
// Process Machine Learning asynchronously
(async () => {
try {
// Dynamically inject TensorFlow.js if not already present
if (typeof window.tf === 'undefined') {
await new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.21.0/dist/tf.min.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
// Dynamically inject MobileNet if not already present
if (typeof window.mobilenet === 'undefined') {
await new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet@2.1.0/dist/mobilenet.min.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
drawMessage('AI Models successfully loaded. Scanning image details...');
// Load the MobileNet model
const model = await window.mobilenet.load();
// Classify the image
const predictions = await model.classify(originalImg, maxPredictions);
// Clear the message area to draw final results table
ctx.fillStyle = '#1e293b';
ctx.fillRect(0, imgH + 58, canvas.width, canvas.height - imgH - 58);
// Draw Table Header
ctx.fillStyle = '#64748b';
ctx.font = 'bold 12px sans-serif';
ctx.fillText('IDENTIFIED OBJECT / DESCRIPTION', 20, imgH + 80);
ctx.fillText('CONFIDENCE SCORE', canvas.width * 0.5 + 40, imgH + 80);
// Set up prediction rows
ctx.font = '16px sans-serif';
const maxTextWidth = canvas.width * 0.5;
const barX = maxTextWidth + 40;
const barWidth = canvas.width - barX - 70;
predictions.forEach((p, i) => {
const y = imgH + 115 + (i * 40);
// Truncate overly long labels so they stay inside their column
let label = (i + 1) + '. ' + p.className.charAt(0).toUpperCase() + p.className.slice(1);
if (ctx.measureText(label).width > maxTextWidth) {
while (ctx.measureText(label + '...').width > maxTextWidth && label.length > 0) {
label = label.slice(0, -1);
}
label += '...';
}
// Draw Label string
ctx.fillStyle = '#e2e8f0';
ctx.fillText(label, 20, y);
// Determine color based on probability score
const barColor = p.probability > 0.5 ? '#22c55e' : (p.probability > 0.2 ? '#eab308' : '#ef4444');
// Draw percentage text
const probText = (p.probability * 100).toFixed(2) + '%';
ctx.fillStyle = barColor;
ctx.fillText(probText, canvas.width - 65, y);
// Draw Background visualization bar
ctx.fillStyle = '#334155';
ctx.fillRect(barX, y - 12, barWidth, 12);
// Draw Foreground (active) visualization bar
ctx.fillStyle = barColor;
ctx.fillRect(barX, y - 12, barWidth * p.probability, 12);
});
} catch (err) {
console.error("AI Scanning Error:", err);
drawMessage('Error during analysis: ' + (err.message || 'Check console.'), '#ef4444');
}
})();
// Synchronously returns the canvas to immediately mount while the async model tasks complete visually.
return canvas;
}
Apply Changes