// Minimal canvas compositor const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); let bgImg = null; let fgImg = null; // --- image loader --- function loadImage(file, callback) { if (!file) return; const img = new Image(); img.onload = () => callback(img); img.src = URL.createObjectURL(file); } // --- inputs --- const bgInput = document.getElementById("bgInput"); const fgInput = document.getElementById("fgInput"); const scaleInput = document.getElementById("scale"); const offsetXInput = document.getElementById("offsetX"); const offsetYInput = document.getElementById("offsetY"); // --- event bindings --- bgInput.onchange = (e) => { loadImage(e.target.files[0], (img) => { bgImg = img; // canvas follows background resolution exactly canvas.width = img.width; canvas.height = img.height; draw(); }); }; fgInput.onchange = (e) => { loadImage(e.target.files[0], (img) => { fgImg = img; draw(); }); }; [scaleInput, offsetXInput, offsetYInput].forEach(el => { el.oninput = draw; }); // --- draw pipeline --- function draw() { if (!bgImg) return; // clear + draw background ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(bgImg, 0, 0); if (!fgImg) return; const scale = parseFloat(scaleInput.value) / 100 || 0.2; const offsetX = parseFloat(offsetXInput.value) || 0; const offsetY = parseFloat(offsetYInput.value) || 0; // scale based on background width const targetWidth = bgImg.width * scale; const aspect = fgImg.height / fgImg.width; const targetHeight = targetWidth * aspect; // centered + offsets const x = (bgImg.width - targetWidth) / 2 + offsetX; const y = (bgImg.height - targetHeight) / 2 + offsetY; ctx.drawImage(fgImg, x, y, targetWidth, targetHeight); } // --- download --- document.getElementById("downloadBtn").onclick = () => { if (!bgImg) return; const link = document.createElement("a"); link.download = "overlay_image.png"; link.href = canvas.toDataURL("image/png"); link.click(); };