找回密码
 立即注册
首页 业界区 业界 PowerShell开发小工具 · 四张照片拼成一张 ...

PowerShell开发小工具 · 四张照片拼成一张

渣骑 2025-6-4 22:35:40
小工具的设计与实现------选四张照片拼成一张照片。
很经典的应用情景,市面上有很多类似的小软件,特别是手机应用。为了方便学习巩固PowerShell,今天笔者使用它来实现。
 
【设计思路】


  • 选择四张符合要求的照片或图片[.jpg] [.png]
  • 准备画布,计算其子区域(画布四分之一)宽高比例 $subAspectRatio,然后与每张照片宽高比 $imgAspectRatio 作对比,在比例不变(不拉伸变形)的情况下尽可能铺满。
  • 缩放照片,并拼合在一起
  • 保存该画布,导出成图片格式存入硬盘中。
 
【设计要点】

计算子画布(子图区域),也就是四分之一画布大小的宽高比,与待拼合的照片的宽高比,两者进行比较。即subAspectRatioimgAspectRatio

  • 如果照片较宽,则按宽度缩放
  • 如果照片较高,则按高度缩放
如下图所示:

 
如果理想状态,每张照片能铺满子图区域,如下图:
2.jpeg


而有一种特殊情况,子区域是见方的(1:1宽高), 而每张图片也是见方的:
3.jpeg


这两种情况直接等比缩放即可,而更多的情况是,子区域宽高比和每张照片的宽高比都不同,比如:
4.jpeg


会发现有很多空白区域,没错,正是做了缩放处理。
算法实现:

# 计算子图宽高度
子图宽度 = 最终图片宽度 / 2
子图高度 = 最终图片高度 / 2
# 计算绘制位置
子图x坐标 = (每张照片[标号0 1 2 3] % 2) * 子图宽度
子图y坐标 = [math]::Floor(每张照片[标号0 1 2 3] / 2) * 子图高度
# 计算图片的宽高比
照片的宽高比 = 照片宽度 / 照片高度
子图的宽高比 = 子图宽度 / 子图高度
if (照片的宽高比 > 子图的宽高比) {
    # 图片较宽,按宽度缩放
    相比比例 = 子图宽度 / 照片宽度
    待绘制图片宽度 = 子图宽度
    待绘制图片高度 = [int](照片高度 * 相比比例)
    待绘制图片y坐标 = 子图y坐标 + (子图宽度 - 待绘制图片高度) / 2
    待绘制图片x坐标 = 子图x坐标
}
else {
    # 图片较高,按高度缩放
    相比比例 = 子图宽度 / 照片高度
    待绘制图片高度 = 子图高度
    待绘制图片宽度 = [int](照片宽度 * 相比比例)
    待绘制图片x坐标 = 子图x坐标 + (子图宽度 - 待绘制图片宽度) / 2
    待绘制图片y坐标 = 子图y坐标
}
# 创建缩放后的矩形区域
destRect = (
    待绘制图片x坐标,
    待绘制图片y坐标,
    待绘制图片宽度,
    待绘制图片高度
)
#缩放绘制
[将img即每张照片绘制到destRect区域内!]
 
