有没有办法通过 Windows Batch 删除文件夹中小于一定宽度的所有图像?

Is there a way to delete all images in a folder which are less than a certain width via Windows Batch?

提问人:AL2044 提问时间:11/16/2023 更新时间:11/21/2023 访问量:76

问:

我想编写一个简单的程序,将 Windows 聚光灯图像从它们所在的系统目录提取到一个文件夹中,在那里我可以更轻松地访问它们。到目前为止,我有这个:

@ECHO OFF
if not exist "%homedrive%%homepath%\Downloads\Spotlight" mkdir %homedrive%%homepath%\Downloads\Spotlight
xcopy /s %homedrive%%homepath%\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets\ %homedrive%%homepath%\Downloads\Spotlight
ren %homedrive%%homepath%\Downloads\Spotlight\* *.jpg

它成功地将 spotlight 目录的内容复制到一个新文件夹中,然后重命名所有文件以使其成为 JPG。然而,也出现了一些杂项图标,以及“人像模式”聚光灯图像。我想通过检查输出文件夹中的每个 .jpg 来删除它们,看看它的宽度是否小于 1920 像素,如果是,则删除图像。

我去找 AI 试图解决我的问题,但失败了:

set "SpotlightFolder=%USERPROFILE%\Downloads\Spotlight"
:: Iterate over all .jpg files and delete those with width smaller than 1920 pixels
for %%F in ("%SpotlightFolder%\*.jpg") do (
    for /f %%W in ('powershell -command "& {(Get-ImageDimensions '%%~F').Width}"') do set "Width=%%W"
    if !Width! lss 1920 (
        echo Deleting: %%~nxF
        del "%%F"
    ) else (
        echo Keeping: %%~nxF
    )
)

:: PowerShell script to get image dimensions
<#
function Get-ImageDimensions {
    param([string]$filePath)
    $image = [System.Drawing.Image]::FromFile($filePath)
    $width = $image.Width
    $image.Dispose()
    $width
}
#>

这将返回模糊的“命令的语法不正确”错误,并删除文件夹中的所有图像,而不考虑尺寸。 任何帮助将不胜感激。

Windows PowerShell 批处理文件 命令行

评论

0赞 Stephan 11/16/2023
是什么让你认为,Poweshell 可以访问批处理脚本的一部分?
0赞 Compo 11/16/2023
顺便说一句,您的第一次代码提交可能会减少到只有 1 个。2. .XCopy 将创建目标(如果该目标尚不存在),并且该目标上有一个尾部反斜杠。(这是唯一需要对目录使用尾部反斜杠的情况之一)。@%SystemRoot%\System32\xcopy.exe "%LocalAppData%\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets" "%UserProfile%\Downloads\Spotlight\"@Ren "%UserProfile%\Downloads\Spotlight\*" *.jpg

答:

1赞 lit 11/16/2023 #1

下面是一个 .bat 文件脚本,它将删除宽度小于 1000 的 .jpeg 文件。 编辑 PICDIR 并根据自己的喜好MIN_WIDTH值。当您对将删除正确的文件感到满意时,请从命令中删除 。-WhatIfRemove-Item

SET "PICDIR=%USERPROFILE%\Pictures"
SET "MIN_WIDTH=1000"
pwsh -NoLogo -NoProfile -Command ^
    "Add-Type -AssemblyName System.Drawing;" ^
    "$PicDir = '"%PICDIR%"';" ^
    "Get-ChildItem -File -Path $PicDir -Filter '*.jpeg' |" ^
        "ForEach-Object {" ^
            "$Image = [System.Drawing.Image]::FromFile($_.FullName);" ^
            "if ($Image.Width -lt %MIN_WIDTH%) { $_ };" ^
            "$Image.Dispose();" ^
        "} |" ^
        "Remove-Item -WhatIf;"

评论

