You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, topText = "ПТИЦА", bottomText = "ПОЮН", birdSize = 35, filter = "none") {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const w = originalImg.width;
const h = originalImg.height;
// Set canvas dimensions
canvas.width = w;
canvas.height = h;
// Apply optional filter to the original image
if (filter === "sepia") {
ctx.filter = "sepia(0.8) contrast(1.2)";
} else if (filter === "grayscale") {
ctx.filter = "grayscale(1) contrast(1.2)";
} else if (filter === "contrast") {
ctx.filter = "contrast(1.5) saturate(1.5)";
}
// Draw original image
ctx.drawImage(originalImg, 0, 0);
// Reset filter for graphics
ctx.filter = "none";
// Function to draw the "Poyun Bird" (Singing Bird) vector
const drawPoyunBird = (x, y, scale) => {
ctx.save();
ctx.translate(x, y);
ctx.scale(scale, scale);
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.lineWidth = 3;
// Legs
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.moveTo(10, 80);
ctx.lineTo(10, 120);
ctx.lineTo(-5, 130);
ctx.moveTo(10, 120);
ctx.lineTo(20, 130);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-10, 75);
ctx.lineTo(-10, 115);
ctx.lineTo(-25, 125);
ctx.moveTo(-10, 115);
ctx.lineTo(0, 125);
ctx.stroke();
// Body
ctx.fillStyle = "#4a90e2";
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.ellipse(0, 50, 45, 60, Math.PI / 6, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
// Tail
ctx.fillStyle = "#2a5b8f";
ctx.beginPath();
ctx.moveTo(-35, 80);
ctx.lineTo(-70, 120);
ctx.lineTo(-60, 70);
ctx.closePath();
ctx.fill();
ctx.stroke();
// Wing
ctx.fillStyle = "#357abd";
ctx.beginPath();
ctx.ellipse(-15, 45, 25, 40, Math.PI / 4, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
// Head
ctx.fillStyle = "#4a90e2";
ctx.beginPath();
ctx.arc(35, -5, 35, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
// Eyes
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(45, -15, 12, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(48, -15, 4, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(22, -18, 10, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(24, -18, 3, 0, Math.PI * 2);
ctx.fill();
// Beak (Open for singing)
ctx.fillStyle = "#f5a623";
ctx.beginPath();
ctx.moveTo(65, -10);
ctx.lineTo(105, -25);
ctx.lineTo(70, 5);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(68, 10);
ctx.lineTo(100, 20);
ctx.lineTo(55, 22);
ctx.closePath();
ctx.fill();
ctx.stroke();
// Throat / inside mouth
ctx.fillStyle = "#d0021b";
ctx.beginPath();
ctx.moveTo(66, -8);
ctx.lineTo(80, -2);
ctx.lineTo(69, 5);
ctx.closePath();
ctx.fill();
// Singing Musical Notes
ctx.fillStyle = "black";
ctx.textAlign = "left";
ctx.textBaseline = "alphabetic";
ctx.font = "bold 40px 'Comic Sans MS', sans-serif";
ctx.fillText("♫", 110, -40);
ctx.font = "bold 30px 'Comic Sans MS', sans-serif";
ctx.fillText("♪", 140, -80);
ctx.font = "bold 50px 'Comic Sans MS', sans-serif";
ctx.fillText("♩", 180, -20);
// Action / sound emitting lines from the beak
ctx.beginPath();
ctx.moveTo(105, -5);
ctx.lineTo(130, -10);
ctx.moveTo(102, -15);
ctx.lineTo(125, -30);
ctx.moveTo(98, 10);
ctx.lineTo(120, 25);
ctx.stroke();
ctx.restore();
};
// Calculate bird scale based on the requested birdSize percentage
const targetBirdWidth = (w * birdSize) / 100;
// Approximated total bounding box width of our bird drawing is ~280 units
const scale = targetBirdWidth / 280;
// Position the bird in the bottom left
const margin = targetBirdWidth * 0.1;
const birdX = margin + (70 * scale); // Shift right to account for tail extending to x: -70
const birdY = h - margin - (130 * scale); // Shift up to account for legs ending at y: 130
// Draw the generated Poyun Bird overlay
drawPoyunBird(birdX, birdY, scale);
// Function to draw meme-style top and bottom texts
const drawMemeText = (text, isTop) => {
if (!text) return;
const fontSize = Math.max(20, Math.floor(h / 8));
ctx.font = `bold ${fontSize}px Impact, sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = isTop ? 'top' : 'bottom';
ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
ctx.lineWidth = Math.max(3, fontSize / 15);
ctx.lineJoin = 'round';
const textMargin = fontSize / 3;
const x = w / 2;
const y = isTop ? textMargin : h - textMargin;
ctx.strokeText(text.toUpperCase(), x, y, w * 0.9);
ctx.fillText(text.toUpperCase(), x, y, w * 0.9);
};
// Render captions
drawMemeText(topText, true);
drawMemeText(bottomText, false);
return canvas;
}
Apply Changes