You can edit the below JavaScript code to customize the image tool.
async function processImage(
originalImg,
titleText = "Save The Date",
groomName = "Alexander",
brideName = "Olivia",
conjunction = "&",
weddingDate = "Saturday, June 10, 2028",
weddingTime = "at Four O'Clock in the Afternoon",
venueName = "The Enchanted Garden",
venueAddress = "123 Blossom Lane, Dreamville",
mainFontFamily = "Dancing Script", // For titles and names. Examples: "Dancing Script", "Great Vibes"
detailsFontFamily = "Roboto", // For date, time, venue. Examples: "Roboto", "Montserrat", "Georgia"
textColor = "#FFFFFF",
titleFontSize = 0.08, // Relative to canvas height
namesFontSize = 0.1, // Relative to canvas height
detailsFontSize = 0.035, // Relative to canvas height
nameConjunctionFontSize = 0.07, // Relative to canvas height for '&'
overlayColor = "rgba(0, 0, 0, 0.4)" // e.g., "rgba(0,0,0,0.4)" for dark, "rgba(255,255,255,0.3)" for light. Empty string for no overlay.
) {
// Helper function to load Google Fonts.
// If fontFamilyToLoad is a common web-safe font, it should just work.
// If it's a known Google Font, it attempts to load it.
// Otherwise, it assumes the font is available or relies on system fallbacks.
const _loadGoogleFont = async (fontFamilyToLoad, fallbackFont) => {
try {
// Check if font is already loaded/available (e.g., web-safe like 'Arial', 'Georgia')
// or if it was loaded in a previous call.
if (document.fonts.check(`12px "${fontFamilyToLoad}"`)) {
return fontFamilyToLoad;
}
} catch (e) {
// document.fonts might not be available in some rare contexts.
console.warn("Could not check font status using document.fonts.check. Proceeding with font: " + fontFamilyToLoad, e);
// Fallback to trying to load or assuming it's available.
}
let fontUrl = "";
// Add URLs for common Google fonts you want to support dynamically.
// These URLs point to WOFF2 files for specific weights (usually Regular 400).
if (fontFamilyToLoad === "Dancing Script") {
fontUrl = "https://fonts.gstatic.com/s/dancingscript/v25/If2RXTr6YS-zF4S-kcSWSVi_szLviuEViw.woff2";
} else if (fontFamilyToLoad === "Roboto") {
fontUrl = "https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2";
} else if (fontFamilyToLoad === "Great Vibes") {
fontUrl = "https://fonts.gstatic.com/s/greatvibes/v18/RWmMoKWR9v4ksMfaWd_JN-XMaltJ.woff2";
} else if (fontFamilyToLoad === "Montserrat") {
fontUrl = "https://fonts.gstatic.com/s/montserrat/v26/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw0aXpsog.woff2"; // Regular 400
}
// Add more fonts here if needed
if (fontUrl) {
const font = new FontFace(fontFamilyToLoad, `url(${fontUrl})`);
try {
await font.load();
document.fonts.add(font);
// console.log(`Successfully loaded Google Font: ${fontFamilyToLoad}`);
return fontFamilyToLoad;
} catch (e) {
console.error(`Failed to load Google Font '${fontFamilyToLoad}' from ${fontUrl}. Using fallback font '${fallbackFont}'. Error:`, e);
return fallbackFont;
}
} else {
// console.log(`No pre-configured URL for "${fontFamilyToLoad}". Assuming it's web-safe or already loaded on the system.`);
// If it's not a known Google Font and not web-safe, the browser will use its default font.
return fontFamilyToLoad;
}
};
// Load fonts, using fallbacks if specified fonts fail or aren't pre-configured for dynamic loading
const actualMainFont = await _loadGoogleFont(mainFontFamily, "Georgia, serif");
const actualDetailsFont = await _loadGoogleFont(detailsFontFamily, "Arial, sans-serif");
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set canvas dimensions and background
if (!originalImg || typeof originalImg.naturalWidth === 'undefined' || !originalImg.naturalWidth || !originalImg.naturalHeight) {
console.warn("Original image is invalid or has no dimensions. Using default canvas size 800x1000 and a placeholder background.");
canvas.width = 800;
canvas.height = 1000;
ctx.fillStyle = "#E0E0E0"; // Light gray placeholder background
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#333333"; // Dark text for placeholder message
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const defaultMsgFont = "Arial";
ctx.font = `bold ${Math.round(canvas.height * 0.025)}px ${defaultMsgFont}`; // 20px for 800px height
ctx.fillText("Invalid or Missing Background Image", canvas.width / 2, canvas.height / 2 - Math.round(canvas.height * 0.02));
ctx.font = `${Math.round(canvas.height * 0.02)}px ${defaultMsgFont}`; // 16px for 800px height
ctx.fillText(`Using ${canvas.width}x${canvas.height} placeholder`, canvas.width/2, canvas.height/2 + Math.round(canvas.height * 0.0125));
} else {
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
}
// Apply overlay if specified
if (overlayColor && overlayColor.trim() !== "") {
ctx.fillStyle = overlayColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// Text properties
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'; // Ensures text is vertically centered around the y-coordinate
let currentY = canvas.height * 0.18; // Starting Y position for the first line of text (18% from top)
const xPos = canvas.width / 2; // All text is centered horizontally
const baseLineHeightMultiplier = 1.2; // Multiplier for basic line height (e.g., 1.2 times font size)
const sectionSpacingInFontSizeUnits = 0.6; // Additional spacing after a text "section" (e.g. after title, after names block)
// This is relative to the current line's font size.
// Helper function to draw a line of text and advance currentY
function drawTextLine(text, fontFace, fontSizePercent, additionalSpacingUnitsAfter = 0) {
if (text && text.trim() !== "") {
// Calculate font size in pixels, with a minimum practical size (e.g., 10px)
const fontSizePx = Math.max(10, Math.round(canvas.height * fontSizePercent));
ctx.font = `${fontSizePx}px "${fontFace}"`; // Quote font name for safety with spaces
ctx.fillText(text, xPos, currentY);
// Advance Y position for the next line
currentY += fontSizePx * baseLineHeightMultiplier; // Base line height
currentY += fontSizePx * additionalSpacingUnitsAfter; // Additional spacing if any
}
}
// Draw Wedding Announcement Content
drawTextLine(titleText, actualMainFont, titleFontSize, sectionSpacingInFontSizeUnits);
drawTextLine(groomName, actualMainFont, namesFontSize);
drawTextLine(conjunction, actualMainFont, nameConjunctionFontSize); // conjunction usually same font, maybe different size
drawTextLine(brideName, actualMainFont, namesFontSize, sectionSpacingInFontSizeUnits);
drawTextLine(weddingDate, actualDetailsFont, detailsFontSize);
drawTextLine(weddingTime, actualDetailsFont, detailsFontSize, sectionSpacingInFontSizeUnits * 0.7); // A bit of space before venue details
drawTextLine(venueName, actualDetailsFont, detailsFontSize);
drawTextLine(venueAddress, actualDetailsFont, detailsFontSize * 0.9); // Venue address often slightly smaller
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Wedding Announcement Poster Maker allows you to create personalized wedding announcement posters by combining your chosen images with custom text elements. You can input details such as the couple’s names, wedding date, time, and venue, as well as select font styles and colors to suit your aesthetic. This tool is perfect for anyone planning a wedding, as it helps to design elegant and memorable ‘Save the Date’ announcements or invitations that can be shared online or printed for guests.