0赞 AL2044 11/17/2023
我已经尝试过此选项,我需要将“pwsh”换成“powershell”......除此之外,当我运行 .bat 文件时,命令只是打印出来,什么都不做。我很困惑;它不显示错误,但不会删除任何内容。powershell -NoLogo -NoProfile -Command “$PicDir = '”C:\Users\~\Downloads\Spotlight“';”“Get-ChildItem -File -Path $PicDir -filter '*.jpeg' |”“ForEach-Object {” “$Image = [System.Drawing.Image]::FromFile($_.全名);”“if ($Image.Width -lt 1900) { $_ };”“$Image.Dispose();”"} |"“删除项;”
0赞 lit 11/17/2023
哦,你使用的是较旧的 Windows PowerShell,而不是 PowerShell Core。如果您还从中移除开关会发生什么?-FileGet-ChildItem
0赞 phuclv 11/18/2023
@lit存在于 PowerShell 中,因此它应该可以工作-File
0赞 AL2044 11/21/2023
我得到System.Drawing.Image is not found...
0赞 lit 11/21/2023
尝试添加语句。Windows PowerShell 可能需要我,但当前的 PowerShell Core 不需要。github.com/powershell/powershellAdd-Type
0赞 phuclv 11/16/2023 #2

使用可能不是很有效,因为它实际上解码和加载了整个图像。可以使用 Shell COM 对象Folder.GetDetailsOf() 方法直接访问元数据,因此获取图像的宽度非常便宜。下面是一个简单的 PowerShell 脚本,用于执行所需的操作:Here's a simple PowerShell script to do what you want:System.Drawing.Image

$minWidth = 1920
$SpotlightFolder = "${env:USERPROFILE}\Downloads\Spotlight"

$widthColumnNum = 176 # or 165 or some other value, see below for details
$shell = New-Object -COMObject Shell.Application
$shellfolder = $shell.Namespace($SpotlightFolder)

Get-ChildItem -Filter *.jpg $SpotlightFolder | Where-Object {
    $shellfile = $shellfolder.ParseName($_.Name)
    $w = $shellfolder.GetDetailsOf($shellfile, $widthColumnNum)
    [int]([regex]::Match($w, "\d+").Value) -lt $minWidth
} | Remove-Item -WhatIf

基本上,这将列出指定路径中的所有*.jpg文件,过滤小于传递给的文件。删除执行实际删除的选项Width$minWidthRemove-Item-WhatIf

第 165 列是从这里取自的魔术,或者基于的第 176 列。可以在 Shell32.Folder.GetDetailsOf(..,..) 中运行哪些选项中的 PowerShell 脚本,以查找系统上的实际值,以防它不同:

$objFolder = (New-Object -ComObject Shell.Application).Namespace('c:\')
for ($columnNumber = 0; $columnNumber -lt 500; ++$columnNumber) 
{ 
    $columnName = $objFolder.GetDetailsOf($objFolder.Items, $columnNumber) 
    if ($columnName)
    {
        Write-Output "$(([string]$columnNumber).PadLeft(3)) $columnName"
    }
}

我已经在我的 PC 上测试了它并且它可以工作,图像宽度是预期的字段 176。当然,您也可以自动使用该方法来获取该神奇数字,但我在这里保持简单

有关元数据读取的详细信息,请查看

由于它使用 COM 对象,因此可以从支持 COM 对象的任何语言(例如 JS、VBS 或混合 VBS/混合 JS)调用它

评论

0赞 AL2044 11/17/2023
这会导致错误:无法将值“74d5cee167e1e31f11aa84294db43c2b06815f160af6325907c04f13fda1a379.jpg”转换为类型“System.Int32”。错误:“输入字符串的格式不正确。在 C:\Users\\Downloads\remove.ps1:10 char:5 + [int]($shellfolder。GetDetailsOf($shellfile, $widthColumnNum)) -lt ... + CategoryInfo : InvalidArgument: (:) [], RuntimeException + FullyQualifiedErrorId : InvalidCastFromStringToInteger 我在网上看到类似的结果,但没有提到 JPG。
0赞 phuclv 11/18/2023
@AL2044我已经修复了脚本,它在我的 PC 上运行良好。确保列号和路径正确无误