You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, captionText = "Щёлк, и готово!", filterStyle = "contrast(1.1) saturate(1.1)", frameColor = "#f8f8f8") {
const container = document.createElement('div');
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
container.style.justifyContent = 'center';
container.style.padding = '30px';
container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
container.style.background = 'repeating-linear-gradient(45deg, #eee, #eee 10px, #f5f5f5 10px, #f5f5f5 20px)';
container.style.borderRadius = '12px';
container.style.boxShadow = 'inset 0 0 20px rgba(0,0,0,0.05)';
container.style.position = 'relative';
container.style.overflow = 'hidden';
// Import Google Font for handwriting style caption
if (!document.getElementById('caveat-font')) {
const link = document.createElement('link');
link.id = 'caveat-font';
link.href = 'https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap';
link.rel = 'stylesheet';
document.head.appendChild(link);
}
const canvas = document.createElement('canvas');
canvas.style.maxWidth = '100%';
canvas.style.height = 'auto';
canvas.style.boxShadow = '0 12px 30px rgba(0,0,0,0.25)';
canvas.style.transform = 'rotate(-1.5deg)';
canvas.style.transition = 'transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275)';
canvas.style.cursor = 'pointer';
// Interactive Hover effect for the Polaroid
canvas.addEventListener('mouseenter', () => {
canvas.style.transform = 'scale(1.03) rotate(0deg)';
});
canvas.addEventListener('mouseleave', () => {
canvas.style.transform = 'rotate(-1.5deg)';
});
const videoContainer = document.createElement('div');
videoContainer.style.display = 'none';
videoContainer.style.position = 'relative';
videoContainer.style.maxWidth = '100%';
videoContainer.style.boxShadow = '0 10px 25px rgba(0,0,0,0.3)';
videoContainer.style.borderRadius = '8px';
videoContainer.style.overflow = 'hidden';
videoContainer.style.border = '5px solid #fff';
const video = document.createElement('video');
video.autoplay = true;
video.playsInline = true;
video.style.display = 'block';
video.style.maxWidth = '100%';
video.style.backgroundColor = '#000';
video.style.transform = 'scaleX(-1)'; // Mirror viewfinder
videoContainer.appendChild(video);
const controls = document.createElement('div');
controls.style.display = 'flex';
controls.style.gap = '15px';
controls.style.marginTop = '30px';
controls.style.flexWrap = 'wrap';
controls.style.justifyContent = 'center';
const btnStyle = "padding: 12px 24px; font-size: 16px; font-weight: bold; border: none; border-radius: 30px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 4px 10px rgba(0,0,0,0.15); display: flex; align-items: center; gap: 8px;";
const btnSnap = document.createElement('button');
btnSnap.innerHTML = '📷 Сделать инста-фото';
btnSnap.style.cssText = btnStyle + " background-color: #ff4757; color: white;";
const btnDownload = document.createElement('button');
btnDownload.innerHTML = '💾 Скачать';
btnDownload.style.cssText = btnStyle + " background-color: #2ed573; color: white;";
// Interactive button styles
[btnSnap, btnDownload].forEach(btn => {
btn.addEventListener('mouseenter', () => btn.style.transform = 'translateY(-3px)');
btn.addEventListener('mouseleave', () => btn.style.transform = 'translateY(0)');
});
controls.appendChild(btnSnap);
controls.appendChild(btnDownload);
// Renderer core logic
function drawInstantPhoto(source, isVideo = false) {
const ctx = canvas.getContext('2d');
const srcW = isVideo ? source.videoWidth : source.width;
const srcH = isVideo ? source.videoHeight : source.height;
if (!source || srcW === 0 || srcH === 0) return;
const baseSize = 600;
const margin = baseSize * 0.057;
const bottomMargin = baseSize * 0.297;
canvas.width = baseSize + (margin * 2);
canvas.height = baseSize + margin + bottomMargin;
// Draw Polaroid Frame
ctx.fillStyle = frameColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Crop center square
const minSize = Math.min(srcW, srcH);
const sx = (srcW - minSize) / 2;
const sy = (srcH - minSize) / 2;
ctx.save();
ctx.beginPath();
ctx.rect(margin, margin, baseSize, baseSize);
ctx.clip();
ctx.filter = filterStyle;
if (isVideo) {
// Un-mirror the captured result, simulating how user saw it in perspective
ctx.translate(canvas.width, 0);
ctx.scale(-1, 1);
}
ctx.drawImage(source, sx, sy, minSize, minSize, margin, margin, baseSize, baseSize);
ctx.restore();
// Inner shadow/border for recess effect
ctx.strokeStyle = "rgba(0,0,0,0.12)";
ctx.lineWidth = 2;
ctx.strokeRect(margin, margin, baseSize, baseSize);
// Glossy reflection overlay
ctx.fillStyle = "rgba(255,255,255,0.06)";
ctx.beginPath();
ctx.moveTo(margin, margin);
ctx.lineTo(margin + baseSize, margin);
ctx.lineTo(margin, margin + baseSize);
ctx.fill();
// Handwriting Text
if (captionText) {
ctx.fillStyle = "#2c3e50";
const fontSize = bottomMargin * 0.35;
ctx.font = `${fontSize}px "Caveat", cursive, sans-serif`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.save();
ctx.translate(canvas.width / 2, margin + baseSize + bottomMargin * 0.45);
ctx.rotate(-0.025); // Slight tilt to feel handwritten
ctx.fillText(captionText, 0, 0);
ctx.restore();
}
}
// Initial draw when original image is passed
setTimeout(() => drawInstantPhoto(originalImg, false), 100);
// Redraw robustly after handwriting font is securely loaded
if (document.fonts && document.fonts.ready) {
document.fonts.ready.then(() => {
if (!cameraActive && videoContainer.style.display === 'none') {
drawInstantPhoto(originalImg, false);
}
});
}
let stream = null;
let cameraActive = false;
// Capture logic
btnSnap.addEventListener('click', async () => {
if (!cameraActive) {
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
alert('Камера не поддерживается вашим браузером или требуется безопасное соединение (HTTPS).');
return;
}
try {
stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" } });
video.srcObject = stream;
video.onloadedmetadata = () => {
videoContainer.style.display = 'block';
canvas.style.display = 'none';
btnSnap.innerHTML = '🕒 Снимаем... (3)';
btnSnap.style.backgroundColor = '#ffa502';
cameraActive = true;
let count = 3;
const countdown = setInterval(() => {
count--;
if (count > 0) {
btnSnap.innerHTML = `🕒 Снимаем... (${count})`;
} else {
clearInterval(countdown);
// Visual Flash Effect
const flash = document.createElement('div');
flash.style.position = 'absolute';
flash.style.top = '0'; flash.style.left = '0';
flash.style.width = '100%'; flash.style.height = '100%';
flash.style.backgroundColor = 'white';
flash.style.zIndex = '99';
flash.style.transition = 'opacity 0.6s ease-out';
container.appendChild(flash);
// Actuate snapshot
drawInstantPhoto(video, true);
// Trigger flash fadeout
requestAnimationFrame(() => flash.style.opacity = '0');
setTimeout(() => flash.remove(), 600);
// Gracefully stop camera pipeline
stream.getTracks().forEach(t => t.stop());
videoContainer.style.display = 'none';
canvas.style.display = 'block';
btnSnap.innerHTML = '📷 Переснять';
btnSnap.style.backgroundColor = '#ff4757';
cameraActive = false;
}
}, 1000);
};
} catch (err) {
alert('Не удалось получить доступ к камере. ' + err.message);
cameraActive = false;
}
}
});
// Provide payload link for users to download their photo
btnDownload.addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'instant-capture.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
container.appendChild(videoContainer);
container.appendChild(canvas);
container.appendChild(controls);
return container;
}
Apply Changes