You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg,
name = "John Doe",
title = "Software Engineer",
companyName = "Tech Solutions Inc.",
phoneNumber = "+1 (555) 123-4567",
email = "john.doe@example.com",
website = "www.example.com",
address = "123 Main St\nCity, State 12345",
cardWidth = 350,
cardHeight = 200,
backgroundColor = "#FFFFFF",
textColor = "#000000",
fontFamily = "Arial",
nameFontSize = 20,
titleFontSize = 14,
companyFontSize = 12,
contactFontSize = 10,
logoSize = 25, // Percentage of cardHeight for logo's initial target height
logoPosition = "left", // "left", "right", "topCenter"
padding = 15, // General padding from card edge to content area
itemSpacing = 8 // Spacing between major items (logo-text, name-title, etc.)
) {
const canvas = document.createElement('canvas');
canvas.width = cardWidth;
canvas.height = cardHeight;
const ctx = canvas.getContext('2d');
// Background
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, cardWidth, cardHeight);
// Content area (after outer padding)
const actualPadding = padding;
const availableContentWidth = cardWidth - 2 * actualPadding;
const availableContentHeight = cardHeight - 2 * actualPadding;
let drawLogoWidth = 0;
let drawLogoHeight = 0;
// Check if originalImg is a valid, loaded image
const hasLogo = originalImg &&
typeof originalImg.width === 'number' && originalImg.width > 0 &&
typeof originalImg.height === 'number' && originalImg.height > 0 &&
originalImg.complete; // 'complete' checks if image is fully loaded
if (hasLogo) {
// Initial logo dimensions based on logoSize (as % of cardHeight) and image aspect ratio
let targetLogoHeight = (logoSize / 100) * cardHeight;
let targetLogoWidth = targetLogoHeight * (originalImg.width / originalImg.height);
// Define maximum allowed dimensions for the logo based on its position and available space
let maxAllowedLogoWidth, maxAllowedLogoHeight;
if (logoPosition === "left" || logoPosition === "right") {
// Logo on the side: can take up to 50% of horizontal content space, full vertical content height
maxAllowedLogoWidth = (availableContentWidth - itemSpacing) * 0.5;
maxAllowedLogoHeight = availableContentHeight;
} else { // logoPosition === "topCenter"
// Logo on top: can take full horizontal content width, up to 40% of vertical content space
maxAllowedLogoWidth = availableContentWidth;
maxAllowedLogoHeight = (availableContentHeight - itemSpacing) * 0.4;
}
// Scale to fit max width constraint
if (targetLogoWidth > maxAllowedLogoWidth) {
const scale = maxAllowedLogoWidth / targetLogoWidth;
targetLogoWidth *= scale;
targetLogoHeight *= scale;
}
// Scale to fit max height constraint (applied after width scaling)
if (targetLogoHeight > maxAllowedLogoHeight) {
const scale = maxAllowedLogoHeight / targetLogoHeight;
targetLogoHeight *= scale;
targetLogoWidth *= scale;
}
drawLogoWidth = targetLogoWidth;
drawLogoHeight = targetLogoHeight;
}
// Calculate effective space used by logo (including itemSpacing if logo exists)
const logoSpaceX = (hasLogo && (logoPosition === "left" || logoPosition === "right")) ? (drawLogoWidth + itemSpacing) : 0;
const logoSpaceY = (hasLogo && logoPosition === "topCenter") ? (drawLogoHeight + itemSpacing) : 0;
// Define text block coordinates and dimensions
let textBlockX, textBlockY, textBlockWidth, textBlockHeight;
let logoActualX = 0, logoActualY = 0; // Coordinates where logo will be drawn
if (logoPosition === "left") {
if (hasLogo) {
logoActualX = actualPadding;
logoActualY = actualPadding + (availableContentHeight - drawLogoHeight) / 2; // Vertically center logo
}
textBlockX = actualPadding + logoSpaceX;
textBlockY = actualPadding;
textBlockWidth = availableContentWidth - logoSpaceX;
textBlockHeight = availableContentHeight;
} else if (logoPosition === "right") {
if (hasLogo) {
logoActualX = cardWidth - actualPadding - drawLogoWidth;
logoActualY = actualPadding + (availableContentHeight - drawLogoHeight) / 2; // Vertically center logo
}
textBlockX = actualPadding;
textBlockY = actualPadding;
textBlockWidth = availableContentWidth - logoSpaceX;
textBlockHeight = availableContentHeight;
} else { // topCenter
if (hasLogo) {
logoActualX = actualPadding + (availableContentWidth - drawLogoWidth) / 2; // Horizontally center logo
logoActualY = actualPadding;
}
textBlockX = actualPadding;
textBlockY = actualPadding + logoSpaceY;
textBlockWidth = availableContentWidth;
textBlockHeight = availableContentHeight - logoSpaceY;
}
// Draw Logo
if (hasLogo && drawLogoWidth > 0 && drawLogoHeight > 0) {
ctx.drawImage(originalImg, logoActualX, logoActualY, drawLogoWidth, drawLogoHeight);
}
// Draw Text Content
ctx.fillStyle = textColor;
ctx.textBaseline = 'top'; // Y coordinate will be the top of the text
let currentY = textBlockY; // Starting Y for the text block
const contactLineDetailSpacing = 2; // Small vertical gap between lines of contact info
// Name
if (name && name.trim() !== "") {
if (currentY + nameFontSize > textBlockY + textBlockHeight) return canvas; // Stop if no vertical space
ctx.font = `bold ${nameFontSize}px ${fontFamily}`;
ctx.fillText(name, textBlockX, currentY, textBlockWidth); // textBlockWidth acts as maxWidth for fillText
currentY += nameFontSize + itemSpacing;
}
// Title
if (title && title.trim() !== "") {
if (currentY + titleFontSize > textBlockY + textBlockHeight) return canvas;
ctx.font = `${titleFontSize}px ${fontFamily}`;
ctx.fillText(title, textBlockX, currentY, textBlockWidth);
currentY += titleFontSize + itemSpacing;
}
// Company Name
if (companyName && companyName.trim() !== "") {
if (currentY + companyFontSize > textBlockY + textBlockHeight) return canvas;
ctx.font = `italic ${companyFontSize}px ${fontFamily}`;
ctx.fillText(companyName, textBlockX, currentY, textBlockWidth);
currentY += companyFontSize + itemSpacing;
}
// Contact Info
ctx.font = `${contactFontSize}px ${fontFamily}`;
const contactItemLineHeight = contactFontSize + contactLineDetailSpacing;
if (phoneNumber && phoneNumber.trim() !== "") {
if (currentY + contactFontSize > textBlockY + textBlockHeight) return canvas;
ctx.fillText("P: " + phoneNumber, textBlockX, currentY, textBlockWidth);
currentY += contactItemLineHeight;
}
if (email && email.trim() !== "") {
if (currentY + contactFontSize > textBlockY + textBlockHeight) return canvas;
ctx.fillText("E: " + email, textBlockX, currentY, textBlockWidth);
currentY += contactItemLineHeight;
}
if (website && website.trim() !== "") {
if (currentY + contactFontSize > textBlockY + textBlockHeight) return canvas;
ctx.fillText("W: " + website, textBlockX, currentY, textBlockWidth);
currentY += contactItemLineHeight;
}
if (address && address.trim() !== "") {
// Add a small gap before the address block if other contact info was present
if ((phoneNumber && phoneNumber.trim() !== "") || (email && email.trim() !== "") || (website && website.trim() !== "")) {
currentY += contactLineDetailSpacing; // Additional small gap
}
const addressLines = address.split('\n');
for (const line of addressLines) {
if (currentY + contactFontSize > textBlockY + textBlockHeight) break;
ctx.fillText(line, textBlockX, currentY, textBlockWidth);
currentY += contactItemLineHeight;
}
}
return canvas;
}
Apply Changes