You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(
originalImg,
magazineTitle = "FASHION",
titleColor = "#FFFFFF",
subtitle = "Последний писк моды",
theme = "dark",
filterIntensity = 30
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = originalImg.width;
const height = originalImg.height;
canvas.width = width;
canvas.height = height;
// Dynamically load an elegant Google Font for the fashion magazine aesthetic
const fontName = 'Playfair Display';
if (!document.getElementById('playfair-font-link')) {
const link = document.createElement('link');
link.id = 'playfair-font-link';
link.href = `https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400;1,700&display=swap`;
link.rel = 'stylesheet';
document.head.appendChild(link);
}
try {
await document.fonts.load(`900 10px "${fontName}"`);
await document.fonts.load(`400 10px "${fontName}"`);
await document.fonts.load(`italic 700 10px "${fontName}"`);
} catch(e) {
console.warn("Font rendering fallback: ", e);
}
// Apply editorial fashion filter (boost contrast, slight desaturation)
const intensity = Math.min(Math.max(filterIntensity, 0), 100);
ctx.filter = `contrast(${100 + intensity * 0.4}%) saturate(${100 - intensity * 0.3}%) brightness(95%)`;
ctx.drawImage(originalImg, 0, 0, width, height);
ctx.filter = 'none';
// Set theme variables
const isDark = theme.toLowerCase() === 'dark';
const dimColor = isDark ? '0,0,0' : '255,255,255';
const secondaryTextColor = isDark ? '#FFFFFF' : '#000000';
// Add top gradient to make the magazine title pop
const topGrad = ctx.createLinearGradient(0, 0, 0, height * 0.35);
topGrad.addColorStop(0, `rgba(${dimColor},0.75)`);
topGrad.addColorStop(1, `rgba(${dimColor},0)`);
ctx.fillStyle = topGrad;
ctx.fillRect(0, 0, width, height * 0.35);
// Add bottom gradient for subtitle readability
const bottomGrad = ctx.createLinearGradient(0, height, 0, height * 0.65);
bottomGrad.addColorStop(0, `rgba(${dimColor},0.85)`);
bottomGrad.addColorStop(1, `rgba(${dimColor},0)`);
ctx.fillStyle = bottomGrad;
ctx.fillRect(0, height * 0.65, width, height * 0.35);
// ---- Draw Details (Issue & Date) ----
const smallTextSize = Math.max(width * 0.02, 12);
ctx.font = `600 ${smallTextSize}px sans-serif`;
ctx.fillStyle = secondaryTextColor;
ctx.textBaseline = 'top';
ctx.textAlign = 'left';
ctx.fillText("LATEST TREND", width * 0.04, height * 0.05);
const dateStr = new Date().toLocaleDateString(undefined, { month: 'long', year: 'numeric' }).toUpperCase();
ctx.textAlign = 'right';
ctx.fillText(dateStr, width * 0.96, height * 0.05);
// ---- Draw Main Magazine Title ----
const titleSize = width * 0.18;
ctx.font = `900 ${titleSize}px "${fontName}", serif`;
ctx.fillStyle = titleColor;
// Draw text with calculated letter spacing
const textToDraw = magazineTitle.toUpperCase();
const letterSpacing = width * 0.015;
const chars = textToDraw.split('');
const charWidths = chars.map(char => ctx.measureText(char).width);
const totalWidth = charWidths.reduce((a, b) => a + b, 0) + letterSpacing * (chars.length - 1);
let startX = (width - totalWidth) / 2;
ctx.textAlign = 'left';
for (let i = 0; i < chars.length; i++) {
ctx.fillText(chars[i], startX, height * 0.08);
startX += charWidths[i] + letterSpacing;
}
// ---- Draw "Trending Now" Tagline ----
const badgeSize = Math.max(width * 0.025, 14);
ctx.font = `400 ${badgeSize}px sans-serif`;
ctx.fillStyle = secondaryTextColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillText("TRENDING NOW", width / 2, height * 0.85 - (width * 0.07));
// Line separator
ctx.beginPath();
ctx.moveTo(width / 2 - (width * 0.1), height * 0.85 - (width * 0.05));
ctx.lineTo(width / 2 + (width * 0.1), height * 0.85 - (width * 0.05));
ctx.strokeStyle = titleColor;
ctx.lineWidth = Math.max(width * 0.002, 1);
ctx.stroke();
// ---- Draw Subtitle (Последний писк моды) ----
const subSize = width * 0.06;
ctx.font = `italic 700 ${subSize}px "${fontName}", serif`;
ctx.fillStyle = titleColor;
ctx.fillText(subtitle, width / 2, height * 0.93);
// ---- Draw Barcode detail at bottom right ----
const bcWidth = width * 0.15;
const bcHeight = height * 0.05;
const bcX = width * 0.96 - bcWidth;
const bcY = height * 0.96 - Math.max(bcHeight + smallTextSize + 15, height * 0.08);
// Barcode background
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(bcX - 10, bcY - 10, bcWidth + 20, bcHeight + smallTextSize + 20);
// Barcode lines generator
ctx.fillStyle = '#000000';
let currentX = 0;
// Hardcoded pseudo-random bars for authenticity
const bars = [2, 4, 1, 3, 2, 1, 5, 2, 1, 3, 4, 1, 1, 2, 3, 2, 1, 4, 2];
const totalBarsWidth = bars.reduce((a, b) => a + b, 0);
const scale = bcWidth / (totalBarsWidth * 1.6);
for (let i = 0; i < bars.length; i++) {
let bW = bars[i] * scale;
let gap = ((i % 3) + 1.2) * scale;
if (currentX + bW <= bcWidth) {
ctx.fillRect(bcX + currentX, bcY, bW, bcHeight);
}
currentX += bW + gap;
}
// Barcode digits
ctx.font = `bold ${smallTextSize * 0.8}px monospace`;
ctx.fillStyle = '#000000';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.fillText("9 780201 379624", bcX + bcWidth / 2, bcY + bcHeight + 5);
return canvas;
}
Apply Changes