Convert Images from PNG to AVIF

~2 minutes read


This note describes how to convert PNG images to AVIF format.


When using PageSpeed Insight to measure the performance of a website, a suggestion was raised regarding the file format I used. My initial plan was to use PNG for static images along GIF files for quick illustrations. Since this file format is offering better compression, high image quality and supports animations, it was worth giving a try.

In order to convert my images to this format, I needed a library to perform this task: libavif-bin. There's also ffmpeg.

To install libavif-bin: sudo apt install libavif-bin

After a quick tour of the options, I retained:

avifenc --min 5 
        -j 6 --ignore-exif --ignore-xmp  
        --ignore-profile --max 63 --speed 0 --yuv 420 -d 8 
        --codec aom input.png output.avif

Options detailed:

  • avifenc is the command to encode images to AVIF.
  • --min 5 sets the minimum quantizer for color.
  • --max 63 sets the maximum quantizer for color.
    • min/max defines the acceptable range for compression - 0 being lossless, keeping quality - 63 huge compression, decreasing quality. By setting --min 5, some quality loss is admitted.
  • -j 6 uses 6 CPU cores to perform the job.
  • --ignore-exif ignores EXIF metadata.
  • --ignore-xmp ignores XMP metadata.
  • --ignore-profile ignores embedded color profile.
  • --speed 0 sets the encoding speed (very slow). Slower for better compression and quality results.
  • --yuv 420 reduces the color information without affecting quality to much.
  • -d 8 sets the color depth per channel in bits.
  • --codec aom selects the Alliance for Open Media (AOM) codec.
  • input.png being the source file name to be encoded.
  • output.avif being the output file name in the AVIF format.

On couple screenshots on my side, the files size was reduced by 70% on average.

To encode all the files in a folder and its subfolders, I use this script:

#!/bin/bash

usage="$(basename "$0") [options] -- script to convert *.png files to *.avif within a specified 
folder and its subfolders.

options:
    -d  delete *.png files after encoding [optional]
    -h  show this help text"

R='\x1b[31;49;1m'   # Red's ANSI color code
Y='\x1b[33;49;1m'   # Yellow's ANSI color code

IMG_FOLDER="/home/my-user/images" # Root folder where images are stored. To be updated.
cd $IMG_FOLDER
images=$(find ./ -type f -name *.png)

# Internal Field Separator used to manage files with spaces in their names.
OIFS="$IFS"
IFS=$'\n'

for img in $images; do
  avif_out=${img/.png/.avif} # Replace .png by .avif in $img variable.

  if [ $img -nt $avif_out ]; then
    echo $img
    avifenc --min 5 \
        -j 6 \
        --ignore-exif \
        --ignore-xmp \
        --ignore-profile \
        --max 63 \
        --speed 0 \
        --yuv 420 \
        -d 8 \
        --codec aom "$img" "${img/.png/.avif}"
  fi
done

# Delete files ending in *.png if arg supplied.
if [ -z "$1" ]; then # If arg 1 is NULL.
  echo -e "${Y}No *.png file deletion requested."
else
  if [ "$1" == "-h" ]; then
    echo "Usage: $usage"
  elif [ $1 == "-d" ]; then
    echo -e "${R}Deleting *.png files."
    find ./ -type f -name "*.png" -delete
  fi
fi

IFS="$OIFS"

It's saving some loading time for the website and some storage space as well.

Published

Category

Notes

Stay Connected