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

news/2025/3/1 14:55:55/文章来源:https://www.cnblogs.com/sharpeye/p/18744376

小工具的设计与实现------选四张照片拼成一张照片。

很经典的应用情景,市面上有很多类似的小软件,特别是手机应用。为了方便学习巩固PowerShell,今天笔者使用它来实现。

 

【设计思路】

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

 

【设计要点】

计算子画布(子图区域),也就是四分之一画布大小的宽高比,与待拼合的照片的宽高比,两者进行比较。即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.DrawingWrite-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 / $subHeightif ($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运行,之后得到同文件夹下的新照片:

 

 

【结尾】

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

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

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/891555.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python123画一个五星红旗

点击查看代码 import turtle import math# 初始化画布(推荐设置600x400显示区域) screen = turtle.Screen() screen.colormode(1.0) t = turtle.Turtle() t.speed(10) t.hideturtle()# 国旗标准参数 FLAG_WIDTH = 600 # 旗面宽度 FLAG_HEIGHT = 400 # 严格3:2比例…

擦除0地址codeflash营造空片现象_重新上电即可进入BootLoader程序

芯片在空片时,首次插入USB供电会直接在ISP工具中搜索到USB设备,可以进行首次烧录;原因是在0地址没有用户程序,所以会在停留在boot区域; 利用该特性,可以在固件中加入一些处理,比如USB OUT端点透传数据给芯片,解析成功后,使用FLASH_ROM_ERASE接口擦除0地址数据,此后给…

探秘Transformer之(8)--- 位置编码

从零开始解析Transformer,目标是:(1) 解析Transformer如何运作,以及为何如此运作,让新同学可以入门;(2) 力争融入一些比较新的或者有特色的论文或者理念,让老鸟也可以有所收获。探秘Transformer之(8)--- 位置编码 目录探秘Transformer之(8)--- 位置编码0x00 概述0x01…

day11 用户的管理篇

day11用户的管理篇不同的用户,在不同的目录下,操作不同的文件权限是不一样的用户的路的机器该文件和用户的关系是什么在单位里运维作为服务器的管理员,root权限是有的 而开发,测试,他们是不可能有root权限的 即使需要使用root权限,运维会给他配置(临时使用管理员身份运行…

idea无法跳转到jar包里面的代码

需要添加到library 右键点击jar包,然后添加到library

【vulhub】tomcat CVE-2017-12615(任意写入文件)

CVE-2017-12615 tomcat 任意写入文件 漏洞复现渗透环境 攻击机: 192.168.66.130(Kali) 漏洞收录于:vulhub/tomcat/CVE-2017-12615 涉及知识点:tomcat任意文件写入 漏洞详情 当 Tomcat 运行在 Windows 系统且启用了 HTTP PUT 方法(通过将 readonly 参数设置为 false)时…

太阳花2

from turtle import * color(red,yellow) begin_fill() while True:forward(200)left(170)if abs(pos()) < 1:breakend_fill()done()

reDuh工具:实现端口复用(附下载链接)

本文来自无问社区成员,村口一枝花投稿。 一、端口复用的知识点 有关端口复用的知识点,深入学习一下。存在的安全隐患所指的是在同一个端口上建立了与多个服务之间的连接,在实际场景下多用于绕过防火墙的端口限制。 二、场景设立实验环境 靶机 B 在内网当中,而防火墙只开放了…

【Java免杀】异或加密 (XOR Cipher)实现WebShell免杀

异或加密是一种对每个字符执行位操作的加密方法。通过与一个密钥进行异或运算,明文会被加密,且加密后的文本可以通过相同的密钥再次进行异或解密。 一、加密与解密示例: <%! public static String xorEncryptDecrypt(String text, char key) {StringBuilder result = new…

大厂开源项目,真的太爽啦,字节跳动出品!这个设计系统开源神器,让你的产品颜值与效率齐飞

Semi Design是由抖音前端团队开源的企业级设计系统,**同时支持React/Vue双框架**,提供超过60+高质量组件。不同于普通UI库,它从**设计工程化**角度出发,打通Figma设计资源与前端代码的桥梁,真正实现设计稿到代码的"零误差还原"。目前已在字节跳动200+项目中验证…

微信小程序安装VantWeapp组件

1、网址 https://vant-ui.github.io/vant-weapp/#/popup 2、安装教程:点击快速上手 这里我们通过 npm i @vant/weapp -S --production 来安装 1、右键点开 app.js 点 在内建终端中打开 2、把 npm i @vant/weapp -S --production 放到这里来 按回车安装完成后显示这个 3…

一道面试题——python

写法一:1 paths=[D:\lser\local file1.txt(abcd)file2.txt(wxsd)file3.txt(qqw),E:\path\jdk file2.txt(abcd)file5.txt(vv),C:\duafile\dublock\dufell file4.txt(vv)]2 3 #如题,paths列表中有不同文件路径,对应了n个文件和不同文件内容4 #期望输出,相同文件内容的文件路径…