You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, logoText = 'ГОСТЕЛЕРАДИО СССР', logoColor = 'rgba(255, 255, 220, 0.75)', logoScale = 1.0, scanlineOpacity = 0.1, vignetteIntensity = 0.4, noiseAmount = 15, sepiaAmount = 0.3) {
/**
* Dynamically loads a Google Font stylesheet and waits for it to be available.
* @param {string} fontName - The name of the font family.
* @param {string} fontUrl - The full URL to the Google Fonts CSS.
* @param {string} fontSpec - The font specification string for document.fonts.load().
*/
const loadFont = async (fontName, fontUrl, fontSpec) => {
// Check if font is already loaded to avoid re-fetching
if (document.querySelector(`link[href="${fontUrl}"]`)) {
try {
await document.fonts.load(fontSpec);
} catch(e) { /* ignore */ }
return;
}
const link = document.createElement('link');
link.href = fontUrl;
link.rel = 'stylesheet';
document.head.appendChild(link);
await new Promise((resolve) => {
link.onload = async () => {
try {
await document.fonts.load(fontSpec);
} catch (e) {
console.warn(`Could not load font: ${fontName}. Using fallback.`);
}
resolve();
};
link.onerror = () => {
console.warn(`Could not load font stylesheet: ${fontUrl}`);
resolve(); // Resolve anyway to not block the process
};
});
};
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const w = originalImg.naturalWidth;
const h = originalImg.naturalHeight;
canvas.width = w;
canvas.height = h;
// 1. Apply base image filters for a vintage, analog look
ctx.filter = `sepia(${sepiaAmount}) saturate(1.2) contrast(1.1) brightness(0.95)`;
ctx.drawImage(originalImg, 0, 0, w, h);
ctx.filter = 'none'; // Reset filter for subsequent drawings
// 2. Add noise/grain
if (noiseAmount > 0) {
const imageData = ctx.getImageData(0, 0, w, h);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const noise = (Math.random() - 0.5) * noiseAmount;
data[i] = Math.max(0, Math.min(255, data[i] + noise));
data[i + 1] = Math.max(0, Math.min(255, data[i + 1] + noise));
data[i + 2] = Math.max(0, Math.min(255, data[i + 2] + noise));
}
ctx.putImageData(imageData, 0, 0);
}
// 3. Draw CRT scan lines
if (scanlineOpacity > 0) {
ctx.fillStyle = `rgba(0, 0, 0, ${scanlineOpacity})`;
for (let y = 0; y < h; y += 3) {
ctx.fillRect(0, y, w, 1);
}
}
// 4. Draw vignette effect
if (vignetteIntensity > 0) {
const gradient = ctx.createRadialGradient(w / 2, h / 2, Math.min(w, h) * 0.2, w / 2, h / 2, Math.max(w, h) * 0.8);
gradient.addColorStop(0, 'rgba(0,0,0,0)');
gradient.addColorStop(1, `rgba(0,0,0,${vignetteIntensity})`);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, w, h);
}
// 5. Draw the Gosteleradio logo and text
const baseSize = Math.min(w, h) * 0.13 * logoScale;
const centerX = w - baseSize * 1.5;
const centerY = h - baseSize * 1.5;
const radius = baseSize / 2;
ctx.strokeStyle = logoColor;
ctx.fillStyle = logoColor;
const lineWidth = Math.max(1, baseSize * 0.05);
// Draw the main logo elements
ctx.lineWidth = lineWidth;
ctx.beginPath(); // Outer circle
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath(); // Stylized "T" mast
ctx.moveTo(centerX, centerY + radius * 0.7);
ctx.lineTo(centerX, centerY - radius * 0.25);
ctx.stroke();
ctx.beginPath(); // "T" top arc (antenna dish)
ctx.arc(centerX, centerY - radius * 0.20, radius * 0.5, Math.PI * 1.05, Math.PI * 1.95);
ctx.stroke();
// Helper function to draw a star
const drawStar = (cx, cy, spikes, outerRadius, innerRadius) => {
let rot = Math.PI / 2 * 3;
const step = Math.PI / spikes;
ctx.beginPath();
for (let i = 0; i < spikes; i++) {
ctx.lineTo(cx + Math.cos(rot) * outerRadius, cy + Math.sin(rot) * outerRadius);
rot += step;
ctx.lineTo(cx + Math.cos(rot) * innerRadius, cy + Math.sin(rot) * innerRadius);
rot += step;
}
ctx.closePath();
ctx.fill();
};
drawStar(centerX, centerY - radius * 0.65, 5, radius * 0.2, radius * 0.08);
// Helper function to draw text along an arc
const drawTextOnArc = (txt, cx, cy, r, startAngle) => {
const charSpacing = (Math.PI / 10) * (18 / txt.length); // Adjust spacing based on text length
ctx.save();
ctx.translate(cx, cy);
const totalAngle = (txt.length - 1) * charSpacing;
ctx.rotate(startAngle - totalAngle / 2);
for (let i = 0; i < txt.length; i++) {
ctx.save();
ctx.rotate(i * charSpacing);
ctx.fillText(txt[i], 0, -r);
ctx.restore();
}
ctx.restore();
};
// Load a suitable Cyrillic font and draw the text
const textRadius = radius * 1.15;
const fontSize = Math.max(8, baseSize * 0.15);
const fontName = 'PT Serif';
const fontUrl = `https://fonts.googleapis.com/css2?family=PT+Serif:wght@700&display=swap`;
const fontSpec = `bold ${fontSize}px "${fontName}"`;
await loadFont(fontName, fontUrl, fontSpec);
ctx.font = fontSpec;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
drawTextOnArc(logoText, centerX, centerY, textRadius, -Math.PI / 2);
return canvas;
}
Apply Changes