xlogI125’s blog

パソコン作業を効率化したい

PowerShell練習 モノクロビットマップの解像度を変更してpngファイルとして保存

メモ

  • 用紙のスキャンデータ(白黒2値, 解像度600dpi)を mspaint.exe で編集し、モノクロビットマップで保存する場合を想定
  • ビットマップだとファイルサイズが大きいのでpngファイルで保存

使い捨てスクリプト

# [テスト環境]
#  PowerShell 5.1, Windows 11 (2022年12月頃)

# [ファイル名]
#  "%USERPROFILE%\Desktop\Png600dpi.ps1"
# [エンコード]
#  UTF-8 (BOM付き)

# [ショートカット(.lnk)]
#  リンク先(T):
#   PowerShell.exe -NoLogo -NoExit -NoProfile -ExecutionPolicy RemoteSigned -File "%USERPROFILE%\Desktop\Png600dpi.ps1"
#  作業フォルダー(S):
#   ""

using namespace System.Drawing
using namespace System.Drawing.Imaging
using namespace System.IO

Set-StrictMode -Version Latest

Add-Type -AssemblyName System.Drawing

$VerbosePreference = "Continue"

# 現在のコマンドに関する情報を表示
Write-Verbose "`n$($MyInvocation.MyCommand.Name)`n`n"

if ($args.Length -eq 0) {
  Write-Verbose '$args.Length -eq 0'
  throw
}


Add-Type -UsingNamespace System.Management.Automation `
-Namespace MyNS -Name Array -MemberDefinition @'

public static void Sort(PSObject[] obj, string propertyName) {
  System.Array.Sort(obj, (x, y) => StrCmpLogicalW(
    x.Properties[propertyName].Value.ToString(), 
    y.Properties[propertyName].Value.ToString()
  ));
}

[DllImport(
  "Shlwapi.dll", CharSet = CharSet.Unicode, EntryPoint = "StrCmpLogicalW"
)]
private static extern int StrCmpLogicalW(
  [MarshalAs(UnmanagedType.LPWStr)] string psz1, 
  [MarshalAs(UnmanagedType.LPWStr)] string psz2
);

'@


$argPSObjs = [PSObject[]]@($args.ForEach({
  [PSCustomObject]@{FullName = [string]$_}
}))

[MyNS.Array]::Sort($argPSObjs, "FullName")

$argsSort = [string[]]@($argPSObjs.FullName)

for ($i = 0; $i -lt $argsSort.Length; $i++) {
  # 画像ファイルのパス
  $pathBmpOrTiff = $argsSort[$i]
  $pathPng = [Path]::ChangeExtension($pathBmpOrTiff, ".png")

  # 画像を開く
  try {
    $bmp = [Bitmap]::new($pathBmpOrTiff)
  }
  catch {
    throw $_
  }

  # 画像の情報を取得
  $str = [PSCustomObject]@{
    # 名前
    Name = [Path]::GetFileName($pathBmpOrTiff)
    # ビットの深さ
    ColorDepth = [Image]::GetPixelFormatSize($bmp.PixelFormat)
    # 水平方向の解像度
    DpiX = $bmp.HorizontalResolution
    # 垂直方向の解像度
    DpiY = $bmp.VerticalResolution
    # 幅
    Width = $bmp.Width
    # 高さ
    Height = $bmp.Height
    # 幅[mm]
    WidthMM = $bmp.Width / $bmp.HorizontalResolution * 25.4
    # 高さ[mm]
    HeightMM = $bmp.Height / $bmp.VerticalResolution * 25.4
  } | Format-List | Out-String -Width 80

  # 文字列から空白の行を削除して表示
  Write-Verbose ("`n" + 
  (((($str -split "`n") -replace "^\s+$", "") -ne "") -join "`n") + 
  "`n`n")

  # 画像のピクセル形式が Format1bppIndexed であるかの判断
  if ($bmp.PixelFormat -ne [PixelFormat]::Format1bppIndexed) {
    $bmp.Dispose()
    Write-Verbose "`nPixelFormat が Format1bppIndexed ではありません"
    throw
  }

  # 保存先ファイルが存在するかを確認
  if (Test-Path -LiteralPath $pathPng) {
    $bmp.Dispose()
    Write-Verbose "`n既にpngファイルが存在します`n$pathPng"
    throw
  }

  # 回転も反転も行わない
  $bmp.RotateFlip([RotateFlipType]::RotateNoneFlipNone)

  # 解像度を600dpiに設定
  $bmp.SetResolution(600, 600)

  # PNGファイルとして保存
  $bmp.Save($pathPng, [ImageFormat]::Png)

  $bmp.Dispose()
}