# Утилита на PowerShell (v1.0+), определяющая, можно ли оптимизировать # графику в форматах GIF, PNG, JPEG в указанной папке # для работы требует (должны лежать в папке utils): # — GIFLite (не используется на 64-битных OS) # — SuperGIF 1.5 (должен быть «купленным») # — Optipng # — Pngout # — jpegtran # Евгений Степанищев http://bolknote.ru # последняя модификация — 30.09.2010 # Короткое имя файла function ShortPath([string] $fullname) { (New-Object -ComObject Scripting.FileSystemObject).GetFile($fullname).ShortPath } # Размер файла function FileSize([string] $name) { (Get-ChildItem -path $name).Length } # Создание временного файла с заданным расширением и коротким именем Function TempName([string] $ext) { $dir = "$env:temp\optkit-$PID" If ((Test-Path $dir) -eq $False) { New-Item $dir -type directory | Out-Null } $tmp = $dir + "\" + [System.IO.Path]::GetRandomFileName() + "." + $ext New-Item $tmp -type file | Out-Null ShortPath $tmp } # Подчищаем временные файлы Function ClearTemp() { Remove-Item "$env:temp\optkit-$PID" -recurse } # Запуск утилиты GIFLITE с 4-мя проходами function TryGIF([string] $name, [bool] $os64) { # В Powershell2 это делается куда проще # Тут я забираю короткое имя файла $tmp = (TempName "gif") $short = ShortPath((get-location).Path + "\" + $name) $size = FileSize $name $min = $size # В OS64 не работает giflite :`( If ($os64) { Copy-Item $name $tmp # Так как логгинг может быть отключен, надо что-то придумать с тем, чтобы SuperGIF # было что делать, для этого в конец временного файла я пишу лишний байт Add-Content $tmp "+" Set-ItemProperty $tmp LastWriteTime (Get-Date 1/1/70) $process = [System.Diagnostics.Process]::Start((get-location).Path + "\utils\SuperGIF15.exe", $tmp) While (((Get-ChildItem $tmp).LastWriteTime.Year) -eq 1970) { Start-Sleep -milliseconds 100 } $process.Kill() $min = FileSize $tmp } Else { 0..3 | %{ # Такой странный метод запуска связан с тем, что GIFLITE утилита под DOS # и мне очень хотелось спрятать её запуск $process = New-Object System.Diagnostics.ProcessStartInfo $process.FileName = (Get-Command 'cmd.exe').Definition $process.arguments = "/C " + (get-location).Path + "\utils\giflite.exe -t -b -l -o -m$_ $short $tmp" $process.CreateNoWindow = $False $process.UseShellExecute = $False $process.RedirectStandardOutput = $True $process.RedirectStandardError = $True [System.Diagnostics.Process]::Start($process).WaitForExit() Set-ItemProperty $tmp LastWriteTime (Get-Date 1/1/70) # GIFLITE специально запущен с ключом, которые оставляет свой заголовок внутри GIF, # чтобы SuperGIFу было чем заняться. Иначе он не обновит время модификации файла # и мы не сможем узнать закончил ли SuperGIF свою работу $process = [System.Diagnostics.Process]::Start((get-location).Path + "\utils\SuperGIF15.exe", $tmp) While (((Get-ChildItem $tmp).LastWriteTime.Year) -eq 1970) { Start-Sleep -milliseconds 100 } $process.Kill() $tmpsize = FileSize $tmp If ($min -gt $tmpsize) { $min = $tmpsize } } } Remove-Item $tmp Return $size - $min } # Запуск optipng, получение номера фильтра, запуск с фильтром pngout function TryPNG([string] $name) { $test = $(utils\optipng -o4 -full -sim "$name") $test = @($test | Select-String "Selecting parameters" | %{$test[($_.LineNumber) .. ($_.LineNumber+1)]}) If ($test) { $filter = [int]([regex]::Split($test[0], '=|IDAT'))[4] $tmp = (TempName "png") $(utils\pngout /k0 /n2 /f$filter /force /y "$name" "$tmp") | Out-Null $diff = (FileSize $name) - (FileSize $tmp) Remove-Item $tmp $diff } Else { 0 } } # Запуск jpegtran function TryJPG([string] $name) { $tmp = (TempName "jpg") $(utils\jpegtran -optimize -copy none -progressive "$name" "$tmp") $diff = (FileSize $name) - (FileSize $tmp) Remove-Item $tmp $diff } # Основной цикл программы If ($args) { $path = $args[0] $os64 = (Get-WmiObject Win32_OperatingSystem).OSArchitecture -eq "64-bit" ls $path | %{ $filename = $path + "\" + $_.name $o = "" | Select-Object name, diff, comment $o.name = $_.name $o.comment = '' switch([IO.Path]::GetExtension($filename)) { .gif { $diffpng = TryPNG($filename) $diffgif = (TryGIF $filename $os64) if ($diffpng -gt $diffgif) { $o.comment = "GIF (-{0:N2}Kb) -> PNG" -f ($diffgif / 1Kb) $o.diff = $diffpng } Else { $o.diff = $diffgif } } .jpg { $o.diff = TryJPG($filename) } .png { $o.diff = TryPNG($filename) } default { $o.diff = 0 } } $o } | ?{ $_.diff -gt 0 } | Select name, @{Name="diff (Kb)"; Expression={"{0:N2}" -f ($_.diff / 1Kb)}}, comment ClearTemp } Else { "Usage: optkit.ps1 " }