Implementation approach

  1. First, the original image was shifted in 8 directions
  2. Then fill the moved image with the stroke color
  3. Finally, overlay the original image

The core code

Generate the canvas

Create the canvas, load the image, and set the canvas width and height to the image width and height:

// create canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

// create image
const image = new Image();
image.onload = function() {
    canvas.width = image.width;
    canvas.height = image.height;
};
image.src = url;
image.crossOrigin = "Anonymous";
Copy the code

Pan image

We construct an array with two elements representing one direction.

const dArr = [-1, -1.0, -1.1, -1, -1.0.1.0, -1.1.0.1.1.1];
Copy the code

Set the borderWidth to 4, and depending on the direction and the borderWidth, we can calculate the shifted x,y,

const borderWidth = 4;
const x = dArr[i] * borderWidth;
const y = dArr[i + 1] * borderWidth;
Copy the code

Loop the original drawing in all directions:

for (let i = 0; i < dArr.length; i += 2) {... ctx.drawImage(image, x, y); }Copy the code

The shifted image is equivalent to expanding the borderWidth of the original image.

Fill the stroke color

Here we need to use the Source-in pattern in globalCompositeOperation

Source-in: Draws a new image within the current image and displays only the new image.

ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = "red";
ctx.fillRect(0.0, canvas.width, canvas.height);
Copy the code

Draw the artwork

Change the blend mode to the default source-over and draw the original image:

ctx.globalCompositeOperation = "source-over";
ctx.drawImage(image, 0.0);
Copy the code

Online code

Codepen address

The complete code

/** * image stroke *@param {string} url- Image address or base64 *@param {string} [borderColor=red] - Stroke color *@param {number} [borderWidth=4] - Stroke width *@return {string} base64- Picture string after stroke */
function strokeImage(url, borderColor='red', borderWidth = 4) {
  return new Promise((resolve) = > {
    // create canvas
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");

    // create image
    const image = new Image();
    image.onload = draw;
    image.src = url;
    image.crossOrigin = "Anonymous";

    function draw() {
      canvas.width = image.width;
      canvas.height = image.height;

      const dArr = [-1, -1.0, -1.1, -1, -1.0.1.0, -1.1.0.1.1.1]; // offset array

      // Pan the image
      for (let i = 0; i < dArr.length; i += 2)
        ctx.drawImage(image, dArr[i] * borderWidth, dArr[i + 1] * borderWidth);

      // Fill the stroke color
      ctx.globalCompositeOperation = "source-in";
      ctx.fillStyle = borderColor;
      ctx.fillRect(0.0, canvas.width, canvas.height);

      // Add the original image
      ctx.globalCompositeOperation = "source-over";
      ctx.drawImage(image, 0.0); resolve(canvas.toDataURL()); }}); }Copy the code