@Mit_tt

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

PowerShellでPNG画像をJPEGに変換する際のエラーについて

解決したいこと

PowerShellでPNG画像をJPEGに変換するコードを書いています。
そして、PowerShellのファイルのショートカットを作成しています。

ショートカットのリンク先の文字列

"Windows Powershellのパス" -ExecutionPolicy Bypass -File "PowerShellファイルのフルパス"

PNG画像と同じ階層に拡張子が「JPEG」ですが、名前は同じファイルを作成します。
しかし、エラーが出てしまいます。
正確には、複数のPNG画像がある場合、(おそらく)一番最初に処理をされている画像にエラーが発生しています。
2番目以降のPNG画像は正しく処理され画像も見ることができます。(1番目に処理されたPNG画像は、JPEGファイルとして作成はされていますが、破損しており中身を見ることはできません)

生成AIに聞いた解決策を実行してみても解決されません。

どのような原因なのでしょうか。

よろしくお願いいたします。

発生している問題・エラー

"2" 個の引数を指定して "Save" を呼び出し中に例外が発生しました: "GDI+ で汎用エラーが発生しました。"

該当するソースコード

Add-Type -AssemblyName System.Drawing

Write-Host 'PNGファイルをJPEGに変換するスクリプトです'

# フォルダパスを入力させる(存在確認あり)
while ($true) {
    $folderPath = Read-Host 'フォルダのパスを入力してください'

    if ([string]::IsNullOrWhiteSpace($folderPath)) {continue}

    if (Test-Path -Path $folderPath -PathType Container) {
        break
    } else {
        Write-Host 'そのフォルダは存在しません。もう一度入力してください。' -ForegroundColor Yellow
    }
}


$beforeFormat = 'png'
$afterFormat = 'jpeg'


# 画像の変換処理
Get-ChildItem -Path $folderPath -File -Filter "*.${beforeFormat}" | Sort-Object Name | ForEach-Object {
    try {
        $img = [System.Drawing.Image]::FromFile($_.FullName)
        $imageFormat = [System.Drawing.Imaging.ImageFormat]::$afterFormat
        $newFileName = Join-Path -Path $_.Directory -ChildPath ($_.BaseName + ".${afterFormat}")

        # 上書き保存(事前削除なし)
        $img.Save($newFileName, $imageFormat)
        $img.Dispose()

        Write-Host "変換されたJPEGファイル:$($_.Name)" -ForegroundColor Cyan
    }
    catch {
        Write-Host "変換失敗:$($_.Name)$($_.Exception.Message)" -ForegroundColor Red
    }
}

# ==============================
# キー入力待機(これが重要)
# ==============================
Write-Host "`n処理が完了しました。何かキーを押すと終了します..." -ForegroundColor Green
[void][System.Console]::ReadKey($true)
exit

追記

ほかにも確認してみたところ、特定のPNG画像のみにエラーが出ます。
名前の変更や問題PNG画像の複製でも変わらずエラーが出ます。
問題PNG画像を取り除いたらエラーが出ずに処理が完了しました。
その問題PNG画像は中身を確認することができます。

0 likes

3Answer

試していませんが、以下でどうでしょうか。

- $img = [System.Drawing.Image]::FromFile($_.FullName)
+ # Bitmapで複製
+ $img2 = New-Object System.Drawing.Bitmap ($_.FullName)
+ $img = New-Object System.Drawing.Bitmap ($img2)
  $imageFormat = [System.Drawing.Imaging.ImageFormat]::$afterFormat
  $newFileName = Join-Path -Path $_.Directory -ChildPath ($_.BaseName + ".${afterFormat}")

  # 上書き保存(事前削除なし)
  $img.Save($newFileName, $imageFormat)
  $img.Dispose()
+ $img2.Dispose()

Exif情報が有る画像がエラーになっていると想定します。
その場合は、 Bitmapで複製することでExif情報を取り払うことができると思います。

実際に試したところ、System.Drawing.Bitmap 1回で大丈夫でした。

- $img = [System.Drawing.Image]::FromFile($_.FullName)
+ # Bitmapで複製
+ $img = New-Object System.Drawing.Bitmap ($_.FullName)
  $imageFormat = [System.Drawing.Imaging.ImageFormat]::$afterFormat
  $newFileName = Join-Path -Path $_.Directory -ChildPath ($_.BaseName + ".${afterFormat}")

  # 上書き保存(事前削除なし)
  $img.Save($newFileName, $imageFormat)
  $img.Dispose()

Exif情報が有る画像がエラーになっていると想定します。

Exif情報が有る画像を元のコードで試しましたが、エラーなく変換できました。
原因が違うところにあると、上のコードでも怪しいです。

1Like

Comments

  1. もし。解決したのであれば、何をどうしたのかを追記した上で、当Q&Aをクローズしてください。

  2. @Mit_tt

    Questioner

    Exif情報があったためエラーが出ていたようです。
    exiftoolを使い、Exif情報を削除した後にJPEGへ変換することでエラーが出なくなりました。
    (おそらく!?)これが原因だったのではないかと思います。
    ありがとうございました。

補足しておくとSystem.Drawing.Image抽象クラスです。

つまり直接使えないから、継承しているSystem.Drawing.Bitmapを使えと言うことです。


検証用に書いたコードを一部抜粋しますが、Bitmap()のオブジェクト生成は一度で良いです。

$bitmap = New-Object -TypeName 'System.Drawing.Bitmap' -ArgumentList "pngファイルパス")

$filename = '{0}\{1}.{2}' -f $item.Directory, $item.BaseName, 'jpg'
$bitmap.Save($filename, [System.Drawing.Imaging.ImageFormat]::Jpeg)
$bitmap.Dispose()
1Like

ほかにも確認してみたところ、特定のPNG画像のみにエラーが出ます。

結局は PowerShell のコードの書き方などの問題ではなく png ファイルの破損とかの問題だったということですね?

1Like

Comments

  1. チェックサムで解決したのですかね

Your answer might help someone💌