You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, tolerancePercentage = "5") {
// Determine tolerance allowed for aspect ratios
const tol = parseFloat(tolerancePercentage) / 100;
// Core dimensions and ratios
const w = originalImg.width;
const h = originalImg.height;
const ratio = w / h;
const checkRatio = (target) => Math.abs(ratio - target) <= tol;
let matches = [];
const is16by9 = checkRatio(16/9);
const is1by1 = checkRatio(1);
const is9by16 = checkRatio(9/16);
// Identify standard YouTube Formats
if (is16by9) {
if (w >= 2048) {
matches.push({ type: "Channel Banner", details: "Fits min. 2048x1152 (Rec. 2560x1440)", guide: "banner" });
}
if (w >= 1280) {
matches.push({ type: "HD Thumbnail", details: "Fits requirements (Rec. 1280x720)", guide: null });
} else if (w >= 640) {
matches.push({ type: "Standard Thumbnail", details: "Valid but low-res (Min. 640x360)", guide: null });
} else {
matches.push({ type: "Undersized Thumbnail", details: `Too small for crisp display (${w}x${h})`, guide: null });
}
}
if (is1by1) {
if (w >= 800) {
matches.push({ type: "Profile Picture", details: "Fits requirements (Rec. 800x800)", guide: "circle" });
} else if (w >= 150) {
matches.push({ type: "Profile Pic / Watermark", details: `Valid size (${w}x${h}) / Rec. 150x150`, guide: "circle" });
} else {
matches.push({ type: "Profile Picture (Too Small)", details: `Smaller than rec. dimensions (${w}x${h})`, guide: "circle" });
}
}
if (is9by16) {
matches.push({ type: "Shorts Thumbnail", details: "Valid 9:16 aspect ratio", guide: null });
}
if (matches.length === 0) {
if (checkRatio(4/5)) {
// Unofficial but common standard for community posts
matches.push({ type: "Community Post (4:5)", details: "Valid 4:5 aspect ratio", guide: null });
} else {
matches.push({ type: "Unrecognized Format", details: "Doesn't match standard YT dimensions.", guide: null });
}
}
// Set up output Canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Calculate required height based on content
const requiredHeight = Math.max(450, 240 + matches.length * 55 + 30);
canvas.width = 800;
canvas.height = requiredHeight;
// Draw main background
ctx.fillStyle = "#fafafa";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Header Background
ctx.shadowColor = "rgba(0, 0, 0, 0.2)";
ctx.shadowBlur = 6;
ctx.shadowOffsetY = 2;
ctx.fillStyle = "#FF0000"; // YouTube Red
ctx.fillRect(0, 0, 800, 60);
// Header Text & Icon
ctx.shadowColor = "transparent";
ctx.fillStyle = "#ffffff";
// Draw a small "Play" triangle icon
ctx.beginPath();
ctx.moveTo(30, 20);
ctx.lineTo(30, 40);
ctx.lineTo(45, 30);
ctx.fill();
ctx.font = "bold 24px 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
ctx.fillText("YouTube Photo Identifier", 55, 38);
// Determine constraints and sizes for the Image Preview
const pSize = 330;
const pX = 30;
const pY = 90;
// Checkerboard background for transparent image representations
ctx.fillStyle = "#ffffff";
ctx.fillRect(pX, pY, pSize, pSize);
ctx.fillStyle = "#e8e8e8";
const checker = 15;
for (let i = 0; i < pSize / checker; i++) {
for (let j = 0; j < pSize / checker; j++) {
if ((i + j) % 2 === 0) ctx.fillRect(pX + i * checker, pY + j * checker, checker, checker);
}
}
// Measure to draw original image scaled down to fit preview box
const scale = Math.min(pSize / w, pSize / h);
const dw = w * scale;
const dh = h * scale;
const dx = pX + (pSize - dw) / 2;
const dy = pY + (pSize - dh) / 2;
ctx.drawImage(originalImg, dx, dy, dw, dh);
// Overlays for recognizable elements (Banner safe zones, circular crops)
let paintedGuides = new Set();
matches.forEach(match => {
// Channel Banner Safe-Area Guide Overlay
if (match.guide === "banner" && !paintedGuides.has("banner")) {
paintedGuides.add("banner");
const sw = w * 0.6039; // Safe center dimension ratio
const sh = h * 0.29375;
const sx = (w - sw) / 2;
const sy = (h - sh) / 2;
const scaled_sw = sw * scale;
const scaled_sh = sh * scale;
const scaled_sx = dx + sx * scale;
const scaled_sy = dy + sy * scale;
ctx.strokeStyle = "rgba(255, 0, 0, 0.8)";
ctx.lineWidth = 2;
ctx.setLineDash([4, 4]);
ctx.strokeRect(scaled_sx, scaled_sy, scaled_sw, scaled_sh);
ctx.fillStyle = "rgba(255, 0, 0, 0.1)";
ctx.fillRect(scaled_sx, scaled_sy, scaled_sw, scaled_sh);
ctx.setLineDash([]);
ctx.fillStyle = "rgba(255, 0, 0, 0.8)";
ctx.fillRect(scaled_sx, scaled_sy - 16, 52, 16);
ctx.font = "bold 10px sans-serif";
ctx.fillStyle = "#ffffff";
ctx.fillText("Safe Area", scaled_sx + 4, scaled_sy - 4);
}
// Profile Picture Circular Crop Overlay
if (match.guide === "circle" && !paintedGuides.has("circle")) {
paintedGuides.add("circle");
const radius = (Math.min(dw, dh)) / 2;
const cx = dx + dw/2;
const cy = dy + dh/2;
ctx.strokeStyle = "rgba(0, 150, 255, 0.8)";
ctx.lineWidth = 2;
ctx.setLineDash([4, 4]);
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, 2*Math.PI);
ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = "rgba(255, 255, 255, 0.6)";
ctx.beginPath();
ctx.rect(dx, dy, dw, dh);
ctx.arc(cx, cy, radius, 0, 2*Math.PI, true);
ctx.fill();
ctx.fillStyle = "rgba(0, 150, 255, 0.8)";
ctx.fillRect(cx - 32, cy - radius - 16, 64, 16);
ctx.font = "bold 10px sans-serif";
ctx.fillStyle = "#ffffff";
ctx.fillText("Circle Crop", cx - 25, cy - radius - 4);
}
});
// Outer Frame for Preview
ctx.strokeStyle = "#cccccc";
ctx.lineWidth = 1;
ctx.strokeRect(pX, pY, pSize, pSize);
// Typography setup for side information
const infoX = 400;
let infoY = 110;
// Metadata Properties Section
ctx.fillStyle = "#222222";
ctx.font = "bold 20px 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
ctx.fillText("Image Metadata", infoX, infoY);
infoY += 30;
ctx.font = "15px 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
ctx.fillStyle = "#555555";
ctx.fillText(`Dimensions: ${w}px (W) × ${h}px (H)`, infoX, infoY);
infoY += 24;
let ratioStr = (w/h).toFixed(2) + ":1";
if (is16by9) ratioStr = "16:9 (Widescreen / Regular HD)";
else if (is1by1) ratioStr = "1:1 (Square)";
else if (is9by16) ratioStr = "9:16 (Vertical / Shorts)";
else if (checkRatio(4/5)) ratioStr = "4:5 (Standard Post)";
ctx.fillText(`Aspect Ratio: ${ratioStr}`, infoX, infoY);
// Match Details Section
infoY += 45;
ctx.fillStyle = "#222222";
ctx.font = "bold 20px 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
ctx.fillText("Identified YouTube Formats", infoX, infoY);
infoY += 30;
for (let i = 0; i < matches.length; i++) {
const match = matches[i];
// Match indicator bullet
ctx.beginPath();
ctx.arc(infoX + 6, infoY - 5, 6, 0, 2 * Math.PI, false);
ctx.fillStyle = match.type === "Unrecognized Format" ? "#888888" : "#FF0000";
ctx.fill();
// Primary match text
ctx.fillStyle = "#333333";
ctx.font = "bold 16px 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
ctx.fillText(match.type, infoX + 22, infoY);
// Secondary Details
ctx.font = "14px 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
ctx.fillStyle = "#666666";
ctx.fillText(match.details, infoX + 22, infoY + 20);
infoY += 50;
}
return canvas;
}
Apply Changes