Functions/GenXdev.AI/Invoke-ImageKeywordScan.ps1
################################################################################ <# .SYNOPSIS Scans image files for keywords and descriptions using metadata files. .DESCRIPTION Searches for image files (jpg, jpeg, png) in the specified directory and its subdirectories. For each image, checks associated description.json and keywords.json files for metadata. Can filter images based on keyword matches and display results in a masonry layout web view or return as objects. .PARAMETER Keywords Array of keywords to search for. Supports wildcards. If empty, returns all images with any metadata. .PARAMETER ImageDirectory Directory path to search for images. Defaults to current directory. .PARAMETER PassThru Switch to return image data as objects instead of displaying in browser. .EXAMPLE Invoke-ImageKeywordScan -Keywords "cat","dog" -ImageDirectory "C:\Photos" .EXAMPLE findimages cat,dog "C:\Photos" #> function Invoke-ImageKeywordScan { [CmdletBinding()] [Alias("findimages")] param( ############################################################################### [Parameter( Mandatory = $false, Position = 0, HelpMessage = "The keywords to look for, wildcards allowed." )] [string[]] $Keywords = @(), ############################################################################### [Parameter( Mandatory = $false, Position = 1, HelpMessage = "The image directory path." )] [string] $ImageDirectory = ".\", ############################################################################### [Parameter( Mandatory = $false, Position = 2, HelpMessage = "Don't show the images in the web browser, return as object instead." )] [switch] $PassThru ) begin { # convert relative path to absolute path $path = Expand-Path $ImageDirectory Write-Verbose "Scanning directory: $path" # validate directory exists before proceeding if (-not [System.IO.Directory]::Exists($path)) { Write-Host "The directory '$path' does not exist." return } } process { # search for jpg/jpeg/png files and process each one $results = Get-ChildItem -Path "$path\*.jpg", "$path\*.jpeg", "$path\*.png" ` -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object { $image = $PSItem.FullName Write-Verbose "Processing image: $image" $keywordsFound = @() $descriptionFound = $null # try to load description metadata if it exists if ([System.IO.File]::Exists("$($image):description.json")) { try { $descriptionFound = [System.IO.File]::ReadAllText( "$($image):description.json") | ConvertFrom-Json $keywordsFound = ($null -eq $descriptionFound.keywords) ? @() : $descriptionFound.keywords } catch { $descriptionFound = $null } } # try to load and merge keywords metadata if it exists if ([System.IO.File]::Exists("$($image):keywords.json")) { try { $keywordsFound = [System.IO.File]::ReadAllText( "$($image):keywords.json") | ConvertFrom-Json # merge keywords into description if needed if ($null -eq $descriptionFound.keywords) { Add-Member -NotePropertyName "keywords" ` -InputObject $descriptionFound ` -NotePropertyValue $keywordsFound -Force | Out-Null [System.IO.File]::Delete("$($image):keywords.json") $descriptionFound | ConvertTo-Json -Depth 99 -Compress ` -WarningAction SilentlyContinue | Set-Content "$($image):description.json" } } catch { $keywordsFound = @() } } # skip if no metadata and no search keywords if ( ($null -eq $Keywords -or ($Keywords.Length -eq 0)) -and ($null -eq $keywordsFound -or ($keywordsFound.length -eq 0)) -and ($null -eq $descriptionFound) ) { return } # check if keywords match metadata $found = ($null -eq $Keywords -or ($Keywords.Length -eq 0)) if (-not $found) { $descriptionFound = $null -ne $descriptionFound ? $descriptionFound : "" | ConvertTo-Json -Compress -Depth 10 -WarningAction SilentlyContinue foreach ($requiredKeyword in $Keywords) { $found = "$descriptionFound" -like $requiredKeyword if (-not $found) { if ($null -eq $keywordsFound -or ($keywordsFound.Length -eq 0)) { continue } foreach ($imageKeyword in $keywordsFound) { if ($imageKeyword -like $requiredKeyword) { $found = $true break } } } if ($found) { break } } } # return matching image data if ($found) { Write-Verbose "Found matching image: $image" @{ path = $image keywords = $keywordsFound description = $descriptionFound } } } } end { if ($PassThru) { $results } else { if ((-not $results) -or ($null -eq $results) -or ($results.Length -eq 0)) { if (($null -eq $Keywords) -or ($Keywords.Length -eq 0)) { Write-Host "No images found." } else { Write-Host "No images found with the specified keywords." } return } # generate unique temp file path for masonry layout $filePath = Expand-Path "$env:TEMP\$([DateTime]::Now.Ticks)_images-masonry.html" # set file attributes to temporary and hidden try { Set-ItemProperty -Path $filePath -Name Attributes ` -Value ([System.IO.FileAttributes]::Temporary -bor ` [System.IO.FileAttributes]::Hidden) ` -ErrorAction SilentlyContinue } catch {} # generate and display results in browser GenerateMasonryLayoutHtml -Images $results -FilePath $filePath Open-Webbrowser -NewWindow -Url $filePath -FullScreen } } } ################################################################################ |