You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(
originalImg,
cardNumber = "0",
cardTitle = "THE FOOL",
mainBorderColor = "gold",
innerCardBgColor = "#F0EAD6", // Light Parchment/Beige
textColor = "white",
textBgColor = "#222222", // Dark Grey for text panel backgrounds
imageFrameColor = "#404040", // Medium-Dark Grey for image frame
fontFamily = "Times New Roman, serif"
) {
// Helper function to draw an image with "cover" behavior
// It scales the image to fill the specified dimensions, maintaining aspect ratio,
// and crops any excess parts of the image. Centering by default.
function drawImageCover(ctx, img, x, y, w, h, offsetX = 0.5, offsetY = 0.5) {
if (!img || !img.width || !img.height || img.naturalWidth === 0) {
// console.warn("drawImageCover: Invalid or unloaded image provided.");
// Draw a placeholder if image is invalid/not loaded
ctx.save();
ctx.fillStyle = '#777777'; // Darker gray for placeholder background
ctx.fillRect(x, y, w, h);
ctx.fillStyle = '#DDDDDD'; // Light gray for text
ctx.font = `${Math.min(w,h) / 12}px sans-serif`; // Moderately sized text
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText("No Image Data", x + w / 2, y + h / 2);
ctx.restore();
return;
}
let iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r,
nh = ih * r,
cx, cy, cw, ch, ar = 1;
if (nw < w) ar = w / nw;
// عبارت مطلق برای مقایسه اعداد اعشاری
// Check if nw filled width, then check if nh needs to fill height
if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh;
nw *= ar;
nh *= ar;
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (iw < cx + cw) cw = iw - cx;
if (ih < cy + ch) ch = ih - cy;
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}
const canvas = document.createElement('canvas');
const canvasW = 550; // Standard Tarot aspect ratio (approx 2.75:4.75) scaled up
const canvasH = 950;
canvas.width = canvasW;
canvas.height = canvasH;
const ctx = canvas.getContext('2d');
// Define layout constants
const outerBorderThickness = 20;
const panelPadding = 15; // Padding inside the main card face, around panels and image block
const numberPanelH_config = 70;
const titlePanelH_config = 90;
const gapBetweenElements = 10; // Gap between number panel and image, image and title panel
const imageFrameInset = 5; // Thickness of the image frame border itself
// --- Drawing steps ---
// 1. Outermost Border (using mainBorderColor)
ctx.fillStyle = mainBorderColor;
ctx.fillRect(0, 0, canvasW, canvasH);
// 2. Inner Card Background (e.g., parchment color)
const innerX = outerBorderThickness;
const innerY = outerBorderThickness;
const innerW = canvasW - 2 * outerBorderThickness;
const innerH = canvasH - 2 * outerBorderThickness;
ctx.fillStyle = innerCardBgColor;
ctx.fillRect(innerX, innerY, innerW, innerH);
// 3. Top Number Panel
const numPanelX = innerX + panelPadding;
const numPanelY = innerY + panelPadding;
const numPanelW = innerW - 2 * panelPadding;
const numPanelH = numberPanelH_config;
ctx.fillStyle = textBgColor;
ctx.fillRect(numPanelX, numPanelY, numPanelW, numPanelH);
// Draw Card Number Text
ctx.fillStyle = textColor;
ctx.font = `bold 48px ${fontFamily}`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(String(cardNumber), numPanelX + numPanelW / 2, numPanelY + numPanelH / 2);
// 4. Bottom Title Panel
const titlePanelX = innerX + panelPadding;
const titlePanelH = titlePanelH_config;
const titlePanelY = innerY + innerH - panelPadding - titlePanelH;
const titlePanelW = innerW - 2 * panelPadding;
ctx.fillStyle = textBgColor;
ctx.fillRect(titlePanelX, titlePanelY, titlePanelW, titlePanelH);
// Draw Card Title Text
ctx.fillStyle = textColor;
ctx.font = `bold 36px ${fontFamily}`; // Title font slightly smaller
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(String(cardTitle).toUpperCase(), titlePanelX + titlePanelW / 2, titlePanelY + titlePanelH / 2);
// 5. Image Area (with its own frame)
const imgFrameX = innerX + panelPadding;
const imgFrameY = numPanelY + numPanelH + gapBetweenElements;
const imgFrameW = innerW - 2 * panelPadding;
const imgFrameH = titlePanelY - gapBetweenElements - imgFrameY;
// Draw Image Frame Background (this creates the border for the image)
ctx.fillStyle = imageFrameColor;
ctx.fillRect(imgFrameX, imgFrameY, imgFrameW, imgFrameH);
// Calculate Actual Image Content Drawing Area (inside the frame)
const actualImgX = imgFrameX + imageFrameInset;
const actualImgY = imgFrameY + imageFrameInset;
const actualImgW = imgFrameW - 2 * imageFrameInset;
const actualImgH = imgFrameH - 2 * imageFrameInset;
// Draw the originalImg into the calculated content area
drawImageCover(ctx, originalImg, actualImgX, actualImgY, actualImgW, actualImgH);
return canvas;
}
Apply Changes