文章

windows图片压缩脚本

windows图片压缩脚本

windows图片压缩脚本

概述

compress-images.ps1 是一个 PowerShell 脚本,用于自动压缩中指定目录下的图片文件,将大于指定大小的图片压缩到目标大小以内,可用于优化博客等网站加载速度。

功能特性

  • 🔍 自动扫描: 递归扫描指定目录下的所有图片文件
  • 📏 智能压缩: 通过调整图片质量和尺寸实现压缩
  • 🔄 多次尝试: 自动降低质量直到达到目标大小
  • 💾 安全备份: 自动创建备份,失败时自动恢复
  • 🎯 精确控制: 支持自定义目标文件大小
  • 📊 详细报告: 显示压缩前后的文件大小对比

系统要求

  • Windows 10/11
  • PowerShell 5.1+
  • .NET Framework(系统自带)

使用方法

基本用法

1
2
# 使用默认设置压缩图片
powershell -ExecutionPolicy Bypass -File "compress-images.ps1"

自定义参数

如需修改压缩参数,请编辑脚本中的以下变量:

1
2
$ImagePath = "/img  # 图片目录路径
$MaxSizeKB = 30                        # 目标文件大小(KB)

执行策略说明

如果遇到执行策略限制,可以使用以下方式:

1
2
3
4
5
6
# 方式1:绕过执行策略(推荐)
powershell -ExecutionPolicy Bypass -File "compress-images.ps1"

# 方式2:临时修改执行策略
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
.\compress-images.ps1

压缩策略

支持的图片格式

  • JPG/JPEG
  • PNG

压缩算法

  1. 尺寸调整: 将图片缩放到最大 800×600 像素(保持宽高比)
  2. 质量压缩: 从质量 60 开始,每次降低 10,最低到 10
  3. 智能选择: 选择满足大小要求的最低质量设置

安全机制

  • 自动创建 .backup 备份文件
  • 压缩失败时自动恢复原图
  • 资源自动释放,避免文件占用

注意事项

  1. 备份重要: 脚本会自动备份原图,但建议在运行前手动备份重要图片
  2. 不可逆: 压缩后的图片会替换原图,请确保有备份
  3. 质量损失: 压缩会降低图片质量,请根据实际需求调整参数
  4. 文件占用: 确保图片文件没有被其他程序打开

完整脚本代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# Image compression script
# Compress images to under 30KB

$ImagePath = "/img"
$MaxSizeKB = 30

# Add System.Drawing assembly
Add-Type -AssemblyName System.Drawing

function Compress-Image {
    param(
        [string]$FilePath,
        [int]$MaxSizeKB
    )
    
    try {
        $file = Get-Item $FilePath
        $originalSizeKB = [math]::Round($file.Length / 1KB, 1)
        
        Write-Host "Processing: $($file.Name) - Original size: ${originalSizeKB}KB"
        
        if ($originalSizeKB -le $MaxSizeKB) {
            Write-Host "  Skip - already under ${MaxSizeKB}KB" -ForegroundColor Green
            return
        }
        
        # Create backup
        $backupPath = $FilePath + ".backup"
        Copy-Item $FilePath $backupPath -Force
        
        # Load image
        $image = [System.Drawing.Image]::FromFile($FilePath)
        
        # Calculate new dimensions
        $maxWidth = 800
        $maxHeight = 600
        
        $ratio = [Math]::Min($maxWidth / $image.Width, $maxHeight / $image.Height)
        $newWidth = [int]($image.Width * $ratio)
        $newHeight = [int]($image.Height * $ratio)
        if ($ratio -ge 1) {
            $newWidth = $image.Width
            $newHeight = $image.Height
        }
        
        # Create new bitmap
        $bitmap = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
        $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
        
        # Set high quality interpolation
        $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
        $graphics.DrawImage($image, 0, 0, $newWidth, $newHeight)
        
        # Try multiple compressions with decreasing quality
        $success = $false
        for ($quality = 60; $quality -ge 10; $quality -= 10) {
            $tempFile = $FilePath + ".tmp"
            $encoder = [System.Drawing.Imaging.ImageCodecInfo]::GetImageDecoders() | Where-Object { $_.FormatID -eq [System.Drawing.Imaging.ImageFormat]::JPEG.Guid }
            $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
            $encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, [long]$quality)
            $bitmap.Save($tempFile, $encoder, $encoderParams)
            $compressedSizeKB = [math]::Round((Get-Item $tempFile).Length / 1KB, 1)
            if ($compressedSizeKB -le $MaxSizeKB) {
                $success = $true
                break
            }
            Remove-Item $tempFile -Force
        }
        
        # Clean up resources
        $graphics.Dispose()
        $bitmap.Dispose()
        $image.Dispose()
        
        if ($success) {
            Remove-Item $FilePath -Force
            Move-Item $tempFile $FilePath -Force
            $finalSizeKB = [math]::Round((Get-Item $FilePath).Length / 1KB, 1)
            Write-Host "  Success: ${finalSizeKB}KB (reduced ${($originalSizeKB - $finalSizeKB):F1}KB)" -ForegroundColor Green
            Remove-Item $backupPath
        } else {
            Write-Host "  Still too large after all attempts" -ForegroundColor Yellow
            Copy-Item $backupPath $FilePath -Force
            Remove-Item $backupPath
        }
        
    } catch {
        Write-Host "  Failed: $($_.Exception.Message)" -ForegroundColor Red
        if (Test-Path $backupPath) {
            Copy-Item $backupPath $FilePath -Force
            Remove-Item $backupPath
        }
    }
}

# Get all image files (fix: use -Recurse and -File, and correct -Include usage)
$imageFiles = Get-ChildItem $ImagePath -Recurse -File | Where-Object { ($_.Extension -match "jpg|jpeg|png") -and ($_.Length / 1KB -gt $MaxSizeKB) }

Write-Host "Found $($imageFiles.Count) images larger than ${MaxSizeKB}KB" -ForegroundColor Cyan

foreach ($file in $imageFiles) {
    Compress-Image -FilePath $file.FullName -MaxSizeKB $MaxSizeKB
}

Write-Host "Compression completed!" -ForegroundColor Green
本文由作者按照 CC BY 4.0 进行授权