PowerShell Wrapper for GIMP and ImageMagick

I have a lot of photos that are scanned from 35mm slides and negatives. To make sifting through them faster and easier, I've written some scripts in GIMP Script-Fu and PowerShell, also using ImageMagick for Windows.





Function ConvertImages([parameter(Mandatory=$false)][string]$SourcePath, [parameter(Mandatory=$false)][string]$DestPath, [parameter(Mandatory=$false)][string]$SourceType, [parameter(Mandatory=$false)][string]$NewType,[parameter(Mandatory=$false)][bool]$FoldersOnly=$false, [parameter(Mandatory=$false)]$SourceFrame, [parameter(Mandatory=$false)][int]$Resize="100")
{
$
UnprocessedItems = @()
Write-Debug "Starting ConvertImages()"
#Check for required parameters before starting. if ($DestPath -ne $null)
{
#Create $DestPathr if it doesn't already exist Write-Debug "Checking for presence of $DestPath"
if (!(Test-Path -path $DestPath))
{
Write-Host "Info: Creating DestPath $DestPath"
New-Item $DestPath -type directory
}
else
{
write-Verbose "DestPath $DestPath already exists."
}
}

if ($FoldersOnly -ne $true)
{
Write-Debug "FoldersOnly is $FoldersOnly. Proceeding to process images."

#Check for required parameters before starting. if (($SourceType -ne $Null) -and ($NewType -ne $null) -and ($SourcePath -ne $null) -and ($DestPath -ne $null))
{
Write-Debug "Found required parameters $SourceType $NewType $SourcePath $DestPath"

#$NewType = "." + $NewType $ChildSourceItems = $null #Contains an array of files found in $OrigRoot $Item = $null #used to iterate through arrays of items
Write-Verbose "This scripts takes all the files in $SourcePath, converts them to $NewType, and stores them in $DestPath, creating the folder if it doesn't already exist."


#Fail gently if $SourcePath doesn't exist. Write-Debug "Checking for presence of $SourcePath"
if (!(Test-Path -path $SourcePath))
{
Write-Error "SourcePath $SourcePath doesn't exist! Exiting."
return $false
} else {
Write-Verbose "SourcePath $SourcePath exists."
}

#Call DoConversion to perform conversion Write-Debug "Calling DoConversion $SourcePath $SourceFrame $DestPath $NewType $Resize"
$
UnprocessedItems = $UnprocessedItems + (DoConversion $SourcePath $SourceFrame $DestPath $SourceType $NewType $Resize)


} Else
{
Write-Error "Required Parameters were null! Exiting."
Return $UnprocessedItems
}
}
Return $UnprocessedItems
}
Function DoConversion ([parameter(Mandatory=$true)][string]$SourcePath, [parameter(Mandatory=$false)]$SourceFrame, [parameter(Mandatory=$true)][string]$DestPath, [parameter(Mandatory=$true)][string]$SourceType, [parameter(Mandatory=$true)][string]$NewType, [parameter(Mandatory=$false)][int]$Resize="100")
{
Write-Debug "Entering DoConversion()"

$
MagickSourceTypes = @("jpg", "jpeg", "cr2", "png", "tif", "tiff"); #Array of filetypes to be handled by ImageMagick $ScriptFuSourceTypes = @("xcf"); #Array of filetypes to be handled by GIMP Script-Fu $UseMagick = $false #Boolean flag indicating whether we should use ImageMagick or not. $UseScriptFu = $false #Boolean flag indicating whether we should use GIMP Script-Fu or not. $GimpSourcePath ="" #Gimp Source Paths must have double back-slashes in Windows $NumItems
$
UnprocessedItems = @()

Write-Verbose "I will convert from $MagickSourceTypes using ImageMagick and $ScriptFuSourceTypes using GIMP Script-Fu."
Write-Debug "Getting Child Items of $SourcePath"
$
ChildSourceItems = Get-ChildItem -Path $SourcePath
$
NumItems = $ChildSourceItems.length
Write-Verbose "Found $NumItems items. "
#Verify that we have some files to work with. if ($NumItems -gt 0)
{

#Loop through and act on each file individually. Can't glob this part I'm afraid (ImageMagick globbing limitations on output file naming). Write-Debug "Looping through Child Items"
ForEach ($Item in $ChildSourceItems)
{
$
ItemType = $Item.extension.TrimStart(".")
$
ItemFullName = $Item.Fullname

if ($ItemType)
{

$
ItemNewName = $DestPath + "\" + $Item.Name.Replace($ItemType, $NewType)


#If the current item is the type we're expecting, figure out if we'll use ImageMagick or Script-Fu if (($SourceType -eq $ItemType) -and ($MagickSourceTypes -contains $ItemType)) #Check to see if this is a type we should handle with ImageMagick {

$
UseMagick = $True

Write-Verbose "Item Type $ItemType will be converted to $NewTYpe and resized to $Resize% using ImageMagick."
Write-Verbose "Info: Converting $ItemFullName to $ItemNewName"


if (!(Test-Path -path $ItemNewName))
{

#Appending the desired Source Frames to the source filename for ImageMagick to interpret If ($SourceFrame -ne $null)
{
Write-Verbose "Processing Frame $SourceFrame only."

#Single Frame/Layer/Page $ItemFullName = $ItemFullName + "[" + [string]$SourceFrame + "]"


} Else
{
Write-Verbose "Processing and Merging All Frames."

#Multiple Frames/Layers/Pages $ItemFullName = $ItemFullName + "[0--1]"

}

$
MagickParams = @($ItemFullName, "-layers", "merge", "-resize", "$Resize%", $ItemNewName)
$
MagickConvert = "convert"

Write-Debug "Calling $MagickConvert $MagickParams"

& $MagickConvert $MagickParams



} Else
{
Write-Warning "$ItemNewName already exists. Not overwriting."
$
UnprocessedItems = $UnprocessedItems + $Item
}

}
ElseIf (($SourceType -eq $ItemType) -and ($ScriptFuSourceTypes -contains $ItemType)) #Check to see if this is a type we should handle with ScriptFu {
Write-Verbose "$ItemFullName should be processed using GIMP Script-Fu."
$
UseScriptFu = $True
}
Else
{
#Unknown File Type Write-Warning "$ItemType won't be converted to $NewType. Not being processed with ImageMagick or GIMP."
}


}

} #EndForEach loop through items
if ($UseScriptFu -eq $true)
{
Write-Debug "Preparing Script-Fu"
if ($UseMagick -eq $true) { Write-Warning "$SourcePath Matches both ImageMagick and Script-Fu Source Types. Some files may be converted twice and overwritten." }

$
GimpifiedSourcePath = $SourcePath -replace("\\", "\\")
$
Gimp = "gimp-console-2.6.exe"

if (($NewType -eq "jpg") -OR ($NewType -eq "jpeg"))
{
$
GimpParams = @("-i", "-b", "`"(batch-save-as-jpg \`"$GimpifiedSourcePath\\*.*\`" $Resize)`"", "-b", "`"(gimp-quit 0)`"")
Write-Verbose "Calling $GIMP $GimpParams"
#& $GIMP $GimpParams $p = [diagnostics.process]::Start($Gimp, $GimpParams)
$
p.WaitForExit()


}
ElseIf ($NewType -eq "png")
{
$
GimpParams = @("-i", "-b", "`"(batch-save-as-png \`"$GimpifiedSourcePath\\*.*\`" $Resize)`"", "-b", "`"(gimp-quit 0)`"")
Write-Verbose "Calling $GIMP $GimpParams"
#& $GIMP $GimpParams $p = [diagnostics.process]::Start($Gimp, $GimpParams)
$
p.WaitForExit()

} Else
{

Write-Warning "Cannot convert $ItemType to $NewType using Script-Fu."
$
UnprocessedItems = $UnprocessedItems + $ChildSourceItems

}


#Move GIMP'd files to $DestPath Write-Debug "Getting Child Items of $SourcePath\*$NewType"
$
ChildNewItems = Get-ChildItem "$SourcePath\*.*" -include "*$NewType"
Write-Debug "Found $ChildItems.Length Items."

if ($ChildNewItems.Length -gt 0) {

Write-host "Looping through New Child Items"

ForEach ($Item in $ChildNewItems) {

$
ItemNewName = $DestPath + "\" + $Item.Name
Write-Verbose "$Item.FullName should move to $ItemNewName."

if (Test-Path $ItemNewName) {
Write-Warning "$ItemNewName already exists.!"
$
UnprocessedItems = $UnprocessedItems + $Item
} Else {
Write-Host "Info: Moving Gimpified $Item to $DestPath."
Move-Item $Item.Fullname $DestPath
}

}

} Else {
Write-Warning "Found No New $NewType Items in $SourcePath. Something must have gone wrong in GIMP."
}

}

} Else
{
#Fail Gracefully Write-Error "There were no files in $SourcePath to process."
}
return $UnprocessedItems;
}



Here's a sample PowerShell script showing how to invoke the ConvertImages() function defined above. In this example, I build an array of dictionary objects, each containing the parameters to ConvertImages. This way I can write one script like this for all the folders of images in a project (like all my rolls of film from a recent trip to India), and have it batch process all the images.



$Params=@(
# PREPARE RAW TIF FOLDERS @{DestPath="Z:\media\images\test\raw_tif\"; FoldersOnly=$True},

# now go scan files and put them in the new raw tif folder
# GENERATE RAW JPG @{SourcePath="Z:\media\images\test\raw_tif\"; DestPath="Z:\media\images\test\raw_jpg_1600\"; SourceType="tif"; NewType="jpg"; SourceFrame=0; Resize=25; FoldersOnly=$False},

# GENERATE RAW PNG @{SourcePath="Z:\media\images\test\raw_tif\"; DestPath="Z:\media\images\test\raw_png_120"; SourceType="tif"; NewType="png"; SourceFrame=0; Resize=2.5; FoldersOnly=$False},

# GENERATE RAW XCF @{SourcePath="Z:\media\images\test\raw_tif\"; DestPath="Z:\media\images\test\raw_xcf"; SourceType="tif"; NewType="xcf"; SourceFrame=0; Resize=100; FoldersOnly=$False},

# now go edit some of those XCFs and save them in final_xcf
# GENERATE FINAL JPG from edited XCF @{SourcePath="Z:\media\images\test\final_xcf\"; DestPath="Z:\media\images\test\final_jpg"; SourceType="xcf"; NewType="jpg"; SourceFrame=0; Resize=100; FoldersOnly=$False},

# GENERATE Final PNG 120 from edited XCF @{SourcePath="Z:\media\images\test\final_xcf\"; DestPath="Z:\media\images\test\final_png_120"; SourceType="xcf"; NewType="png"; SourceFrame=0; Resize=2.5 FoldersOnly=$False},
)
Write-Verbose "We have " $params.count "entries in Params."

$
Params | ForEach {
Write-Host "Running ConvertImages " -SourcePath $_.'SourcePath' -DestPath $_.'DestPath' -SourceType $_.'SourceType' -NewType $_.'NewType' -SourceFrame $_.'SourceFrame' -Resize $_.'Resize' -FoldersOnly $_.'FoldersOnly' $UnprocessedItems = $UnprocessedItems + (ConvertImages -SourcePath $_.'SourcePath' -DestPath $_.'DestPath' -SourceType $_.'SourceType' -NewType $_.'NewType' -SourceFrame $_.'SourceFrame' -Resize $_.'Resize' -FoldersOnly $_.'FoldersOnly')}
ForEach ($Item in $UnprocessedItems) {

if ($Item.FullName -gt 0) { Write-Warning $Item.FullName }

}

No comments:

Post a Comment