Issue with simple java app that removes background from one image and overlays it onto another image and downloads the processed image

31 views Asked by At

essentially what i'm trying to create is a simple Java app that when an image is uploaded it removes the black from the background and makes it transparent, then stores this image. Then, the image from this URL 'https://pasteboard.co/VA1RxuEWqS4u.jpg' is used as a background image and the javascript overlays the image with the background that has been removed onto the pasteboard one and automatically downloads the finished result. When I run this, nothing happens, any help would be greatly appreciated.

Here is the code:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Background Remover and Overlay</title>
<style>
  #upload-btn {
    width: 100px;
    height: 40px;
    background-color: #007bff;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
  }
</style>
</head>
<body>
<input type="file" id="file-input" style="display: none;">
<button id="upload-btn">Upload Image</button>
<script>
document.getElementById('upload-btn').addEventListener('click', function() {
  document.getElementById('file-input').click();
});

document.getElementById('file-input').addEventListener('change', function(event) {
  const file = event.target.files[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = function(e) {
    const img = new Image();
    img.onload = function() {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      canvas.width = img.width;
      canvas.height = img.height;
      
      // Draw the image on the canvas
      ctx.drawImage(img, 0, 0);
      
      // Get the image data
      const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      const data = imageData.data;

      // Remove black background (set alpha to 0 for black pixels)
      for (let i = 0; i < data.length; i += 4) {
        const r = data[i];
        const g = data[i + 1];
        const b = data[i + 2];
        // Check if the pixel is black (you can adjust the threshold as needed)
        if (r < 30 && g < 30 && b < 30) {
          data[i + 3] = 0; // Set alpha to 0
        }
      }
      
      // Put the modified image data back onto the canvas
      ctx.putImageData(imageData, 0, 0);

      // Convert canvas to image and download
      const transparentImageUrl = canvas.toDataURL('image/png');
      
      // Load the overlay image from the hosting website
      const overlayImageUrl = 'https://pasteboard.co/VA1RxuEWqS4u.jpg';
      const overlayImg = new Image();
      overlayImg.crossOrigin = 'anonymous';
      overlayImg.onload = function() {
        // Draw the overlay image on the canvas
        ctx.drawImage(overlayImg, 0, 0, canvas.width, canvas.height);
        
        // Convert canvas to image and download the final image
        const finalImageUrl = canvas.toDataURL('image/png');
        const downloadLink = document.createElement('a');
        downloadLink.href = finalImageUrl;
        downloadLink.download = 'final_image.png';
        downloadLink.click();
      };
      overlayImg.src = overlayImageUrl;
    };
    img.src = e.target.result;
  };
  reader.readAsDataURL(file);
});
</script>
</body>
</html>


1

There are 1 answers

0
FiddlingAway On

Your code is failing for a couple of reasons:

  1. You're drawing what's supposed to be the background image over the image you want to poke holes in (i.e. make the black pixels transparent). It should be the other way around - the remote image should go first, and then, on top of it, the uploaded image with its black pixels removed.

  2. The other issue is that you're trying to load a remote resource which is not an image (despite the JPG extension). You actually need to work with this (obtained via right-clicking on the image loaded from your original link).

  3. The third issue might be CORS, especially if you're testing your code locally (your computer, no local server running, etc). You can overcome this with a browser extension (I used CORS Everywhere - I am in no way affiliated with whoever made it, I just needed something to debug your code, and I settled on this).

One way of addressing these issues is with the following modifications in your code.

// the true image URL - perhaps it's better to provide an input
// and let the user set their own URL
// then you'd also have some sort of error handling if the URL
// is not that of an image
const overlayImageUrl = 'https://gcdnb.pbrd.co/images/VA1RxuEWqS4u.jpg';

document.getElementById('file-input').addEventListener('change', function(event) {
    const file = event.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = function(e) {
        const img = new Image();
        img.onload = function() {
            // this was done so that its meaning
            // it's easily recognizable later on
            const frameWidth = img.width;
            const frameHeight = img.height;

            // the top layer - from the locally loaded image
            const topLayer = document.createElement('canvas');
            const topCtx = topLayer.getContext('2d');
            topLayer.width = frameWidth;
            topLayer.height = frameHeight;

            // draw the top layer
            topCtx.drawImage(img, 0, 0);
            // Get the image data
            const imageData = topCtx.getImageData(0, 0, frameWidth, frameHeight);
            const data = imageData.data;
            // Remove black background (set alpha to 0 for black pixels)
            for (let i = 0; i < data.length; i += 4) {
                const r = data[i];
                const g = data[i + 1];
                const b = data[i + 2];
                // Check if the pixel is black (you can adjust the threshold as needed)
                if (r < 30 && g < 30 && b < 30) {
                    data[i + 3] = 0; // Set alpha to 0
                }
            }

            // Put the modified image data back onto the canvas
            topCtx.putImageData(imageData, 0, 0);

            // Load the overlay image from the hosting website
            const overlayImg = new Image();
            overlayImg.crossOrigin = 'anonymous';
            overlayImg.src = overlayImageUrl;
            overlayImg.onload = function() {
                // the background layer - from the remotely loaded image
                // it's using its own canvas
                const bgLayer = document.createElement('canvas');
                bgLayer.width = img.width;
                bgLayer.height = img.height;
                const bgCtx = bgLayer.getContext('2d');
                bgCtx.drawImage(overlayImg, 0, 0, frameWidth, frameHeight);

                // the composite - here to host the background
                // and the top layer (the one we poked holes in)
                const compositeCanvas = document.createElement('canvas');
                compositeCanvas.width = frameWidth;
                compositeCanvas.height = frameHeight;
                const composite = compositeCanvas.getContext('2d');

                // first the background...
                composite.drawImage(bgLayer,0,0);
                // ... then the top layer - our uploaded image
                composite.drawImage(topLayer,0,0);
                // now the canvas holds two other canvases
                // Convert canvas to image and download the final image
                const finalImageUrl = compositeCanvas.toDataURL('image/png');
                const downloadLink = document.createElement('a');
                downloadLink.href = finalImageUrl;
                downloadLink.download = 'final_image.png';
                downloadLink.click();
            };
        };
        img.src = e.target.result;
    };
    reader.readAsDataURL(file);
});