このスクリプトを実行する場合、引数で開始位置と幅と高さを指定します。
指定する値は、だいたいの当たりをつけて引数の値を変えて希望のサイズにトリミングするわけですが、この作業が意外と面倒なので、視覚的に確認するスクリプトを作成しました。
スクリプト
<#
.SYNOPSIS
画像のトリミングする位置を確認する
はサポートしていません
.DESCRIPTION
画像をトリミングする開始位置と幅と高さを確認するスクリプト
#>
using namespace System.Windows.Forms
using namespace System.Drawing
using namespace System.IO
Set-StrictMode -Version Latest
$ErrorActionPreference = "STOP"
# アセンブリのロード
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
function Main
{
function trim {
$w = [int]$form.Controls["NUM_W"].Text
$h = [int]$form.Controls["NUM_H"].Text
$x = [int]$form.Controls["NUM_X"].Text
$y = [int]$form.Controls["NUM_Y"].Text
$before = $form.Controls["PIC_BEFORE"].Image
Write-Host ("w:{0} h:{1} x:{2} y:{3}" -f $w, $h, $x, $y)
$bmp = [Bitmap]::new($w, $h)
$gra = [Graphics]::FromImage($bmp)
$src = [Rectangle]::new($x, $y, $w, $h)
$dst = [Rectangle]::new(0, 0, $w, $h)
$gra.DrawImage($before, $dst, $src, 2)
if ($form.Controls["PIC_AFTER"].Image -Is [IDisposable]) {
$form.Controls["PIC_AFTER"].Image.Dispose()
}
$form.Controls["PIC_AFTER"].Image = $bmp
$gra.Dispose()
}
$form = [Form]::new() | % {
$_.Name = "MAIN_FORM"
$_.Size = "800,600"
$_
}
$controls = @(
[Label]::new() | % {
$_.Name = "LABEL_W"
$_.Location = "10,10"
$_.Text = "幅:"
$_.TextAlign = "MiddleCenter"
$_.Size = "30,20"
$_
}
[NumericUpDown]::new() | % {
$_.Name = "NUM_W"
$_.Location = "40,10"
$_.TextAlign = "Right"
$_.Size = "50,0"
$_.Minimum = "0"
$_.Maximum = "5000"
$_.Add_ValueChanged({
trim
})
$_
}
[Label]::new() | % {
$_.Name = "LABEL_H"
$_.Location = "90,10"
$_.Text = "高さ:"
$_.TextAlign = "MiddleCenter"
$_.Size = "30,20"
$_
}
[NumericUpDown]::new() | % {
$_.Name = "NUM_H"
$_.Location = "120,10"
$_.TextAlign = "Right"
$_.Size = "50,0"
$_.Minimum = "0"
$_.Maximum = "5000"
$_.Add_ValueChanged({
trim
})
$_
}
[Label]::new() | % {
$_.Name = "LABEL_X"
$_.Location = "170,10"
$_.Text = "X:"
$_.TextAlign = "MiddleCenter"
$_.Size = "30,20"
$_
}
[NumericUpDown]::new() | % {
$_.Name = "NUM_X"
$_.Location = "200,10"
$_.TextAlign = "Right"
$_.Size = "50,0"
$_.Minimum = "0"
$_.Maximum = "5000"
$_.Add_ValueChanged({
trim
})
$_
}
[Label]::new() | % {
$_.Name = "LABEL_Y"
$_.Location = "250,10"
$_.Text = "Y:"
$_.TextAlign = "MiddleCenter"
$_.Size = "30,20"
$_
}
[NumericUpDown]::new() | % {
$_.Name = "NUM_Y"
$_.Location = "280,10"
$_.TextAlign = "Right"
$_.Size = "50,0"
$_.Minimum = "0"
$_.Maximum = "5000"
$_.Add_ValueChanged({
trim
})
$_
}
[Label]::new() | % {
$_.Name = "LABEL_BEFORE"
$_.Location = "10,60"
$_.Text = "変更前(枠内にファイルをドラック&ドロップしてください。)"
$_.TextAlign = "MiddleCenter"
$_.Size = "300,20"
$_
}
[PictureBox]::new() | % {
$_.Name = "PIC_BEFORE"
$_.Location = "10,80"
$_.Size = "360,460"
$_.SizeMode = "Zoom"
$_.BorderStyle = "FixedSingle"
$_.AllowDrop = $true
$_.Add_DragEnter({$_.Effect = "ALL"})
$_.Add_DragDrop({
$file = @($_.Data.GetData("FileDrop"))[0]
if ($fs = [FileStream]::new($file, [FileMode]::Open,[FileAccess]::Read)) {
try {
if ($this.Image) { $this.Image.Dispose() }
$this.Image = [System.Drawing.Image]::FromStream($fs)
$num_w = $this.parent.Controls["NUM_W"]
$num_h = $this.parent.Controls["NUM_H"]
$num_w.Text = $this.Image.Width
$num_h.Text = $this.Image.Height
trim
} finally {
$fs.Close()
}
}
})
$_
}
[Label]::new() | % {
$_.Name = "LABEL_AFTER"
$_.Location = "410,60"
$_.Text = "変更後"
$_.TextAlign = "MiddleCenter"
$_.Size = "80,20"
$_
}
[PictureBox]::new() | % {
$_.Name = "PIC_AFTER"
$_.Location = "410,80"
$_.Size = "360,460"
$_.SizeMode = "Zoom"
$_
}
)
$form.Controls.AddRange($controls)
$form.ShowDialog()
}
Main
powershell_ise.exeなどに貼り付けて保存してください。
PowerShellスクリプトを初めて実行する場合
使い方
powershell.exe又はpowershell_ise.exeからスクリプトを実行します。
「変更前」の枠内に画像ファイルをドラック&ドロップしてください。
ドロップされた画像の「幅」「高さ」がセットされます。
「幅」「高さ」「X」「Y」の値を矢印ボタンを押すことで値が変更され、連動して右側の「変更後」の画像が変更されます。数値を直接入力することも出ます。
大まかな数値を直接入力して、後は矢印ボタンで1ピクセル単位で調整する様な使い方になります。
機能的には以上となります。このスクリプト自体にトリミングする機能は無いです。
スクリプトの中身の話になりますが、今回からusing namespaceを使うことで名前空間を省略してみました。それに合わせてオブジェクトの作成もNew-Objectから[オブジェクト名]::new()を使ったところ入力量が大分減りました。
また、formにコントロールを配置する場合、form.Controls.Add(「コントロールのオブジェクト」)というメソッドで登録するわけですが、一括登録する場合form.Controls.AddRange(「コントロールオブジェクトの配列」)方法が使えます。登録する直前に配列を作っていたのですが、コントロールオブジェクトの生成を配列の初期化時に行うようにしてみました。%(ForEach-Object)内で各コントロールの初期化やイベント登録をしていますので結構すっきりしたように思えます。短めのスクリプトであればこの記述方法も良いのではと思います。ただ個々のコントロールに対するコード量が増えると見通しが悪くなりそうです。
コメント