Saturday, January 7, 2023
HomeWeb DevelopmentAutomate picture optimization utilizing the TinyPNG API

Automate picture optimization utilizing the TinyPNG API


If you wish to find out about automating picture optimization, then you definitely’ve come to the precise place, as you are able to do simply that with the TinyPNG API! This publish will exhibit clearly how to do this so you possibly can optimize your photographs with ease in your initiatives.

Soar forward:

Photographs and optimization

Photographs are a giant a part of the online — they’re additionally a giant a part of the online’s payload. If we’re not cautious, we are able to find yourself with a website that’s sluggish to load and costly to host; a very unhealthy combo!

I run Lighthouse on my weblog and I’m at all times in search of methods to enhance the efficiency of the positioning; one of many issues that Lighthouse flags is picture optimization. It’s a good suggestion to optimize our photographs to verify they’re not unhelpfully massive and hindering the efficiency of our initiatives.

We are able to do that manually utilizing instruments like TinyPNG or Squoosh, nevertheless it’s additionally potential to automate this course of utterly. On this publish, I’ll present you how you can optimize photographs mechanically utilizing the TinyPNG API.

TinyPNG API

The TinyPNG API is a paid service. We are able to get a free API key which permits us to optimize 500 photographs per 30 days. If we have to optimize greater than that, we’ll must pay for a subscription. I personally hardly ever discover I optimize greater than 500 photographs per 30 days, so I’m proud of the free plan.

It’s value noting that the identify “TinyPNG” is a little bit of a misnomer. The API helps a variety of picture codecs together with PNG, JPEG, and WebP, so it’s not only for PNGs — in truth, we’ll be utilizing the WebP format on this publish.

You possibly can simply use the API instantly if you happen to like, however I choose to make use of a consumer library — we’ll be utilizing the Node.js library.

We’re going to initialize a easy Node.js console software referred to as tinify utilizing TypeScript and ts-node:

mkdir tinify
cd tinify
npm init -y
npm set up @varieties/node tinify ts-node typescript
npx tsc --init

You’ll observe that we’re utilizing the tinify npm package deal that’s developed right here. Handily, this package deal ships with TypeScript definitions, so we don’t want to put in a separate varieties package deal.

In our package deal.json file, we’ll add a begin script to run our software:

  "scripts": {
    "begin": "ts-node index.ts"
  },

In our tsconfig.json file, we’ll additionally up the goal to a brand new ECMAScript emit model to permit us to make use of some newer language options. We don’t want this for TinyPNG, nevertheless it’s good to make use of the newer options:

{
  "compilerOptions": {
    "goal": "es2021"
  }
}

Now, we are able to create our index.ts file:

import fs from 'fs';
import path from 'path';
import tinify from 'tinify';

operate setUpTinify() {
  if (!course of.env.TINIFY_KEY) {
    console.log(
      'Run with: TINIFY_KEY=$YOUR_API_KEY IMAGE_DIR=$YOUR_IMAGE_DIRECTORY yarn begin'
    );
    course of.exit(1);
  }

  tinify.key = course of.env.TINIFY_KEY;
}

operate getImageFilesFromDirectory(dir: string) 
        file.endsWith('.jpeg') 

async operate processImageFiles(imageFiles: string[]) {
  let processed = 0;
  let totalOriginalSizeKb = 0n;
  let totalNewSizeKb = 0n;
  let failed: string[] = [];

  for (const imageFilePath of imageFiles) {
    attempt {
      console.log(`
🖼️  Processing ${imageFilePath}
`);
      const originalImageFilePrefix = imageFilePath.substring(
        0,
        imageFilePath.lastIndexOf('.')
      );

      const originalStats = await fs.guarantees.stat(imageFilePath, {
        bigint: true,
      });
      const originalSizeKb = originalStats.measurement / 1024n;

      const supply = tinify.fromFile(imageFilePath);
      const transformed = supply.convert({ kind: ['image/webp', 'image/png'] });
      const convertedExtension = await transformed.end result().extension();
      const newImageFilePath = `${originalImageFilePrefix}.${convertedExtension}`;
      await transformed.toFile(newImageFilePath);

      const newStats = await fs.guarantees.stat(newImageFilePath, {
        bigint: true,
      });
      const newSizeKb = newStats.measurement / 1024n;

      const imageFileName = path.basename(imageFilePath);
      const newImageFileName = path.basename(newImageFilePath);

      totalOriginalSizeKb += originalSizeKb;
      totalNewSizeKb += newSizeKb;

      console.log(`- 🔴 ${originalSizeKb}kb - ${imageFileName}
- 🟢 ${newSizeKb}kb - ${newImageFileName}
- 🔽 ${calculatePercentageReduction({ originalSizeKb, newSizeKb }).toFixed(
        2
      )}% discount

✅ Processed! (${++processed} of ${imageFiles.size})

----------------------`);
    } catch (e) {
      console.log(`n❌ Didn't course of ${imageFilePath}`);
      failed.push(imageFilePath);
    }
  }

  console.log(`
************************************************
* Complete financial savings for ${imageFiles.size} photographs 
- 🔴 ${totalOriginalSizeKb}kb
- 🟢 ${totalNewSizeKb}kb
- 🔽 ${calculatePercentageReduction({
    originalSizeKb: totalOriginalSizeKb,
    newSizeKb: totalNewSizeKb,
  }).toFixed(2)}% discount
************************************************
`);

  if (failed.size > 0) console.log('Didn't course of', failed);
}

operate calculatePercentageReduction({
  originalSizeKb,
  newSizeKb,
}: {
  originalSizeKb: bigint;
  newSizeKb: bigint;
}) {
  return (
    ((Quantity(originalSizeKb) - Quantity(newSizeKb)) / Quantity(originalSizeKb)) *
    100
  );
}

async operate run() {
  setUpTinify();

  let listing = course of.env.IMAGE_DIR;

  if (!listing) {
    console.log('No listing specified!');
    course of.exit(1);
  }

  const imageFiles = getImageFilesFromDirectory(listing);
  console.log(`Discovered ${imageFiles.size} picture information in ${listing}`);
  await processImageFiles(imageFiles);
}

// do it!
run();

There are a variety of issues occurring right here, so let me stroll by way of it in a little bit extra element.

Every time we run it, we’re checking that we’ve got a TinyPNG API key and a picture listing specified. If not, we’ll exit with an error message.

Then, we’re getting an inventory of picture information from the required listing. We seek for information with the extensions .jpg, .jpeg, .webp, and .png (these codecs supported by TinyPNG) and we additionally filter out any information which can be empty.

Subsequent, we’re looping by way of the picture information and processing them one after the other. We’re utilizing the tinify package deal to shrink the picture and we are saying we’ll settle for both webp or png as our goal format. Tinify will determine which is essentially the most optimum format upon every request and render accordingly.

Lastly, we’re saving the brand new information to the identical listing as the unique file and we’re calculating the share discount in file measurement.

To get an concept of what’s occurring right here, we are able to take a look at the code that does the conversion:

const supply = tinify.fromFile(imageFilePath);
const transformed = supply.convert({ kind: ['image/webp', 'image/png'] });
const convertedExtension = await transformed.end result().extension();
const newImageFilePath = `${originalImageFilePrefix}.${convertedExtension}`;
await transformed.toFile(newImageFilePath);

With our instrument written, we now must try it out. I’ve a listing of photographs that I wish to compress:

~/code/github/open-graph-sharing-previews/images-to-shrink

Screenshot Of Images Before Optimization

Now, let’s run our instrument towards that listing and see what occurs.

TINIFY_KEY=YOUR_API_KEY_GOES_HERE IMAGE_DIR=~/code/github/open-graph-sharing-previews/images-to-shrink yarn begin

yarn run v1.22.18
$ ts-node index.ts
Discovered 6 picture information in /dwelling/john/code/github/open-graph-sharing-previews/images-to-shrink

🖼️  Processing /dwelling/john/code/github/open-graph-sharing-previews/images-to-shrink/screenshot-of-demo-with-devtools-open.png

- 🔴 253kb - screenshot-of-demo-with-devtools-open.png
- 🟢 83kb - screenshot-of-demo-with-devtools-open.png
- 🔽 67.19% discount

✅ Processed! (1 of 6)

----------------------

🖼️  Processing /dwelling/john/code/github/open-graph-sharing-previews/images-to-shrink/screenshot-of-email-demonstrating-sharing-with-a-non-cropped-image.png

- 🔴 158kb - screenshot-of-email-demonstrating-sharing-with-a-non-cropped-image.png
- 🟢 50kb - screenshot-of-email-demonstrating-sharing-with-a-non-cropped-image.png
- 🔽 68.35% discount

✅ Processed! (2 of 6)

----------------------

🖼️  Processing /dwelling/john/code/github/open-graph-sharing-previews/images-to-shrink/screenshot-of-tweet-demonstrating-sharing-with-a-cropped-image.png

- 🔴 391kb - screenshot-of-tweet-demonstrating-sharing-with-a-cropped-image.png
- 🟢 64kb - screenshot-of-tweet-demonstrating-sharing-with-a-cropped-image.webp
- 🔽 83.63% discount

✅ Processed! (3 of 6)

----------------------

🖼️  Processing /dwelling/john/code/github/open-graph-sharing-previews/images-to-shrink/screenshot-of-tweet-demonstrating-sharing.png

- 🔴 407kb - screenshot-of-tweet-demonstrating-sharing.png
- 🟢 78kb - screenshot-of-tweet-demonstrating-sharing.webp
- 🔽 80.84% discount

✅ Processed! (4 of 6)

----------------------

🖼️  Processing /dwelling/john/code/github/open-graph-sharing-previews/images-to-shrink/screenshot-of-twitter-validator.png

- 🔴 162kb - screenshot-of-twitter-validator.png
- 🟢 49kb - screenshot-of-twitter-validator.webp
- 🔽 69.75% discount

✅ Processed! (5 of 6)

----------------------

🖼️  Processing /dwelling/john/code/github/open-graph-sharing-previews/images-to-shrink/title-image.png

- 🔴 308kb - title-image.png
- 🟢 49kb - title-image.webp
- 🔽 84.09% discount

✅ Processed! (6 of 6)

----------------------

************************************************
* Complete financial savings for six photographs
- 🔴 1679kb
- 🟢 373kb
- 🔽 77.78% discount
************************************************

Executed in 25.23s.

Isn’t that spectacular? We’ve diminished the file measurement of all of those photographs by a median quantity of 77.78%! That’s an enormous saving!

If we glance a little bit nearer, we’ll see that on two events the format remained a PNG file and the scale shrunk. In 4 circumstances, the format has modified to a WebP file. After we take a look at our listing once more, we are able to see that the information have been up to date, and a few new WebP information have been created:

Images After Optimization Tinify Tiny API Reduced Sizes

Conclusion

On this article, we’ve seen how we are able to use the TinyPNG API to optimize our photographs. Along with this, we additionally demonstrated how one can construct a instrument that makes use of the TinyPNG API to mechanically optimize the pictures in a given listing.

It’s all automated, so we are able to now run this script each time we wish to optimize photographs in anyplace we would like!

: Full visibility into your internet and cell apps

LogRocket is a frontend software monitoring answer that permits you to replay issues as in the event that they occurred in your individual browser. As an alternative of guessing why errors occur, or asking customers for screenshots and log dumps, LogRocket helps you to replay the session to rapidly perceive what went mistaken. It really works completely with any app, no matter framework, and has plugins to log extra context from Redux, Vuex, and @ngrx/retailer.

Along with logging Redux actions and state, LogRocket data console logs, JavaScript errors, stacktraces, community requests/responses with headers + our bodies, browser metadata, and customized logs. It additionally devices the DOM to file the HTML and CSS on the web page, recreating pixel-perfect movies of even essentially the most advanced single-page and cell apps.

.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments