问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
CSDN
1.
https://blog.csdn.net/weixin_41268132/article/details/145957280

本文介绍了一个使用PowerShell脚本实现四张照片拼接成一张的功能。通过计算子区域宽高比与照片宽高比的对比,实现照片在保持原有比例的情况下尽可能铺满目标区域。文章详细介绍了设计思路、算法实现和具体脚本代码,并提供了多个示例展示不同场景下的拼接效果。

设计思路

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

设计要点

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

  • 如果照片较宽,则按宽度缩放
  • 如果照片较高,则按高度缩放

如下图所示:

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

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

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

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

算法实现:

计算子图宽高度

子图宽度 = 最终图片宽度 / 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
    格式的照片保存至文件夹内
# 加载必要的.NET绘图程序集(需确保系统已安装.NET Framework)
try {
    Add-Type -AssemblyName System.Drawing
    Write-Host "成功加载必要的.NET绘图程序集。"
}
catch {
    Write-Error "加载.NET绘图程序集时出现错误: $_"
    return
}
# 定义输入输出参数
$inputFolder = $PSScriptRoot  # 使用 $PSScriptRoot 变量获取脚本所在文件夹
$outputFile = "combined.jpg"  # 输出文件名
$targetWidth = 2000   # 最终图片宽度
$targetHeight = 2000  # 最终图片高度
# 从指定文件夹中获取前四张jpg或png图片
Write-Host "正在从 $inputFolder 文件夹中查找前四张jpg或png图片..."
$inputFiles = Get-ChildItem -Path $inputFolder -File | Where-Object { $_.Extension -match '\.(jpg|png)' } | Select-Object -First 4 | ForEach-Object { $_.FullName }
# 检查是否找到四张图片
if ($inputFiles.Count -ne 4) {
    Write-Error "未在指定文件夹 $inputFolder 中找到四张jpg或png图片,仅找到 $($inputFiles.Count) 张。"
    return
}
else {
    Write-Host "成功找到四张图片:"
    foreach ($file in $inputFiles) {
        Write-Host "- $file"
    }
}
# 创建目标画布
Write-Host "正在创建目标画布..."
try {
    $combinedBitmap = New-Object System.Drawing.Bitmap($targetWidth, $targetHeight)
    $graphics = [System.Drawing.Graphics]::FromImage($combinedBitmap)
    $graphics.Clear([System.Drawing.Color]::White)
    Write-Host "成功创建目标画布。"
}
catch {
    Write-Error "创建目标画布时出现错误: $_"
    return
}
# 计算每个子图区域尺寸
$subWidth = $targetWidth / 2
$subHeight = $targetHeight / 2
Write-Host "已计算每个子图区域尺寸:宽度 $subWidth,高度 $subHeight。"
# 遍历处理每张图片
for ($i = 0; $i -lt 4; $i++) {
    Write-Host "正在处理图片 $($inputFiles[$i])..."
    try {
        $img = [System.Drawing.Image]::FromFile($inputFiles[$i])
        # 计算绘制位置
        $x = ($i % 2) * $subWidth
        $y = [math]::Floor($i / 2) * $subHeight
        # 计算图片的宽高比
        $imgAspectRatio = $img.Width / $img.Height
        $subAspectRatio = $subWidth / $subHeight
        if ($imgAspectRatio -gt $subAspectRatio) {
            # 图片较宽,按宽度缩放
            $scale = $subWidth / $img.Width
            $newWidth = $subWidth
            $newHeight = [int]($img.Height * $scale)
            $offsetY = $y + ($subHeight - $newHeight) / 2
            $offsetX = $x
        }
        else {
            # 图片较高,按高度缩放
            $scale = $subHeight / $img.Height
            $newHeight = $subHeight
            $newWidth = [int]($img.Width * $scale)
            $offsetX = $x + ($subWidth - $newWidth) / 2
            $offsetY = $y
        }
        # 创建缩放后的矩形区域
        $destRect = New-Object System.Drawing.Rectangle(
            $offsetX, $offsetY,
            $newWidth,
            $newHeight
        )
        # 高质量缩放绘制
        $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
        $graphics.DrawImage($img, $destRect)
        $img.Dispose()
        Write-Host "成功处理图片 $($inputFiles[$i])。"
    }
    catch {
        Write-Error "处理图片 $($inputFiles[$i]) 时出现错误: $_"
    }
}
# 保存输出文件
Write-Host "正在保存拼接后的图片到 $outputFile..."
try {
    $combinedBitmap.Save($outputFile, [System.Drawing.Imaging.ImageFormat]::Jpeg)
    Write-Host "成功保存拼接后的图片到 $outputFile。"
}
catch {
    Write-Error "保存拼接后的图片时出现错误: $_"
}
# 释放资源
Write-Host "正在释放资源..."
try {
    $graphics.Dispose()
    $combinedBitmap.Dispose()
    Write-Host "成功释放资源。"
}
catch {
    Write-Error "释放资源时出现错误: $_"
}
Write-Host "图片拼接完成,输出文件:$outputFile"

示例1:

给出四张示例照片或图片:

目标照片大小:2000 * 2000

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

示例2:

给出四张示例照片或图片:

目标照片大小:1600* 800

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

示例3:

给出四张示例照片或图片:

目标照片大小:2000 * 1450

将四张照片放入一个文件夹,然后将上述脚本保存成
.ps1




也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:

示例4:

给出四张示例照片或图片:

目标照片大小:2000 * 2000

将四张照片放入一个文件夹,然后将上述脚本保存成
.ps1

也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:

示例5:

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

目标照片大小:1600 * 1600

将四张照片放入一个文件夹,然后将上述脚本保存成
.ps1




也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:

结尾

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

  1. 图片的格式问题,支持更多格式
  2. 拼合的顺序,可以让用户自定义
  3. 可以让用户看到运行状态,方便调试修改



  4. 设配置文件,如目标照片大小、文件夹地址、生成文件类型等参数,可以更好的管理

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

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号