【PowerShell】Cwebpで圧縮したJPGだとiTextSharpでPDFに変換出来ない
はじまり


まずは何が起きたのか。
今回遭遇した不思議現象は、 Libwebp パッケージのcwebpツールで変換圧縮したJPGファイルが、 iTextSharp パッケージを使った PDF 変換処理で変換できなかったというものです。
Libwebp パッケージは Scoop でインストールします。
cd C:\Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserInvoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression$username = (Get-ChildItem Env:USERNAME).Value; Set-Location "C:\Users\$username\Downloads\picture_backup";scoop updatescoop install libwebpiTextSharp パッケージはここからダウンロードしたものを使いました。 iTextSharp のバージョンは5.5.13です。
まずは、cwebpで JPG に変換圧縮します。また、今回は PowerShell で一連の処理を行っていきます。
function Optimize-ImageWithCompressing(){ param ( [array]$pathList, [string]$suffix, [int]$quality )
Add-Type -AssemblyName System.Drawing foreach ($file in $pathList) { $extension = (Get-Item $file.FullName).Extension; $outputImg = "{0}_{1:D2}{2}" -f $file.FullName.Substring(0, $file.FullName.Length-$extension.Length), $suffix, ".jpg"; Write-Output "<Source File Name: $file>"; cwebp -preset photo -metadata icc -sharp_yuv -q $quality -o $outputImg -progress -short $file.FullName; $updatedCount++; Write-Output "----------------"; }; Write-Output("{0} .jpg images converted." -f $updatedCount); Write-Output "----------------";}そしたら次に、圧縮した 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);}すると、この処理でエラーになります。
$image = [iTextSharp.text.Image]::GetInstance($path.FullName);表示されたエラーメッセージはこんなやつです。さて、どうしたものか・・・。
"1" 個の引数を指定して "GetInstance" を呼び出し中に例外が発生しました: "file:///C:/.../Screenshot_20250101-212015_trimmed_compressed.jpg is not a recognized imageformat."発生場所 C:\...\hogehoge.ps1:161 文字:5+ $image = [iTextSharp.text.Image]::GetInstance($path.FullName);+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : IOException原因を調べたのだが分からなかった。
先程出てきたエラーメッセージなのですが、原因が全く分からなかったんですよね。
まず、cwebpで圧縮する前の JPG 画像ではそのエラーは発生せずに、問題なく PDF にまとめることが出来ました。(しかし、圧縮していないので、サイズの大きな PDF ファイルが出来上がってしまいます・・・。)
「iTextsharp jpg is not a recognized imageformat」とかでググっても有力そうな情報が出てこない・・・。
そこで、cwebpで JPG に圧縮する時のパラメータを変化させれば対処出来るかどうかを調べました。今回 JPG 圧縮に使っていたcwebpコマンドの打ち方はこうでした。
cwebp -preset photo -metadata icc -sharp_yuv -q $quality -o $outputImg -progress -short $file.FullName; $updatedCount++;調べたパラメータの組み合わせは以下の通りです。-preset(特定の種類のソース素材に合わせて、事前定義された一連のパラメータを指定する。)と、-sharp_yuv(より正確でシャープな RGB -> YUV 変換を使用する。)のパラメータが怪しかったので、そこだけで総当たりさせました。
-preset パラメータ | -sharp_yuv オン | -sharp_yuv オフ |
|---|---|---|
| default | ✕ | ✕ |
| drawing | ✕ | ✕ |
| photo | ✕ | ✕ |
| picture | ✕ | ✕ |
| icon | ✕ | ✕ |
| text | ✕ | ✕ |
調査の結果は全滅・・・。どうやら Cwebp 自体を使って、圧縮した JPG を PDF としてまとめることは止めておいた方が良さそうです。
System.Drawing名前空間を使って圧縮する。
そしたら、 Cwebp 以外のパッケージを使って JPG ファイルを圧縮していくことにしましょう。
次に、.NET FrameworkのSystem.Drawing名前空間を使って、 JPG を作っていきます。Image.Save メソッドで保存する画像ファイルの圧縮率を指定出来るエンコーダを引数に渡せば、 JPG を圧縮できそうです。

しかし、公式の解説は C# でしか書かれていないので、 PowerShell として直すのが面倒ですね・・・。はい、 Gemini Code Assist 君に書かせたら秒で終わりました。cwebpコマンドを打ち込んでいた行で、代わりに以下の関数を呼び出せば 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() } }}上記の処理で圧縮した JPG ファイルを先程の PDF 変換処理に渡せば、複数の JPG を1つの PDF にまとめることが出来るようになりました!
しかしなぁ、 Cwebp と iTextSharp の不和の原因は一体何だったのだろう・・・。調べたら沼りそうなのでやめておきます・・・。
まとめ
今回は、 iTextSharp を PowerShell で叩いて、複数枚の JPG 画像を一つの PDF にまとめる処理を実装する試みでした。
以下が、本記事のまとめです。
- Libwebp パッケージの
cwebpツールで変換した JPG 画像は、 iTextSharp パッケージで PDF に変換しようとすると失敗する。 System.Drawing名前空間で変換した JPG 画像は、 iTextSharp パッケージで PDF に変換することが可能である。
同じ JPG ファイルを出力したというのに、使えるファイルと使えないファイルに分かれるというのが何とも不思議でした。回避できて良かった。
その他のPowerShell関連の記事


おしまい


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