Powershell - скрипт для сортировки фотографий по размерам, имеющий проблемы с оценкой "чисел"

Я пытаюсь написать скрипт Powershell для сортировки тысяч фотографий в соответствующие папки по ширине их изображения.

Мне бы хотелось:

  • фотографии шириной до 300px классифицируются как маленькие.
  • фотографии размером от 301 до 799 пикселей классифицируются как средние.
  • фотографии размером 800px и выше должны быть классифицированы как большие.

Я нашел эту замечательную функцию, которую я использую: статья MS technet

Проблема в том, что у Powershell, похоже, возникают проблемы с правильной оценкой чисел / изображений шириной более 1000 пикселей.

Код, который у меня есть, здесь (по общему признанию, не очень красивый / упрощенный):

Function Get-FileMetaData
{
Param([string[]]$folder)
foreach($sFolder in $folder)
{
$a = 0
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.namespace($sFolder)

foreach ($File in $objFolder.items())
{ 
 $FileMetaData = New-Object PSOBJECT
  for ($a ; $a  -le 266; $a++)
   { 
     if($objFolder.getDetailsOf($File, $a))
       {
         $hash += @{$($objFolder.getDetailsOf($objFolder.items, $a))  =
               $($objFolder.getDetailsOf($File, $a)) }
        $FileMetaData | Add-Member $hash
        $hash.clear() 
       } #end if
   } #end for 
 $a=0
 $FileMetaData
} #end foreach $file
} #end foreach $sfolder
} #end Get-FileMetaData

$photodir="C:\photos\"
Get-FileMetaData -folder $photodir | select path,dimensions | 
ForEach-Object -Process {

if ($_.dimensions -ne $null){
$filename=$_.path;
$dimensions=$($_.dimensions);
$dimensions_split=$dimensions.split();
$dimensions_width=$($dimensions_split[0]);

if ($dimensions_width -gt "799"){"$filename is $dimensions_width so is large";"---";}
if (($dimensions_width -lt "800") -and ($dimensions_width -gt "300")){"$filename is     $dimensions_width so is medium";"---";}
if ($dimensions_width -lt "300"){"$filename is $dimensions_width so is small";"---";}

Это дает результаты:

C:\photos\logo1024x1024.jpg is ‪1024 so is small
---
C:\photos\logo128x128.jpg is ‪128 so is small
---
C:\photos\logo1600x1600.jpg is ‪1600 so is small
---
C:\photos\logo1920x1080.jpg is ‪1920 so is small
---
C:\photos\logo512x512.jpg is ‪512 so is medium
---
C:\photos\logo960x960.jpg is ‪960 so is large
---

Так что я подумал, может быть, это проблема, потому что они строки. Что, если я заставлю их быть целыми числами, надеюсь, что Powershell сможет их правильно оценить:

if ([int]$dimensions_width -gt 800){"$filename is $dimensions_width so is large";"---";}

Это дает ошибку:

Cannot convert value "‪1024" to type "System.Int32". Error: "Input string was 
not in a correct format."
At C:\scripts\sort_photos_sm_md_lg.ps1:39 
char:9
+     if ([int]$dimensions_width -gt 799){"$filename is $dimensions_width so 
is la ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger

Что не имеет смысла для меня, так как 1024 выглядит как целое число для меня?

Если я сделаю это таким образом, Powershell понравится синтаксис, но все равно не сможет правильно его оценить:

if (($dimensions_width -as [int]) -gt 799){"$filename is $dimensions_width so is large";"---";}

Несмотря на просмотр нескольких страниц результатов Google, я не могу найти ответ.

Кто-нибудь может помочь?

3 ответа

Решение

Что касается обходного пути, GDI + может использоваться для чтения большого разнообразия метаданных файла. Просто открываем файл какDrawing.Bitmap обеспечивает размеры тоже. Вот так,

# Load the drawing assembly
add-type -assemblyname System.Drawing
# Open the image
$img = new-object Drawing.Bitmap("C:\MyBigImage.jpg")
# Print dimensions
$("w:{0} h:{1}" -f $img.Width, $img.Height)
w:3264 h:2448 # Quite big a picture
# Don't forget to dispose the bitmap
$img.Dispose()

Попробуй это:

$photodir= "C:\photos"
Get-FileMetaData -folder $photodir | select percorso,dimensioni | 
ForEach-Object -Process {
    if ($_.dimensioni -ne $null)
    {
        $filename=$_.percorso;
        $dimensions=$($_.dimensioni);
        $dimensions_width= [int](-join ((( $dimensions -split ' ' )[0]).ToCharArray() )[1..4])
    }

    switch  ($dimensions_width) 
    {
        {$_ -gt 799} {"$filename is $dimensions_width so is large";"---";break}
        {$_ -lt 800 -and $dimensions_width -gt 300} {"$filename is     $dimensions_width so is medium";"---";break}
        default {"$filename is $dimensions_width so is small"; "---";break}
    }
}

Проблема, упомянутая @Raf, является недопустимым символом после разбиения, но это не пробел, а [char][int]8234 значение, которое не зависит от trim() метод.

Скорее всего, вы ведете или преследуете нелегального персонажа внутри $dimensions_width, Вы можете проверить это, повторив $dimensions_width.Length который является количеством символов в строке:

...
$dimensions_width=$($dimensions_split[0]);
Write-Host ("Width " + $dimensions_width + ",Length " + $dimensions_width.Length)

if ($dimensions_width -gt "799")....
....

Если на 1024 вы получите длину больше 4, то так и будет. Пытаться

$dimensions_width=$($dimensions_split[0].Trim() -replace "`n|`r|`t","");

избавиться от пробелов.

Другие вопросы по тегам