Cropping a masked clipped image

95 Views Asked by At

I have created an SVG mask that allows showing only a certain part of an image. Here is the code for that:

.svg-defs {
  position: absolute;
  width: 0;
  height: 0;
}

.container {
  position: relative;
  top: 20px;
  left: 50px;
}

.background::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: url(https://fastly.picsum.photos/id/553/200/300.jpg?hmac=-A3VLW_dBmwUaXOe7bHhCt-lnmROrPFyTLslwNHVH1A) no-repeat;
  opacity: .1;
}
   
img {
  clip-path: url(#clipper);
}
<svg class='svg-defs'>
  <defs>
    <clipPath id='clipper'>
      <rect x="30" y="120" width="100" height="100" />
    </clipPath>
  </defs>
</svg>
    
<div class='container'>
  <div class='background'>
    <img src="https://fastly.picsum.photos/id/553/200/300.jpg?hmac=-A3VLW_dBmwUaXOe7bHhCt-lnmROrPFyTLslwNHVH1A" />
  </div>
</div>

Please note that I am using .background::before in CSS for the sole purpose of displaying the image as a faded background, for aesthetics.

Now, so far, everything is great. What I want to do is write JavaScript code, which when executed (maybe triggered via a click of a button), it will crop the image to the clipped part only (or the bright part in the image above), and which I should be able to save into a file eventually (in other words, I only want to save the bright section of the image as a new image, or at least be able to display it in a separate img tag)

Thank you.

1

There are 1 best solutions below

0
Greeso On BEST ANSWER

After a lot of investigation, and reading the article suggested by @BretDonald, I came up with the following solution. I am putting it here for the greater good.

const cropSize = {
    width: 100,
  height: 100
}

// Function to crop the image
const crop = () => {
    const canvas = document.querySelector("#cropped");
  const ctx = canvas.getContext('2d');
  
  ctx.drawImage(img, 70, 140, cropSize.width, cropSize.height, 0, 0, cropSize.width, cropSize.height);
}


const img = new Image();
img.src = 'https://fastly.picsum.photos/id/290/200/300.jpg?hmac=kjRyFwJ6i5kuROjzxcs6QbXbBr8EptbH5AuVxtMxhQ0';

img.onload = (() => {

    const canvas = document.querySelector("#image");
  const ctx = canvas.getContext('2d');
  
  ctx.drawImage(img, 70, 140, cropSize.width, cropSize.height, 70, 140, cropSize.width, cropSize.height);
  
});
#main {
  display: flex;
  flex-direction: column;
  align-items: center;
  
  box-sizing: border-box;
  
  width: 500px;
  height: 400px;
  
}

#container {
  flex-grow: 1;
  
  box-sizing: border-box;
  border: 1px solid black;
  background-color: lightgray;
  
  position: relative;
  width: 100%;
  height: 100%;
  

  
  
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

#image-and-background {
  
  position: relative;
  
  width: 200px;
  height: 300px;
  
  background-color: white;
  
}

#background::before {
  content: '';
  background: url('https://fastly.picsum.photos/id/290/200/300.jpg?hmac=kjRyFwJ6i5kuROjzxcs6QbXbBr8EptbH5AuVxtMxhQ0') no-repeat;
  opacity: 0.3;
  
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
<div id='main'>
  <div id='container'>
    <div id='image-and-background'>
      <div id='background'>
        <canvas id='image' width='200' height='300'></canvas>
      </div>
    </div>
  </div>
</div>


<div>
  <p>Click on the "Crop" button below for a cropped image</p>
  <canvas id='cropped' width='100', height='100'></canvas>
  <div id='buttons'>
    <input type="button" id="button1" onclick="crop()" value="Crop" />
  </div>
</div>