xlogI125’s blog

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

JPEGファイルのピクセル数を縦横半分にする

  • JPEGファイルのピクセル数を縦横半分にしたファイルを%USERPROFILE%\Desktop\tmpに作成
  • 画像の縮小にはTransformedBitmap(BitmapSource, ScaleTransform)を用いる
# [テスト環境]
#  PowerShell 5.1, Windows 11 (2024年11月頃)
# [スクリプトファイル(.ps1)]
#  <ファイル名>
#   "%USERPROFILE%\Desktop\test.ps1"
#  <エンコード>
#   UTF-8 (BOM付き)
# [ショートカット(.lnk)]
#  <リンク先(T)>
#   PowerShell.exe -NoLogo -NoExit -NoProfile -ExecutionPolicy RemoteSigned -File "%USERPROFILE%\Desktop\test.ps1"
#  <作業フォルダー(S)>
#   ""

$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop

Set-StrictMode -Version Latest

Add-Type -AssemblyName PresentationCore
Add-Type -AssemblyName PresentationFramework

$paths = & {
  $paths = [System.Collections.Specialized.StringCollection]::new()
  $w = New-Object -TypeName System.Windows.Window -Property @{
    Title     = "ドラッグ&ドロップ"
    Width     = 300
    Height    = 200
    AllowDrop = $true
  }
  $w.add_Drop({
    $paths.AddRange($_.Data.GetFileDropList())
    # ウィンドウに逆順で表示
    $l = [System.Collections.Generic.List[string]]::new([string[]]$paths)
    $l.Reverse()
    $w.Content = $l -join "`n"
  })
  $null = $w.ShowDialog()
  return (, [string[]]$paths)
}

