【PowerShell】Dwebpで伸長したPNGをiTextSharpでPDFにまとめる
はじまり


DwebpとSystem.Drawing名前空間でPDFに変換可能なJPGを作る。
今回は、複数枚の webp 画像を PDF として一つにまとめる処理を実装する流れを紹介します。断片化した webp を PDF にまとめることで、ストレージに対してデフラグを行うことが狙いです。
PDF への変換には 「iTextSharp」 を利用していきますが、以前に、 Cwebp で圧縮した JPG が iTextSharp で PDF に変換することが出来なかったため、今回のdwebpツールを使った処理でも同様に、 PDF に変換可能な JPG は作成できないと仮定します。

そこで今回は、 Dwebp ツールで webp を png に伸長・変換して、.NET FrameworkのSystem.Drawing名前空間でその png を jpg に変換する。そして、その jpg 画像を PDF にまとめるという流れで、処理を実装していきます。それではやっていきましょう。
全体的な処理のコード
Dwebp ツールで webp を png に変換して、System.Drawing名前空間でその png を jpg に変換する。
その処理をこの関数で定義します。
function Optimize-ImagesWithDecompressing() { <# .SYNOPSIS Converts multiple WebP images to JPEG format with specified quality. .DESCRIPTION This function converts WebP images to JPEG format. It first decompresses each WebP to PNG using dwebp, then compresses the PNG to JPEG using the specified quality. .PARAMETER pathList An array of full file paths to the WebP images to be converted. .PARAMETER suffix A string suffix to append to the filename before the .png extension during the decompression stage. This suffix is not used in final jpeg filename. .PARAMETER quality An integer representing the JPEG compression quality (0-100). 100 is highest quality. .EXAMPLE $images = Get-ChildItem -Path "C:\path\to\images" -Filter "*.webp" Optimize-ImagesWithDecompressing -pathList $images.FullName -suffix "decompressed" -quality 85 .INPUTS System.Array, System.String, System.Int32 .OUTPUTS None. Output files are written to disk. .NOTES Requires the dwebp tool and System.Drawing assembly. .LINK dwebp, [System.Drawing.Image] #> [CmdletBinding()] param ( [array]$pathList, [string]$suffix, [int]$quality )
# Add-Type -AssemblyName System.Drawing foreach ($file in $pathList) { $extension = (Get-Item $file.FullName).Extension; $outputImg1 = "{0}_{1:D2}{2}" -f $file.FullName.Substring(0, $file.FullName.Length - $extension.Length), $suffix, ".png"; Write-Output "<1st Source File Name: $file>"; Optimize-ImageWithDecompressing -ImagePath $file -OutputPath $outputImg1;
$extension = (Get-Item $outputImg1).Extension; $outputImg2 = "{0}{1}" -f $outputImg1.Substring(0, $outputImg1.Length - $extension.Length), ".jpg"; Write-Output "<2nd Source File Name: $outputImg>"; Optimize-ImageWithCompressing -ImagePath $outputImg1 -OutputPath $outputImg2 -Quality $quality;
$updatedCount++; Write-Output "----------------"; }; Write-Output("{0} .jpg images converted." -f $updatedCount); Write-Output "----------------";}
$targetFolder = (Get-Location).Path;$imgPathList = Get-ChildItem -Path $targetFolder | Where-Object { $_.Extension -in @(".webp") };$suffix = "compressed";$quality = [int]($Args[0]); # 0-100
Optimize-ImagesWithDecompressing $imgPathList $suffix $quality;
$tmp = Read-Host "Input 'y' if you wanna move original images......";If ($tmp -eq "y") { Move-Item -Path $imgPathList -Destination .\5_original_files; $imgPathList = Get-ChildItem -Path $targetFolder | Where-Object { $_.Extension -in @(".png") }; Move-Item -Path $imgPathList -Destination .\5_original_files;}Dwebpツールでwebpをpngに変換する。
「Libwebp」という Google 製のパッケージに、「Dwebp」という機能があるので、その機能を使って webp を png に変換していきます。

