Check whether output is smaller than input? (ffmpeg conversion with batch)

I've made a batch file that's able to compress many png files (with ffmpeg) as well as remove any unneeded metadata (using exiftool).

@echo off
title Compress png to png
color 08

FOR %%a IN (*.png) DO (

echo Compressing: %%~na

exiftool "%%a" -all= -overwrite_original

ffmpeg -i "%%a" "converted\%%~na.png"

del "%%a"
)

This results in up to 60x smaller file sizes! (In small png icons at least)

enter image description here

Unfortunately sometimes the compression with ffmpeg does not actually reduce file size, but rather increase it—especially when the image is larger—Which ruins the whole purpose of this process.

So I wonder whether there is a way to check the output (once compressed by ffmpeg) and see whether it's smaller in size than the input. And then act accordingly.

Like this...

@echo off
title Compress png to png
color 08

FOR %%a IN (*.png) DO (

echo Compressing: %%~na

exiftool "%%a" -all= -overwrite_original

ffmpeg -i "%%a" "converted\%%~na.png"



CHECK:  Is compressed file smaller in size than "%%a" ?

If not, then delete converted\%%~na.png, and move* "%%a" in \converted

If it is, then just delete "%%a"


del "%%a"
)

Download requires files, if you wanna test it and figure it out (22.7MB)

Also let me know whether there is a better way to do all this.


Here is some PowerShell logic that only performs a copy operation if the new file is smaller than the original file that I've used for jpg files in the past.

This also resets the new smaller file to the original file's CreationTime, LastWriteTime, and LastAccessTime essentially preserving that metadata as part of the process.

I've made some adjustments based on your comments for your specific needs. I've also included a batch script example for it to execute the PowerShell script as you need once extracted.

Execute PowerShell via batch

Note: This is the batch script extracted to double click to execute the PS script extracted to the same location.

SET PSScriptName=Compress.ps1
CD /D "C:\Windows\System32\WindowsPowerShell\v1.0"
PowerShell -NoProfile -ExecutionPolicy Bypass -file "%~dp0%PSScriptName%"

PowerShell

$scriptPath = (Split-Path $MyInvocation.MyCommand.Path -Parent);
$pnglocation = "$scriptPath";
$convertedlocation = "$env:LOCALAPPDATA\Temp";
 
$src  = Get-ChildItem -Path "$pnglocation\*" -File | ? {$_.extension -match ".png|.bmp"};
$dest = $convertedlocation;
$originals = "$scriptPath\originals";
 
$scnt = $src.count;
$cnt  = 0;
 
$src | % { Process {
 
        $cnt += 1
        $sz = [math]::round(($_.Length / 1MB),2)
 
        If($_.extension -match ".png|.bmp"){ 
            
            Copy-Item -Path $_.FullName -Destination "$originals\$($_.basename)$($_.Extension)_original" -Force;
            
            Start-Process exiftool -Wait -WindowStyle Hidden "`"$($_.FullName)`" -all= -overwrite_original";
            Start-Process ffmpeg -Wait -WindowStyle Hidden "-i `"$($_.FullName)`" `"$($dest)\$($_.Basename).png`"";
 
            $osize = "";
            $dsize = "";
            $osize = (Get-Childitem $_.FullName).Length;
            $dsize = (Get-Childitem "$($dest)\$($_.Basename).png").Length;
            $nsz = [math]::round(($dsize / 1MB),2)
            $osz = [math]::round(($osize / 1MB),2)
 
            If($osize -gt $dsize){    
                $ct = $_.CreationTime;
                $wt = $_.LastWriteTime;
                $at = $_.LastAccessTime;
 
                Copy-Item -Path "$($dest)\$($_.Basename).png" -Destination "$($_.Directory.FullName)\$($_.Basename).png" -Force;
 
                Set-ItemProperty -Path "$($_.Directory.FullName)\$($_.Basename).png" -Name CreationTime   -Value $ct;
                Set-ItemProperty -Path "$($_.Directory.FullName)\$($_.Basename).png" -Name LastWriteTime  -Value $wt;
                Set-ItemProperty -Path "$($_.Directory.FullName)\$($_.Basename).png" -Name LastAccessTime -Value $at;
 
                Write-Host "$cnt of $scnt from $osz MB to $nsz MB ==> $($_.Directory.FullName)\$($_.Basename).png" -ForegroundColor Green;
 
                Remove-Item -Path "$($dest)\$($_.Basename).png" -Force;
                } Else { Remove-Item -Path "$($dest)\$($_.Basename).png" -Force; Write-Host "$cnt of $scnt orig size $osz MB smaller than new size $nsz MB ==> $($_.Directory.FullName)\$($_.Basename).png" -ForegroundColor Gray; }
            };
    }};

Supporting Resources

  • Get-ChildItem

    • Get-ChildItem usually returns a FileInfo object. Those objects contain a few useful properties—among them are...

      • the full path, file name, and extension (FullName),
      • the path alone (DirectoryName),
      • the file name (Name), and
      • the file name without its extension (BaseName)

      Source

  • about_Assignment_Operators

  • Start-Process

  • Math.Round Method

  • If

  • Copy-Item

  • Remove-Item

  • Set-ItemProperty

  • PowerShell Operators