Image cliping is not working on the node canvas

69 views Asked by At

I am trying to draw an uploaded image on a frame image which is a tilted frame image already saved on the server using node canvas.

The issue I am facing right now is the clipping functionality for the uploaded image from top and bottom to show it inside the frame properly adjusted is not working.

The code I am trying right now is:

const responseFileName = `${Date.now()}.png`;
const frameImageMetadata = await sharp(frames[i]).metadata();

const canvas = createCanvas(
  frameImageMetadata.width,
  frameImageMetadata.height
);

const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;

const [frameImage, customImage] = await Promise.all([
  loadImage(frames[i]),
  loadImage(userUploadedImage),
]);

const frameWidth = frameImage.width;
const frameHeight = frameImage.height;

ctx.drawImage(frameImage, 0, 0, frameWidth, frameHeight);

// Set the size for the custom image (you may adjust these dimensions)
const customWidth = frameWidth * 0.92; // 80% of frame width
const customHeight = frameHeight * 0.95; // 80% of frame height

const tempCanvas = createCanvas(customWidth, customHeight);

const tempCtx = tempCanvas.getContext("2d");
tempCtx.imageSmoothingEnabled = false;
tempCtx.mozImageSmoothingEnabled = false;
tempCtx.webkitImageSmoothingEnabled = false;

// Draw the custom image
tempCtx.drawImage(customImage, 0, 0, customWidth, customHeight);

// Define the diagonal shape parameters
ctx.rect(50, 20, 200, 120);
ctx.stroke();
tempCtx.clip();

const tempResponseFileName = `${Date.now()}.png`;

const tempGeneratedFile = path.join(
  __dirname,
  "public",
  "generated-images",
  tempResponseFileName
);

const tempOutput = fs.createWriteStream(tempGeneratedFile);
const tempStream = tempCanvas.createPNGStream({ compressionLevel: 0 });

await new Promise((resolve, reject) => {
  tempStream.pipe(tempOutput);
  tempOutput.on("finish", resolve);
  tempOutput.on("error", reject);
});

// Draw the clipped custom image
ctx.drawImage(tempCanvas, 51, 25);

const generatedFile = path.join(
  __dirname,
  "public",
  "generated-images",
  responseFileName
);
const output = fs.createWriteStream(generatedFile);
const stream = canvas.createPNGStream({ compressionLevel: 0 });

await new Promise((resolve, reject) => {
  stream.pipe(output);
  output.on("finish", resolve);
  output.on("error", reject);
});

images.push(`generated-images/${responseFileName}`);`

The frame image that I am using is:

frame image

1

There are 1 answers

2
James On

use console.log the code to see if customWidth and customHeight are being passed to the clip() function in the correct way.
Also clip() alone does not have any effect.
the image needs to be followed by a new drawing function after you called tempCtx.clip();
tempCtx.drawImage(customImage, 0, 0, customWidth, customHeight);

try this code that make you redraw after the clip:

/* rest of the code */

const tempCtx = tempCanvas.getContext("2d");
tempCtx.imageSmoothingEnabled = false;
tempCtx.mozImageSmoothingEnabled = false;
tempCtx.webkitImageSmoothingEnabled = false;

// Draw the custom image
tempCtx.drawImage(customImage, 0, 0, customWidth, customHeight);

// Define the diagonal shape parameters
tempCtx.rect(50, 20, 200, 120);  // Define the shape on tempCtx instead of ctx
tempCtx.clip();  // Apply the clipping on tempCtx

tempCtx.drawImage(customImage, 0, 0, customWidth, customHeight);  // add this line

/* rest of the code */

since it is difficult to grasp these concept let's try something simpler:

// Create a canvas
var canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
document.body.appendChild(canvas);

// Get the context
var ctx = canvas.getContext('2d');

// Create an image
var img = new Image();
img.src = 'https://example.com/image.png';
img.onload = function() {
  // Draw the image
  ctx.drawImage(img, 0, 0, img.width, img.height);

  // Define the clipping region
  ctx.rect(50, 50, 100, 100);
  ctx.clip();

  // Draw the image again to apply the clipping
  ctx.drawImage(img, 0, 0, img.width, img.height);
};
  1. image is loaded and drawn onto a canvas
  2. a clipping region is defined using ctx.rect(), and the clip() function is called to apply the clipping
  3. the image is drawn again in the clipped region