foreach ($path in $paths) {
  $inStream = [System.IO.File]::Open(
    $path,
    [System.IO.FileMode]::Open,
    [System.IO.FileAccess]::Read,
    [System.IO.FileShare]::ReadWrite -bor [System.IO.FileShare]::Delete
  )
  $inBmpSource = [System.Windows.Media.Imaging.JpegBitmapDecoder]::new(
    $inStream,
    [System.Windows.Media.Imaging.BitmapCreateOptions]::PreservePixelFormat,
    [System.Windows.Media.Imaging.BitmapCacheOption]::Default
  ).Frames[0]

  $t = [System.Windows.Media.ScaleTransform]::new(0.5, 0.5)
  $transformedBmp = [System.Windows.Media.Imaging.TransformedBitmap]::new($inBmpSource, $t)

  $newDpi = $inBmpSource.DpiX / 2

  # 解像度を設定
  $outBmpSource = & {
    param(
      [Parameter(Mandatory)][ValidateNotNull()][System.Windows.Media.Imaging.BitmapSource]$BitmapSource,
      [Parameter(Mandatory)][ValidateNotNull()][double]$DpiNew
    )
    $stride = [int][System.Math]::Truncate(($BitmapSource.Format.BitsPerPixel * $BitmapSource.PixelWidth + 7) / 8)
    $pixels = [byte[]]::new($stride * $BitmapSource.PixelHeight)
    $BitmapSource.CopyPixels($pixels, $stride, 0)
    $newBitmapSource = [System.Windows.Media.Imaging.BitmapSource]::Create(
      $BitmapSource.PixelWidth,
      $BitmapSource.PixelHeight,
      $DpiNew,
      $DpiNew,
      $BitmapSource.Format,
      $BitmapSource.Palette,
      $pixels,
      $stride
    )
    $newBitmapSource
  } -BitmapSource $transformedBmp -DpiNew $newDpi

  $jpgBmpEncoder = [System.Windows.Media.Imaging.JpegBitmapEncoder]::new()
  $jpgBmpEncoder.Frames.Add(
    [System.Windows.Media.Imaging.BitmapFrame]::Create($outBmpSource)
  )
  $outStream = [System.IO.File]::Create("$env:USERPROFILE\Desktop\tmp\" + [System.IO.Path]::GetFileName($path))
  $jpgBmpEncoder.Save($outStream)
  $outStream.Dispose()
  $inStream.Dispose()
}

PowerShellでのOpenFileDialogがウイルス対策ソフトでブロックされる

Windows PowerShellでのMicrosoft.Win32.OpenFileDialog.ShowDialogSystem.Windows.Forms.OpenFileDialog.ShowDialogがウイルス対策ソフトでブロックされる。

# PowerShell 5.1, Windows 11 (2024年10月頃)
Add-Type -AssemblyName PresentationFramework
$dlg = [Microsoft.Win32.OpenFileDialog]::new()

# ウイルス対策ソフトでブロックされる
$dlg.ShowDialog()
# PowerShell 5.1, Windows 11 (2024年10月頃)
Add-Type -AssemblyName System.Windows.Forms
$dlg = [System.Windows.Forms.OpenFileDialog]::new()

# ウイルス対策ソフトでブロックされる
$dlg.ShowDialog()

ウイルス対策ソフトで今のところ、フォームへのドラッグ&ドロップはブロックされない様子。

# PowerShell 5.1, Windows 11 (2024年10月頃)
Set-StrictMode -Version Latest
Add-Type -AssemblyName PresentationFramework
$paths = [System.Collections.Specialized.StringCollection]::new()
$w = New-Object -TypeName System.Windows.Window -Property @{
  Title     = "ドラッグ&ドロップ"
  Width     = 300
  Height    = 200
  AllowDrop = $true
}
$w.add_Drop([System.Windows.DragEventHandler]{
  param([object]$sender, [System.Windows.DragEventArgs]$e)
  $paths = $e.Data.GetFileDropList()
  $paths | Write-Host -ForegroundColor Cyan
  $global:paths.AddRange($paths)
})

# ウイルス対策ソフトで今のところブロックされない様子
$w.ShowDialog()

$paths
# PowerShell 5.1, Windows 11 (2024年10月頃)
Set-StrictMode -Version Latest
Add-Type -AssemblyName System.Windows.Forms
$paths = [System.Collections.Specialized.StringCollection]::new()
$f = New-Object -TypeName System.Windows.Forms.Form -Property @{
  Text      = "ドラッグ&ドロップ"
  Width     = 300
  Height    = 200
  AllowDrop = $true
}
$f.add_DragEnter([System.Windows.Forms.DragEventHandler]{
  param([object]$sender, [System.Windows.Forms.DragEventArgs]$e)
  $e.Effect = [System.Windows.Forms.DragDropEffects]::All
})
$f.add_DragDrop([System.Windows.Forms.DragEventHandler]{
  param([object]$sender, [System.Windows.Forms.DragEventArgs]$e)
  $paths = $e.Data.GetFileDropList()
  $paths | Write-Host -ForegroundColor Cyan
  $global:paths.AddRange($paths)
})

# ウイルス対策ソフトで今のところブロックされない様子
$f.ShowDialog()

$paths

XamlReader

Set-StrictMode -Version Latest

Add-Type -AssemblyName PresentationFramework

$xaml = @'
<Window Title="テスト" Width="600" Height="300" 
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <DockPanel>
    <TextBox AcceptsReturn="True" 
     HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" 
     FontFamily="MS ゴシック" FontSize="16">
      テキストを入力してください
    </TextBox>
  </DockPanel>
</Window>
'@

$window = [System.Windows.Markup.XamlReader]::Load(
  [System.Xml.XmlReader]::Create(
    [System.IO.StringReader]::new($xaml)
  )
) -as [System.Windows.Window]

$window.ShowDialog()
Set-StrictMode -Version Latest

Add-Type -AssemblyName PresentationFramework

$btn = New-Object -TypeName System.Windows.Controls.Button -Property @{
  Width   = 150
  Height  = 75
  Content = "クリックしてください"
}

$tBox = New-Object -TypeName System.Windows.Controls.TextBox -Property @{
  HorizontalScrollBarVisibility = [System.Windows.Controls.ScrollBarVisibility]::Visible
  VerticalScrollBarVisibility   = [System.Windows.Controls.ScrollBarVisibility]::Visible
  AcceptsReturn                 = $true
  FontFamily                    = [System.Windows.Media.FontFamily]::new("MS ゴシック")
  FontSize                      = 16
  Text                          = "テキストを入力してください"
}

$panel = [System.Windows.Controls.DockPanel]::new()
$panel.Children.Add($btn)
$panel.Children.Add($tBox)

$wnd = New-Object -TypeName System.Windows.Window -Property @{
  Width   = 600
  Height  = 300
  Title   = "テスト"
  Content = $panel
}

$hTextBoxTextChanged = [System.Windows.Controls.TextChangedEventHandler] {
  param([object]$s, [System.Windows.Controls.TextChangedEventArgs]$e)

  $btn.Content = "テキストが変更されました"
}

$hButtonClick = [System.Windows.RoutedEventHandler] {
  param([object]$s, [System.Windows.RoutedEventArgs]$e)

  $s.Content = "クリックされました"

  try {
    $xaml = $tBox.Text
    $stringReader = [System.IO.StringReader]::new($xaml)
    $xmlReader = [System.Xml.XmlReader]::Create($stringReader)
    $window = [System.Windows.Markup.XamlReader]::Load($xmlReader) -as [System.Windows.Window]
    $window.ShowDialog()
  }
  catch {
    $_ | Write-Verbose -Verbose
  }
}

$tBox.Text = [System.Windows.Markup.XamlWriter]::Save($wnd) -replace "><", ">`n<"

$tBox.add_TextChanged($hTextBoxTextChanged)
$btn.add_Click($hButtonClick)

$wnd.ShowDialog()