node-potrace icon indicating copy to clipboard operation
node-potrace copied to clipboard

Handle PNG alpha

Open zimonitrome opened this issue 2 years ago • 2 comments

Hello,

Love this package. My only issue is that alpha channel in png images are treated as #ffffff white, so doing a trace on a png image with white in it will treat the two colors the same. Preferably I would only want to trace the outline of the PNG (i.e. only use the alpha channel).

Is there a way to do this or could it be added?

zimonitrome avatar Jun 15 '23 23:06 zimonitrome

with using "sharp" package, you can extract alpha channel and run trace only on that.

        const imgBuffer = await sharp(imagePath).extractChannel("alpha").negate().png().toBuffer()
        potrace.trace(imgBuffer, {}, (_, svg) => {
            fs.writeFileSync('./output.svg', svg)
        })

I just started using this potrace, I'm very happy that it exists, I still have to make change the stroke color and have fill to be "none"

stemaDev avatar Feb 10 '24 14:02 stemaDev

Sharp seems nice, but I didn't manage to get it working client side.

Instead, I wrote my own "getAlpha" function which is probably slow since it uses canvases:

async function getAlpha(src: string): Promise<string> {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = "Anonymous";
    img.onload = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      if (!ctx) {
        reject('Could not get canvas context');
        return;
      }

      canvas.width = img.width;
      canvas.height = img.height;

      ctx.drawImage(img, 0, 0);
      const imageData = ctx.getImageData(0, 0, img.width, img.height);
      const data = imageData.data;

      // Invert alpha and convert to grayscale
      for (let i = 0; i < data.length; i += 4) {
        const invertedAlpha = 255 - data[i + 3];
        data[i] = invertedAlpha; // Copy the alpha value to the red channel
        data[i + 1] = invertedAlpha; // Copy the alpha value to the green channel
        data[i + 2] = invertedAlpha; // Copy the alpha value to the blue channel
        // Set alpha channel to fully opaque
        data[i + 3] = 255;
      }

      ctx.putImageData(imageData, 0, 0);

      // Convert the canvas to a data URL
      resolve(canvas.toDataURL('image/png'));
    };

    img.onerror = (error) => reject(error);
    img.src = src;
  });
}

Usage:

        const imgBuffer = await getAlpha(imagePath);
        potrace.trace(imgBuffer, {}, (_, svg) => {
            fs.writeFileSync('./output.svg', svg)
        })

But I would still prefer if potrace could do this internally.

zimonitrome avatar Feb 18 '24 14:02 zimonitrome