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
随机推荐
- GooseFS透明加速能力,助力加速 CosN 访问 COS 的性能
01 前言 原生的对象存储接口协议并不兼容HDFS文件语义,因此对象存储COS提供了COSN工具这一的标准的 Hadoop 文件系统实现,可以为 Hadoop.Spark 以及 Tez 等大数据计算框 ...
- HTML 面试题
.code { background-color: rgba(246, 246, 246, 1); color: rgba(232, 62, 140, 1) } DOCTYPE的作用? DOCTYPE ...
- 【机器学习】SVM(支持向量机)算法实验
(一)实验名称:SVM(支持向量机)算法实验 (二)实验目的: 学习支持向量机SVM的基本概念 了解核函数的基本概念 掌握使用scikit-learn API函数实现SVM算法 (三)实验内容:使用s ...
- Docker OCI runtime exec failed: exec failed: container_linux.go:344: starting container process caus
docker执行命令:docker exec -it 1e33b26152e1 /bin/bash 在进入容器报错:OCI runtime exec failed: exec failed: cont ...
- Qt开源作品21-日志重定向输出类
一.前言 用qt开发商业程序已经十年了,陆陆续续开发过至少几十个程序,除了一些算不算项目的小工具外,大部分的程序都需要有个日志的输出功能,希望可以将程序的运行状态存储到文本文件或者数据库或者做其他处理 ...
- [转]CUDA,NVIDIA Driver,Linux,GCC之间的版本对应关系表格
在安装CUDA时一定要注意其与英伟达显卡驱动以及Linux系统和GCC版本的对应关系,如果版本之间不匹配,是安装不成功的. 一.CUDA与Driver的对应版本 参考链接:https://docs.n ...
- 微信团队分享:来看看微信十年前的IM消息收发架构,你做到了吗
本文由微信技术团队分享,原题"十年前的微信消息收发架构长啥样?",下文进行了排版和内容优化等. 1.引言 2023 年,微信及 WeChat 的 DAU(月活用户)达到 13.4 ...
- 前端vue获取excell中的数据
这个功能我觉得还是挺好的,比如要批量上传一些数据,然后不用一个一个填入直接写个excell表然后一起上传,然后我在这边记录一下 首先用到了xlsx这个插件 下载 npm i xlsx --save 使 ...
- Xrm.Internal.openDialog打开对话框自定义页面
在Dynamics CRM平台中使用自定义页面拓展功能实现有多种方式,比如嵌套iframe,比如直接打开一个新页面,再就是打开对话框了,对话框里为自定义页面. 调用方式很简单,先把自定义页面上传好后, ...
- sshd 启动失败
解决方法 yum remove openssh yum install openssh openssh-server openssh-clients systemctl start sshd syst ...