Batch Convert WebP and AVIF images using PowerShell

Unfortunately, WebP and AVIF are not supported by most graphics software. Here’s a script that converts PNG files to WebP and AVIF using PowerShell.

By Squirrel Logic on Sep 23, 2020

With the launch of the AVIF image format, I’ve been seeing requests about AVIF support in Affinity Designer. I’m not optimistic, looking at recent history. None of the major graphics applications support WebP, which has been around for a decade. The new AVIF image format, with its impressive results, is probably going to follow that same fate.

But there’s still a solution to easily getting your WebP and AVIF files. And because we are running a script, we can get some added benefits, too, such as making your PNG and JPEG files even smaller without any loss in quality.

At Squirrel Logic, we’ve been using PowerShell scripts to prepare artwork for the web. The script optimizes all PNG and JPEG files in place and converts the PNG files to WebP and AVIF.

What the script does

The PowerShell script creates an array of all PNG and JPEG files in a folder. The $inputFolder variable specifies the location of the input folder. The script will search for all files within that folder, including all subfolders using the -Recurse attribute.

If the file is a JPEG, the script will run jpegoptim to strip any unnecessary data and reduce the file size without harming the image quality.

If the file is a PNG, the script will losslessly optimize the PNG file in place to dramatically reduce the file size, but then it will also create both a WebP file and an AVIF file. We use PNG as the source file to create the other lossy formats (WebP and AVIF). This means that even though you may intend to use only the lossy version of the image file on your site (JPG, WebP and AVIP) you should still export PNGs out of your design software so that WebP and AVIF files can be made by the script.

1. Download the binaries

This PowerShell script depends on a handful of files to be downloaded and placed in a /bin folder:

2. PowerShell script source code

Save this script in a .ps1 file. I have it named web-image-optimizer.ps1, but the name doesn’t matter.

# Source: https://www.squirrellogic.dev/articles/how-to-batch-convert-webp-and-avif-images-powershell/

# Binaries for jpegoptim
# https://github.com/XhmikosR/jpegoptim-windows/releases

# Binaries for OptiPNG
# http://optipng.sourceforge.net/

# Binaries for Google's WebP
# https://developers.google.com/speed/webp/docs/using
# https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html

# Binaryies for AVIF
# https://ci.appveyor.com/project/louquillio/libavif/build/artifacts

# Configuration
$inputFolder = ".\input\"

# Setup
$pngs = Get-ChildItem -Path $inputFolder -Include "*.png" -Recurse
$jpgs = Get-ChildItem -Path $inputFolder -Include "*.jpg" -Recurse
$imagesTotal = ($pngs.Length * 3) + $jpgs.Length
$imagesDone = 0

foreach ($jpg in $jpgs) {
    $imageName = $jpg.Name
    $imageFullName = $jpg.FullName
    $percent = ( $imagesDone / $imagesTotal ) * 100

    # Optimize JPGs
    Write-Progress -Activity "Optimizing $imageName" -PercentComplete $percent -Status "jpegoptim"
    Invoke-Expression ".\bin\jpegoptim.exe -s `"$imageFullName`""
    $imagesDone++
}

foreach ($png in $pngs) {
    $imageName = $png.Name
    $imageBaseName = $png.BaseName
    $imageFullName = $png.FullName
    $percent = ( $imagesDone / $imagesTotal ) * 100

    # Optimize PNGs
    Write-Progress -Activity "Optimizing $imageName" -PercentComplete $percent -Status "optipng"
    Invoke-Expression ".\bin\optipng.exe `"$imageFullName`" -nc -nb -o1 -strip all -quiet"
    $imagesDone++

    # Create WebP 
    $percent = ( $imagesDone / $imagesTotal ) * 100
    Write-Progress -Activity "Converting $imageName to WebP" -PercentComplete $percent -Status "cwebp"
    Invoke-Expression ".\bin\cwebp.exe -q 75 `"$inputFolder$imageName`" -o `"$inputFolder$imageBaseName.webp`""
    $imagesDone++

    # Create AVIF
    $percent = ( $imagesDone / $imagesTotal ) * 100
    Write-Progress -Activity "Converting $imageName to AVIF" -PercentComplete $percent -Status "avifenc.exe"
    Write-Output `"$inputFolder$imageName`"
    Invoke-Expression ".\bin\avifenc.exe `"$inputFolder$imageName`" `"$inputFolder$imageBaseName.avif`""
    $imagesDone++
}

Write-Progress -Activity "Optimizing finished!" -Status "DONE" -Completed

3. Usage

Just run the script via command line or right-click on the file and select “Run with PowerShell.” The script will run using the input folder specified in the script.

Running a PowerShell script for the first time

If you have never run a PowerShell script before, you’ll need to do some initial setup first. By default, the ability to run PowerShell scripts is disabled.

To enable PowerShell scripts, first you need to run Windows PowerShell as an admin.

  • Type “PowerShell” in the “Start Menu” search, right-click on the “Windows PowerShell” icon, and select “Run as administrator.”

  • In the terminal, run the command Set-ExecutionPolicy RemoteSigned.

This will allow you to run scripts on your computer, but not scripts downloaded from the internet. If for some reason you want to run a script that PowerShell blocks, right click on the .ps1 file and choose ”Properties.” On the “General” tab, under “Security,” click the “Unblock” check box, then click OK.

At this point the scripts should work.

How to use WebP and AVIF images on the web with fallbacks

As we wait for Apple to catch up with a 10-year-old image format, WebP is not universally supported. At time of writing, AVIF is so new that less than 1% of web users are running supporting browsers, although you can check out caniuse.com’s AVIF support table and the WebP support table to check current browser support.

You can still use these new formats safely using the <picture> element to specify fallback images.

Here’s an example:

<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="">
</picture>

I like to implement this using partials or components in my front-end framework. If you are using WordPress, just stick with JPEG and PNGs for now. This script still optimizes both of those formats for you.

Share: