You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, brandName = "WILD LIFE", figureName = "REAL ANIMAL FIGURE", themeColor = "#2a9d8f", ageRating = "3+") {
const canvas = document.createElement('canvas');
canvas.width = 600;
canvas.height = 900;
const ctx = canvas.getContext('2d');
// Helper for rounded rectangles to ensure compatibility
function drawRoundRect(x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
}
// 1. Draw Cardboard Background
drawRoundRect(0, 0, 600, 900, 25);
ctx.clip(); // Keep everything inside the shape of the card
// Gradient base
const bgGrad = ctx.createLinearGradient(0, 0, 0, 900);
bgGrad.addColorStop(0, themeColor);
bgGrad.addColorStop(1, '#111111');
ctx.fillStyle = bgGrad;
ctx.fillRect(0, 0, 600, 900);
// Dynamic sunburst background graphic
ctx.save();
ctx.translate(300, 500);
const rays = 24;
ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
for (let i = 0; i < rays; i++) {
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.arc(0, 0, 1000, i * 2 * Math.PI / rays, (i + 0.5) * 2 * Math.PI / rays);
ctx.fill();
}
ctx.restore();
// 2. Punch Out Peg Hole (for hanging the toy)
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
ctx.beginPath();
drawRoundRect(270, 30, 60, 20, 10); // horizontal slot
ctx.fill();
ctx.beginPath();
ctx.arc(300, 25, 15, 0, Math.PI * 2); // top circle
ctx.fill();
ctx.restore();
// 3. Text and Graphics Layout
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Brand Name
ctx.font = 'bold 70px "Arial Black", Impact, sans-serif';
ctx.lineWidth = 8;
ctx.strokeStyle = '#000000';
ctx.strokeText(brandName, 300, 120); // Bold black stroke
// Brand Name Fill
const textGrad = ctx.createLinearGradient(0, 80, 0, 150);
textGrad.addColorStop(0, '#FFFFFF');
textGrad.addColorStop(1, '#DDDDDD');
ctx.fillStyle = textGrad;
ctx.fillText(brandName, 300, 120);
// Toy Figure Name
ctx.font = 'bold 36px Impact, "Arial Black", sans-serif';
ctx.lineWidth = 5;
ctx.strokeStyle = '#000000';
ctx.strokeText(figureName, 300, 190);
ctx.fillStyle = '#FFD166'; // Vintage yellow pop
ctx.fillText(figureName, 300, 190);
// Age Rating Circle Top-Right
ctx.save();
ctx.translate(510, 110);
ctx.beginPath();
ctx.arc(0, 0, 45, 0, Math.PI * 2);
ctx.fillStyle = '#EF476F';
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = '#FFFFFF';
ctx.stroke();
ctx.fillStyle = '#FFFFFF';
ctx.font = 'bold 18px Arial';
ctx.fillText("AGES", 0, -10);
ctx.font = 'bold 28px Arial';
ctx.fillText(ageRating, 0, 15);
ctx.restore();
// 4. Place Original Image (The "Toy")
ctx.save();
// Maximum bounds for the image inside the blister pack
const imgMaxW = 380;
const imgMaxH = 460;
const scale = Math.min(imgMaxW / originalImg.width, imgMaxH / originalImg.height);
const nw = originalImg.width * scale;
const nh = originalImg.height * scale;
// Center it into the bubble container
const nx = 300 - nw / 2;
const ny = 520 - nh / 2;
// Apply intense drop shadow to push the figure out visually into 3D space
ctx.shadowColor = 'rgba(0, 0, 0, 0.7)';
ctx.shadowBlur = 20;
ctx.shadowOffsetX = 12;
ctx.shadowOffsetY = 15;
ctx.drawImage(originalImg, nx, ny, nw, nh);
ctx.restore();
// 5. Draw Blister Pack (Plastic Bubble) Over the Toy
const bx = 80;
const by = 260;
const bw = 440;
const bh = 520;
const br = 20;
// Soft drop shadow generated from the plastic flange glued on the card
ctx.save();
ctx.shadowColor = 'rgba(0, 0, 0, 0.6)';
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 4;
ctx.shadowOffsetY = 4;
ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
drawRoundRect(bx, by, bw, bh, br);
ctx.fill(); // the fill triggers the drop shadow below
ctx.restore();
// Plastic rim flange
drawRoundRect(bx, by, bw, bh, br);
ctx.lineWidth = 12;
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.stroke();
// Crisp glued edge
ctx.lineWidth = 1;
ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)';
ctx.stroke();
// The upward extrusion crease of the blister pack
const cx = bx + 16;
const cy = by + 16;
const cw = bw - 32;
const ch = bh - 32;
const cr = 10;
ctx.save();
drawRoundRect(cx, cy, cw, ch, cr);
ctx.lineWidth = 2;
const borderGrad = ctx.createLinearGradient(cx, cy, cx + cw, cy + ch);
borderGrad.addColorStop(0, 'rgba(255, 255, 255, 0.9)');
borderGrad.addColorStop(0.5, 'rgba(255, 255, 255, 0.1)');
borderGrad.addColorStop(1, 'rgba(0, 0, 0, 0.4)');
ctx.strokeStyle = borderGrad;
ctx.stroke();
ctx.restore();
// General Plastic Bubble sheen overlay
ctx.save();
drawRoundRect(cx, cy, cw, ch, cr);
ctx.clip(); // Ensure lighting effects don't leak out of bubble bounds
const sheen = ctx.createLinearGradient(cx, cy, cx + cw, cy + ch);
sheen.addColorStop(0, 'rgba(255, 255, 255, 0.3)');
sheen.addColorStop(0.2, 'rgba(255, 255, 255, 0)');
sheen.addColorStop(0.8, 'rgba(255, 255, 255, 0)');
sheen.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
ctx.fillStyle = sheen;
ctx.fill();
// Detailed Curved Reflections highlighting molded contours
ctx.filter = 'blur(4px)'; // Frosted/specular look via blur
// Top primary swoosh
ctx.beginPath();
ctx.moveTo(cx + 20, cy + 50);
ctx.quadraticCurveTo(cx + cw / 2, cy - 20, cx + cw - 20, cy + 40);
ctx.lineWidth = 14;
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
ctx.stroke();
// Bottom right linear reflection
ctx.beginPath();
ctx.moveTo(cx + cw - 15, cy + ch - 120);
ctx.lineTo(cx + cw - 15, cy + ch - 30);
ctx.lineWidth = 12;
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.stroke();
// Left inner edge rim highlight
ctx.beginPath();
ctx.moveTo(cx + 8, cy + 80);
ctx.lineTo(cx + 8, cy + 220);
ctx.lineWidth = 6;
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.stroke();
ctx.restore();
// 6. Bottom Information Area: Choking Hazard and Realism Barcode
ctx.save();
// Safety warning box
drawRoundRect(50, 800, 320, 60, 5);
ctx.fillStyle = '#FFFFFF';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = '#000000';
ctx.stroke();
ctx.fillStyle = '#000000';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.font = 'bold 12px Arial';
ctx.fillText("⚠ WARNING:", 60, 810);
ctx.font = 'bold 11px Arial';
ctx.fillText("CHOKING HAZARD - Small parts.", 60, 826);
ctx.font = '10px Arial';
ctx.fillText("Not for children under 3 years.", 60, 840);
// Simulated Product Barcode
const barX = 460;
const barY = 800;
const barW = 90;
const barH = 60;
// Barcode background
ctx.fillStyle = '#FFFFFF';
drawRoundRect(barX, barY, barW, barH, 5);
ctx.fill();
// Generating stripes
ctx.fillStyle = '#000000';
let currentX = barX + 5;
const pattern = [2, 1, 4, 1, 1, 3, 2, 2, 1, 1, 4, 2, 1, 3, 1, 2, 1, 4, 1, 2];
for (let w of pattern) {
ctx.fillRect(currentX, barY + 5, w, barH - 20);
currentX += w + 1; // move ahead by line width + space
if (currentX > barX + barW - 6) break;
}
// Barcode sequence numbers
ctx.font = '10px Courier New, Courier, monospace';
ctx.textAlign = 'center';
ctx.fillText("7 41342 09218 5", barX + barW / 2, barY + barH - 12);
ctx.restore();
return canvas;
}
Apply Changes