4

I have a project where I need to bulk convert large amounts of .png files to .jpgs, with some control over compression quality. Using the node module sharp works like a charm on individual files, e.g.:

const sharp = require("sharp");

sharp("input/82.png")
  .toFormat("jpeg")
  .jpeg({ quality: 70 })
  .toFile("output/82.jpg");

But I have hundreds of files I need to convert at a shot. I had hoped to be able to use some wildcard for files, like:

sharp("input/*.png")
  .toFormat("jpeg")
  .jpeg({ quality: 70 })
  .toFile("output/*.jpg");

though that of course doesn't work, nor has any attempt I've done to loop through all the files, or using the node module glob. Appreciate any guidance that can be provided here.

jimiayler
  • 674
  • 2
  • 11
  • 27
  • 1
    You mention that your attempts to iterate over the files have failed. What were those attempts? If you post the code, it will be possible to help debug it. – Robert Kawecki May 05 '21 at 14:47
  • A fair request but, because I'm such a newbie and the attempt was so primitive, it never came close to working — nothing really to debug there, unfortunately. – jimiayler May 05 '21 at 14:55

1 Answers1

4

With the help of another developer, the answer turned out to be a bit more complex than I anticipated, and requires the use of the node module glob:

// example run : node sharp-convert.js ~/Projects/docs/public/images/output/new

const fs = require('fs');
const process = require('process');
const path = require('path');
const glob = require("glob")


const dir = process.argv[2];

const input_path = path.join(dir, '**', '*.png');
const output_path = path.join(dir, "min");

const sharp = require('sharp');

glob(input_path, function (err, files) {
  if (err != null) { throw err; }
  fs.mkdirSync(output_path, { recursive: true });
  files.forEach(function(inputFile) {
  sharp(inputFile)
    .jpeg({ mozjpeg: true, quality: 60, force: true })
    .toFile(path.join(output_path, path.basename(inputFile, path.extname(inputFile))+'.jpg'), (err, info) => {
      if(err === null){
          fs.unlink(inputFile, (err2) => {
              if (err2) throw err2;
              console.log('successfully compressed and deleted '+inputFile);
          });
      } else { throw err }
    });
  });
});

NOTE: This method is destructive and will delete any existing .pngs. Make sure to have a backup of your originals.

jimiayler
  • 674
  • 2
  • 11
  • 27