変換処理のコードは以下の通りです。実質1行で事足りますが。
function Optimize-ImageWithDecompressing { # Load System.Drawing assembly Add-Type -AssemblyName System.Drawing try { dwebp $ImagePath -o $OutputPath; Write-Host "Image decompressed and saved to: $OutputPath"; } catch { Write-Error "An error occurred: $_" } finally { if ($image) { $image.Dispose() } }}System.Drawing名前空間を使って圧縮する。
そしたら次に、 Dwebp で変換した PNG ファイルを JPG ファイルとして圧縮していくことにしましょう。この処理を噛ませることで、 PDF のサイズを小さく出来ます。
.NET FrameworkのSystem.Drawing名前空間を使って、 JPG を作っていきます。Image.Save メソッドで保存する画像ファイルの圧縮率を指定出来るエンコーダを引数に渡せば、 JPG を圧縮できそうです。

その公式のコードを参考に、 PowerShell として書き直します。そして、以下の関数を呼び出せば JPG に圧縮することが出来ました。
function Optimize-ImageWithCompressing { param ( [string]$ImagePath, [string]$OutputPath, [int]$Quality # 0-100, 100 is highest quality (least compression) )
# Load System.Drawing assembly Add-Type -AssemblyName System.Drawing try { # Load the image $image = [System.Drawing.Image]::FromFile($ImagePath)
# Create an EncoderParameter object for quality $qualityParam = New-Object System.Drawing.Imaging.EncoderParameter( [System.Drawing.Imaging.Encoder]::Quality, $Quality )
# Get the JPEG codec $jpegCodec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageDecoders() | Where-Object { $_.FormatID -eq [System.Drawing.Imaging.ImageFormat]::Jpeg.Guid }
# Create an EncoderParameters object $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1) $encoderParams.Param[0] = $qualityParam
# Save the image with the specified quality $image.Save($OutputPath, $jpegCodec[0], $encoderParams)
Write-Host "Image compressed and saved to: $OutputPath" } catch { Write-Error "An error occurred: $_" } finally { if ($image) { $image.Dispose() } }}iTextSharpでPDFにまとめる。
そしたら次に、圧縮した JPG を iTextSharp で PDF に変換します。
function Merge-ImagesIntoPdfWithITextSharp([array]$imgPathList, [string]$iTextSharpPath) { Unblock-File -Path $iTextSharpPath;
# [System.Reflection.Assembly]::LoadFrom($iTextSharpPath); # Add-Type -Path $iTextSharpPath Add-Type -LiteralPath $iTextSharpPath # $error[0].Exception.GetBaseException().LoaderExceptions
$ext = ".pdf"; $pdfName = "{0}\{1}{2}" -f $imgPathList[0].DirectoryName, $imgPathList[0].BaseName, $ext;
Write-Output $imgPathList; Write-Host ("{0}: decided PDF file name`n" -f $MyInvocation.MyCommand.Name); Write-Output $pdfName;
$doc = New-Object iTextSharp.text.Document; $pdfWriter = [iTextSharp.text.pdf.PdfWriter]::GetInstance($doc, [System.IO.File]::Create($pdfName)) $doc.Open()
# Get image files to add into PDF. foreach ($path in $imgPathList) { Write-Output $path; Write-Output $path.GetType().FullName; Write-Output $path.FullName.GetType().FullName; Write-Host ("{0}: adding an image into a PDF...`n" -f $MyInvocation.MyCommand.Name); $image = [iTextSharp.text.Image]::GetInstance($path.FullName);
# Scale images to each page size. $doc.SetPageSize($image); $doc.NewPage(); $image.SetAbsolutePosition(0, 0); # $image.ScaleToFit($doc.PageSize.Width, $doc.PageSize.Height); $image.Alignment = [iTextSharp.text.Image]::ALIGN_CENTER;
$doc.Add($image); }
$doc.Close(); $pdfWriter.Close(); Write-Host ("{0}: completed adding images into a PDF`n" -f $MyInvocation.MyCommand.Name);}今までの一連の処理を行えば、複数の WEBP 画像を1つの PDF にまとめることが出来るようになりました! めでたしめでたし。
ちなみに、Dwebpを飛ばすと失敗する。
今回、以下の流れで処理を実装しました。
- Dwebp で webp を png に変換する。
System.Drawing名前空間で png を jpg に変換する。- iTextSharp で jpg を pdf に変換する。
ちなみに、上記の工程で1の工程をすっ飛ばして、System.Drawing名前空間で webp を jpg に変換しようとすると失敗します。
Optimize-ImageWithDecompressing : An error occurred: "1" 個の引数を指定して "FromFile" を呼び出し中に例外が発生しました : "メモリが不足しています。"発生場所 C:\Users\...\Z5-9_decompress_webp_to_jpg_with_sys_draw.ps1:88 文字:5 + Optimize-ImageWithDecompressing -ImagePath $file -OutputPath $out ...+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Optimize-ImageWithDecompressingまとめ
今回は、 iTextSharp を PowerShell で叩いて、複数枚の Webp 画像を一つの PDF にまとめる処理を実装する試みでした。
以下が、本記事のまとめです。
- iTextSharp パッケージで複数の画像ファイルを PDF にまとめることが可能である。 JPG 画像でまとめればサイズをより減らせる。
- Libwebp パッケージの
dwebpツールで、 WEBP 画像ファイルを PNG 画像に変換することが可能である。 System.Drawing名前空間で PNG 画像を JPG 画像に変換することが可能である。しかし、 WEBP 画像を変換しようとすると失敗する。
Webp ファイルは高品質で低サイズの画像ファイルを構成できますが、フラグメンテーションを放置するのは勿体ないとも思います。そんな時に使えそうなツールでした。
その他のPowerShell関連の記事


おしまい


以上になります!
記事を共有
この記事が役に立ったなら、ぜひ他の人と共有してください!