You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, caption = "Фото на память", date = "2024", filterType = "vintage", frameColor = "#FAFAFA", textColor = "#222222") {
// 1. Dynamically load Google Font "Caveat" for a handwriting effect
const fontName = 'Caveat';
if (!document.getElementById('memory-maker-font')) {
const link = document.createElement('link');
link.id = 'memory-maker-font';
link.rel = 'stylesheet';
link.href = `https://fonts.googleapis.com/css2?family=${fontName}:wght@400;700&display=swap`;
document.head.appendChild(link);
}
// Yield execution to allow the browser to load the font
try {
await document.fonts.load(`700 16px "${fontName}"`);
await document.fonts.load(`400 16px "${fontName}"`);
} catch(e) {
console.warn("Font loading failed, falling back to basic cursive.", e);
}
// 2. Define dimensions and scale down if image is too large
// to prevent extremely slow processing or exceeding max canvas limits.
let w = originalImg.width;
let h = originalImg.height;
const maxDim = 1500;
if (w > maxDim || h > maxDim) {
const ratio = Math.min(maxDim / w, maxDim / h);
w = Math.floor(w * ratio);
h = Math.floor(h * ratio);
}
// 3. Calculate polaroid-style borders
// Thick uniform side/top borders, heavily extended bottom border for text
const border = Math.floor(Math.max(w, h) * 0.045);
const paddingX = Math.max(border, 15);
const paddingYTop = paddingX;
const paddingYBot = Math.max(border * 4, 80);
const canvasW = w + paddingX * 2;
const canvasH = h + paddingYTop + paddingYBot;
// 4. Set up Canvas
const canvas = document.createElement('canvas');
canvas.width = canvasW;
canvas.height = canvasH;
const ctx = canvas.getContext('2d');
// Draw the main frame background
ctx.fillStyle = frameColor;
ctx.fillRect(0, 0, canvasW, canvasH);
// Subtle outer border for the polaroid paper effect
ctx.strokeStyle = "#D3D3D3";
ctx.lineWidth = 1;
ctx.strokeRect(0, 0, canvasW, canvasH);
// 5. Configure Photo Filters
const filters = {
"vintage": "sepia(0.5) contrast(1.1) brightness(0.9) saturate(0.8) hue-rotate(-10deg)",
"sepia": "sepia(0.8) contrast(1.1)",
"grayscale": "grayscale(1) contrast(1.1)",
"bw": "grayscale(1) contrast(1.3) brightness(1.1)",
"black-and-white": "grayscale(1) contrast(1.3) brightness(1.1)",
"none": "none"
};
const selectedFilter = filters[filterType.toLowerCase()] || "none";
// Fill a black rectangle behind the image area to support original transparency
ctx.fillStyle = "#000000";
ctx.fillRect(paddingX, paddingYTop, w, h);
// Draw original image with CSS filters active
ctx.filter = selectedFilter;
ctx.drawImage(originalImg, paddingX, paddingYTop, w, h);
ctx.filter = "none";
// 6. Draw vignette effect if a filter is applied (adds depth and vintage feel)
if (selectedFilter !== "none") {
ctx.globalCompositeOperation = 'multiply';
const cx = paddingX + w / 2;
const cy = paddingYTop + h / 2;
const radius = Math.sqrt(Math.pow(w/2, 2) + Math.pow(h/2, 2));
const gradient = ctx.createRadialGradient(cx, cy, radius * 0.4, cx, cy, radius);
gradient.addColorStop(0, "rgba(0, 0, 0, 0)");
gradient.addColorStop(1, "rgba(20, 10, 0, 0.45)"); // Sepia-tinted shadow
ctx.fillStyle = gradient;
ctx.fillRect(paddingX, paddingYTop, w, h);
ctx.globalCompositeOperation = 'source-over';
}
// Inner shadow/border framing the image print itself
ctx.strokeStyle = "rgba(0, 0, 0, 0.08)";
ctx.lineWidth = 2;
ctx.strokeRect(paddingX, paddingYTop, w, h);
// 7. Render Text (Caption & Date)
ctx.fillStyle = textColor;
// Position in the vertical center of bottom spacing
const textCenterY = canvasH - (paddingYBot / 2);
// Auto-scale font size for caption so it doesn't overflow
let fontSize = Math.max(Math.floor(paddingYBot * 0.35), 14);
ctx.font = `700 ${fontSize}px "${fontName}", cursive`;
let textWidth = ctx.measureText(caption).width;
while (textWidth > canvasW * 0.85 && fontSize > 12) {
fontSize -= 2;
ctx.font = `700 ${fontSize}px "${fontName}", cursive`;
textWidth = ctx.measureText(caption).width;
}
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(caption, canvasW / 2, textCenterY);
// Position the date neatly in the bottom-right corner
if (date.trim() !== "") {
let dateFontSize = Math.max(Math.floor(paddingYBot * 0.18), 10);
ctx.font = `400 ${dateFontSize}px "${fontName}", cursive`;
ctx.textAlign = "right";
ctx.textBaseline = "bottom";
const dateBottomMargin = Math.max(paddingX * 0.5, 10);
ctx.fillText(date, canvasW - paddingX, canvasH - dateBottomMargin);
}
return canvas;
}
Apply Changes