You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, sugarDensity = "50", captionText = "Матроскин в сахаре", overlayCatFace = "true") {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0);
// Parse sugar density parameter
let density = parseFloat(sugarDensity);
if (isNaN(density)) density = 50;
density = Math.max(0, Math.min(100, density));
// Get image data to apply "Sugar Crystals" directly to the pixels (efficient and precise)
const imgData = ctx.getImageData(0, 0, w, h);
const data = imgData.data;
// Size of the sugar crystals scales slightly with the image resolution
const crystalSize = Math.max(1, Math.floor(Math.max(w, h) / 800));
// Number of crystals based on density
const numCrystals = Math.floor((w * h) * (density / 100) * 0.1);
for (let i = 0; i < numCrystals; i++) {
const x = Math.floor(Math.random() * w);
const y = Math.floor(Math.random() * h);
// Randomly adjust the brightness to simulate sparkling crystals
const val = Math.floor(220 + Math.random() * 35);
const alphaFloat = Math.floor(180 + Math.random() * 75) / 255;
const alphaInt = Math.floor(alphaFloat * 255);
// Scatter a little cluster block per crystal
for(let dy = 0; dy < crystalSize; dy++) {
for(let dx = 0; dx < crystalSize; dx++) {
const px = x + dx;
const py = y + dy;
if (px < w && py < h) {
const idx = (py * w + px) * 4;
// Blend the "sugar" white/grey over the existing pixel color
data[idx] += (val - data[idx]) * alphaFloat; // R
data[idx+1] += (val - data[idx+1]) * alphaFloat; // G
data[idx+2] += (val - data[idx+2]) * alphaFloat; // B
// Ensure the crystal is opaque enough even on transparent backgrounds
data[idx+3] = Math.max(data[idx+3], alphaInt); // Alpha
}
}
}
}
// Repaint image with the sugar overlaid
ctx.putImageData(imgData, 0, 0);
// Draw "Sugar Mounds" at the bottom frame
ctx.fillStyle = "rgba(255, 255, 255, 0.85)";
ctx.beginPath();
ctx.moveTo(0, h);
ctx.lineTo(0, h - h * 0.2);
ctx.quadraticCurveTo(w * 0.25, h - h * 0.3, w * 0.5, h - h * 0.15);
ctx.quadraticCurveTo(w * 0.75, h - h * 0.05, w, h - h * 0.25);
ctx.lineTo(w, h);
ctx.fill();
ctx.fillStyle = "rgba(245, 245, 245, 0.95)";
ctx.beginPath();
ctx.moveTo(0, h);
ctx.lineTo(0, h - h * 0.15);
ctx.quadraticCurveTo(w * 0.3, h - h * 0.2, w * 0.6, h - h * 0.08);
ctx.quadraticCurveTo(w * 0.85, h + h * 0.05, w, h - h * 0.15);
ctx.lineTo(w, h);
ctx.fill();
// Draw stylized Matroskin cat overlay (Ears, stripes, nose, whiskers)
if (overlayCatFace.toString().toLowerCase() === "true" || overlayCatFace === "1") {
const cx = w / 2;
const cy = h / 2;
const scale = Math.min(w, h) / 500;
ctx.lineJoin = "round";
ctx.lineCap = "round";
// Helper to draw an ear
function drawEar(flip) {
ctx.save();
ctx.translate(cx + (flip ? 80 : -80) * scale, h * 0.02 + 50 * scale);
if (flip) ctx.scale(-1, 1);
// Grey base for the cat ear
ctx.beginPath();
ctx.moveTo(0, 50 * scale);
ctx.lineTo(30 * scale, -70 * scale);
ctx.lineTo(110 * scale, 50 * scale);
ctx.closePath();
ctx.fillStyle = "#a1a5a8"; // Grey base (typical striped cat)
ctx.fill();
ctx.lineWidth = 4 * scale;
ctx.strokeStyle = "#2b2b2b";
ctx.stroke();
// Pink inner ear
ctx.beginPath();
ctx.moveTo(15 * scale, 40 * scale);
ctx.lineTo(35 * scale, -45 * scale);
ctx.lineTo(85 * scale, 40 * scale);
ctx.fillStyle = "#e0b8b8";
ctx.fill();
// Classic dark Matroskin stripes on ears
ctx.strokeStyle = "#2b2b2b";
ctx.lineWidth = 6 * scale;
ctx.beginPath();
ctx.moveTo(70 * scale, 0);
ctx.lineTo(92 * scale, 15 * scale);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(50 * scale, -25 * scale);
ctx.lineTo(72 * scale, -8 * scale);
ctx.stroke();
ctx.restore();
}
drawEar(false); // Left Ear
drawEar(true); // Right Ear
// Helper to draw cat whiskers
function drawWhiskers(flip) {
ctx.save();
ctx.translate(cx, cy);
if (flip) ctx.scale(-1, 1);
ctx.strokeStyle = "#ffffff"; // White whiskers
ctx.shadowColor = "rgba(0,0,0,0.6)"; // Dark shadow to pop out
ctx.shadowBlur = 4 * scale;
ctx.lineWidth = 3.5 * scale;
ctx.beginPath();
ctx.moveTo(40 * scale, -10 * scale);
ctx.quadraticCurveTo(100 * scale, -30 * scale, 170 * scale, -25 * scale);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(45 * scale, 5 * scale);
ctx.quadraticCurveTo(110 * scale, 0, 180 * scale, 10 * scale);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(40 * scale, 20 * scale);
ctx.quadraticCurveTo(100 * scale, 40 * scale, 160 * scale, 55 * scale);
ctx.stroke();
ctx.restore();
}
drawWhiskers(false); // Right side
drawWhiskers(true); // Left side
// Nose
ctx.shadowBlur = 0;
ctx.fillStyle = "#d38383";
ctx.beginPath();
ctx.moveTo(cx - 15 * scale, cy);
ctx.lineTo(cx + 15 * scale, cy);
ctx.lineTo(cx, cy + 12 * scale);
ctx.closePath();
ctx.fill();
ctx.lineWidth = 2.5 * scale;
ctx.strokeStyle = "#2b2b2b";
ctx.stroke();
// Mouth details
ctx.beginPath();
ctx.moveTo(cx, cy + 12 * scale);
ctx.lineTo(cx, cy + 25 * scale);
ctx.quadraticCurveTo(cx - 15 * scale, cy + 35 * scale, cx - 30 * scale, cy + 25 * scale);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cx, cy + 25 * scale);
ctx.quadraticCurveTo(cx + 15 * scale, cy + 35 * scale, cx + 30 * scale, cy + 25 * scale);
ctx.stroke();
// Forehead stripes standard to this particular cat meme character
ctx.lineWidth = 5 * scale;
ctx.beginPath();
ctx.moveTo(cx, cy - 80 * scale);
ctx.lineTo(cx, cy - 40 * scale);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cx - 20 * scale, cy - 75 * scale);
ctx.lineTo(cx - 15 * scale, cy - 45 * scale);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cx + 20 * scale, cy - 75 * scale);
ctx.lineTo(cx + 15 * scale, cy - 45 * scale);
ctx.stroke();
}
// Embed the defined caption text ("Матроскин в сахаре")
if (captionText && captionText.trim() !== "") {
const fontSize = Math.max(24, Math.floor(w * 0.06));
ctx.font = `bold ${fontSize}px "Arial Black", "Impact", "Trebuchet MS", sans-serif`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// Give it a thick stroke and shadow for dynamic readability
ctx.lineWidth = Math.max(3, Math.floor(fontSize * 0.15));
ctx.strokeStyle = "#ffffff";
ctx.fillStyle = "#1e3a8a"; // Impactful deep blue core
const textY = h - Math.max(fontSize * 0.8, h * 0.08);
ctx.shadowColor = "rgba(0,0,0,0.3)";
ctx.shadowBlur = 8;
ctx.strokeText(captionText, w / 2, textY);
ctx.shadowBlur = 0;
ctx.fillText(captionText, w / 2, textY);
}
return canvas;
}
Apply Changes