前几天一个同事问我能不能帮她将一张图片转成PDF,她说在wps里面可以转,但是有水印,没有水印的需要会员。唉这个年头为软件付费的也还是少,人要自力更生,我想能不能用powershell来实现这一功能呢?
需求
将单张图片(单个文件)转成一个PDF,要求PDF也是一页,不分页,生成的PDF在桌面,按照原来的图片文件名加时间戳命名
完整代码
#set-ExecutionPolicy RemoteSigned
function PicToPDF ($Path)
{
#$pic_path = "C:\Users\Lenovo\Pictures\Saved Pictures\badio.jpg"
[system.reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
$pic = New-Object System.Drawing.Bitmap($Path)
$day = Get-Date -Format "yyyyMMdd"
$pdfName = $Path -match "(?<=(\\))[^\\]*?(?=(\.))"
$file_name = $Matches[0]
$whole_pdf_name = "C:\Users\Lenovo\Desktop\" + $file_name + $day + ".pdf"
$xl = New-Object -ComObject Excel.Application -Property @{
Visible = $false
DisplayAlerts = $false
}
$xlFixedFormat = "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type]
$wb = $xl.WorkBooks.Add()
$sh = $wb.Sheets.Item(‘Sheet1’)
$sh.PageSetup.FitToPagesWide = 1
$sh.PageSetup.FitToPagesTall = 1
$sh.Shapes.AddPicture($Path,1,0,0,0, $pic.Width, $pic.Height)
$wb.Saved = $true
$wb.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $whole_pdf_name, $IgnorePrintAreas::$false)
echo "Done"
}
PicToPDF("C:\Users\Lenovo\Pictures\Saved Pictures\153_171115103009_2.jpg")
- 定义了一个PicToPDF函数,有一个参数
$Path
是需要转换为PDF图片的路径 - 调用.NET中的一个类
[system.reflection.assembly]
,System.Drawing.Bitmap
用来处理图像获得图像的元数据,比如长宽高等等 - 处理时间
get-date
获得当前的时间,-format
可以格式化输出,输出的格式为"yyyyMMdd"
和在excel中操作单元格格式类似 - 使用正则表达式将文件路径中的文件名匹配出来,由于有转义符号
\
的存在,虽然使用.*?
但人可能失效,会将前面的文件夹路径也一起匹配进去了,所以改成了(?<=(\\))[^\\]*?(?=(\.))
中间中括号内表示为不含有\
转义符的,这样就匹配出了文件名 new-object
调用一个COM,实例化一个excel程序,由于没有虽然电脑里面没有安装excel但是wps也可以,因为是调用COM来进行的,没有excel也无所谓- excel这里的作用是作为一个中转站,由于windows中并没有直接将图片转成PDF的工具,或许有但是我在网上也没有找到,imagemagick可以,但是需要另外下载,命令行操作有些麻烦,这里将图片复制到excel中,再将excel转成PDF
- 整个过程在后台进行,
visible=$false
- 初始化一个.NET类
interop
,用来进行下面的的转化 - PageSetup来调整图片的位置,这里将值都设为1,等同于再excel中设置一个打印区域将图片打印在一页
$wb.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $whole_pdf_name, $IgnorePrintAreas::$false)
这里将excel固定输出为PDF,IgnorePrintAreas
这里设置为$false
因为是用我们之前设置过的打印区域,如果是$true
就是默认的打印区域,这样转出来的PDF是分页的不符合要求。加上QT的界面
为了更好地让他人使用这个脚本,因为很多同事并不使用命令行,在外面套了一个窗口,用来输入图片的路径参数,完整代码如下
set-ExecutionPolicy RemoteSigned
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Data Entry Form'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'
$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(75,120)
$okButton.Size = New-Object System.Drawing.Size(75,23)
$okButton.Text = '开始转换'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)
$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Location = New-Object System.Drawing.Point(150,120)
$cancelButton.Size = New-Object System.Drawing.Size(75,23)
$cancelButton.Text = '取消'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = '请输入图片的文件的地址例C:\xx\xx\图片.jpg'
$form.Controls.Add($label)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)
$form.Topmost = $true
$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$x = $textBox.Text
$x
function PicToPDF ($Path)
{
#$pic_path = "C:\Users\Lenovo\Pictures\Saved Pictures\badio.jpg"
[system.reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
$pic = New-Object System.Drawing.Bitmap($Path)
$day = Get-Date -Format "yyyyMMdd"
$pdfName = $Path -match "(?<=(\\))[^\\]*?(?=(\.))"
$file_name = $Matches[0]
$whole_pdf_name = "C:\Users\fcb\Desktop\" + $file_name + $day + ".pdf"
$xl = New-Object -ComObject Excel.Application -Property @{
Visible = $false
DisplayAlerts = $false }
$xlFixedFormat = "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type]
$wb = $xl.WorkBooks.Add()
$sh = $wb.Sheets.Item(‘Sheet1’)
$sh.PageSetup.FitToPagesWide = 1
$sh.PageSetup.FitToPagesTall = 1
$sh.Shapes.AddPicture($Path,1,0,0,0, $pic.Width, $pic.Height)
$wb.Saved = $true
$wb.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $whole_pdf_name, $IgnorePrintAreas::$false)
echo "Done"
}
Get-Process *wps* | Stop-Process
PicToPDF($x)
}
结果
文件夹原图
运行脚本后生成的PDF
程序比较好的达到了我们的要求,将单张图片转成了PDF😄