How to optimize PNG images#

PNG is a lossless image format that supports transparency. It is a good alternative to JPEG for images with a lot of detail and/or transparency. However, PNG images can be quite large. This post shows how to optimize PNG images instead of converting images to WebP as not everyone is ready to publish WebP images yet.

Installing optipng#

With optipng you can optimize PNG images. It is available in the repositories of most Linux distributions as shown below for Ubuntu and Debian.

Install optipng on Ubuntu or Debian#
$ sudo apt-get install optipng

On Fedora and CentOS you can install optipng with the following command.

Install optipng on Fedora or CentOS#
$ sudo dnf install optipng

Note

An alternative way is to install optipng-bin with npm as it the executable is part of the package/module.

$ npm install optipng

Optimize PNG images#

If we take the images same images from a previous post How to Convert Images to WebP we can optimize them with optipng as shown below and see how much space we can save.

Before optimizing images with optipng#
$ ls -l add-issues-to-projects-*
-rw-r--r--. 1 user01 user01  40653 Mar 22 10:48  add-issues-to-projects-1.png
-rw-r--r--. 1 user01 user01  14164 Mar 22 10:49  add-issues-to-projects-1.webp
-rw-r--r--. 1 user01 user01  94538 Mar 22 10:48  add-issues-to-projects-2.png
-rw-r--r--. 1 user01 user01  34864 Mar 22 10:49  add-issues-to-projects-2.webp

The command optipng is used to optimize PNG images. It takes the name of the PNG image as an argument. The -o option can be used to set the optimization level. The default is 2. The higher the optimization level the more time it takes to optimize the image. The same goes for additional filter types, but lets start with the default options.

Optimize PNG images with optipng#
$ optipng add-issues-to-projects-*.png
** Processing: add-issues-to-projects-1.png
983x305 pixels, 4x8 bits/pixel, RGB+alpha
Reducing image to 3x8 bits/pixel, RGB
Input IDAT size = 40438 bytes
Input file size = 40653 bytes

Trying:
  zc = 9  zm = 8  zs = 0  f = 0         IDAT size = 27158

Selecting parameters:
  zc = 9  zm = 8  zs = 0  f = 0         IDAT size = 27158

Output IDAT size = 27158 bytes (13280 bytes decrease)
Output file size = 27324 bytes (13329 bytes = 32.79% decrease)

* Processing: add-issues-to-projects-2.png
983x735 pixels, 4x8 bits/pixel, RGB+alpha
Reducing image to 3x8 bits/pixel, RGB
Input IDAT size = 94239 bytes
Input file size = 94538 bytes

Trying:
  zc = 9  zm = 8  zs = 0  f = 0         IDAT size = 64324

Selecting parameters:
  zc = 9  zm = 8  zs = 0  f = 0         IDAT size = 64324

Output IDAT size = 64324 bytes (29915 bytes decrease)
Output file size = 64490 bytes (30048 bytes = 31.78% decrease)

After optimization we can see that the PNG images are smaller than before and the WebP images are still smaller, but the 30% decrease in size is still significant.

Output after optimizing images with optipng#
$ ls -l add-issues-to-projects-*
-rw-r--r--. 1 user01 user01  27324 Mar 26 10:48  add-issues-to-projects-1.png
-rw-r--r--. 1 user01 user01  14164 Mar 22 10:49  add-issues-to-projects-1.webp
-rw-r--r--. 1 user01 user01  64490 Mar 26 10:48  add-issues-to-projects-2.png
-rw-r--r--. 1 user01 user01  34864 Mar 22 10:49  add-issues-to-projects-2.webp

Note

The command optipng has other options like -strip all and -fix. The -strip all option can be used to remove all metadata from the image. The -fix option can be used to fix some errors in the image. The -quiet option can be used to suppress the output.

Converting PNG images to WebP#

In previous post How to Convert Images to WebP the PNG images were converted to WebP images with the command cwebp. But can optimized PNG images be converted to WebP images with cwebp and have a differen size. They can still be converted, but the file size doesn’t change.

Output after optimizing images with cwebp#
$ ls -l add-issues-to-projects-*
-rw-r--r--. 1 user01 user01  27324 Mar 26 10:48  add-issues-to-projects-1.png
-rw-r--r--. 1 user01 user01  14164 Mar 26 10:49  add-issues-to-projects-1.webp
-rw-r--r--. 1 user01 user01  64490 Mar 26 10:48  add-issues-to-projects-2.png
-rw-r--r--. 1 user01 user01  34864 Mar 26 10:49  add-issues-to-projects-2.webp

The problem here is that optimized images are already compressed and the compression algorithm used by cwebp is not able to compress the image further as there is no more data to compress. The only way to reduce the file size is to use a different compression algorithm, but there is a limit to how much the file size can be reduced.

Run optipng with GitHub Actions#

Using the command optipng to optimize PNG images is easy, but it is not very convenient to run it on a local machine as it doesn’t garantee that the images are optimized. It is better to run it on a CI server like GitHub Actions. The following example shows how to run optipng on GitHub Actions before pushing it to a content delivery network (CDN).

Add steps to run optipng to .github/workflows/ci.yml#
---
name: CI

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

jobs:
  optipng:
    name: Optimize and push PNG images
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Optimize PNG images
        uses: actions/setup-node@v3
        with:
          node-version: latest

      - name: Optimize PNG images
        run: |
          npm install optipng-bin
          npx optipng `git ls-files *\.png`

      - name: Pushing assets to CDN
        run: |
          echo "Do something with the optimized images"