Friday, January 6, 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 definately’ve come to the fitting place, as you are able to do simply that with the TinyPNG API! This submit will display clearly how to do this so you possibly can optimize your pictures with ease in your initiatives.

Leap forward:

Pictures and optimization

Pictures 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 pictures to verify they’re not unhelpfully massive and hindering the efficiency of our initiatives.

We will do that manually utilizing instruments like TinyPNG or Squoosh, nevertheless it’s additionally attainable to automate this course of fully. On this submit, I’ll present you the best way to optimize pictures robotically utilizing the TinyPNG API.

TinyPNG API

The TinyPNG API is a paid service. We will get a free API key which permits us to optimize 500 pictures monthly. 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 pictures monthly, 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 plenty of picture codecs together with PNG, JPEG, and WebP, so it’s not only for PNGs — in reality, we’ll be utilizing the WebP format on this submit.

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

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

mkdir tinify
cd tinify
npm init -y
npm set up @sorts/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 sorts 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) 

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({ sort: ['image/webp', 'image/png'] });
      const convertedExtension = await transformed.consequence().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❌ Did not course of ${imageFilePath}`);
      failed.push(imageFilePath);
    }
  }

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

  if (failed.size > 0) console.log('Did not 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 selection of issues occurring right here, so let me stroll by it in slightly extra element.

Every time we run it, we’re checking that we have now 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 might be empty.

Subsequent, we’re looping by 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 thought 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({ sort: ['image/webp', 'image/png'] });
const convertedExtension = await transformed.consequence().extension();
const newImageFilePath = `${originalImageFilePrefix}.${convertedExtension}`;
await transformed.toFile(newImageFilePath);

With our instrument written, we now must try it out. I’ve a listing of pictures 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 /residence/john/code/github/open-graph-sharing-previews/images-to-shrink

🖼️  Processing /residence/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 /residence/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 /residence/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 /residence/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 /residence/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 /residence/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)

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

************************************************
* Whole financial savings for six pictures
- 🔴 1679kb
- 🟢 373kb
- 🔽 77.78% discount
************************************************

Executed in 25.23s.

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

If we glance slightly nearer, we’ll see that on two events the format remained a PNG file and the dimensions shrunk. In 4 instances, the format has modified to a WebP file. Once 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 pictures. Along with this, we additionally demonstrated how one can construct a instrument that makes use of the TinyPNG API to robotically 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 pictures in anyplace we would like!

: Full visibility into your net and cellular apps

LogRocket is a frontend software monitoring resolution that permits you to replay issues as in the event that they occurred in your individual browser. As a substitute of guessing why errors occur, or asking customers for screenshots and log dumps, LogRocket helps you to replay the session to shortly perceive what went flawed. 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 information console logs, JavaScript errors, stacktraces, community requests/responses with headers + our bodies, browser metadata, and customized logs. It additionally devices the DOM to report the HTML and CSS on the web page, recreating pixel-perfect movies of even essentially the most advanced single-page and cellular apps.

.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments