前几天一个同事问我能不能帮她将一张图片转成PDF,她说在wps里面可以转,但是有水印,没有水印的需要会员。唉这个年头为软件付费的也还是少,人要自力更生,我想能不能用powershell来实现这一功能呢?
需求
将单张图片(单个文件)转成一个PDF,要求PDF也是一页,不分页,生成的PDF在桌面,按照原来的图片文件名加时间戳命名
完整代码
#set-ExecutionPolicy RemoteSignedfunction 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 = $falseDisplayAlerts = $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 RemoteSignedAdd-Type -AssemblyName System.Windows.FormsAdd-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$xfunction 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 = $falseDisplayAlerts = $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-ProcessPicToPDF($x)}
结果
文件夹原图
运行脚本后生成的PDF

程序比较好的达到了我们的要求,将单张图片转成了PDF😄
