tooolbox / node-potrace

JavaScript port of Potrace, for NodeJS
GNU General Public License v2.0
391 stars 33 forks source link

Handle PNG alpha #21

Open zimonitrome opened 1 year ago

zimonitrome commented 1 year ago

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?

stemaDev commented 9 months ago

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"

zimonitrome commented 8 months ago

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.