You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, labelText = "Запасы на зиму", tintColor = "rgba(170, 190, 150, 0.35)") {
// Canvas dimensions
const canvas = document.createElement("canvas");
const width = 600;
const height = 800;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
// 1. Draw Background Wall (Cellar style)
const bgGrad = ctx.createRadialGradient(width / 2, height / 2, 100, width / 2, height / 2, 600);
bgGrad.addColorStop(0, "#3a3a3a");
bgGrad.addColorStop(1, "#111111");
ctx.fillStyle = bgGrad;
ctx.fillRect(0, 0, width, height);
// 2. Shelf Construction
// Front Ledge
const ledgeGrad = ctx.createLinearGradient(0, 615, 0, 635);
ledgeGrad.addColorStop(0, "#5E3A21");
ledgeGrad.addColorStop(0.5, "#422816");
ledgeGrad.addColorStop(1, "#26160C");
ctx.fillStyle = ledgeGrad;
ctx.fillRect(0, 615, width, 20);
// Main Shelf Surface
const woodGrad = ctx.createLinearGradient(0, 635, 0, 800);
woodGrad.addColorStop(0, "#331C0D");
woodGrad.addColorStop(1, "#1A0E06");
ctx.fillStyle = woodGrad;
ctx.fillRect(0, 635, width, height - 635);
// 3. Drop Shadow of the Jar
ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
ctx.shadowColor = "rgba(0, 0, 0, 0.8)";
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.ellipse(300, 620, 170, 18, 0, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0; // reset
// 4. Jar Body Path Definition
const jarPath = new Path2D();
jarPath.moveTo(230, 200);
jarPath.bezierCurveTo(160, 200, 120, 240, 120, 290);
jarPath.lineTo(120, 590);
jarPath.bezierCurveTo(120, 625, 480, 625, 480, 590);
jarPath.lineTo(480, 290);
jarPath.bezierCurveTo(480, 240, 440, 200, 370, 200);
jarPath.closePath();
// 5. Draw the Clipped Original Image
ctx.save();
ctx.clip(jarPath);
// Scale image to cover the bound 360x425 area
const imgW = originalImg.width;
const imgH = originalImg.height;
const scale = Math.max(360 / imgW, 425 / imgH);
const drawW = imgW * scale;
const drawH = imgH * scale;
const drawX = 120 + (360 - drawW) / 2;
const drawY = 200 + (425 - drawH) / 2;
ctx.drawImage(originalImg, drawX, drawY, drawW, drawH);
// Inner Volume Shading
const shadowGrad = ctx.createLinearGradient(120, 0, 480, 0);
shadowGrad.addColorStop(0, "rgba(0,0,0,0.6)");
shadowGrad.addColorStop(0.1, "rgba(0,0,0,0.05)");
shadowGrad.addColorStop(0.9, "rgba(0,0,0,0.05)");
shadowGrad.addColorStop(1, "rgba(0,0,0,0.6)");
ctx.fillStyle = shadowGrad;
ctx.fill(jarPath);
// Brine/Preserve Tint Over Image
ctx.fillStyle = tintColor;
ctx.fill(jarPath);
// Simple Bubbles for authenticity
ctx.fillStyle = "rgba(255, 255, 255, 0.3)";
for (let i = 0; i < 25; i++) {
const bX = 140 + Math.random() * 320;
const bY = 220 + Math.random() * 380;
const bR = 1 + Math.random() * 4;
ctx.beginPath();
ctx.arc(bX, bY, bR, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
// Outline Jar
ctx.strokeStyle = "rgba(255, 255, 255, 0.4)";
ctx.lineWidth = 3;
ctx.stroke(jarPath);
// 6. Neck Details (Threads under the lid)
ctx.fillStyle = "rgba(255, 255, 255, 0.2)";
ctx.fillRect(225, 175, 150, 4);
ctx.fillRect(225, 185, 150, 4);
ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(230, 172); ctx.lineTo(230, 200);
ctx.moveTo(370, 172); ctx.lineTo(370, 200);
ctx.stroke();
// 7. Golden Tin Lid
const lidGrad = ctx.createLinearGradient(200, 0, 400, 0);
lidGrad.addColorStop(0, "#734A12");
lidGrad.addColorStop(0.15, "#D4AF37");
lidGrad.addColorStop(0.4, "#FFEC8B");
lidGrad.addColorStop(0.8, "#D4AF37");
lidGrad.addColorStop(1, "#5E3A0E");
ctx.fillStyle = lidGrad;
ctx.beginPath();
ctx.moveTo(220, 130);
ctx.lineTo(380, 130);
ctx.quadraticCurveTo(390, 130, 390, 140);
ctx.lineTo(390, 160);
ctx.quadraticCurveTo(390, 170, 380, 170);
ctx.lineTo(220, 170);
ctx.quadraticCurveTo(210, 170, 210, 160);
ctx.lineTo(210, 140);
ctx.quadraticCurveTo(210, 130, 220, 130);
ctx.fill();
// Lid Rim Ridges
ctx.strokeStyle = "rgba(0, 0, 0, 0.15)";
ctx.lineWidth = 1.5;
for (let lx = 216; lx <= 384; lx += 6) {
ctx.beginPath();
ctx.moveTo(lx, 135);
ctx.lineTo(lx, 165);
ctx.stroke();
}
// Lid Bottom Edge
ctx.strokeStyle = "rgba(255,255,255,0.4)";
ctx.beginPath();
ctx.moveTo(215, 168);
ctx.lineTo(385, 168);
ctx.stroke();
// 8. Rustic String Bundle around neck
ctx.strokeStyle = "#C2A379";
ctx.lineWidth = 3;
ctx.shadowColor = "rgba(0,0,0,0.5)";
ctx.shadowBlur = 3;
ctx.beginPath();
ctx.moveTo(230, 185);
ctx.quadraticCurveTo(300, 195, 370, 185);
ctx.stroke();
// String Bow
ctx.beginPath(); // left loop
ctx.ellipse(280, 190, 15, 5, 2.7, 0, Math.PI * 2);
ctx.stroke();
ctx.beginPath(); // right loop
ctx.ellipse(320, 190, 15, 5, 0.4, 0, Math.PI * 2);
ctx.stroke();
// String Tails
ctx.beginPath();
ctx.moveTo(300, 192); ctx.quadraticCurveTo(295, 210, 285, 240);
ctx.moveTo(300, 192); ctx.quadraticCurveTo(315, 210, 310, 235);
ctx.stroke();
// Bow Knot
ctx.fillStyle = "#A38157";
ctx.beginPath();
ctx.arc(300, 192, 4, 0, Math.PI * 2);
ctx.fill();
ctx.shadowColor = "transparent";
// 9. Label Wrapper
ctx.save();
ctx.translate(300, 450); // Center translation for drawing label
ctx.shadowColor = "rgba(0, 0, 0, 0.6)";
ctx.shadowBlur = 10;
ctx.shadowOffsetY = 4;
ctx.fillStyle = "#FDF5E6"; // Craft paper color
// Curved Label Shape
ctx.beginPath();
ctx.moveTo(-110, -45);
ctx.quadraticCurveTo(0, -55, 110, -45);
ctx.lineTo(110, 45);
ctx.quadraticCurveTo(0, 55, -110, 45);
ctx.closePath();
ctx.fill();
ctx.shadowColor = "transparent";
// Label Inner Border
ctx.strokeStyle = "#C9A77D";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(-100, -36);
ctx.quadraticCurveTo(0, -46, 100, -36);
ctx.lineTo(100, 36);
ctx.quadraticCurveTo(0, 46, -100, 36);
ctx.closePath();
ctx.stroke();
// Label Text - Scale properly
ctx.fillStyle = "#5c331a";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
let fontSize = 28;
const maxTextWidth = 180;
do {
ctx.font = `bold ${fontSize}px "Courier New", Courier, monospace`;
fontSize--;
} while (ctx.measureText(labelText).width > maxTextWidth && fontSize > 10);
// Slightly offset Y axis to match curve
ctx.fillText(labelText, 0, 2);
ctx.restore();
// 10. Front Glass Reflection (Highlight)
ctx.fillStyle = "rgba(255, 255, 255, 0.12)";
ctx.beginPath();
ctx.moveTo(140, 290);
ctx.bezierCurveTo(140, 250, 160, 220, 200, 212);
ctx.lineTo(220, 212);
ctx.bezierCurveTo(180, 230, 165, 270, 165, 320);
ctx.lineTo(165, 560);
ctx.bezierCurveTo(165, 590, 195, 600, 225, 605);
ctx.lineTo(195, 605);
ctx.bezierCurveTo(150, 595, 140, 575, 140, 560);
ctx.closePath();
ctx.fill();
// Right Glass Side Highlight
ctx.fillStyle = "rgba(255, 255, 255, 0.08)";
ctx.beginPath();
ctx.moveTo(460, 320);
ctx.lineTo(470, 320);
ctx.lineTo(470, 550);
ctx.lineTo(460, 550);
ctx.closePath();
ctx.fill();
return canvas;
}
Apply Changes