Windows 11 PowerShell 腳本雙擊執行方法

這篇文章將介紹如何在 Windows 11 上讓 PowerShell 腳本(.ps1 檔案)雙擊執行。以下是操作過程:

1. 下載並解壓縮 SetUserFTA 工具:https://kolbi.cz/SetUserFTA.zip

2. 以管理員身份打開 CMD,執行以下指令(使用 Windows PowerShell):

ftype Microsoft.PowerShellScript.1="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -ExecutionPolicy Bypass -f "%1"

3. 使用 SetUserFTA 工具,給予參數執行:

SetUserFTA.exe .ps1 Microsoft.PowerShellScript.1

若選擇使用 PowerShell 7,將第二步驟指令替換為:

ftype Microsoft.PowerShellScript.1="C:\Program Files\PowerShell\7\pwsh.exe" -NoLogo -ExecutionPolicy Bypass -f "%1"

完成上述操作後,即可在 Windows 11 上雙擊 .ps1 檔案進行執行。

參考資料:
https://www.elevenforum.com/t/run-ps1-files-double-click-on-windows-11.2433/

【ChatGPT 出張嘴寫程式】全程紀錄:GIF 動圖尺寸縮放 (搭配 Magick)

現在不用當上架構或主管,出一張嘴就能寫程式了
不過還是要知道一些術語,不然和 AI 也有可能會花不少溝通成本。
前後大約對話了快要一小時,可能都會有人吐槽,這樣還不如自己寫比較快www
但是出一張嘴就是爽啦 結果還不是要打字

給程式小白

這是什麼? 這是幫你改變 GIF 動圖大小的軟體~很適合拿來做 Discord 的 Emoji 或 Source 遊戲噴漆前置作業。

比起網路上抓不知名的軟體,這個程式安全一百倍,不用怕中毒! (除非你不相信 ImageMagick)

只想要一個可以在 Windows 執行的 Gif 動畫尺寸調整軟體的人,只要這樣做:

  1. 下載安裝 https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-7-Q16-HDRI-x64-dll.exe
  2. 勾選 Add to system path
  3. 打開記事本,複製完整程式碼,儲存為 gif_resizer.ps1
  4. gif_resizer.ps1 點滑鼠右鍵,點選 以 Powershell 執行
  5. 開始使用!

有遇到問題的人,不需要註冊或登入帳號,直接在下方留言。

完整程式碼

Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Windows.Forms;

public class FileDropLabel : Label
{
    public FileDropLabel()
    {
        AllowDrop = true;
        DragEnter += (s, e) =>
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
        };
    }
}
"@ -ReferencedAssemblies @('System.Windows.Forms.dll', 'System.Drawing.dll')

$global:originalWidth = [ref]0
$global:originalHeight = [ref]0
$global:inputImagePath = New-Object System.Management.Automation.PSReference("")

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked -and $global:originalWidth.Value -gt 0 -and $global:originalHeight.Value -gt 0) {
        if ($textboxWidth.Focused) {
            if ([int32]::TryParse($textboxWidth.Text, [ref]$null)) {
                $height = [int]($textboxWidth.Text) * $global:originalHeight.Value / $global:originalWidth.Value
                $textboxHeight.Text = [string]$height
            }
        } elseif ($textboxHeight.Focused) {
            if ([int32]::TryParse($textboxHeight.Text, [ref]$null)) {
                $width = [int]($textboxHeight.Text) * $global:originalWidth.Value / $global:originalHeight.Value
                $textboxWidth.Text = [string]$width
            }
        }
    }
}

$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Text = 'Image Resizer'
$mainForm.Width = 400
$mainForm.Height = 250

