You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, productionTitle = "AWESOME MOVIE", directorName = "JOHN DOE", cameraStr = "CINEMA", sceneNumber = "01", takeNumber = "03", dateString = "2023-10-24", cinematicBars = 1) {
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 uploaded image
ctx.drawImage(originalImg, 0, 0, w, h);
const addBars = parseInt(cinematicBars) || 0;
// Add cinematic letterbox (only if the picture is horizontal)
if (addBars === 1 && w > h) {
const targetRatio = 2.35;
const currentRatio = w / h;
if (currentRatio < targetRatio) {
const newHeight = w / targetRatio;
const barHeight = (h - newHeight) / 2;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, w, barHeight);
ctx.fillRect(0, h - barHeight, w, barHeight);
} else {
const newWidth = h * targetRatio;
const barWidth = (w - newWidth) / 2;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, barWidth, h);
ctx.fillRect(w - barWidth, 0, barWidth, h);
}
}
// Add Vignette for atmospheric filmic look
const cx = w / 2;
const cy = h / 2;
const r = Math.max(w, h) * 0.7;
const grad = ctx.createRadialGradient(cx, cy, r * 0.4, cx, cy, r);
grad.addColorStop(0, 'rgba(0,0,0,0)');
grad.addColorStop(1, 'rgba(0,0,0,0.6)');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, w, h);
// Add 'REC' dot indicator
if (addBars === 1) {
const dotR = Math.max(w * 0.008, 5);
const padX = Math.max(w * 0.04, 20);
const padY = Math.max(h * 0.06, 20);
ctx.fillStyle = "#ff0000";
ctx.beginPath();
ctx.arc(w - padX, padY, dotR, 0, Math.PI * 2);
ctx.fill();
ctx.font = `bold ${dotR * 2.5}px Arial, sans-serif`;
ctx.textAlign = "right";
ctx.textBaseline = "middle";
ctx.fillText("REC", w - padX - dotR * 1.5, padY);
}
// --- CLAPPERBOARD SLATE / MOVIE IDENTIFIER WIDGET ---
// Dimensional Setup
const cbW = Math.min(w * 0.75, 800);
const cbH = cbW * 0.65;
const stickH = cbH * 0.12;
const boardH = cbH - (2 * stickH);
const cbX = (w - cbW) / 2;
const topY = (h - cbH) / 2 + h * 0.1; // Centered, offset slightly down
const cbY = topY + 2 * stickH;
const hingeX = cbX + stickH * 0.5;
const hingeY = cbY - stickH * 0.5;
// First layer: Shadow caster for a 3D overlay effect
ctx.save();
ctx.shadowColor = 'rgba(0, 0, 0, 0.75)';
ctx.shadowBlur = 25;
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 15;
ctx.fillStyle = "#111";
ctx.beginPath();
ctx.rect(cbX, cbY, cbW, boardH); // Main Board
ctx.rect(cbX, cbY - stickH, cbW, stickH); // Bottom Stick
ctx.fill();
// Shadow caster for the Top stick (angled open)
ctx.save();
ctx.translate(hingeX, hingeY);
ctx.rotate(-15 * Math.PI / 180);
ctx.fillRect(-stickH * 0.5, -stickH * 0.5, cbW, stickH);
ctx.restore();
ctx.restore(); // remove shadows for individual text/stripes layer drawing
// Draw Top Stick
ctx.save();
ctx.translate(hingeX, hingeY);
ctx.rotate(-15 * Math.PI / 180);
ctx.translate(-stickH * 0.5, -stickH * 0.5);
drawStick(ctx, cbW, stickH);
ctx.restore();
// Draw Bottom Stick
ctx.save();
ctx.translate(cbX, cbY - stickH);
drawStick(ctx, cbW, stickH);
ctx.restore();
// Draw Metal Hinge Bolt
ctx.beginPath();
ctx.arc(hingeX, hingeY, stickH * 0.25, 0, Math.PI * 2);
ctx.fillStyle = "#999";
ctx.fill();
ctx.strokeStyle = "#222";
ctx.lineWidth = stickH * 0.05;
ctx.stroke();
// Screw slot
ctx.beginPath();
ctx.moveTo(hingeX - stickH * 0.15, hingeY);
ctx.lineTo(hingeX + stickH * 0.15, hingeY);
ctx.stroke();
// --- Draw the Chalk/Markers Board ---
ctx.fillStyle = "#151515"; // Matte black slate
ctx.fillRect(cbX, cbY, cbW, boardH);
const bw = cbW - 4;
const bh = boardH - 4;
const bx = cbX + 2;
const by = cbY + 2;
// Board Outline
ctx.strokeStyle = "#e0e0e0";
ctx.lineWidth = Math.max(cbW * 0.005, 2);
ctx.strokeRect(bx, by, bw, bh);
// Board Grid Lines
ctx.beginPath();
ctx.lineWidth = Math.max(cbW * 0.003, 1);
const r1Y = by + bh * 0.25;
ctx.moveTo(bx, r1Y); ctx.lineTo(bx + bw, r1Y);
const r2Y = by + bh * 0.5;
ctx.moveTo(bx, r2Y); ctx.lineTo(bx + bw, r2Y);
const c1X = bx + bw * 0.33;
const c2X = bx + bw * 0.66;
ctx.moveTo(c1X, r1Y); ctx.lineTo(c1X, r2Y);
ctx.moveTo(c2X, r1Y); ctx.lineTo(c2X, r2Y);
const r3Y = by + bh * 0.75;
ctx.moveTo(bx, r3Y); ctx.lineTo(bx + bw, r3Y);
const c3X = bx + bw * 0.55;
ctx.moveTo(c3X, r2Y); ctx.lineTo(c3X, r3Y);
ctx.stroke();
// Insert Chalk Text Settings
const baseFontSize = Math.max(bh * 0.04, 6);
const labelFont = `bold ${baseFontSize}px 'Courier New', Courier, monospace`;
const valFont = `bold ${Math.max(bh * 0.13, 10)}px 'Courier New', Courier, monospace`;
function drawSection(label, val, x, y, width, height) {
// Label Section
ctx.font = labelFont;
ctx.fillStyle = "#a0a0a0";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText(label, x + bw * 0.015, y + bh * 0.015);
// Value Input Section (Centered auto width)
ctx.font = valFont;
ctx.fillStyle = "#ffffff";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(val, x + width / 2, y + height / 2 + bh * 0.015, width - bw * 0.03);
}
// Row 1
drawSection("PROD.", productionTitle, bx, by, bw, r1Y - by);
// Row 2
drawSection("ROLL", "A01", bx, r1Y, c1X - bx, r2Y - r1Y);
drawSection("SCENE", sceneNumber, c1X, r1Y, c2X - c1X, r2Y - r1Y);
drawSection("TAKE", takeNumber, c2X, r1Y, bx + bw - c2X, r2Y - r1Y);
// Row 3
drawSection("DIRECTOR", directorName, bx, r2Y, c3X - bx, r3Y - r2Y);
drawSection("CAMERA", cameraStr, c3X, r2Y, bx + bw - c3X, r3Y - r2Y);
// Row 4
drawSection("DATE", dateString, bx, r3Y, bw, by + bh - r3Y);
return canvas;
// Helper sub-function to consistently map and draw styled diagonal bars for clapperboard's sticks
function drawStick(c, wStick, hStick) {
c.fillStyle = "#ffffff";
c.fillRect(0, 0, wStick, hStick);
c.fillStyle = "#111111"; // Sharp black chevrons/stripes
c.save();
c.beginPath();
c.rect(0, 0, wStick, hStick);
c.clip();
const sWidth = hStick * 1.0;
const count = Math.ceil(wStick / sWidth) + 2;
for (let i = -1; i < count; i++) {
c.beginPath();
c.moveTo(i * sWidth * 2, 0);
c.lineTo(i * sWidth * 2 + sWidth, 0);
c.lineTo(i * sWidth * 2 + sWidth + hStick * 0.5, hStick); // Angle downwards Right
c.lineTo(i * sWidth * 2 + hStick * 0.5, hStick);
c.fill();
}
c.restore();
// Edge stroke wrap
c.strokeStyle = "#222";
c.lineWidth = Math.max(wStick * 0.002, 1);
c.strokeRect(0, 0, wStick, hStick);
}
}
Apply Changes