background

I was in the middle of a busy, boring, boring day when the product manager came up with a request: Because the algorithm engine wanted to be more efficient, the images that they would have captured would now be captured by the front end. I suddenly feel like my fishing days are about to be shattered. Finally, an interesting requirement. I stared at demand for five minutes, lost in thought. Three more minutes of meditation… I can’t.

But if the product manager says so, you can’t just say no. This is not my front five image!

I was lost in thought again. Suddenly, a word popped out of my sandbaggy head: Canvas yes, canva! Then I went to MDN to search the relevant API, and it worked. Then grab my 24-karat gold keyboard and grab a shuttle.

The preliminary implementation

By looking at the MDN documentation, the Canvas first needs a canvas space

<canvas id="canvas"></canvas>
Copy the code

The javascript section then needs to get a reference to this element and get its context, where the image will be rendered.

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
Copy the code

Ok, at this point, canvas initialization is complete. But we’re dealing with images. So, we need to first recognize the image object.

// Initialize the image object
const img = new Image();
// In the local environment, the image address with the domain name exists cross-domain. Set crossOrigin to allow cross-domain
img.setAttribute("crossOrigin"."Anonymous");
img.src = url;
img.onload = function () {
// TODO
};
Copy the code

Now, all the steps are done in the beginning. The next step is to combine the two steps.

// Initialize the image object
const img = new Image();
// In the local environment, the image address with the domain name exists cross-domain. Set crossOrigin to allow cross-domain
img.setAttribute("crossOrigin"."Anonymous");
img.src = url;
img.onload = function () {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    if(! ctx) {console.error("cannot init screenshot canvas");
      return;
    }
    // TODO
};
Copy the code

The reason why we don’t create HTML here is because we react. How can we use such a low way

Basically completed

Now let’s take a look at how canvas does screenshots. Canvas provides two apis:

  • drawImage()
  • toDataURL

DrawImage is used to draw the image, and toDataURL is used to export the image. Please go to MDN for details.

Some people may ask, Canvas implementation clipping has a special API clip, why not?

First, the clip method does crop images, but you need to create clipping paths. Of course, for complex shapes like pentagons, it’s better to use clip, but we’re only dealing with rectangles. Therefore, if you want to further improve this method, you can study and supplement by yourself. Now we assign the canvas the size to be clipped based on the point position. The point positions are shown in the figure.

The points that are highlighted in red. Now, all the parameters needed to evaluate the drawImage are required

let dx = 0;
let dy = 0;
let width = 0;
let height = 0;

dx = _.get(points, "[0] [0]." ".0);
dy = _.get(points, "[0] [1]".0);
const ex = _.get(points, "[1] [0]." ".0);
const ey = _.get(points, "[1] [1]".0);
width = ex - dx;
height = ey - dy;
Copy the code

So far, all the work is finished, reward yourself a small star ✨

Ultimate encapsulation

We use React. Of course we need to react-code this code. Hooks deserve it. Here is the complete code:

import { useState } from "react";

import _ from "lodash";

export const useCutImg = (url: string | undefined, points: number[][]) = > {
  const [result, setResult] = useState<string | undefined> ();if (points.length > 3 || points.length < 1) {
    console.error("points's length should be 2");
    return [""];
  }
  if(! url) {console.error("can not find image url");
    return [""];
  }
  let dx = 0;
  let dy = 0;
  let width = 0;
  let height = 0;

  dx = _.get(points, "[0] [0]." ".0);
  dy = _.get(points, "[0] [1]".0);
  const ex = _.get(points, "[1] [0]." ".0);
  const ey = _.get(points, "[1] [1]".0);
  width = ex - dx;
  height = ey - dy;

  const img = new Image();
  // In the local environment, the image address with the domain name exists cross-domain. Set crossOrigin to allow cross-domain
  img.setAttribute("crossOrigin"."Anonymous");
  img.src = url;
  img.onload = function () {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    if(! ctx) {console.error("cannot init screenshot canvas");
      return;
    }
    canvas.width = width;
    canvas.height = height;
    ctx.drawImage(img, dx, dy, width, height, 0.0, width, height);
    const data = canvas.toDataURL("image/png");
    setResult(data);
  };
  return [result];
};
Copy the code

The last

Once encapsulation is complete, usage is simple, introduce this hooks, and then

const [result] = useCutImg('xxx.img'The [[200.100], [1000.800]])
Copy the code

Thank you for seeing this! Feel useful, you can like collection yo, pen core ~