You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, text = "Самая лучшая история", blurAmount = 40, overlayOpacity = 0.3) {
// This generator converts any standard image into a 9:16 Social Media "Story" format
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Standard 9:16 Instagram/Social Media story dimensions
const width = 1080;
const height = 1920;
canvas.width = width;
canvas.height = height;
// 1. Calculate Background Measurements (Cover Mode)
const imgRatio = originalImg.width / originalImg.height;
const canvasRatio = width / height;
let bgWidth, bgHeight, bgX, bgY;
if (imgRatio > canvasRatio) {
bgHeight = height;
bgWidth = height * imgRatio;
bgX = (width - bgWidth) / 2;
bgY = 0;
} else {
bgWidth = width;
bgHeight = width / imgRatio;
bgX = 0;
bgY = (height - bgHeight) / 2;
}
// 2. Draw heavily blurred background
// We scale it up slightly to hide the unblurred edges that css/canvas blur might leave
const numBlur = Number(blurAmount);
ctx.filter = `blur(${numBlur}px)`;
const scaleUp = 1.1;
const scaledBgWidth = bgWidth * scaleUp;
const scaledBgHeight = bgHeight * scaleUp;
const scaledBgX = bgX - (scaledBgWidth - bgWidth) / 2;
const scaledBgY = bgY - (scaledBgHeight - bgHeight) / 2;
ctx.drawImage(originalImg, scaledBgX, scaledBgY, scaledBgWidth, scaledBgHeight);
// Reset filters
ctx.filter = 'none';
// 3. Add a darkening overlay to make the foreground stand out
ctx.fillStyle = `rgba(0, 0, 0, ${Number(overlayOpacity)})`;
ctx.fillRect(0, 0, width, height);
// 4. Calculate Foreground Measurements (Contain Mode)
let fgWidth, fgHeight, fgX, fgY;
const padding = 100;
const availableWidth = width - padding * 2;
const availableHeight = height - padding * 2 - 250; // Leave space for text near bottom
const availableRatio = availableWidth / availableHeight;
if (imgRatio > availableRatio) {
fgWidth = availableWidth;
fgHeight = availableWidth / imgRatio;
} else {
fgHeight = availableHeight;
fgWidth = availableHeight * imgRatio;
}
fgX = (width - fgWidth) / 2;
fgY = (height - fgHeight) / 2 - 80; // Shifted up to make room for text
// 5. Create foreground element with rounded corners on an offscreen canvas
const fgCanvas = document.createElement('canvas');
fgCanvas.width = fgWidth;
fgCanvas.height = fgHeight;
const fgCtx = fgCanvas.getContext('2d');
const radius = 40;
fgCtx.beginPath();
fgCtx.moveTo(radius, 0);
fgCtx.lineTo(fgWidth - radius, 0);
fgCtx.quadraticCurveTo(fgWidth, 0, fgWidth, radius);
fgCtx.lineTo(fgWidth, fgHeight - radius);
fgCtx.quadraticCurveTo(fgWidth, fgHeight, fgWidth - radius, fgHeight);
fgCtx.lineTo(radius, fgHeight);
fgCtx.quadraticCurveTo(0, fgHeight, 0, fgHeight - radius);
fgCtx.lineTo(0, radius);
fgCtx.quadraticCurveTo(0, 0, radius, 0);
fgCtx.closePath();
fgCtx.clip();
fgCtx.drawImage(originalImg, 0, 0, fgWidth, fgHeight);
// 6. Draw foreground to main canvas with a smooth drop shadow
ctx.shadowColor = 'rgba(0, 0, 0, 0.6)';
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 20;
ctx.drawImage(fgCanvas, fgX, fgY);
// Reset shadow params
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// 7. Write the "Story" text
if (text) {
ctx.shadowColor = 'rgba(0, 0, 0, 0.8)';
ctx.shadowBlur = 12;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 5;
ctx.font = 'bold 56px system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
ctx.fillStyle = '#ffffff';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const words = text.toString().split(' ');
let line = '';
const lines = [];
const maxWidth = width - 120;
for (let i = 0; i < words.length; i++) {
const testLine = line + words[i] + ' ';
const metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && i > 0) {
lines.push(line.trim());
line = words[i] + ' ';
} else {
line = testLine;
}
}
lines.push(line.trim());
const lineHeight = 75;
let textY = height - 200 - ((lines.length - 1) * lineHeight) / 2;
// Adjust vertically if text gets too close to the image
const textTopBoundary = textY - lineHeight / 2;
const foregroundBottomBoundary = fgY + fgHeight + 40;
if (textTopBoundary < foregroundBottomBoundary) {
textY = foregroundBottomBoundary + lineHeight / 2 + 10;
}
for (let i = 0; i < lines.length; i++) {
ctx.fillText(lines[i], width / 2, textY);
textY += lineHeight;
}
}
return canvas;
}
Apply Changes