background

PNG images will store more space than JPG images, but the quality of PNG images is significantly better. Sometimes the quality of the image is not required to be very good, but in order to reduce the volume, some optimizations need to be made, such as compressing images, converting PNG images without transparent pixels into JPG images. This article will focus on how to use Node.js to detect PNG images without transparent pixels and how to convert them to JPG images.

code

Go straight to code

import canvas from 'canvas';
import fs from 'fs';

/** * Determine whether a PNG image has transparent pixels **@param {*} PngPath PNG image path *@param {number} [limit=255] Specifies the maximum number of transparent pixels@param {boolean} [isToJpg=false] Whether to convert JPG images if there are no transparent pixels *@returns* /
function hasOpacity(pngPath, limit = 255, isToJpg = false) {
  // Get the buffer of the image
  const buffer = fs.readFileSync(pngPath);

  // The width of the image is stored in bytes 17 to 20 of the buffer
  const width = buffer.readUInt32BE(16);
  // The width of the image is stored in bytes 21 to 24 of the buffer
  const height = buffer.readUInt32BE(20);

  // Create a canvas
  const pngCanvas = canvas.createCanvas(width, height);
  // Get the brush
  const context = pngCanvas.getContext('2d');
  // Create an image
  const img = new canvas.Image();
  // Write the image
  img.src = buffer;
  // Use the brush to draw the picture on the canvas
  context.drawImage(img, 0.0, width, height);

  // Get the pixel data of the PNG image data
  let res = context.getImageData(0.0, width, height);
  let imgData = res.data;
  // Each pixel takes up 4 bytes and calculates how many pixels there are
  // [r, g, b, a]
  let piexCount = imgData.length / 4;

  // Whether transparent pixels have been found
  let isOpacity = false;

  for (let i = 0; i < piexCount; i++) {
    // Walk through each pixel to find the transparent channel
    let opacity = imgData[i * 4 + 3];
    if (opacity < limit) {
        // If less than limit, there are transparent pixels, exit
      isOpacity = true;
      break; }}// If there are no transparent pixels and isToJpg is true, convert to JPG format
  if(! isOpacity && isToJpg) {const out = fs.createWriteStream(pngPath.split('. ') [0] + '.jpg');
    pngCanvas.createJPEGStream().pipe(out);
    out.on('finish'.() = > console.log(pngPath, 'Converted to JPG successful'));
  }

  / / return
  return isOpacity;
}

console.log(hasOpacity('hh.png'.254.true));
console.log(hasOpacity('jj.png'));

Copy the code

Principle: Canvas uses four bytes to store pixels, [R, G, B, A], which respectively represent red channel, green channel, blue channel and transparent channel. Each byte is 8 bits, so the data for each channel is between 0 and 255. For transparent channels, 255 means completely opaque and 0 means completely transparent. We use The Buffer and canvas of Node.js to convert the PNG image into the data of each pixel point, and then we can find whether the PNG image has transparent pixels by traversating each transparent channel.

Is it? Why is there a limit parameter? This is because in practice, there may be a small number of transparent passes of 254 and 253, which look like completely opaque pixels, so they are treated as non-transparent pixels as well. This is based on its own acceptable limit to send parameters.

Examples of pictures

Transparent pixel

No transparent pixels

canvas

More use on canvas, please refer to www.npmjs.com/package/can…