【实际脚本】


  •  导入程序集 System.Drawing ,负责绘制任务
  •  定义参数,如文件夹地址、输出文件名、最终图片宽度和高度
  •  获取文件夹内的照片(四张jpg或png)
  •  创建目标画布
  •  读取每张照片[遍历],按照上述算法进行计算,绘制在目标画布上
  •  保存目标画布,导出成.jpg格式的照片保存至文件夹内
  1. # 加载必要的.NET绘图程序集(需确保系统已安装.NET Framework)
  2. try {
  3.     Add-Type -AssemblyName System.Drawing
  4.     Write-Host "成功加载必要的.NET绘图程序集。"
  5. }
  6. catch {
  7.     Write-Error "加载.NET绘图程序集时出现错误: $_"
  8.     return
  9. }
  10. # 定义输入输出参数
  11. $inputFolder = $PSScriptRoot  # 使用 $PSScriptRoot 变量获取脚本所在文件夹
  12. $outputFile = "combined.jpg"  # 输出文件名
  13. $targetWidth = 2000   # 最终图片宽度
  14. $targetHeight = 2000  # 最终图片高度
  15. # 从指定文件夹中获取前四张jpg或png图片
  16. Write-Host "正在从 $inputFolder 文件夹中查找前四张jpg或png图片..."
  17. $inputFiles = Get-ChildItem -Path $inputFolder -File | Where-Object { $_.Extension -match '\.(jpg|png)' } | Select-Object -First 4 | ForEach-Object { $_.FullName }
  18. # 检查是否找到四张图片
  19. if ($inputFiles.Count -ne 4) {
  20.     Write-Error "未在指定文件夹 $inputFolder 中找到四张jpg或png图片,仅找到 $($inputFiles.Count) 张。"
  21.     return
  22. }
  23. else {
  24.     Write-Host "成功找到四张图片:"
  25.     foreach ($file in $inputFiles) {
  26.         Write-Host "- $file"
  27.     }
  28. }
  29. # 创建目标画布
  30. Write-Host "正在创建目标画布..."
  31. try {
  32.     $combinedBitmap = New-Object System.Drawing.Bitmap($targetWidth, $targetHeight)
  33.     $graphics = [System.Drawing.Graphics]::FromImage($combinedBitmap)
  34.     $graphics.Clear([System.Drawing.Color]::White)
  35.     Write-Host "成功创建目标画布。"
  36. }
  37. catch {
  38.     Write-Error "创建目标画布时出现错误: $_"
  39.     return
  40. }
  41. # 计算每个子图区域尺寸
  42. $subWidth = $targetWidth / 2
  43. $subHeight = $targetHeight / 2
  44. Write-Host "已计算每个子图区域尺寸:宽度 $subWidth,高度 $subHeight。"
  45. # 遍历处理每张图片
  46. for ($i = 0; $i -lt 4; $i++) {
  47.     Write-Host "正在处理图片 $($inputFiles[$i])..."
  48.     try {
  49.         $img = [System.Drawing.Image]::FromFile($inputFiles[$i])
  50.         # 计算绘制位置
  51.         $x = ($i % 2) * $subWidth
  52.         $y = [math]::Floor($i / 2) * $subHeight
  53.         # 计算图片的宽高比
  54.         $imgAspectRatio = $img.Width / $img.Height
  55.         $subAspectRatio = $subWidth / $subHeight
  56.         if ($imgAspectRatio -gt $subAspectRatio) {
  57.             # 图片较宽,按宽度缩放
  58.             $scale = $subWidth / $img.Width
  59.             $newWidth = $subWidth
  60.             $newHeight = [int]($img.Height * $scale)
  61.             $offsetY = $y + ($subHeight - $newHeight) / 2
  62.             $offsetX = $x
  63.         }
  64.         else {
  65.             # 图片较高,按高度缩放
  66.             $scale = $subHeight / $img.Height
  67.             $newHeight = $subHeight
  68.             $newWidth = [int]($img.Width * $scale)
  69.             $offsetX = $x + ($subWidth - $newWidth) / 2
  70.             $offsetY = $y
  71.         }
  72.         # 创建缩放后的矩形区域
  73.         $destRect = New-Object System.Drawing.Rectangle(
  74.             $offsetX, $offsetY,
  75.             $newWidth,
  76.             $newHeight
  77.         )
  78.         # 高质量缩放绘制
  79.         $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
  80.         $graphics.DrawImage($img, $destRect)
  81.         $img.Dispose()
  82.         Write-Host "成功处理图片 $($inputFiles[$i])。"
  83.     }
  84.     catch {
  85.         Write-Error "处理图片 $($inputFiles[$i]) 时出现错误: $_"
  86.     }
  87. }
  88. # 保存输出文件
  89. Write-Host "正在保存拼接后的图片到 $outputFile..."
  90. try {
  91.     $combinedBitmap.Save($outputFile, [System.Drawing.Imaging.ImageFormat]::Jpeg)
  92.     Write-Host "成功保存拼接后的图片到 $outputFile。"
  93. }
  94. catch {
  95.     Write-Error "保存拼接后的图片时出现错误: $_"
  96. }
  97. # 释放资源
  98. Write-Host "正在释放资源..."
  99. try {
  100.     $graphics.Dispose()
  101.     $combinedBitmap.Dispose()
  102.     Write-Host "成功释放资源。"
  103. }
  104. catch {
  105.     Write-Error "释放资源时出现错误: $_"
  106. }
  107. Write-Host "图片拼接完成,输出文件:$outputFile"
复制代码
 
示例1:

给出四张示例照片或图片:
5.jpeg
  
6.jpeg
  
7.jpeg
  
8.jpeg

目标照片大小:2000 * 2000
将四张照片放入一个文件夹,然后将上述脚本保存成 .ps1 也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:
 
9.jpeg

 

示例2:

给出四张示例照片或图片:
10.jpeg
 
11.jpeg
 
12.jpeg
 
13.jpeg

目标照片大小:1600* 800
将四张照片放入一个文件夹,然后将上述脚本保存成 .ps1 也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:
 
14.jpeg

 

示例3:

给出四张示例照片或图片:
15.jpeg
 
16.jpeg
 
17.jpeg
 
18.jpeg

目标照片大小:2000 * 1450
将四张照片放入一个文件夹,然后将上述脚本保存成 .ps1 也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:
 
19.jpeg

 
示例4:

给出四张示例照片或图片:
20.jpeg
 
21.jpeg
 
22.jpeg
 
23.png

目标照片大小:2000 * 2000
将四张照片放入一个文件夹,然后将上述脚本保存成 .ps1 也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:

24.jpeg

 

示例5:


给出四张示例照片或图片(四张规格大小一致,都是见方1:1):
25.jpeg
 
26.jpeg
 
27.jpeg
 
28.jpeg

目标照片大小:1600 * 1600
将四张照片放入一个文件夹,然后将上述脚本保存成 .ps1 也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:
 
29.jpeg

 

【结尾】

还是挺方便的,如果没有其他工具在手的话。当然,还有很多点值得优化,如:

  • 图片的格式问题,支持更多格式
  • 拼合的顺序,可以让用户自定义
  • 可以让用户看到运行状态,方便调试修改
  • 设配置文件,如目标照片大小、文件夹地址、生成文件类型等参数,可以更好的管理






总之,这是一次很好的开发经历,虽然脚本不算复杂,但是很实用,能充分体现脚本灵活易修改维护的特点。PowerShell,一直伴随你左右。。。
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册