Извлечение страниц из PDF с использованием itextsharp в Powershell - PullRequest
0 голосов
/ 11 октября 2018

Я изучаю это уже несколько недель и, похоже, не могу найти много оснований для этого вопроса.У меня большой PDF (более 900 страниц), который является результатом слияния.В результате получается более 900 копий одного и того же документа на одной странице, с той лишь разницей, что чье-то имя внизу.Я пытаюсь сделать так, чтобы скрипт powershell считывал документ с помощью itextsharp и сохранял страницы, содержащие определенную строку (имя человека), в соответствующую папку.

Это то, чем я управлял до сих пор.

Add-Type -Path C:\scripts\itextsharp.dll

$reader = New-Object iTextSharp.text.pdf.pdfreader -ArgumentList 
"$pwd\downloads\TMs.pdf"
for($page = 1; $page -le $reader.NumberOfPages; $page++) {


    $pageText = [iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($reader,$page).Split([char]0x000A)

    if($PageText -match 'DAN KAGAN'){
    Write-Host "DAN FOUND"
    }
    }

Как вы видите, я сейчас использую только одно имя для тестирования.Сценарий правильно находит имя 10 раз.Похоже, я не могу найти какую-либо информацию о том, как извлечь страницы, на которых появляется эта строка.

Надеюсь, это было понятно.Если я могу помочь, пожалуйста, дайте мне знать.

Спасибо!

1 Ответ

0 голосов
/ 11 октября 2018

Я на самом деле только что закончил писать очень похожий сценарий.С моим сценарием мне нужно отсканировать PDF отчетных карточек, найти имя и идентификационный номер учащегося, а затем извлечь эту страницу и назвать ее соответствующим образом.Тем не менее, каждая отчетная карточка может занимать несколько страниц.

Похоже, вы используете iTextSharp 5, что хорошо, потому что я тоже. Синтаксис iTextSharp 7 сильно отличается, и я его еще не изучил.

Вот логика, которая выполняет извлечение страницы, примерно:

    $Document = [iTextSharp.text.Document]::new($PdfReader.GetPageSizeWithRotation($StartPage))
    $TargetMemoryStream = [System.IO.MemoryStream]::new()
    $PdfCopy = [iTextSharp.text.pdf.PdfSmartCopy]::new($Document, $TargetMemoryStream)

    $Document.Open()
    foreach ($Page in $StartPage..$EndPage) {
        $PdfCopy.AddPage($PdfCopy.GetImportedPage($PdfReader, $Page));
    }
    $Document.Close()

    $NewFileName = 'Elementary Student Record - {0}.pdf' -f $Current.Student_Id
    $NewFileFullName = [System.IO.Path]::Combine($OutputFolder, $NewFileName)
    [System.IO.File]::WriteAllBytes($NewFileFullName, $TargetMemoryStream.ToArray())

Вот полный рабочий скрипт.Я удалил как можно меньше, чтобы предоставить вам почти рабочий пример:

Import-Module -Name SqlServer -Cmdlet Invoke-Sqlcmd
Add-Type -Path 'C:\...\itextsharp.dll'

# Get table of valid student IDs
$ServerInstance = '...'
$Database = '...'
$Query = @'
select student_id, student_name from student
'@
$ValidStudents = @{}
Invoke-Sqlcmd -Query $Query -ServerInstance $ServerInstance -Database $Database -OutputAs DataRows | ForEach-Object {
    [void]$ValidStudents.Add($_.student_id.trim(), $_.student_name)
}

$PdfFiles = Get-ChildItem "G:\....\*.pdf" -File |
    Select-Object -ExpandProperty FullName
$OutputFolder = 'G:\...'

$StudentIDSearchPattern = '(?mn)^(?<Student_Id>\d{6,7}) - (?<Student_Name>.*)$'
foreach ($PdfFile in $PdfFiles) {
    $PdfReader = [iTextSharp.text.pdf.PdfReader]::new($PdfFile)

    $StudentStack = [System.Collections.Stack]::new()

    # Map out the PDF file.
    foreach ($Page in 1..($PdfReader.NumberOfPages)) {
        [iTextSharp.text.pdf.parser.PdfTextExtractor]::GetTextFromPage($PdfReader, $Page) |
            Where-Object { $_ -match $StudentIDSearchPattern } |
            ForEach-Object {
            $StudentStack.Push([PSCustomObject]@{
                    Student_Id   = $Matches['Student_Id']
                    Student_Name = $Matches['Student_Name']
                    StartPage    = $Page
                    IsValid      = $ValidStudents.ContainsKey($Matches['Student_Id'])
                })
        }
    }

    # Extract the pages and save the files
    $LastPage = $PdfReader.NumberOfPages
    while ($StudentStack.Count -gt 0) {
        $Current = $StudentStack.Pop()

        $StartPage = $Current.StartPage
        $EndPage = $LastPage

        $Document = [iTextSharp.text.Document]::new($PdfReader.GetPageSizeWithRotation($StartPage))
        $TargetMemoryStream = [System.IO.MemoryStream]::new()
        $PdfCopy = [iTextSharp.text.pdf.PdfSmartCopy]::new($Document, $TargetMemoryStream)

        $Document.Open()
        foreach ($Page in $StartPage..$EndPage) {
            $PdfCopy.AddPage($PdfCopy.GetImportedPage($PdfReader, $Page));
        }
        $Document.Close()

        $NewFileName = 'Elementary Student Record - {0}.pdf' -f $Current.Student_Id
        $NewFileFullName = [System.IO.Path]::Combine($OutputFolder, $NewFileName)
        [System.IO.File]::WriteAllBytes($NewFileFullName, $TargetMemoryStream.ToArray())

        $LastPage = $Current.StartPage - 1
    }
}

В моей тестовой среде около 500 студентов обрабатывают 5 исходных PDF-файлов за 15 секунд.

Iсклонны использовать конструкторы вместо New-Object, но между ними нет реальной разницы.Мне просто их легче читать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...