前几天一个同事问我能不能帮她将一张图片转成PDF,她说在wps里面可以转,但是有水印,没有水印的需要会员。唉这个年头为软件付费的也还是少,人要自力更生,我想能不能用powershell来实现这一功能呢?

需求

将单张图片(单个文件)转成一个PDF,要求PDF也是一页,不分页,生成的PDF在桌面,按照原来的图片文件名加时间戳命名

完整代码

  1. #set-ExecutionPolicy RemoteSigned
  2. function PicToPDF ($Path)
  3. {
  4. #$pic_path = "C:\Users\Lenovo\Pictures\Saved Pictures\badio.jpg"
  5. [system.reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
  6. $pic = New-Object System.Drawing.Bitmap($Path)
  7. $day = Get-Date -Format "yyyyMMdd"
  8. $pdfName = $Path -match "(?<=(\\))[^\\]*?(?=(\.))"
  9. $file_name = $Matches[0]
  10. $whole_pdf_name = "C:\Users\Lenovo\Desktop\" + $file_name + $day + ".pdf"
  11. $xl = New-Object -ComObject Excel.Application -Property @{
  12. Visible = $false
  13. DisplayAlerts = $false
  14. }
  15. $xlFixedFormat = "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type]
  16. $wb = $xl.WorkBooks.Add()
  17. $sh = $wb.Sheets.Item(‘Sheet1’)
  18. $sh.PageSetup.FitToPagesWide = 1
  19. $sh.PageSetup.FitToPagesTall = 1
  20. $sh.Shapes.AddPicture($Path,1,0,0,0, $pic.Width, $pic.Height)
  21. $wb.Saved = $true
  22. $wb.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $whole_pdf_name, $IgnorePrintAreas::$false)
  23. echo "Done"
  24. }
  25. 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的界面

    为了更好地让他人使用这个脚本,因为很多同事并不使用命令行,在外面套了一个窗口,用来输入图片的路径参数,完整代码如下
  1. set-ExecutionPolicy RemoteSigned
  2. Add-Type -AssemblyName System.Windows.Forms
  3. Add-Type -AssemblyName System.Drawing
  4. $form = New-Object System.Windows.Forms.Form
  5. $form.Text = 'Data Entry Form'
  6. $form.Size = New-Object System.Drawing.Size(300,200)
  7. $form.StartPosition = 'CenterScreen'
  8. $okButton = New-Object System.Windows.Forms.Button
  9. $okButton.Location = New-Object System.Drawing.Point(75,120)
  10. $okButton.Size = New-Object System.Drawing.Size(75,23)
  11. $okButton.Text = '开始转换'
  12. $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
  13. $form.AcceptButton = $okButton
  14. $form.Controls.Add($okButton)
  15. $cancelButton = New-Object System.Windows.Forms.Button
  16. $cancelButton.Location = New-Object System.Drawing.Point(150,120)
  17. $cancelButton.Size = New-Object System.Drawing.Size(75,23)
  18. $cancelButton.Text = '取消'
  19. $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
  20. $form.CancelButton = $cancelButton
  21. $form.Controls.Add($cancelButton)
  22. $label = New-Object System.Windows.Forms.Label
  23. $label.Location = New-Object System.Drawing.Point(10,20)
  24. $label.Size = New-Object System.Drawing.Size(280,20)
  25. $label.Text = '请输入图片的文件的地址例C:\xx\xx\图片.jpg'
  26. $form.Controls.Add($label)
  27. $textBox = New-Object System.Windows.Forms.TextBox
  28. $textBox.Location = New-Object System.Drawing.Point(10,40)
  29. $textBox.Size = New-Object System.Drawing.Size(260,20)
  30. $form.Controls.Add($textBox)
  31. $form.Topmost = $true
  32. $form.Add_Shown({$textBox.Select()})
  33. $result = $form.ShowDialog()
  34. if ($result -eq [System.Windows.Forms.DialogResult]::OK)
  35. {
  36. $x = $textBox.Text
  37. $x
  38. function PicToPDF ($Path)
  39. {
  40. #$pic_path = "C:\Users\Lenovo\Pictures\Saved Pictures\badio.jpg"
  41. [system.reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
  42. $pic = New-Object System.Drawing.Bitmap($Path)
  43. $day = Get-Date -Format "yyyyMMdd"
  44. $pdfName = $Path -match "(?<=(\\))[^\\]*?(?=(\.))"
  45. $file_name = $Matches[0]
  46. $whole_pdf_name = "C:\Users\fcb\Desktop\" + $file_name + $day + ".pdf"
  47. $xl = New-Object -ComObject Excel.Application -Property @{
  48. Visible = $false
  49. DisplayAlerts = $false }
  50. $xlFixedFormat = "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type]
  51. $wb = $xl.WorkBooks.Add()
  52. $sh = $wb.Sheets.Item(‘Sheet1’)
  53. $sh.PageSetup.FitToPagesWide = 1
  54. $sh.PageSetup.FitToPagesTall = 1
  55. $sh.Shapes.AddPicture($Path,1,0,0,0, $pic.Width, $pic.Height)
  56. $wb.Saved = $true
  57. $wb.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $whole_pdf_name, $IgnorePrintAreas::$false)
  58. echo "Done"
  59. }
  60. Get-Process *wps* | Stop-Process
  61. PicToPDF($x)
  62. }

结果

文件夹原图
image.png

运行脚本后生成的PDF
image.png
image.png
程序比较好的达到了我们的要求,将单张图片转成了PDF😄