diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..74fbad6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dprint.json +test/ diff --git a/README.md b/README.md index 5fb8533..9da9c95 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ -# image_overlay +# image_overlay -Tiny web app to combine a background image and a foreground image \ No newline at end of file +Tiny web app to combine a background image and a foreground image. + +## Usage + +1. Open [index.html](index.html) in your browser. +2. Upload a background image and a foreground image. +3. Set the relative size, X offset, and Y offset of the foreground image. +4. Click **Download**. + +## Dependencies + +* A browser +* Two images +* Nothing else diff --git a/app.js b/app.js new file mode 100644 index 0000000..c4fd4fc --- /dev/null +++ b/app.js @@ -0,0 +1,85 @@ +// 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 = "wallpaper.png"; + link.href = canvas.toDataURL("image/png"); + link.click(); +}; diff --git a/index.html b/index.html new file mode 100644 index 0000000..ff54d96 --- /dev/null +++ b/index.html @@ -0,0 +1,32 @@ + + +
+ +