【问题标题】:Writing a script to copy images of certain dimensions编写脚本以复制特定尺寸的图像
【发布时间】:2019-06-14 16:09:15
【问题描述】:

我要做的是让一个脚本在照片目录(即 C:\user\userid\Pictures)中运行,包括子目录,并复制大于 LxH 尺寸(即 1920x1080)的目录进入另一个文件夹(即 C:\user\userid\Destination)。这将在一台 Windows 机器上运行,它的主文件夹中有超过 100 万张照片和 300 多个子目录。速度对我来说不是问题(任何事情都比手动浏览每个子目录要快),所以即使是需要数天才能完成的事情也绰绰有余。

所以算法可能看起来像这样:

Function findLargeImages(curr, dest):
    For each file/folder in curr:
        if file:
            if file is image:
                if (image.width >= ####) AND (image.height >= ####)
                    copy image to dest
        else if folder:
            findImage(folder, dest)
    return (the sound of happiness)

但我可能完全错过了使用脚本语言的意义。

我已经看到 Powershell 有一个 Copy-ItemGet-ChildItem,但我不知道如何使用它们,因为我对 Powershell 的了解是它是蓝色的并且“替换”了命令行。我缺乏安全遍历文件系统和获取某种属性来确定图像高度/宽度的知识。

Powershell 是我开始研究这个时遇到的第一件事,但如果它可以在 Windows 上运行,那我会非常高兴。如果需要,我可以轻松安装大多数其他语言并运行该代码。如果已经有一些软件可以做到这一点,那么你的 Google-fu 比我的要好得多。

如果我设法丢失了我的登录信息,非常感谢任何提前提供帮助的人!

【问题讨论】:

标签: powershell scripting


【解决方案1】:

您可以使用 .NET System.Drawing.Image 类来做到这一点:

$source      = 'C:\user\userid\Pictures'
$destination = 'C:\user\userid\Destination'
$maxWidth    = 1920
$maxHeight   = 1080

# if the destination path does not exist, create it
if (!(Test-Path -Path $destination -PathType Container)) {
    New-Item -Path $destination -ItemType Directory | Out-Null
}

# Add System.Drawing assembly
Add-Type -AssemblyName System.Drawing

Get-ChildItem -Path $source -File -Recurse | ForEach-Object {
    # capture the full filename so we can use it in the catch block
    $fileName = $_.FullName
    # Open image file
    try {
        $img = [System.Drawing.Image]::FromFile($fileName)
        # use '-ge'  if you want to copy files with a width and/or height Greater Or Equal To the max dimensions
        # use '-and' if you want to copy files where both the Width and the Height exceed the max dimensions
        if ($img.Width -gt $maxWidth -or $img.Height -gt $maxHeight) {
            $_ | Copy-Item -Destination $destination -Force
        }
    }
    catch {
        Write-Warning "Could not open file '$fileName'. Not an image file?"
    }
}

【讨论】:

  • 感谢您的帮助西奥!正如我问德鲁,在某些子目录中有视频文件会损害程序吗?我可以用-ge 替换-gt 以获得大于或等于符号,以及用-and 替换-or 吗?
  • @TheMediocreProgrammer 我在代码中添加了一个try{..} catch{..} 块来跳过不是图像的文件。我还对使用-ge-gt 以及您是否想要-or-and 发表了一些评论。
  • 我的作品很棒。但是,出于某种原因,警告不会显示文件名。 WARNING: Could not open file ''. Not an image file?" 弹出很好,但没有给出文件名。我在其中一个文件夹(包括各种子文件夹和视频)上对其进行了测试,它运行得又快又轻松。非常感谢!
  • @TheMediocreProgrammer 啊,是的,对不起,我的错。在catch{..} 块内,自动变量$_ 不再是FileInfo 对象,而是ErrorRecord 对象。该对象当然描述了已发生的错误并且没有文件的FullName 属性。我已经编辑了我的代码以捕获文件名,以便我们可以在 catch 块中使用它。
  • 是的,我的意思是告诉你,我认为 $_ 不再在范围内。我一夜之间运行它,醒来后看到一个大小合适的图像文件夹。你为我节省了数周的手工整理工作。我还设法编辑它以允许在我选择的日期范围内的文件。再次感谢您!
【解决方案2】:

至少你的例子中有逻辑。我怀疑大多数人会为你敲一些东西。

我假设您不知道如何将代码编写到此任务所需的级别,请花点时间学习和理解以下解决方案。如有需要,请提出问题。

# Parent Directory
$Directory = "C:\user\userid\" 

# This includes any folders with the word Pictures in the file path
$Folders = Get-ChildItem -Dir $Directory -Recurse -Include "*Pictures*"
$objShell = New-Object -ComObject Shell.Application

Foreach($Folder in $Folders) {
    $objFolder = $objShell.namespace($Folder.FullName)
    Foreach ($file in $objFolder.Items()){

        # Index 31 is the Dimensions in the metadata
        # Splits it as it returns 3880 x 5184 as an example
        $Dimensions = $objFolder.getDetailsOf($File, 31) -split ' x '
        # Index 165 is the Extension in the metadata, e.g. ".JPG"
        $FileType = $objFolder.getDetailsOf($File, 165)

        # If 3880 is greater than or equal to 1920 AND 5184 is greater than or equal to 1080
        If(($Dimensions[0] -ge 1920) -and ($Dimensions[1] -ge 1080) -and ($FileType -in ('.jpg','.png'))) {
            Copy-Item -Path $File.Path -Destination 'C:\user\userid\Destination' 
        }
    } 
}

【讨论】:

  • 非常感谢德鲁!我还没有时间运行这个,但我确实有几个问题。我需要扫描每个文件夹,所以我可以将*Pictures* 替换为* 作为通用通配符吗?此外,某些文件夹也可能包含视频文件。这会损害程序,还是因为它们没有 Dimension 属性而无关紧要?
  • 要包含$Directory 的所有子文件夹,请删除-Include "*Pictures*"。我已经更新了代码,以便您可以包含文件类型。
猜你喜欢
  • 2017-05-21
  • 1970-01-01
  • 2017-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多