$labelDropImage = New-Object FileDropLabel
$labelDropImage.Text = 'Drag and drop an image here'
$labelDropImage.Size = New-Object System.Drawing.Size(350, 50)
$labelDropImage.Location = New-Object System.Drawing.Point(20, 20)
$labelDropImage.BackColor = [System.Drawing.SystemColors]::ControlLight
$labelDropImage.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$labelDropImage.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
    if ($files.Count -eq 1 -and [System.IO.File]::Exists($files[0])) {
        $imageExtensions = @('.jpg', '.jpeg', '.png', '.bmp', '.gif')
        $fileExtension = [System.IO.Path]::GetExtension($files[0]).ToLower()
        if ($imageExtensions -contains $fileExtension) {
            $originalImage = [System.Drawing.Image]::FromFile($files[0])
            $global:originalWidth.Value = $originalImage.Width
            $global:originalHeight.Value = $originalImage.Height
            $textboxWidth.Text = $global:originalWidth.Value
            $textboxHeight.Text = $global:originalHeight.Value
            $global:inputImagePath.Value = $files[0].ToString()
            $labelDropImage.Text = $global:inputImagePath.Value
        } else {
            [System.Windows.Forms.MessageBox]::Show('Unsupported image format.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})

$mainForm.Controls.Add($labelDropImage)

$labelWidth = New-Object System.Windows.Forms.Label
$labelWidth.Text = 'Width:'
$labelWidth.Location = New-Object System.Drawing.Point(20, 80)
$labelWidth.Size = New-Object System.Drawing.Size(50, 20)
$mainForm.Controls.Add($labelWidth)

$textboxWidth = New-Object System.Windows.Forms.TextBox
$textboxWidth.Location = New-Object System.Drawing.Point(80, 80)
$textboxWidth.Size = New-Object System.Drawing.Size(50, 20)
# $textboxWidth.Add_Leave({ UpdateAspectRatio })
$textboxWidth.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxWidth)

$labelHeight = New-Object System.Windows.Forms.Label
$labelHeight.Text = 'Height:'
$labelHeight.Location = New-Object System.Drawing.Point(150, 80)
$labelHeight.Size = New-Object System.Drawing.Size(50, 20) 

$mainForm.Controls.Add($labelHeight)

$textboxHeight = New-Object System.Windows.Forms.TextBox
$textboxHeight.Location = New-Object System.Drawing.Point(210, 80)
$textboxHeight.Size = New-Object System.Drawing.Size(50, 20)
# $textboxHeight.Add_Leave({ UpdateAspectRatio })
$textboxHeight.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxHeight)

$checkboxMaintainAspectRatio = New-Object System.Windows.Forms.CheckBox
$checkboxMaintainAspectRatio.Text = 'Maintain Aspect Ratio'
$checkboxMaintainAspectRatio.Location = New-Object System.Drawing.Point(20, 110)
$checkboxMaintainAspectRatio.Checked = $true
$mainForm.Controls.Add($checkboxMaintainAspectRatio)

$buttonResize = New-Object System.Windows.Forms.Button
$buttonResize.Text = 'Resize Image'
$buttonResize.Location = New-Object System.Drawing.Point(20, 140)
$buttonResize.Size = New-Object System.Drawing.Size(100, 30)
$buttonResize.Add_Click({
    if (-not [string]::IsNullOrEmpty($global:inputImagePath)) {
        $outputImagePath = [System.IO.Path]::ChangeExtension($global:inputImagePath.Value, '_resized' + [System.IO.Path]::GetExtension($global:inputImagePath.Value))

        $resizeCommand = "magick `"$($global:inputImagePath.Value)`" -resize $($textboxWidth.Text)`x$($textboxHeight.Text) `"$($outputImagePath)`""
        try {
            $resizeResult = Invoke-Expression -Command $resizeCommand
            [System.Windows.Forms.MessageBox]::Show("Image resized and saved as `n$outputImagePath", 'Success', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        } catch {
            $errorMessage = $_.Exception.Message
            [System.Windows.Forms.MessageBox]::Show("Error occurred during resizing: `n$errorMessage", 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show('Please drag and drop an image to be resized.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

$mainForm.Controls.Add($buttonResize)

$mainForm.Add_Closing({
    $mainForm.Dispose()
})
[void][System.Windows.Forms.Application]::EnableVisualStyles()
[void][System.Windows.Forms.Application]::Run($mainForm)

完整對話

Hollen9

我想要你幫我做一個 powershell 的 gui 程式,不用和我解釋原理,我只要程式碼,做出來的程式介面要英文,程式的註解也用英文寫;但是你和我的回答必須全程使用台灣繁體中文。

拖曳圖片到 gui,圖片尺寸按照使用者需求縮放,使用者可勾選是否保留長寬比,若保留,長或寬的欄位其中一邊會自動調整成對應原比例的直。

我希望可以支援所有主流圖片格式,不過最主要是要能夠保留 gif 動畫的前提下,縮放後並儲存到來源文件夾。

GPT4

好的,請查看以下的 PowerShell GUI 程式碼。這個程式將根據您的要求製作一個圖片縮放工具,並支援保留 GIF 動畫。注意,需要安裝 ImageMagick 來處理圖像縮放和保留動畫。

請先安裝 ImageMagick,並將其添加到您的系統環境變量中。

Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Windows.Forms;

public class FileDropLabel : Label
{
    public FileDropLabel()
    {
        AllowDrop = true;
        DragEnter += (s, e) =>
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
        };
    }
}
"@

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked) {
        if ($textboxWidth.Focused) {
            $height = [int]($textboxWidth.Text) * $originalHeight / $originalWidth
            $textboxHeight.Text = [math]::Round($height)
        } elseif ($textboxHeight.Focused) {
            $width = [int]($textboxHeight.Text) * $originalWidth / $originalHeight
            $textboxWidth.Text = [math]::Round($width)
        }
    }
}

$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Text = 'Image Resizer'
$mainForm.Width = 400
$mainForm.Height = 250

$labelDropImage = New-Object FileDropLabel
$labelDropImage.Text = 'Drag and drop an image here'
$labelDropImage.Size = New-Object System.Drawing.Size(350, 50)
$labelDropImage.Location = New-Object System.Drawing.Point(20, 20)
$labelDropImage.BackColor = [System.Drawing.SystemColors]::ControlLight
$labelDropImage.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$labelDropImage.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
    if ($files.Count -eq 1 -and [System.IO.File]::Exists($files[0])) {
        $imageExtensions = @('.jpg', '.jpeg', '.png', '.bmp', '.gif')
        $fileExtension = [System.IO.Path]::GetExtension($files[0]).ToLower()
        if ($imageExtensions -contains $fileExtension) {
            $originalImage = [System.Drawing.Image]::FromFile($files[0])
            $originalWidth = $originalImage.Width
            $originalHeight = $originalImage.Height
            $textboxWidth.Text = $originalWidth
            $textboxHeight.Text = $originalHeight
            $inputImagePath = $files[0]
            $labelDropImage.Text = $inputImagePath
        } else {
            [System.Windows.Forms.MessageBox]::Show('Unsupported image format.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})
$mainForm.Controls.Add($labelDropImage)

$labelWidth = New-Object System.Windows.Forms.Label
$labelWidth.Text = 'Width:'
$labelWidth.Location = New-Object System.Drawing.Point(20, 80)
$mainForm.Controls.Add($labelWidth)

$text

Hollen9

請繼續,從
‵‵‵
$mainForm.Controls.Add($labelDropImage)

$labelWidth = New-Object System.Windows.Forms.Label
$labelWidth.Text = 'Width:'
$labelWidth.Location = New-Object System.Drawing.Point(20, 80)
$mainForm.Controls.Add($labelWidth)
‵‵‵
接續

GPT4

好的,請參考以下程式碼:

$textboxWidth = New-Object System.Windows.Forms.TextBox
$textboxWidth.Location = New-Object System.Drawing.Point(80, 80)
$textboxWidth.Size = New-Object System.Drawing.Size(50, 20)
$textboxWidth.Add_Leave({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxWidth)

$labelHeight = New-Object System.Windows.Forms.Label
$labelHeight.Text = 'Height:'
$labelHeight.Location = New-Object System.Drawing.Point(150, 80)
$mainForm.Controls.Add($labelHeight)

$textboxHeight = New-Object System.Windows.Forms.TextBox
$textboxHeight.Location = New-Object System.Drawing.Point(210, 80)
$textboxHeight.Size = New-Object System.Drawing.Size(50, 20)
$textboxHeight.Add_Leave({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxHeight)

$checkboxMaintainAspectRatio = New-Object System.Windows.Forms.CheckBox
$checkboxMaintainAspectRatio.Text = 'Maintain Aspect Ratio'
$checkboxMaintainAspectRatio.Location = New-Object System.Drawing.Point(20, 110)
$checkboxMaintainAspectRatio.Checked = $true
$mainForm.Controls.Add($checkboxMaintainAspectRatio)

$buttonResize = New-Object System.Windows.Forms.Button
$buttonResize.Text = 'Resize Image'
$buttonResize.Location = New-Object System.Drawing.Point(20, 140)
$buttonResize.Size = New-Object System.Drawing.Size(100, 30)
$buttonResize.Add_Click({
    if (-not [string]::IsNullOrEmpty($inputImagePath)) {
        $outputImagePath = [System.IO.Path]::ChangeExtension($inputImagePath, '_resized' + [System.IO.Path]::GetExtension($inputImagePath))
        $resizeCommand = "magick `"$inputImagePath`" -resize $textboxWidth.Text`x$textboxHeight.Text `"$outputImagePath`""
        try {
            $resizeResult = Invoke-Expression -Command $resizeCommand
            [System.Windows.Forms.MessageBox]::Show("Image resized and saved as `n$outputImagePath", 'Success', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        } catch {
            [System.Windows.Forms.MessageBox]::Show('Error occurred during resizing.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show('Please drag and drop an image to be resized.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})
$mainForm.Controls.Add($buttonResize)

$mainForm.Add_Closing({
    $mainForm.Dispose()
})
[void][System.Windows.Forms.Application]::Run($mainForm)

這段程式碼將繼續創建圖形界面,包括寬度、高度的標籤和文本框,保持長寬比的複選框以及用於執行縮放操作的按鈕。當用戶拖曳圖像到界面並點擊“Resize Image”按鈕時,將使用 ImageMagick 對圖像進行縮放,並將結果保存到源文件夾中。

Hollen9

程式執行我可以看到視窗 GUI,但是 powershell 的 console 有報錯:

PS C:\Users\Hollen9> . 'c:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1'
Add-Type : c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(2) : The type or namespace name 'Forms' does not exist in the namespace 'System.Windows' (are you missing an assembly reference?)
c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(1) : using System;
c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(2) : >>> using System.Windows.Forms;
c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(3) :
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:2 char:1
+ Add-Type -TypeDefinition @"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception
    + FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand

Add-Type : c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(4) : The type or namespace name 'Label' could not be found (are you missing a using directive or an assembly reference?)
c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(3) :
c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(4) : >>> public class FileDropLabel : Label
c:\Users\Hollen9\AppData\Local\Temp\gsrfdomm.0.cs(5) : {
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:2 char:1
+ Add-Type -TypeDefinition @"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception
    + FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand

Add-Type : Cannot add type. Compilation errors occurred.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:2 char:1
+ Add-Type -TypeDefinition @"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Add-Type], InvalidOperationException
    + FullyQualifiedErrorId : COMPILER_ERRORS,Microsoft.PowerShell.Commands.AddTypeCommand

New-Object : Cannot find type [FileDropLabel]: verify that the assembly containing this type is loaded.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:36 char:19
+ $labelDropImage = New-Object FileDropLabel
+                   ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

The property 'Text' cannot be found on this object. Verify that the property exists and can be set.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:37 char:1
+ $labelDropImage.Text = 'Drag and drop an image here'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

The property 'Size' cannot be found on this object. Verify that the property exists and can be set.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:38 char:1
+ $labelDropImage.Size = New-Object System.Drawing.Size(350, 50)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

The property 'Location' cannot be found on this object. Verify that the property exists and can be set.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:39 char:1
+ $labelDropImage.Location = New-Object System.Drawing.Point(20, 20)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

The property 'BackColor' cannot be found on this object. Verify that the property exists and can be set.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:40 char:1
+ $labelDropImage.BackColor = [System.Drawing.SystemColors]::ControlLig ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

The property 'TextAlign' cannot be found on this object. Verify that the property exists and can be set.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:41 char:1
+ $labelDropImage.TextAlign = [System.Drawing.ContentAlignment]::Middle ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

The property 'BorderStyle' cannot be found on this object. Verify that the property exists and can be set.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:42 char:1
+ $labelDropImage.BorderStyle = [System.Windows.Forms.BorderStyle]::Fix ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

You cannot call a method on a null-valued expression.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:43 char:1
+ $labelDropImage.Add_DragDrop({
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

GPT4

抱歉之前的回答中出現了問題。請使用以下修正後的程式碼:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Windows.Forms;

public class FileDropLabel : Label
{
    public FileDropLabel()
    {
        AllowDrop = true;
        DragEnter += (s, e) =>
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
        };
    }
}
"@ -ReferencedAssemblies @('System.Windows.Forms.dll', 'System.Drawing.dll')

# 省略與上一段程式碼相同的部分...

[void][System.Windows.Forms.Application]::EnableVisualStyles()
[void][System.Windows.Forms.Application]::Run($mainForm)

這個修正將在 Add-Type 指令中添加了參數 -ReferencedAssemblies 以引用所需的組件,並在最後一行添加了 [void][System.Windows.Forms.Application]::EnableVisualStyles() 以應用主題樣式。請確保在 PowerShell 中以管理員身份運行此程式,以避免出現權限問題。

Hollen9

Weight 和 Height 的 Label 寬度太寬了,把右側的 Textbox 蓋住了

GPT4

抱歉造成困擾,請將 $labelWidth$labelHeightSize 屬性進行調整,以避免覆蓋相鄰的控件。請參考以下修改後的程式碼:

$labelWidth = New-Object System.Windows.Forms.Label
$labelWidth.Text = 'Width:'
$labelWidth.Location = New-Object System.Drawing.Point(20, 80)
$labelWidth.Size = New-Object System.Drawing.Size(50, 20)  # 修改後的 Size 屬性
$mainForm.Controls.Add($labelWidth)

$labelHeight = New-Object System.Windows.Forms.Label
$labelHeight.Text = 'Height:'
$labelHeight.Location = New-Object System.Drawing.Point(150, 80)
$labelHeight.Size = New-Object System.Drawing.Size(50, 20)  # 修改後的 Size 屬性
$mainForm.Controls.Add($labelHeight)

# 省略與上一段程式碼相同的部分...

這樣應該能避免覆蓋問題。請確保根據需要調整其他控件的位置和大小。

Hollen9

我發現當我還沒拖曳圖片進去時,去修改尺寸會出現以下錯誤:

Attempted to divide by zero.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:25 char:13
+             $width = [int]($textboxHeight.Text) * $originalWidth / $o ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

程式還是可以繼續執行就是了

GPT4

抱歉造成困擾。這是因為在拖曳圖片之前, $originalWidth$originalHeight 的值為零。要解決這個問題,可以在 UpdateAspectRatio 函數開頭添加一個條件,檢查 $originalWidth$originalHeight 是否大於零。請參考以下修改後的程式碼:

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked -and $originalWidth -gt 0 -and $originalHeight -gt 0) {
        if ($textboxWidth.Focused) {
            $height = [int]($textboxWidth.Text) * $originalHeight / $originalWidth
            $textboxHeight.Text = [string]$height
        } elseif ($textboxHeight.Focused) {
            $width = [int]($textboxHeight.Text) * $originalWidth / $originalHeight
            $textboxWidth.Text = [string]$width
        }
    }
}

# 省略與上一段程式碼相同的部分...

這樣在尚未拖曳圖片時,修改尺寸不會觸發錯誤。

Hollen9

我發現 $originalWidth 和 $originalHeight 在圖片拖曳進去的時候的確有正確數值,但當我在讓 長或 寬的 textbox 去 focus 的時候,$originalWidth 和 $originalHeight 都是 ""

GPT4

抱歉,這是因為 $originalWidth$originalHeightUpdateAspectRatio 函數內部作為局部變量使用,導致在 UpdateAspectRatio 函數中無法訪問它們的值。為了解決這個問題,請將 $originalWidth$originalHeight 定義為全局變量,並在 Add_DragDrop 事件處理程序中更新它們的值。以下是修改後的程式碼:

$originalWidth = 0
$originalHeight = 0

$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([System.Windows.Forms.DataFormats]::FileDrop)
    if ($files -and $files.Count -gt 0) {
        $filePath = $files[0]
        $image = [System.Drawing.Image]::FromFile($filePath)
        $originalWidth = $image.Width
        $originalHeight = $image.Height
        $textboxWidth.Text = [string]$originalWidth
        $textboxHeight.Text = [string]$originalHeight
    }
})

# 省略與上一段程式碼相同的部分...

這樣應該可以解決 $originalWidth$originalHeightUpdateAspectRatio 函數中無法訪問的問題。

Hollen9

總之我程式現在如下所示,到了 UpdateAspectRatio 那兩個變數還是恆為 0。

Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Windows.Forms;

public class FileDropLabel : Label
{
    public FileDropLabel()
    {
        AllowDrop = true;
        DragEnter += (s, e) =>
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
        };
    }
}
"@ -ReferencedAssemblies @('System.Windows.Forms.dll', 'System.Drawing.dll')

$originalWidth = 0
$originalHeight = 0

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked -and $originalWidth -gt 0 -and $originalHeight -gt 0) {
        if ($textboxWidth.Focused) {
            $height = [int]($textboxWidth.Text) * $originalHeight / $originalWidth
            $textboxHeight.Text = [string]$height
        } elseif ($textboxHeight.Focused) {
            $width = [int]($textboxHeight.Text) * $originalWidth / $originalHeight
            $textboxWidth.Text = [string]$width
        }
    }
}

$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Text = 'Image Resizer'
$mainForm.Width = 400
$mainForm.Height = 250

$labelDropImage = New-Object FileDropLabel
$labelDropImage.Text = 'Drag and drop an image here'
$labelDropImage.Size = New-Object System.Drawing.Size(350, 50)
$labelDropImage.Location = New-Object System.Drawing.Point(20, 20)
$labelDropImage.BackColor = [System.Drawing.SystemColors]::ControlLight
$labelDropImage.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$labelDropImage.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
    if ($files.Count -eq 1 -and [System.IO.File]::Exists($files[0])) {
        $imageExtensions = @('.jpg', '.jpeg', '.png', '.bmp', '.gif')
        $fileExtension = [System.IO.Path]::GetExtension($files[0]).ToLower()
        if ($imageExtensions -contains $fileExtension) {
            $originalImage = [System.Drawing.Image]::FromFile($files[0])
            $originalWidth = $originalImage.Width
            $originalHeight = $originalImage.Height
            $textboxWidth.Text = $originalWidth
            $textboxHeight.Text = $originalHeight
            $inputImagePath = $files[0]
            $labelDropImage.Text = $inputImagePath
        } else {
            [System.Windows.Forms.MessageBox]::Show('Unsupported image format.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})
$mainForm.Controls.Add($labelDropImage)

$labelWidth = New-Object System.Windows.Forms.Label
$labelWidth.Text = 'Width:'
$labelWidth.Location = New-Object System.Drawing.Point(20, 80)
$labelWidth.Size = New-Object System.Drawing.Size(50, 20)
$mainForm.Controls.Add($labelWidth)

$textboxWidth = New-Object System.Windows.Forms.TextBox
$textboxWidth.Location = New-Object System.Drawing.Point(80, 80)
$textboxWidth.Size = New-Object System.Drawing.Size(50, 20)
$textboxWidth.Add_Leave({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxWidth)

$labelHeight = New-Object System.Windows.Forms.Label
$labelHeight.Text = 'Height:'
$labelHeight.Location = New-Object System.Drawing.Point(150, 80)
$labelHeight.Size = New-Object System.Drawing.Size(50, 20) 

$mainForm.Controls.Add($labelHeight)

$textboxHeight = New-Object System.Windows.Forms.TextBox
$textboxHeight.Location = New-Object System.Drawing.Point(210, 80)
$textboxHeight.Size = New-Object System.Drawing.Size(50, 20)
$textboxHeight.Add_Leave({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxHeight)

$checkboxMaintainAspectRatio = New-Object System.Windows.Forms.CheckBox
$checkboxMaintainAspectRatio.Text = 'Maintain Aspect Ratio'
$checkboxMaintainAspectRatio.Location = New-Object System.Drawing.Point(20, 110)
$checkboxMaintainAspectRatio.Checked = $true
$mainForm.Controls.Add($checkboxMaintainAspectRatio)

$buttonResize = New-Object System.Windows.Forms.Button
$buttonResize.Text = 'Resize Image'
$buttonResize.Location = New-Object System.Drawing.Point(20, 140)
$buttonResize.Size = New-Object System.Drawing.Size(100, 30)
$buttonResize.Add_Click({
    if (-not [string]::IsNullOrEmpty($inputImagePath)) {
        $outputImagePath = [System.IO.Path]::ChangeExtension($inputImagePath, '_resized' + [System.IO.Path]::GetExtension($inputImagePath))
        $resizeCommand = "magick `"$inputImagePath`" -resize $textboxWidth.Text`x$textboxHeight.Text `"$outputImagePath`""
        try {
            $resizeResult = Invoke-Expression -Command $resizeCommand
            [System.Windows.Forms.MessageBox]::Show("Image resized and saved as `n$outputImagePath", 'Success', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        } catch {
            [System.Windows.Forms.MessageBox]::Show('Error occurred during resizing.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show('Please drag and drop an image to be resized.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})
$mainForm.Controls.Add($buttonResize)

$mainForm.Add_Closing({
    $mainForm.Dispose()
})
[void][System.Windows.Forms.Application]::EnableVisualStyles()
[void][System.Windows.Forms.Application]::Run($mainForm)

GPT4

謝謝您的反饋。我注意到您使用 Add_Leave 事件,但是它在離開輸入框時才會觸發。為了解決這個問題,請將原本的 Add_Leave 事件更改為 Add_TextChanged 事件。這樣一來,在您修改寬度或高度的時候,它就會立即更新另一個數值,保持寬高比。

修改後的程式碼:

$textboxWidth.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxWidth)

# ...

$textboxHeight.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxHeight)

這樣修改後,應該可以在輸入框中修改寬度或高度時立即更新另一個數值,並且保持寬高比。請注意,如果您在輸入框中輸入非數字字符,可能會導致錯誤。如果需要防止非數字字符的輸入,可以進一步修改腳本以檢查輸入值。

Hollen9

這個修改不錯是不錯,我也有想做。但你沒有討懂我的問題:
我說恆為零,是因為 Drop 事件中存取的 $originalWidth 和 $originalHeight 是區域變數的樣子,在不同 Scope 的 UpdateAspectRatio() 沒辦法獲得變數的新值,才會一直都是最初宣告的 0

GPT4

抱歉,我理解錯誤。請將 $originalWidth$originalHeight 放在全局變量的位置,可以將它們定義為 [ref] 類型,以便在多個範疇中存取和修改它們。

請將以下程式碼:

$originalWidth = 0
$originalHeight = 0

替換為:

$global:originalWidth = [ref]0
$global:originalHeight = [ref]0

然後,在 UpdateAspectRatio 函數和拖放事件中,用 $global:originalWidth.Value$global:originalHeight.Value 替換 $originalWidth$originalHeight

以下是修改後的 UpdateAspectRatio 函數和拖放事件:

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked -and $global:originalWidth.Value -gt 0 -and $global:originalHeight.Value -gt 0) {
        if ($textboxWidth.Focused) {
            $height = [int]($textboxWidth.Text) * $global:originalHeight.Value / $global:originalWidth.Value
            $textboxHeight.Text = [string]$height
        } elseif ($textboxHeight.Focused) {
            $width = [int]($textboxHeight.Text) * $global:originalWidth.Value / $global:originalHeight.Value
            $textboxWidth.Text = [string]$width
        }
    }
}

$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
    if ($files.Count -eq 1 -and [System.IO.File]::Exists($files[0])) {
        $imageExtensions = @('.jpg', '.jpeg', '.png', '.bmp', '.gif')
        $fileExtension = [System.IO.Path]::GetExtension($files[0]).ToLower()
        if ($imageExtensions -contains $fileExtension) {
            $originalImage = [System.Drawing.Image]::FromFile($files[0])
            $global:originalWidth.Value = $originalImage.Width
            $global:originalHeight.Value = $originalImage.Height
            $textboxWidth.Text = $global:originalWidth.Value
            $textboxHeight.Text = $global:originalHeight.Value
            $inputImagePath = $files[0]
            $labelDropImage.Text = $inputImagePath
        } else {
            [System.Windows.Forms.MessageBox]::Show('Unsupported image format.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})

現在,當您修改寬度或高度時,UpdateAspectRatio 函數應該能夠正確地讀取和更新 $global:originalWidth.Value$global:originalHeight.Value

Hollen9

長寬問題解決了,但我發現 $inputImagePath 等變數也有類似的問題

GPT4

對於 $inputImagePath,您可以採用與 $originalWidth$originalHeight 相同的解決方案。將 $inputImagePath 定義為全局 [ref] 變量,並在需要時使用 $global:inputImagePath.Value 存取和修改它。

首先,將以下程式碼:

$inputImagePath = ""

替換為:

$global:inputImagePath = [ref]""

然後在拖放事件和按鈕點擊事件中,使用 $global:inputImagePath.Value 替換 $inputImagePath

以下是修改後的拖放事件和按鈕點擊事件:

$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
    if ($files.Count -eq 1 -and [System.IO.File]::Exists($files[0])) {
        $imageExtensions = @('.jpg', '.jpeg', '.png', '.bmp', '.gif')
        $fileExtension = [System.IO.Path]::GetExtension($files[0]).ToLower()
        if ($imageExtensions -contains $fileExtension) {
            $originalImage = [System.Drawing.Image]::FromFile($files[0])
            $global:originalWidth.Value = $originalImage.Width
            $global:originalHeight.Value = $originalImage.Height
            $textboxWidth.Text = $global:originalWidth.Value
            $textboxHeight.Text = $global:originalHeight.Value
            $global:inputImagePath.Value = $files[0]
            $labelDropImage.Text = $global:inputImagePath.Value
        } else {
            [System.Windows.Forms.MessageBox]::Show('Unsupported image format.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})

$buttonResize.Add_Click({
    if (-not [string]::IsNullOrEmpty($global:inputImagePath.Value)) {
        $outputImagePath = [System.IO.Path]::ChangeExtension($global:inputImagePath.Value, '_resized' + [System.IO.Path]::GetExtension($global:inputImagePath.Value))
        $resizeCommand = "magick `"$global:inputImagePath.Value`" -resize $textboxWidth.Text`x$textboxHeight.Text `"$outputImagePath`""
        try {
            $resizeResult = Invoke-Expression -Command $resizeCommand
            [System.Windows.Forms.MessageBox]::Show("Image resized and saved as `n$outputImagePath", 'Success', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        } catch {
            [System.Windows.Forms.MessageBox]::Show('Error occurred during resizing.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show('Please drag and drop an image to be resized.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

現在,$global:inputImagePath.Value 應該在需要時正確地存取和修改。

Hollen9

catch {

    }

我要怎麼改成 能夠顯示錯誤訊息的 像是 e.Message 之類的

GPT4

要在錯

Hollen9

剛剛 OpenAI 出現錯誤,我看到你的回答長這樣:

要在錯

GPT4

抱歉剛才的回答被截斷了。以下是完整的回答:

要在錯誤對話框中顯示特定的錯誤訊息,您可以使用 $_ 變量來獲取當前錯誤的詳細信息。在 catch 塊中,您可以使用 Exception.Message 屬性來獲取有關異常的更多信息。您可以通過修改 catch 塊中的代碼來顯示錯誤訊息,如下所示:

catch {
    $errorMessage = $_.Exception.Message
    [System.Windows.Forms.MessageBox]::Show("Error occurred during resizing: `n$errorMessage", 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
}

這將在錯誤對話框中顯示當前異常的錯誤訊息。

Hollen9

我看到顯示成功的 MsgBox,但是沒有真的成功 (沒有新的圖片檔)
且 Console 印出以下訊息:

magick.exe: unable to open image 'System.Management.Automation.PSReference1[System.String].Value': No such file or directory @ error/blob.c/OpenBlob/3569.
magick.exe: unable to open module file 'C:\Program Files\ImageMagick\modules\coders\IM_MOD_RL_VALUE_.dll': No such file or directory @ warning/module.c/GetMagickModulePath/677.
magick.exe: no decode delegate for this image format `VALUE' @ error/constitute.c/ReadImage/746.

GPT4

這個錯誤是因為在命令行中的變量引用不正確。您需要將 $inputImagePath$outputImagePath 變量的值直接傳遞給 magick 命令。請修改 $buttonResize.Add_Click 腳本塊如下:

$buttonResize.Add_Click({
    if (-not [string]::IsNullOrEmpty($global:inputImagePath)) {
        $outputImagePath = [System.IO.Path]::ChangeExtension($global:inputImagePath, '_resized' + [System.IO.Path]::GetExtension($global:inputImagePath))
        $resizeCommand = "magick `"$($global:inputImagePath)`" -resize $($textboxWidth.Text)`x$($textboxHeight.Text) `"$($outputImagePath)`""
        try {
            $resizeResult = Invoke-Expression -Command $resizeCommand
            [System.Windows.Forms.MessageBox]::Show("Image resized and saved as `n$outputImagePath", 'Success', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        } catch {
            $errorMessage = $_.Exception.Message
            [System.Windows.Forms.MessageBox]::Show("Error occurred during resizing: `n$errorMessage", 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show('Please drag and drop an image to be resized.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

這樣應該可以解決問題。請確保您使用的是 global: 修飾符來訪問全局變量。

Hollen9

Cannot convert value "\" to type "System.Int32". Error: "Input string was not in a correct format."
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:27 char:13
+             $height = [int]($textboxWidth.Text) * $global:originalHei ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastFromStringToInteger

Cannot convert value "\" to type "System.Int32". Error: "Input string was not in a correct format."
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:27 char:13
+             $height = [int]($textboxWidth.Text) * $global:originalHei ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastFromStringToInteger

magick.exe: unable to open image 'System.Management.Automation.PSReference1[System.String]': No such file or directory @ error/blob.c/OpenBlob/3569.
magick.exe: no decode delegate for this image format `' @ error/constitute.c/ReadImage/746.

我現在全部的程式長這樣:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Windows.Forms;

public class FileDropLabel : Label
{
    public FileDropLabel()
    {
        AllowDrop = true;
        DragEnter += (s, e) =>
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
        };
    }
}
"@ -ReferencedAssemblies @('System.Windows.Forms.dll', 'System.Drawing.dll')

$global:originalWidth = [ref]0
$global:originalHeight = [ref]0
$global:inputImagePath = [ref]""

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked -and $global:originalWidth.Value -gt 0 -and $global:originalHeight.Value -gt 0) {
        if ($textboxWidth.Focused) {
            $height = [int]($textboxWidth.Text) * $global:originalHeight.Value / $global:originalWidth.Value
            $textboxHeight.Text = [string]$height
        } elseif ($textboxHeight.Focused) {
            $width = [int]($textboxHeight.Text) * $global:originalWidth.Value / $global:originalHeight.Value
            $textboxWidth.Text = [string]$width
        }
    }
}

$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Text = 'Image Resizer'
$mainForm.Width = 400
$mainForm.Height = 250

$labelDropImage = New-Object FileDropLabel
$labelDropImage.Text = 'Drag and drop an image here'
$labelDropImage.Size = New-Object System.Drawing.Size(350, 50)
$labelDropImage.Location = New-Object System.Drawing.Point(20, 20)
$labelDropImage.BackColor = [System.Drawing.SystemColors]::ControlLight
$labelDropImage.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$labelDropImage.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
    if ($files.Count -eq 1 -and [System.IO.File]::Exists($files[0])) {
        $imageExtensions = @('.jpg', '.jpeg', '.png', '.bmp', '.gif')
        $fileExtension = [System.IO.Path]::GetExtension($files[0]).ToLower()
        if ($imageExtensions -contains $fileExtension) {
            $originalImage = [System.Drawing.Image]::FromFile($files[0])
            $global:originalWidth.Value = $originalImage.Width
            $global:originalHeight.Value = $originalImage.Height
            $textboxWidth.Text = $global:originalWidth.Value
            $textboxHeight.Text = $global:originalHeight.Value
            $global:inputImagePath.Value = $files[0]
            $labelDropImage.Text = $global:inputImagePath.Value
        } else {
            [System.Windows.Forms.MessageBox]::Show('Unsupported image format.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})

$mainForm.Controls.Add($labelDropImage)

$labelWidth = New-Object System.Windows.Forms.Label
$labelWidth.Text = 'Width:'
$labelWidth.Location = New-Object System.Drawing.Point(20, 80)
$labelWidth.Size = New-Object System.Drawing.Size(50, 20)
$mainForm.Controls.Add($labelWidth)

$textboxWidth = New-Object System.Windows.Forms.TextBox
$textboxWidth.Location = New-Object System.Drawing.Point(80, 80)
$textboxWidth.Size = New-Object System.Drawing.Size(50, 20)
# $textboxWidth.Add_Leave({ UpdateAspectRatio })
$textboxWidth.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxWidth)

$labelHeight = New-Object System.Windows.Forms.Label
$labelHeight.Text = 'Height:'
$labelHeight.Location = New-Object System.Drawing.Point(150, 80)
$labelHeight.Size = New-Object System.Drawing.Size(50, 20) 

$mainForm.Controls.Add($labelHeight)

$textboxHeight = New-Object System.Windows.Forms.TextBox
$textboxHeight.Location = New-Object System.Drawing.Point(210, 80)
$textboxHeight.Size = New-Object System.Drawing.Size(50, 20)
# $textboxHeight.Add_Leave({ UpdateAspectRatio })
$textboxHeight.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxHeight)

$checkboxMaintainAspectRatio = New-Object System.Windows.Forms.CheckBox
$checkboxMaintainAspectRatio.Text = 'Maintain Aspect Ratio'
$checkboxMaintainAspectRatio.Location = New-Object System.Drawing.Point(20, 110)
$checkboxMaintainAspectRatio.Checked = $true
$mainForm.Controls.Add($checkboxMaintainAspectRatio)

$buttonResize = New-Object System.Windows.Forms.Button
$buttonResize.Text = 'Resize Image'
$buttonResize.Location = New-Object System.Drawing.Point(20, 140)
$buttonResize.Size = New-Object System.Drawing.Size(100, 30)
$buttonResize.Add_Click({
    if (-not [string]::IsNullOrEmpty($global:inputImagePath)) {
        $outputImagePath = [System.IO.Path]::ChangeExtension($global:inputImagePath, '_resized' + [System.IO.Path]::GetExtension($global:inputImagePath))
        $resizeCommand = "magick `"$($global:inputImagePath)`" -resize $($textboxWidth.Text)`x$($textboxHeight.Text) `"$($outputImagePath)`""
        try {
            $resizeResult = Invoke-Expression -Command $resizeCommand
            [System.Windows.Forms.MessageBox]::Show("Image resized and saved as `n$outputImagePath", 'Success', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        } catch {
            $errorMessage = $_.Exception.Message
            [System.Windows.Forms.MessageBox]::Show("Error occurred during resizing: `n$errorMessage", 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show('Please drag and drop an image to be resized.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

$mainForm.Controls.Add($buttonResize)

$mainForm.Add_Closing({
    $mainForm.Dispose()
})
[void][System.Windows.Forms.Application]::EnableVisualStyles()
[void][System.Windows.Forms.Application]::Run($mainForm)

GPT4

對不起,我看到問題了。問題出在將文字框中的值轉換為整數時,可能會有不允許的字符導致轉換失敗。為了解決這個問題,我們可以在進行轉換之前檢查文字框中的值是否為有效的整數。請將UpdateAspectRatio函數更改為以下:

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked -and $global:originalWidth.Value -gt 0 -and $global:originalHeight.Value -gt 0) {
        if ($textboxWidth.Focused) {
            if ([int32]::TryParse($textboxWidth.Text, [ref]$null)) {
                $height = [int]($textboxWidth.Text) * $global:originalHeight.Value / $global:originalWidth.Value
                $textboxHeight.Text = [string]$height
            }
        } elseif ($textboxHeight.Focused) {
            if ([int32]::TryParse($textboxHeight.Text, [ref]$null)) {
                $width = [int]($textboxHeight.Text) * $global:originalWidth.Value / $global:originalHeight.Value
                $textboxWidth.Text = [string]$width
            }
        }
    }
}

這樣應該可以解決輸入的轉換問題。

Hollen9

MsgBox:

Image resized and saved as
System.Management.Automation.PSReference`1[System._resized.String]

Console:

magick.exe: unable to open image 'System.Management.Automation.PSReference1[System.String]': No such file or directory @ error/blob.c/OpenBlob/3569.
magick.exe: no decode delegate for this image format `' @ error/constitute.c/ReadImage/746.

還是失敗

GPT4

對不起,我犯了一個錯誤。我們需要去掉$global:inputImagePath$outputImagePath的引用([ref])。請將以下兩行更改為:

$global:inputImagePath = ""

並將:

$outputImagePath = [System.IO.Path]::ChangeExtension($global:inputImagePath, '_resized' + [System.IO.Path]::GetExtension($global:inputImagePath))

更新為:

$outputImagePath = [System.IO.Path]::ChangeExtension($global:inputImagePath.Value, '_resized' + [System.IO.Path]::GetExtension($global:inputImagePath.Value))

這樣應該可以解決問題。請再試一次,看看這是否有效。

Hollen9

改完之後,我只是拖曳圖片進去,就出錯了,本來還正常的:

The property 'Value' cannot be found on this object. Verify that the property exists and can be set.
At C:\Program Files (Portable)\SomePowershell\ImageResize - DEV.ps1:64 char:13
+             $global:inputImagePath.Value = $files[0]
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

我現在的整體程式長這樣:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Windows.Forms;

public class FileDropLabel : Label
{
    public FileDropLabel()
    {
        AllowDrop = true;
        DragEnter += (s, e) =>
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
        };
    }
}
"@ -ReferencedAssemblies @('System.Windows.Forms.dll', 'System.Drawing.dll')

$global:originalWidth = [ref]0
$global:originalHeight = [ref]0
$global:inputImagePath = ""

function UpdateAspectRatio {
    if ($checkboxMaintainAspectRatio.Checked -and $global:originalWidth.Value -gt 0 -and $global:originalHeight.Value -gt 0) {
        if ($textboxWidth.Focused) {
            if ([int32]::TryParse($textboxWidth.Text, [ref]$null)) {
                $height = [int]($textboxWidth.Text) * $global:originalHeight.Value / $global:originalWidth.Value
                $textboxHeight.Text = [string]$height
            }
        } elseif ($textboxHeight.Focused) {
            if ([int32]::TryParse($textboxHeight.Text, [ref]$null)) {
                $width = [int]($textboxHeight.Text) * $global:originalWidth.Value / $global:originalHeight.Value
                $textboxWidth.Text = [string]$width
            }
        }
    }
}

$mainForm = New-Object System.Windows.Forms.Form
$mainForm.Text = 'Image Resizer'
$mainForm.Width = 400
$mainForm.Height = 250

$labelDropImage = New-Object FileDropLabel
$labelDropImage.Text = 'Drag and drop an image here'
$labelDropImage.Size = New-Object System.Drawing.Size(350, 50)
$labelDropImage.Location = New-Object System.Drawing.Point(20, 20)
$labelDropImage.BackColor = [System.Drawing.SystemColors]::ControlLight
$labelDropImage.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$labelDropImage.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$labelDropImage.Add_DragDrop({
    $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
    if ($files.Count -eq 1 -and [System.IO.File]::Exists($files[0])) {
        $imageExtensions = @('.jpg', '.jpeg', '.png', '.bmp', '.gif')
        $fileExtension = [System.IO.Path]::GetExtension($files[0]).ToLower()
        if ($imageExtensions -contains $fileExtension) {
            $originalImage = [System.Drawing.Image]::FromFile($files[0])
            $global:originalWidth.Value = $originalImage.Width
            $global:originalHeight.Value = $originalImage.Height
            $textboxWidth.Text = $global:originalWidth.Value
            $textboxHeight.Text = $global:originalHeight.Value
            $global:inputImagePath.Value = $files[0]
            $labelDropImage.Text = $global:inputImagePath.Value
        } else {
            [System.Windows.Forms.MessageBox]::Show('Unsupported image format.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    }
})

$mainForm.Controls.Add($labelDropImage)

$labelWidth = New-Object System.Windows.Forms.Label
$labelWidth.Text = 'Width:'
$labelWidth.Location = New-Object System.Drawing.Point(20, 80)
$labelWidth.Size = New-Object System.Drawing.Size(50, 20)
$mainForm.Controls.Add($labelWidth)

$textboxWidth = New-Object System.Windows.Forms.TextBox
$textboxWidth.Location = New-Object System.Drawing.Point(80, 80)
$textboxWidth.Size = New-Object System.Drawing.Size(50, 20)
# $textboxWidth.Add_Leave({ UpdateAspectRatio })
$textboxWidth.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxWidth)

$labelHeight = New-Object System.Windows.Forms.Label
$labelHeight.Text = 'Height:'
$labelHeight.Location = New-Object System.Drawing.Point(150, 80)
$labelHeight.Size = New-Object System.Drawing.Size(50, 20) 

$mainForm.Controls.Add($labelHeight)

$textboxHeight = New-Object System.Windows.Forms.TextBox
$textboxHeight.Location = New-Object System.Drawing.Point(210, 80)
$textboxHeight.Size = New-Object System.Drawing.Size(50, 20)
# $textboxHeight.Add_Leave({ UpdateAspectRatio })
$textboxHeight.Add_TextChanged({ UpdateAspectRatio })
$mainForm.Controls.Add($textboxHeight)

$checkboxMaintainAspectRatio = New-Object System.Windows.Forms.CheckBox
$checkboxMaintainAspectRatio.Text = 'Maintain Aspect Ratio'
$checkboxMaintainAspectRatio.Location = New-Object System.Drawing.Point(20, 110)
$checkboxMaintainAspectRatio.Checked = $true
$mainForm.Controls.Add($checkboxMaintainAspectRatio)

$buttonResize = New-Object System.Windows.Forms.Button
$buttonResize.Text = 'Resize Image'
$buttonResize.Location = New-Object System.Drawing.Point(20, 140)
$buttonResize.Size = New-Object System.Drawing.Size(100, 30)
$buttonResize.Add_Click({
    if (-not [string]::IsNullOrEmpty($global:inputImagePath)) {
        $outputImagePath = [System.IO.Path]::ChangeExtension($global:inputImagePath.Value, '_resized' + [System.IO.Path]::GetExtension($global:inputImagePath.Value))

        $resizeCommand = "magick `"$($global:inputImagePath)`" -resize $($textboxWidth.Text)`x$($textboxHeight.Text) `"$($outputImagePath)`""
        try {
            $resizeResult = Invoke-Expression -Command $resizeCommand
            [System.Windows.Forms.MessageBox]::Show("Image resized and saved as `n$outputImagePath", 'Success', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
        } catch {
            $errorMessage = $_.Exception.Message
            [System.Windows.Forms.MessageBox]::Show("Error occurred during resizing: `n$errorMessage", 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
        }
    } else {
        [System.Windows.Forms.MessageBox]::Show('Please drag and drop an image to be resized.', 'Error', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
    }
})

$mainForm.Controls.Add($buttonResize)

$mainForm.Add_Closing({
    $mainForm.Dispose()
})
[void][System.Windows.Forms.Application]::EnableVisualStyles()
[void][System.Windows.Forms.Application]::Run($mainForm)

GPT4

抱歉剛才的更改導致問題。現在我明白了問題所在。請將以下代碼:

$global:inputImagePath = ""

更改為:

$global:inputImagePath = New-Object System.Management.Automation.PSReference("")

然後將:

$global:inputImagePath.Value = $files[0]

更新為:

$global:inputImagePath.Value = $files[0].ToString()

這樣應該可以解決您遇到的問題。請再次嘗試執行腳本。

Hollen9

MsgBox 正常了。
但是關鍵的圖片產出還是失敗:
Console

magick.exe: unable to open image 'System.Management.Automation.PSReference': No such file or directory @ error/blob.c/OpenBlob/3569.
magick.exe: unable to open module file 'C:\Program Files\ImageMagick\modules\coders\IM_MOD_RL_PSREFERENCE_.dll': No such file or directory @ warning/module.c/GetMagickModulePath/677.
magick.exe: no decode delegate for this image format `PSREFERENCE' @ error/constitute.c/ReadImage/746.

GPT4

請將以下代碼:

$resizeCommand = "magick `"$($global:inputImagePath)`" -resize $($textboxWidth.Text)`x$($textboxHeight.Text) `"$($outputImagePath)`""

更改為:

$resizeCommand = "magick `"$($global:inputImagePath.Value)`" -resize $($textboxWidth.Text)`x$($textboxHeight.Text) `"$($outputImagePath)`""

這樣應該可以解決您遇到的問題。請再次嘗試執行腳本。

Hollen9

成功了!

GPT4

(當掉沒有回應)

一鍵將 iOS Illustail 的圖片傳到 Synology NAS

需求、目標群眾

  1. 使用 Illustail iOS 版的人,或是平常喜歡抓 Booru、Twitter 類圖片的人。
  2. 有群輝 NAS。
  3. iOS 裝置空間不夠用。

什麼是 Illustail

Illustail 是一個專門用來閱覽、下載、搜尋網路上 Booru 圖片網站的 iOS App。你可以在 iPhone、iPad 或 Mac 上使用它,並且可以輕鬆地把圖片儲存到裝置或雲端空間 。Illustail 支援多種圖片網站,包括 TINAMI、Danbooru、Tumblr、Twitter、Misskey 和 Mastodon。
自帶 iOS 桌面小工具,可以用來點綴你的桌面。

簡言之, Illustail 就是幫助你在 iOS 上色色的工具啦。

免費版本會有廣告,你可以選擇付費消除廣告加以支持 App 作者。

問題

我的 iPad 儲存空間存圖很快就滿了! 而且 Illustail 在 2023 唯一提供的雲端儲存選項只有 Dropbox。而 Dropbox 免費版只有 4.75 GB,根本也不夠用啊~~

明明有好大的群輝 NAS 卻不能用不是很可惜嗎!?
所以本篇簡述如何使用群輝 NAS 內建套件,不用打指令,傻瓜都會設定!

步驟

  1. 去群輝 NAS 的套件中心安裝 Cloud Sync
  2. 開啟 Cloud Sync,新增 Dropbox 的備份工作。
  3. 進行細項設定。
    • Connection Name 自己取好辨認的;
    • Local path 設定你想要儲存的 NAS 目的資料夾;
    • Remote path 設定 Dropbox 上面想讓 Illustail 上傳的資料夾。
    • Sync direction 設為 Download remote changes only。
    • 勾選 Don't remove files in the destination folder when they are removed in the source folder.
    • Schedule settings 設定工作排程時間,我是全勾。
  4. 設定好還可以再調整一些細項,例如 polling seconds 要多久去偵測一次。我是設定 60 秒。設定的時間愈短,就表示你的 NAS 愈忙。
  5. 回到 Illustail,將分享上傳的目的地設為 Dropbox 的指定資料夾。這樣就大功告成了!
  6. 來試試看 Illustail 的上傳功能,看看自己的 NAS 有沒有出現相應圖片吧。

Modify .hcacess on Apache Server to allow CORS for specified domains

Motivation

I purchased a .tech domain recently, and made it a alias domain to hollen9.com.
However, some src request are blocked due to CORS policy.
Typical symptoms are blank images, failure to load external fonts, scripts, etc. You can verify it by checking your dev console on the browser by pressing Shift+Ctrl / Command+i.

Solution

Locate your .htacess file of your website, for analog it is a config file just like web.config on IIS.
Open it with a text editor, insert the following:

<IfModule mod_headers.c>
    # Allow loading of alias domain resources
    # You should modify the domains to suit your need.
    SetEnvIf Origin "http(s)?://(www\.)?(holllen.tech|hollen9.com)$" AccessControlAllowOrigin=$0
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header merge Vary Origin
</IfModule>

Force reload your previous page by pressing Ctrl+F5 or Command+Shift+R, and viola! Now all images are visible!

References