LoginSignup
2
10

More than 5 years have passed since last update.

PowerShellでPDF Fill Form

Last updated at Posted at 2018-02-21

PDFフォームにデータを差し込むことができればどんなに楽だろうか?
上手くいけばPDFフォームが帳票テンプレートして使えるんじゃないだろうか。

Windowsでは

  • PowerShell標準装備
  • PowerShellはdllからライブラリを呼べる

iTextSharpというiTextをC#で弄れるライブラリが存在する。
PowerShellからiTextSharpを呼べばPDFフォームにデータを差し込めるんじゃないだろうか。

PowerShellでPDF Fill Formをやってみたいと思います。

見つけた!

そのまんまのを見つけてしまった。(^-^;
How To Fill In PDF Forms Using PowerShell

このScriptちと問題が…。

  • Find-iTextLibrary を実行すると常にiTextSharp.dllをダウンロード
  • Get-Fields でdll指定しないとFind-iTextLibraryを即実行
  • 既にdllがあると解凍時にエラー吐きまくる

ウザい!
使いやすいように改造することにする。

改造

もう何もかも内蔵してCmdletとして呼び出せばいいんだよ。
下記の方針で行きます。

  • Module化
  • dll内蔵

Module化

PowerShellGetに登録は却下。
だって僕のコードじゃないんだもの。

個人で使うライブラリは $env:USERPROFILE\Documents\WindowsPowerShell/Modules に置きます。

Module化
# フォルダ作成
PS> mkdir $env:USERPROFILE\Documents\WindowsPowerShell/Modules\PdfForm
# PdfForm.psm1をダウンロード
PS> Invoke-WebRequest -Uri https://raw.githubusercontent.com/adbertram/Random-PowerShell-Work/master/Random%20Stuff/PdfForm.psm1 -OutFile $env:USERPROFILE\Documents\WindowsPowerShell/Modules\PdfForm\PdfForm.psm1

iTextSharpも用意

iTextSharp.dll
# iTextSharp.dllをダウンロード GitHubにあるよ。
PS> Invoke-WebRequest -Uri 'https://github.com/itext/itextsharp/releases/download/5.5.10/itextsharp-all-5.5.10.zip' -OutFile $env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfFrom\itextsharp.zip
# 解凍
PS> cd $env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfFrom
PS> Expand-Archive $env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfFrom\itextsharp.zip
PS> Expand-Archive $env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfFrom\itextsharp\itextsharp-dll-core.zip
# このitextsharp.dllを使うようにする。
PS>  ls .\itextsharp-dll-core

    ディレクトリ: C:\Users\username\Documents\WindowsPowerShell\Modules\PdfFrom\itextsharp-dll-core

Mode                LastWriteTime         Length Name                                                                                                                                                            
----                -------------         ------ ----                                                                                                                                                            
-a----       2016/10/07     15:33        4059136 itextsharp.dll                                                                                                                                                  
-a----       2016/10/07     15:33        3164846 iTextSharp.xml

PdfForm.psm1を下記のように書き換えてしまう。

PdfForm.psm1
#Requires -Version 4

## Find-iTextLibraryは削除


function Get-PdfFieldNames
{
    [OutputType([string])]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern('\.pdf$')]
        [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
        [string]$FilePath,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern('\.dll$')]
        [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
        #[string]$ITextLibraryPath = (Find-ITextSharpLibrary).FullName
        [string]$ITextLibraryPath = "$env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfFrom\itext-core-dll\itextsharp.dll"
    )
    begin
    {
        $ErrorActionPreference = 'Stop'
        ## Load the iTextSharp DLL to do all the heavy-lifting 
        [System.Reflection.Assembly]::LoadFrom($ITextLibraryPath) | Out-Null
    }
    process
    {
        try
        {
            $reader = New-Object iTextSharp.text.pdf.PdfReader -ArgumentList $FilePath
            $reader.AcroFields.Fields.Key
        }
        catch
        {
            $PSCmdlet.ThrowTerminatingError($_)
        }
    }
}

function Save-PdfField
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$Fields,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern('\.pdf$')]
        [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
        [string]$InputPdfFilePath,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern('\.pdf$')]
        [ValidateScript({ -not (Test-Path -Path $_ -PathType Leaf) })]
        [string]$OutputPdfFilePath,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern('\.dll$')]
        [ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
        #[string]$ITextSharpLibrary = (Find-ITextSharpLibrary).FullName
        [string]$ITextLibraryPath = "$env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfFrom\itext-core-dll\itextsharp.dll"
    )
    begin
    {
        $ErrorActionPreference = 'Stop'
    }
    process
    {
        try
        {
            $reader = New-Object iTextSharp.text.pdf.PdfReader -ArgumentList $InputPdfFilePath
            $stamper = New-Object iTextSharp.text.pdf.PdfStamper($reader, [System.IO.File]::Create($OutputPdfFilePath))

            ## Apply all hash table elements into the PDF form
            foreach ($j in $Fields.GetEnumerator())
            {
                $null = $stamper.AcroFields.SetField($j.Key, $j.Value)
            }
        }
        catch
        {
            $PSCmdlet.ThrowTerminatingError($_)
        }
        finally
        {
            ## Close up shop 
            $stamper.Close()
            Get-Item -Path $OutputPdfFilePath
        }
    }
}

保存します。
これでModule完成です。

load
# 通常はこれで読込む
PS> Import-Module PdfForm
# ダメならフルパス指定で読込
PS> Import-Module "$env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfForm"

これで使える!

使用方法

フォームのフィールド名を取得
PS> Get-PdfFieldNames -FilePath .\pdfform.pdf
name
gender

フィールドにデータを埋めて出力
PS>  Save-PdfField -Fields @{'name'='オレオレ';'gender'='不明'} -InputPdfFilePath .\pdfform.pdf -OutputPdfFilePath .\fill.pdf


    ディレクトリ: C:\Users\yusuke


Mode                LastWriteTime         Length Name                                                                                                                                                            
----                -------------         ------ ----                                                                                                                                                            
-a----       2018/02/21     11:18           6707 fill.pdf

AdobeReaderで開いてみましょう。

動いてますね。

複数のデータを差込

ソース
Write-Output "csvデータ読み込み"
$data=Import-Csv -Path formdata.csv -Delimiter `t
$data

Import-Module $env:USERPROFILE\Documents\WindowsPowerShell\Modules\PdfFrom

Write-Output " "
Write-Output "FieldNameを取得"
Get-PdfFieldNames -FilePath .\pdfform.pdf

Write-Output " "
Write-Output "データ差込実行"
$i=0
foreach($d in $data){
     Save-PdfField -InputPdfFilePath .\pdfform.pdf -OutputPdfFilePath .\fill$i.pdf -Fields @{'name'=$d.name;'gender'=$d.gender}
     $i=$i+1
}

実行結果
PS> fillforms.ps1
csvデータ読み込み

name      gender
----      ------
のびた            
ドラえもん          
しずか            

FieldNameを取得
name
gender

データ差込実行
fill0.pdf       
fill1.pdf       
fill2.pdf       

fill2.pdfに しずかちゃんが入っているはず。

output1.png

OK。
出来てるね。

Lisences

サンプルソースなのでご自由にお使い下さい。
但し、iTextSharp.dllのライセンスがAGPLv3なので商用時にはiTextにライセンス料を払う必要があるかと。

iTextSharp Lisence AGPLv3

2
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
10