You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
title = "CERTIFICATE OF BIRTH",
namePlaceholder = "[Full Name of Child]",
dobPlaceholder = "[Date of Birth]",
pobPlaceholder = "[Place of Birth: City, State]",
motherNamePlaceholder = "[Mother's Full Maiden Name]",
fatherNamePlaceholder = "[Father's Full Name]",
textColor = "#2c3e50", // Dark grayish blue
accentColor = "#3498db", // Nice blue
borderColor = "#bdc3c7", // Silver/Gray border
backgroundColor = "#ffffff",
fontFamily = "serif",
photoX = 50,
photoY = 160,
photoWidth = 100,
photoHeight = 130
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const canvasWidth = 794; // Approx A4 width at 96 DPI landscape, or common web width
const canvasHeight = 560; // Landscape orientation, approximates 11 x 8.5 ratio
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// 1. Background
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// 2. Border
const borderWidth = 20; // Padding for the border from canvas edge
ctx.strokeStyle = borderColor;
ctx.lineWidth = 2;
// Outer line of main border
ctx.strokeRect(borderWidth / 2, borderWidth / 2, canvasWidth - borderWidth, canvasHeight - borderWidth);
// Inner line of main border (decorative)
ctx.strokeStyle = accentColor;
ctx.lineWidth = 1;
ctx.strokeRect(borderWidth / 2 + 4, borderWidth / 2 + 4, canvasWidth - borderWidth - 8, canvasHeight - borderWidth - 8);
// Utility to draw text
function drawText(text, x, y, size, color, align = 'left', baseLine = 'alphabetic', weight = 'normal') {
ctx.font = `${weight} ${size}px ${fontFamily}`;
ctx.fillStyle = color;
ctx.textAlign = align;
ctx.textBaseline = baseLine;
ctx.fillText(text, x, y);
}
// Utility to draw a line for filling in text
function drawDataLine(x, y, width) {
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + width, y);
ctx.strokeStyle = textColor; // Use main text color for data lines
ctx.lineWidth = 0.75;
ctx.stroke();
}
// 3. Title
drawText(title, canvasWidth / 2, 70, 36, accentColor, 'center', 'middle', 'bold');
drawText("This certifies that", canvasWidth / 2, 105, 16, textColor, 'center', 'middle');
// Content layout constants
const contentStartXFields = photoX + photoWidth + 30;
const contentMaxWidthFields = canvasWidth - contentStartXFields - (borderWidth + 10);
const dataLineOffsetY = 10; // For lines under text (textbaseline middle + this offset)
const fieldTextSize = 16; // Font size for main data fields
// Vertical Spacing
const fieldLineHeight = 30;
const spaceAfterSeparator = 20;
const spaceFactorAfterParents = 1.2;
const detailsBoxHeight = 60;
const paddingAfterDetailsBox = 15;
// 4. Original Image (Photo placeholder)
ctx.strokeStyle = borderColor;
ctx.lineWidth = 1;
ctx.strokeRect(photoX, photoY, photoWidth, photoHeight); // Photo box border
if (originalImg && originalImg.complete && originalImg.naturalWidth > 0) {
try {
// Clear the area inside the photo box border before drawing image
ctx.fillStyle = backgroundColor;
ctx.fillRect(photoX + 1, photoY + 1, photoWidth - 2, photoHeight - 2);
ctx.drawImage(originalImg, photoX, photoY, photoWidth, photoHeight);
} catch (e) {
console.error("Error drawing original image:", e);
drawText("Photo", photoX + photoWidth / 2, photoY + photoHeight / 2, 14, borderColor, 'center', 'middle');
}
} else {
drawText("Photo", photoX + photoWidth / 2, photoY + photoHeight / 2, 14, borderColor, 'center', 'middle');
}
// 5. Certificate Details
let currentY = 160; // Start Y for main content area (aligned with photo top)
// Child's Name
const childNameLabel = "Child's Full Name:";
ctx.font = `normal ${fieldTextSize}px ${fontFamily}`; // Set font for measuring label
const childNameLabelWidth = ctx.measureText(childNameLabel).width;
drawText(childNameLabel, contentStartXFields, currentY, fieldTextSize, textColor, 'left', 'middle');
drawText(namePlaceholder, contentStartXFields + childNameLabelWidth + 5, currentY, fieldTextSize, textColor, 'left', 'middle');
drawDataLine(contentStartXFields + childNameLabelWidth + 5, currentY + dataLineOffsetY, contentMaxWidthFields - (childNameLabelWidth + 5));
currentY += fieldLineHeight;
// Date of Birth
const dobLabelText = "Date of Birth:";
// Font already set for fieldTextSize
const dobLabelWidth = ctx.measureText(dobLabelText).width;
drawText(dobLabelText, contentStartXFields, currentY, fieldTextSize, textColor, 'left', 'middle');
drawText(dobPlaceholder, contentStartXFields + dobLabelWidth + 5, currentY, fieldTextSize, textColor, 'left', 'middle');
drawDataLine(contentStartXFields + dobLabelWidth + 5, currentY + dataLineOffsetY, contentMaxWidthFields - (dobLabelWidth + 5));
currentY += fieldLineHeight;
// Place of Birth
const pobLabelText = "Place of Birth:";
const pobLabelWidth = ctx.measureText(pobLabelText).width;
drawText(pobLabelText, contentStartXFields, currentY, fieldTextSize, textColor, 'left', 'middle');
drawText(pobPlaceholder, contentStartXFields + pobLabelWidth + 5, currentY, fieldTextSize, textColor, 'left', 'middle');
drawDataLine(contentStartXFields + pobLabelWidth + 5, currentY + dataLineOffsetY, contentMaxWidthFields - (pobLabelWidth + 5));
currentY += fieldLineHeight;
// Separator Line
currentY += 10;
ctx.beginPath();
ctx.moveTo(borderWidth + 10, currentY);
ctx.lineTo(canvasWidth - (borderWidth + 10), currentY);
ctx.strokeStyle = borderColor;
ctx.lineWidth = 0.5;
ctx.stroke();
currentY += spaceAfterSeparator;
// Parents' Names (side-by-side)
const parentsFieldY = currentY;
ctx.font = `normal ${fieldTextSize}px ${fontFamily}`;
const motherLabelString = "Mother's Name:";
const fatherLabelString = "Father's Name:";
const measuredMotherLabelWidth = ctx.measureText(motherLabelString).width;
const measuredFatherLabelWidth = ctx.measureText(fatherLabelString).width;
const actualParentLabelWidth = Math.max(measuredMotherLabelWidth, measuredFatherLabelWidth);
const totalWidthForOneParentEntry = (canvasWidth - 2*(borderWidth+10) - 20) / 2; // 20 is mid_gap
const parentNameInputLineWidth = totalWidthForOneParentEntry - actualParentLabelWidth - 5; // 5 is padding after label
const motherLabelX = borderWidth + 10;
drawText(motherLabelString, motherLabelX, parentsFieldY, fieldTextSize, textColor, 'left', 'middle');
drawText(motherNamePlaceholder, motherLabelX + actualParentLabelWidth + 5, parentsFieldY, fieldTextSize, textColor, 'left', 'middle');
drawDataLine(motherLabelX + actualParentLabelWidth + 5, parentsFieldY + dataLineOffsetY, parentNameInputLineWidth);
const fatherLabelX = canvasWidth / 2 + 10;
drawText(fatherLabelString, fatherLabelX, parentsFieldY, fieldTextSize, textColor, 'left', 'middle');
drawText(fatherNamePlaceholder, fatherLabelX + actualParentLabelWidth + 5, parentsFieldY, fieldTextSize, textColor, 'left', 'middle');
drawDataLine(fatherLabelX + actualParentLabelWidth + 5, parentsFieldY + dataLineOffsetY, parentNameInputLineWidth);
currentY += fieldLineHeight * spaceFactorAfterParents;
// Additional Details Box
const detailsBoxX = borderWidth + 10;
const detailsBoxY = currentY;
const detailsBoxWidth = canvasWidth - 2 * (borderWidth + 10);
ctx.strokeStyle = borderColor;
ctx.lineWidth = 1;
ctx.strokeRect(detailsBoxX, detailsBoxY, detailsBoxWidth, detailsBoxHeight);
drawText("Additional Details:", detailsBoxX + 10, detailsBoxY + 15, 14, accentColor, 'left', 'middle');
let detailTextY = detailsBoxY + detailsBoxHeight - 20;
const detailLabelFontSize = 12;
ctx.font = `normal ${detailLabelFontSize}px ${fontFamily}`;
let currentDetailX = detailsBoxX + 15;
const numDetailFields = 3;
const detailFieldSpacing = 15;
const detailFieldContentWidth = (detailsBoxWidth - 30 - (numDetailFields - 1) * detailFieldSpacing) / numDetailFields;
const sexLabel = "Sex:";
drawText(sexLabel, currentDetailX, detailTextY, detailLabelFontSize, textColor, 'left', 'middle');
const sexLabelWidth = ctx.measureText(sexLabel).width;
drawDataLine(currentDetailX + sexLabelWidth + 5, detailTextY + dataLineOffsetY * 0.8, detailFieldContentWidth - (sexLabelWidth + 5)); // Adjusted line Y
currentDetailX += detailFieldContentWidth + detailFieldSpacing;
const weightLabel = "Weight:";
drawText(weightLabel, currentDetailX, detailTextY, detailLabelFontSize, textColor, 'left', 'middle');
const weightLabelWidth = ctx.measureText(weightLabel).width;
drawDataLine(currentDetailX + weightLabelWidth + 5, detailTextY + dataLineOffsetY * 0.8, detailFieldContentWidth - (weightLabelWidth + 5));
currentDetailX += detailFieldContentWidth + detailFieldSpacing;
const timeLabel = "Time:";
drawText(timeLabel, currentDetailX, detailTextY, detailLabelFontSize, textColor, 'left', 'middle');
const timeLabelWidth = ctx.measureText(timeLabel).width;
drawDataLine(currentDetailX + timeLabelWidth + 5, detailTextY + dataLineOffsetY * 0.8, detailFieldContentWidth - (timeLabelWidth + 5));
currentY += detailsBoxHeight + paddingAfterDetailsBox;
// 6. Seal, Signatures, Date Issued (Bottom Area)
const bottomElementsYStart = Math.max(currentY, canvasHeight - 130);
const sealCenterX = canvasWidth / 2;
const sealCenterY = bottomElementsYStart + 35;
ctx.beginPath();
ctx.arc(sealCenterX, sealCenterY, 30, 0, 2 * Math.PI, false);
ctx.strokeStyle = accentColor;
ctx.lineWidth = 1.5;
ctx.stroke();
drawText("OFFICIAL", sealCenterX, sealCenterY - 8, 10, accentColor, 'center', 'middle', 'bold');
drawText("SEAL", sealCenterX, sealCenterY + 8, 10, accentColor, 'center', 'middle', 'bold');
const signatureY = bottomElementsYStart + 80;
const signatureLineLength = (canvasWidth - 2 * (borderWidth + 10) - 40) / 2;
const officialSigX = borderWidth + 10;
drawDataLine(officialSigX, signatureY, signatureLineLength);
drawText("Official Attendant / Registrar", officialSigX + signatureLineLength/2, signatureY + 15, 12, textColor, 'center', 'top');
const parentSigX = canvasWidth - (borderWidth + 10) - signatureLineLength;
drawDataLine(parentSigX, signatureY, signatureLineLength);
drawText("Parent / Guardian Signature", parentSigX + signatureLineLength/2, signatureY + 15, 12, textColor, 'center', 'top');
drawText("Date Issued: ____________________", canvasWidth/2, signatureY + 35, 12, textColor, 'center', 'middle');
return canvas;
}
Apply Changes