PowerShell开发小工具 · 四张照片拼成一张
小工具的设计与实现------选四张照片拼成一张照片。
很经典的应用情景,市面上有很多类似的小软件,特别是手机应用。为了方便学习巩固PowerShell,今天笔者使用它来实现。
【设计思路】
- 选择四张符合要求的照片或图片
[.jpg] [.png] - 准备画布,计算其子区域(画布四分之一)宽高比例
$subAspectRatio,然后与每张照片宽高比$imgAspectRatio作对比,在比例不变(不拉伸变形)的情况下尽可能铺满。 - 缩放照片,并拼合在一起
- 保存该画布,导出成图片格式存入硬盘中。
【设计要点】
计算子画布(子图区域),也就是四分之一画布大小的宽高比,与待拼合的照片的宽高比,两者进行比较。即subAspectRatio和imgAspectRatio
- 如果照片较宽,则按宽度缩放
- 如果照片较高,则按高度缩放
如下图所示:

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

而有一种特殊情况,子区域是见方的(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
将四张照片放入一个文件夹,然后将上述脚本保存成 .vbs 也放入其中,右键 - 使用PowerShell运行,之后得到同文件夹下的新照片:

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

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

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

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

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

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

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

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

【结尾】
还是挺方便的,如果没有其他工具在手的话。当然,还有很多点值得优化,如:
- 图片的格式问题,支持更多格式
- 拼合的顺序,可以让用户自定义
- 可以让用户看到运行状态,方便调试修改
- 设配置文件,如目标照片大小、文件夹地址、生成文件类型等参数,可以更好的管理
总之,这是一次很好的开发经历,虽然脚本不算复杂,但是很实用,能充分体现脚本灵活易修改维护的特点。PowerShell,一直伴随你左右。。。
PowerShell开发小工具 · 四张照片拼成一张的更多相关文章
- Android 开发小工具之:Tools 属性 (转)
Android 开发小工具之:Tools 属性 http://blog.chengyunfeng.com/?p=755#ixzz4apLZhfmi 今天来介绍一些 Android 开发过程中比较有用但 ...
- 用adb命令组装PowerShell实用小工具——Android测试小助手
[本文出自天外归云的博客园] 简介 APP性能测试一般对以下几个方面进行测试: 1.启动时间(可以通过本工具测试): 2.CPU的占用(可以通过本工具测试): 3.内存的占用(可以通过本工具测试): ...
- Android 开发—— 小工具,大效率
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者:姚志锋 一.Hugo插件 -- 打印方法运行时间 首先申明下,此Hugo非 彼Hugo(Hugo是由Go ...
- xamarin开发的mac开发小工具集合
兄弟们我拖控件拖到了mac系统去了, 工具上传到百度网盘,下载地址 链接:https://pan.baidu.com/s/1Q64zoRjE3u66jJnzF8rhww提取码:ljx2 这款工具我是用 ...
- javaWeb开发小工具---MailUtils及其单元测试
本次介绍的是,在javaWeb开发中,我们不免会遇到发送邮件的需求,比如:用户注册账号,需要激活登录,以及服务器定期向会员发送礼品信息等.所以参考有关资料,写了这个MailUtils工具类. 1.Ma ...
- javaWeb开发小工具--MyCommonUtils
MyCommonUtils 参考一些资料,写了这个工具类.在这个工具类中,主要实现了2个方法: 1.生成随机的序列号 uuid(): 2.将Map中的数据封装到javaBean对象中toBean(Ma ...
- 分享原创powershell脚本小工具ctracert.ps1
----------[脚本介绍]----------- 脚本名称:ctracert.ps1软件名称:灰主牛 跟踪路由 归属地版 V1.0脚本作用:1跟踪路由.2显示归属地.(注意不带显示时间功能)脚本 ...
- Qt开发小工具之gif转换器(使用QMovie截取每一帧为QImage,然后用QFile另存为图片文件)
最近,QQ上好多各种gif表情.每一个都很经典呀..于是我就想把它转换成一张张静态图片...没学过ps.于是写了几行代码.完工.核心代码如下 主要是借助QMovie类.文件读取模式选择QMovie:: ...
- CSS便捷开发小工具汇总
1.Prefix free 可以帮助开发者省去编写各种CSS3属性前缀的工作,只需要在页面中引入prefixfree.js即可. 2. Normalize 是一个CSS Reset工具, 相比传统的R ...
- android 开发小工具收集
http://blog.csdn.net/tikitoo/article/details/51089422
随机推荐
- COS 音视频实践|给你的视频加把锁
导语 为了保障视频内容安全,防止视频被非法下载和传播,对象存储(Cloud Object Storage,COS)数据处理基于数据万象 CI 提供了 HLS 视频加密的功能,拥有相比于私有读文件更高的 ...
- Excel 真的很强大之 Excel DDE 攻击
https://pentestlab.blog/2018/01/16/microsoft-office-dde-attacks/ =cmd|'/c calc.exe'!A1 =MSEXCEL|'\.. ...
- 【Vue】前端直接显示MySQL Datatime时间,显示为英文如何处理
问题如图 想让时间显示为自己想要的格式,可以自己编写一个函数 const formatDate= (timestamp)=> { const date = new Date(timestamp) ...
- Windows修改电脑DNS
访问浏览器出现无法访问此页面,找不到DNS地址,则可以通过如下方式修改DNS 按下windows键+R键(两个键一起按) 出现下面窗口 输入control按回车键(Enter键)就会出现下面的窗口 D ...
- 【转载】 Locust 官方文档
链接:https://www.jianshu.com/p/40102e9a24cb 安装 一般直接通过 pip 就可以安装: $ pip install locust 注意: Locust 1.x 版 ...
- React部署到线上Nginx环境中刷新页面后404解决方案
我们需要在Nginx的配置文件中修改以下内容(通常Nginx配置文件位置为/etc/nginx/nginx.conf): server { # ... location / { # ... # 增加下 ...
- Qt编写物联网管理平台49-设备模拟工具
一.前言 本系统专门配备了设备模拟工具,用来在没有外接真实设备的时候,模拟modbus协议数据,支持多个设备,支持串口和网络方式,可切换正常数据和报警数据,反应到主程序上.对应主程序中两种端口,一种是 ...
- Qt数据库应用20-csv文件转xls
一.前言 最近又多了个需求就是将csv格式的文件转xls,需求一个接着一个,还好都是真实的需求,而且都是有用的需求,并不是不靠谱的需求,不靠谱的需求就比如程序自动识别手机壳颜色自动换背景颜色或者边框颜 ...
- [转]IRIG-B码授时工作原理
在授时设备中有一种是B码授时的,但是大部分人不太清楚何为B码授时?这种类型的授时工作原理是怎么样? 首先我们要知道什么是B码,然后再介绍它的授时工作原理,B码是一种电力术语,它是IRIG-B码的通俗叫 ...
- 如何查看一个域名所对应的IP地址?
具体步骤如下: 1.点击电脑左下角开始菜单,打开"运行"选项. 2.然后输入"cmd"并打开. 3.在弹出的页面输入ping+你想要查看的域名,比如新浪网,pi ...