You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, themeColor = '#007bff') {
// Create main container
const container = document.createElement('div');
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
container.style.gap = '15px';
container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
container.style.position = 'relative';
container.style.width = '100%';
container.style.maxWidth = '800px';
container.style.margin = '0 auto';
container.style.padding = '20px';
container.style.backgroundColor = '#2c2c2c';
container.style.borderRadius = '12px';
container.style.boxShadow = '0 8px 16px rgba(0,0,0,0.3)';
container.style.boxSizing = 'border-box';
// Create the display view area for the camera preview / taken photo
const viewArea = document.createElement('div');
viewArea.style.position = 'relative';
viewArea.style.width = '100%';
viewArea.style.display = 'flex';
viewArea.style.justifyContent = 'center';
viewArea.style.alignItems = 'center';
viewArea.style.overflow = 'hidden';
viewArea.style.borderRadius = '8px';
viewArea.style.backgroundColor = '#000';
viewArea.style.minHeight = '300px';
const video = document.createElement('video');
video.autoplay = true;
video.playsInline = true;
video.style.maxWidth = '100%';
video.style.maxHeight = '60vh';
video.style.objectFit = 'contain';
const canvas = document.createElement('canvas');
canvas.style.display = 'none';
canvas.style.maxWidth = '100%';
canvas.style.maxHeight = '60vh';
canvas.style.objectFit = 'contain';
viewArea.appendChild(video);
viewArea.appendChild(canvas);
// Aesthetic Viewfinder overlay targeting the center
const viewfinder = document.createElement('div');
viewfinder.style.position = 'absolute';
viewfinder.style.top = '50%';
viewfinder.style.left = '50%';
viewfinder.style.transform = 'translate(-50%, -50%)';
viewfinder.style.width = '50%';
viewfinder.style.height = '50%';
viewfinder.style.pointerEvents = 'none';
const bracketStyle = 'position: absolute; width: 30px; height: 30px; border-color: rgba(255,255,255,0.7); border-style: solid;';
viewfinder.innerHTML = `
<div style="${bracketStyle} top: 0; left: 0; border-width: 4px 0 0 4px;"></div>
<div style="${bracketStyle} top: 0; right: 0; border-width: 4px 4px 0 0;"></div>
<div style="${bracketStyle} bottom: 0; left: 0; border-width: 0 0 4px 4px;"></div>
<div style="${bracketStyle} bottom: 0; right: 0; border-width: 0 4px 4px 0;"></div>
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 6px; height: 6px; border-radius: 50%; background: rgba(255,0,0,0.7);"></div>
`;
viewArea.appendChild(viewfinder);
// Flash effect element for "Щёлк!" feedback
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 = '#fff';
flash.style.opacity = '0';
flash.style.pointerEvents = 'none';
flash.style.transition = 'opacity 0.2s ease-out';
viewArea.appendChild(flash);
// Buttons Container
const controls = document.createElement('div');
controls.style.display = 'flex';
controls.style.gap = '15px';
controls.style.flexWrap = 'wrap';
controls.style.justifyContent = 'center';
controls.style.marginTop = '10px';
const createBtn = (text, bgColor) => {
const btn = document.createElement('button');
btn.innerHTML = text;
btn.style.padding = '12px 24px';
btn.style.fontSize = '16px';
btn.style.fontWeight = 'bold';
btn.style.cursor = 'pointer';
btn.style.border = 'none';
btn.style.borderRadius = '30px';
btn.style.backgroundColor = bgColor;
btn.style.color = '#fff';
btn.style.transition = 'transform 0.1s, opacity 0.2s';
btn.onmousedown = () => btn.style.transform = 'scale(0.95)';
btn.onmouseup = () => btn.style.transform = 'scale(1)';
btn.onmouseover = () => btn.style.opacity = '0.9';
btn.onmouseout = () => btn.style.opacity = '1';
return btn;
};
const captureBtn = createBtn('📸 Capture', themeColor);
const retryBtn = createBtn('🔄 Retake', '#6c757d');
const dlBtn = createBtn('💾 Save Photo', '#28a745');
retryBtn.style.display = 'none';
dlBtn.style.display = 'none';
controls.appendChild(captureBtn);
controls.appendChild(retryBtn);
controls.appendChild(dlBtn);
container.appendChild(viewArea);
container.appendChild(controls);
let stream = null;
let fallbackMode = false;
// Start Webcam or Fallback to Original Image
async function startCamera() {
try {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user' }, audio: false });
video.srcObject = stream;
fallbackMode = false;
} else {
throw new Error("getUserMedia not supported");
}
} catch (err) {
console.warn("Camera access denied/unavailable. Implementing fallback mechanism using originalImg.");
fallbackMode = true;
video.style.display = 'none';
canvas.style.display = 'block';
canvas.width = originalImg.naturalWidth || originalImg.width || 800;
canvas.height = originalImg.naturalHeight || originalImg.height || 600;
const ctx = canvas.getContext('2d');
if (canvas.width > 0 && canvas.height > 0) {
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
} else {
ctx.fillStyle = '#444';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#fff';
ctx.font = '24px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('Camera unavailable & No Image Provided', canvas.width / 2, canvas.height / 2);
}
}
}
startCamera();
// Listeners for functionality
captureBtn.addEventListener('click', () => {
// Shutter flash effect
flash.style.opacity = '1';
setTimeout(() => flash.style.opacity = '0', 150);
viewfinder.style.display = 'none';
if (!fallbackMode) {
const w = video.videoWidth || 640;
const h = video.videoHeight || 480;
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, w, h);
video.style.display = 'none';
canvas.style.display = 'block';
}
captureBtn.style.display = 'none';
retryBtn.style.display = 'block';
dlBtn.style.display = 'block';
});
retryBtn.addEventListener('click', () => {
viewfinder.style.display = 'block';
if (!fallbackMode) {
video.style.display = 'block';
canvas.style.display = 'none';
}
captureBtn.style.display = 'block';
retryBtn.style.display = 'none';
dlBtn.style.display = 'none';
});
dlBtn.addEventListener('click', () => {
const link = document.createElement('a');
link.download = `photo_capture_${Date.now()}.png`;
link.href = canvas.toDataURL('image/png', 1.0);
link.click();
});
// Cleanup tracks safely when element is removed from DOM to prevent webcam staying active
let wasInDOM = false;
const observer = new MutationObserver(() => {
const inDOM = document.body.contains(container);
if (inDOM) {
wasInDOM = true;
} else if (wasInDOM && !inDOM) {
if (stream) {
stream.getTracks().forEach(track => track.stop());
}
observer.disconnect();
}
});
observer.observe(document.body, { childList: true, subtree: true });
return container;
}
Apply Changes