Skip to content

Instantly share code, notes, and snippets.

@vt-idiot
Last active June 28, 2023 04:03
Show Gist options
  • Save vt-idiot/f77a4265ea277d7fe2f5aad054ddae2d to your computer and use it in GitHub Desktop.
Save vt-idiot/f77a4265ea277d7fe2f5aad054ddae2d to your computer and use it in GitHub Desktop.
an insane man's script to convert NovelAI and stable-diffusion-webui images to JPG while preserving metadata and file creation/modification dates
<#
.Description
PROOMPT PRESSER 1.3
.PARAMETER Delete
Permenantly erase all input PNGs. Default behavior does not delete input PNGs.
.PARAMETER Recurse
Process subdirectories. Default behavior only processes working directory.
.PARAMETER Quality
JPEG compression level. Defaults to 88 if unset.
.PARAMETER TXT
Keeps a .txt copy of metadata extracted during conversion.
.PARAMETER InstallPS7
Installs PowerShell 7...technically it can update PowerShell 7 for you too.
.INPUTS
PNG images with NovelAI or webui metadata. You cannot pipe .NET objects to this script, it runs on the current directory, and does not recurse subdirectories unless specified.
.OUTPUTS
Compressed JPEG images with preserved metadata.
.EXAMPLE
PS> .\Insanity.ps1
Runs with default settings: converts to JPG at 88 Quality, copies metadata, does not delete input PNGs, does not store a .txt copy of metadata.
.EXAMPLE
PS> .\Insanity.ps1 -Delete
Converts to JPG at 88 Quality, copies metadata, deletes input PNGs.
.EXAMPLE
PS> .\Insanity.ps1 -Delete -TXT -Quality 69
Converts to JPG using 69 Quality, copies metadata, deletes input PNGs, stores an additional .txt copy of metadata.
.EXAMPLE
PS> .\Insanity.ps1 -TXT -Quality 75 -Recurse
Converts all PNGs in current folder AND subfolders to JPG at 75 Quality, copies metadata, stores a .txt copy of metadata.
.LINK
Source : https://gist.github.com/vt-idiot/f77a4265ea277d7fe2f5aad054ddae2d
.LINK
Install ImageMagick : https://imagemagick.org/script/download.php#windows
.LINK
Download exiftool : https://exiftool.org/
.SYNOPSIS
1. Take a folder full of stable-diffusion-webui or NovelAI generated PNGs
2. Compress them to JPG
3. Preserve the prompt metadata
4. Maintain the Date Created/Date Modified from the original PNGs
5. (Optionally) Delete the PNGs
#>
<#PATH REQUIREMENTS
1. imagemagick's "convert", "identify", and "mogrify"
https://imagemagick.org/script/download.php#windows
If installing the .exe, make sure to check "Add application directory to system path"
If using the portable distribution, make sure it's in your PATH
2. exiftool
Download the https://exiftool.org/ "Windows Executable"
"exiftool" has to be "exiftool.exe" - default download is "exiftool(-k).exe" or something, rename it!
#>
<#LIMITATIONS
1. ENSD value likely NOT be correct for images that were img2img/inpainted/upscaled/"enhanced" using NovelAI
2. That's it. Everything else works great now.#>
param(
[Parameter()][switch]$Delete,
[Parameter()][switch]$TXT,
[Parameter()][switch]$InstallPS7,
[Parameter()][switch]$Recurse,
[Parameter()][ValidateRange(0,100)][int]$Quality=88
)
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
CHCP 65001
#halt execution if magick.exe and exiftool.exe not found in $PATH
Write-Host "Checking PATH for ImageMagick"
$magickpath = Get-Command -CommandType Application magick.exe -ErrorAction SilentlyContinue | Select-Object -expandproperty Path
If ($magickpath) {Write-Host "ImageMagick found at" $magickpath}
Else {
Write-Warning -Message 'ImageMagick not found in your PATH, exiting!';throw #Go install ImageMagick!
}
Write-Host "Checking PATH for exiftool"
$exiftoolpath = Get-Command -CommandType Application exiftool.exe -ErrorAction SilentlyContinue | Select-Object -expandproperty Path
If ($exiftoolpath) {Write-Host "exiftool found at" $exiftoolpath}
Else {
Write-Warning -Message 'exiftool not found in your PATH, exiting!';throw #Go install exiftool!
}
if ($Recurse) {$GCI = Get-ChildItem . -Recurse -Filter *.png}
else {$GCI = Get-ChildItem . -Filter *.png}
$PS7 = $PSVersionTable.PSVersion.Major -ge 7
if ($PS7) {
Write-Host "PowerShell" $($PSVersionTable.PSVersion) "detected, parallel execution enabled."
$GCI | ForEach-Object -Parallel {
$Quality = $using:Quality
$Delete = $using:Delete
$TXT = $using:TXT
magick convert "$($_.FullName)" -quality $Quality -define preserve-timestamp=true "$($_.Directory)\$($_.BaseName).jpg"
#uses ImageMagick "identify" to read webui prompt
$comments = magick identify -format '%[Parameters]' -verbose "$($_.FullName)" 2>$null
if (-not $comments) {
Write-Host -ForegroundColor Red $_ "either contained Unicode characters in the proompt, or was a NovelAI file, buckle up."
$NAIerror = magick identify -format '%[Description]' -verbose "$($_.FullName)" 2>$null
$NAItitle = magick identify -format '%[Title]' -verbose "$($_.FullName)" 2>$null
if ($NAIerror) {
Write-Host -ForegroundColor Green $_ "is a NovelAI file with an ANSI prompt."
Write-Host -ForegroundColor Red "Did you use Unicode in your negatives, but not in the prompt? Too bad, this is already disgusting to look at."
mogrify -strip "$($_.Directory)\$($_.BaseName).jpg" #magick convert copies the novelai "comment" which normally contains some JSON formatted prompt parameters, but not the full prompt, we need to delete it
$NAImetadataA = magick identify -format '%[Title]\n%[Description]\n%[Software]\n%[Source]\n%[Comment]' -verbose "$($_.FullName)" 2>$null #read novelai prompt, add linebreaks between tEXt tags
$NAIresolutionA = magick identify -format '%wx%h' "$($_.FullName)" #read novelai resolution
$NAIcommentA = $NAImetadataA -split "`n"
$NAIoutputA += $NAIcommentA[1] + "`n" #put prompt on first line of new output
$jsonDataA = (ConvertFrom-Json $NAIcommentA[4]) #parse that novelai JSON "comment"
$NAIoutputA += "Negative prompt: " + $jsonDataA.uc + "`n" #extract negative prompt
$NAIoutputA += "Steps: " + $jsonDataA.steps + ", " #extract steps
$samplerA = $jsonDataA.sampler #sampler handler, rewrites all 5 novelai sampler options to match webui metadata, ChatGPT actually insisted on the final "else", lol
if ($samplerA -eq "k_euler_ancestral") {
$NAIoutputA += "Sampler: Euler a, "
}
elseif ($samplerA -eq "k_euler") {
$NAIoutputA += "Sampler: Euler, "
}
elseif ($samplerA -eq "ddim") {
$NAIoutputA += "Sampler: DDIM, "
}
elseif ($samplerA -eq "k_lms") {
$NAIoutputA += "Sampler: LMS, "
}
elseif ($samplerA -eq "plms") {
$NAIoutputA += "Sampler: PLMS, "
}
else {
$NAIoutputA += "Sampler: " + $samplerA + ", "
}
#add the rest of the prompt, including the resolution we read from the file
#note - if you upscaled using novelai's "enhance", this won't be very helpful!
#I think changing their noise and strength options while using "enhance" technically changes the ENSD value
#if you still have the base, pre-"enhance" gen, KEEP IT, and use THAT image/prompt/seed for e.g. latent upscaling
#if you did NOT use enhance to upscale, but made a BASE generation at a higher resolution, then YOU SHOULD BE FINE
$NAIoutputA += "CFG scale: " + $jsonDataA.scale + ", Seed: " + $jsonDataA.seed + ", Size: " + $NAIresolutionA + ", "
$stableDiffA = $NAIcommentA[3].Split(" ")[2]
if ($stableDiffA -eq "1D44365E") {
$NAIoutputA += "Model hash: 1d4a34af, Model: animesfw-final-pruned"
}
elseif ($stableDiffA -eq "81274D13") {
$NAIoutputA += "Model hash: 925997e9, Model: animefull-final-pruned"
}
else { $NAIoutputA += "Model hash: Not specified, Model: Not specified" }
#see note beginning on line 65, ENSD value is hard coded, not calculated
$NAIoutputA += ", Clip skip: 2, ENSD: 31337"
$NAIoutputA | Out-File -LiteralPath "$($_.Directory)\$($_.BaseName).txt" -Encoding utf8
exiftool -P "-ExifIFD:UserComment<=$($_.Directory)\$($_.BaseName).txt" "$($_.Directory)\$($_.BaseName).jpg" -overwrite_original
$PNGA = Get-Item -LiteralPath "$($_)"
$JPGA = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGA.CreationTime = $PNGA.CreationTime
$JPGA.LastWriteTime = $PNGA.LastWriteTime
If ($Delete) {Remove-Item -LiteralPath "$($_)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.Directory)\$($_.BaseName).txt"}
If ($TXT) {$NAImetadata | Out-File -LiteralPath "$($_.Directory)\$($_.BaseName).nai.txt" -Encoding utf8}
}
#this might work, it might not, exiftool is stuck in the 20th century and cannot properly see a UTF-8 filename unless it's passed to it via a text file. wonderful! "$($_.Directory)\$($_.BaseName).$(Get-Random).txt"
elseif ($NAItitle) {
Write-Host -ForegroundColor Yellow -NoNewline $_ ; Write-Host -ForegroundColor Red " is a NovelAI File with Unicode in the PROOMPT"
Write-Host -ForegroundColor Green "Now trying exiftool Bodge Job. It's not any better...don't look at the code."
$exiftoolfilenameB = $($_.BaseName) -replace '[^\x30-\x39\x41-\x5A\x61-\x7A]+', ''
$exiftoolfilenameB += "." + $(Get-Random)
Add-Content -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt" -Value $_.FullName -Encoding utf8
$NAIutf = exiftool -charset filename=utf8 -@ "$($_.Directory)\$($exiftoolfilenameB).txt" "-*Description*"
Remove-Item -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt"
$NAIresolutionB = magick identify -format '%wx%h' "$($_.FullName)"
$NAImetadataB = magick identify -format '%[Title]\n\n%[Software]\n%[Source]\n%[Comment]' -verbose "$($_.FullName)" 2>$null
$NAIutf = $NAIutf -split "Description : "
$NAIoutputB = $NAIutf[1] + "`n"
$NAImetadataB = $NAImetadataB -split "`n"
$jsonDataB = (ConvertFrom-Json $NAImetadataB[4])
$NAIoutputB += "Negative prompt: " + $jsonDataB.uc + "`n"
$NAIoutputB += "Steps: " + $jsonDataB.steps + ", "
$samplerB = $jsonDataB.sampler
if ($samplerB -eq "k_euler_ancestral") {
$NAIoutputB += "Sampler: Euler a, "
}
elseif ($samplerB -eq "k_euler") {
$NAIoutputB += "Sampler: Euler, "
}
elseif ($samplerB -eq "ddim") {
$NAIoutputB += "Sampler: DDIM, "
}
elseif ($samplerB -eq "k_lms") {
$NAIoutputB += "Sampler: LMS, "
}
elseif ($samplerB -eq "plms") {
$NAIoutputB += "Sampler: PLMS, "
}
else {
$NAIoutputB += "Sampler: " + $samplerB + ", "
}
$NAIoutputB += "CFG scale: " + $jsonDataB.scale + ", Seed: " + $jsonDataB.seed + ", Size: " + $NAIresolutionB + ", "
$stableDiffB = $NAImetadataB[3].Split(" ")[2]
if ($stableDiffB -eq "1D44365E") {
$NAIoutputB += "Model hash: 1d4a34af, Model: animesfw-final-pruned"
}
elseif ($stableDiffB -eq "81274D13") {
$NAIoutputB += "Model hash: 925997e9, Model: animefull-final-pruned"
}
else { $NAIoutputB += "Model hash: Not specified, Model: Not specified" }
$NAIoutputB += ", Clip skip: 2, ENSD: 31337"
$NAIoutputB | Out-File -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt" -Encoding utf8
Rename-Item "$($_.Directory)\$($_.BaseName).jpg" "$($_.Directory)\$($exiftoolfilenameB).jpg"
mogrify -strip "$($_.Directory)\$($exiftoolfilenameB).jpg"
exiftool -P "-ExifIFD:UserComment<=$($_.Directory)\$($exiftoolfilenameB).txt" "$($_.Directory)\$($exiftoolfilenameB).jpg" -overwrite_original
Rename-Item "$($_.Directory)\$($exiftoolfilenameB).jpg" "$($_.Directory)\$($_.BaseName).jpg"
$PNGB = Get-Item -LiteralPath "$($_)"
$JPGB = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGB.CreationTime = $PNGB.CreationTime
$JPGB.LastWriteTime = $PNGB.LastWriteTime
If ($Delete) {Remove-Item -LiteralPath "$($_)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt"}
ElseIf ($TXT) {Rename-Item "$($_.Directory)\$($exiftoolfilenameB).txt" "$($_.Directory)\$($_.BaseName).txt"}
}
elseif (-not $NAItitle) {
Write-Host -ForegroundColor Red "Unicode Parsing Error For ASSUMED webui File " -NoNewline; Write-Host -ForegroundColor Yellow $_
Write-Host -ForegroundColor Green "Now trying exiftool Bodge Job. It's not any better...don't look at the code."
$exiftoolfilenameC = $($_.BaseName) -replace '[^\x30-\x39\x41-\x5A\x61-\x7A]+', ''
$exiftoolfilenameC += "." + $(Get-Random)
Add-Content -LiteralPath "$($_.Directory)\$($exiftoolfilenameC).txt" -Value $_.FullName -Encoding utf8
$webuiutf = exiftool -charset filename=utf8 -@ "$($_.Directory)\$($exiftoolfilenameC).txt" "-*parameters*"
$webuisplit = $webuiutf -split "Parameters : "
$webuineg = $webuisplit -split "Negative prompt: "
$webuisteps = $webuineg -split "Steps: "
$webuiout = $webuisteps[1] + "`n" + "Negative prompt: " + $webuisteps[2] + "`n" + "Steps: " + $webuisteps[3]
$webuiout | Out-File -LiteralPath "$($_.Directory)\$($exiftoolfilenameC).txt" -Encoding utf8
Rename-Item "$($_.Directory)\$($_.BaseName).jpg" "$($_.Directory)\$($exiftoolfilenameC).jpg"
exiftool -P "-ExifIFD:UserComment<=$($_.Directory)\$($exiftoolfilenameC).txt" "$($_.Directory)\$($exiftoolfilenameC).jpg" -overwrite_original
Rename-Item "$($_.Directory)\$($exiftoolfilenameC).jpg" "$($_.Directory)\$($_.BaseName).jpg"
$PNGC = Get-Item -LiteralPath "$($_)"
$JPGC = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGC.CreationTime = $PNGC.CreationTime
$JPGC.LastWriteTime = $PNGC.LastWriteTime
If ($Delete) {Remove-Item -LiteralPath "$($_)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.Directory)\$($exiftoolfilenameC).txt"}
ElseIf ($TXT) {Rename-Item "$($_.Directory)\$($exiftoolfilenameC).txt" "$($_.Directory)\$($_.BaseName).txt"}
}
else {Write-Host -ForegroundColor Red "HELLO LINK, I AM ERROR"}
}
#webui ansi prompt handling
elseif ($comments) {
Write-Host -ForegroundColor Green $_ "is a webui PNG with purely ANSI metadata."
$comments | Out-File -LiteralPath "$($_.FullName).txt" -Encoding utf8 #write prompt to txt for exiftool
exiftool -P "-ExifIFD:UserComment<=$($_.FullName).txt" "$($_.Directory)\$($_.BaseName).jpg" -overwrite_original #set exif comment
$PNGD = Get-Item -LiteralPath "$($_)"
$JPGD = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGD.CreationTime = $PNGD.CreationTime #set date created to match png
$JPGD.LastWriteTime = $PNGD.LastWriteTime #set date modified to match png
If ($Delete) {Remove-Item -LiteralPath "$($_)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.FullName).txt"}
}
else {
#This exception will actually never be caught. I couldn't think of any other way to catch webui Unicode parameters. If you see actually see this error below, congratulations. You win!
Write-Host -ForegroundColor Red "Unspecified Error for File " -NoNewline; Write-Host -ForegroundColor Yellow $_
Write-Host -ForegroundColor DarkRed "Maybe it doesn't have metadata? Wait, this error is supposed to be impossible to trigger..."
Write-Host -ForegroundColor Green "Screw exiftool and ImageMagick anyways. And PowerShell. And everything. Why did I think this was a good idea?"
Rename-Item -LiteralPath $($_.Directory)\$($_.BaseName).jpg $($_.Directory)\Metadata-Error-$($_.BaseName).jpg
}
}
}
else {
Write-Host "PowerShell" $($PSVersionTable.PSVersion) "does not support parallel ForEach-Object execution. Will run single threaded and a bit more slowly. Run with `"-InstallPS7`" to download and install PowerShell 7 from Microsoft automatically."
if($InstallPS7) {
Write-Host "Now installing PowerShell 7."
Invoke-Expression "& { $(Invoke-RestMethod https://aka.ms/install-powershell.ps1) } -UseMSI"
throw "Go run it using pwsh.exe"
}
Write-Warning "Keep going, or quit to install PowerShell 7 and run it there?" -WarningAction Inquire
$GCI | ForEach-Object {
magick convert "$($_.FullName)" -quality $Quality -define preserve-timestamp=true "$($_.Directory)\$($_.BaseName).jpg"
#uses ImageMagick "identify" to read webui prompt
$comments = magick identify -format '%[Parameters]' -verbose "$($_.FullName)" 2>$null
if (-not $comments) {
Write-Host -ForegroundColor Red $_ "either contained Unicode characters in the proompt, or was a NovelAI file, buckle up."
$NAIerror = magick identify -format '%[Description]' -verbose "$($_.FullName)" 2>$null
$NAItitle = magick identify -format '%[Title]' -verbose "$($_.FullName)" 2>$null
if ($NAIerror) {
Write-Host -ForegroundColor Green $_ "is a NovelAI file with an ANSI prompt."
Write-Host -ForegroundColor Red "Did you use Unicode in your negatives, but not in the prompt? Too bad, this is already disgusting to look at."
mogrify -strip "$($_.Directory)\$($_.BaseName).jpg" #magick convert copies the novelai "comment" which normally contains some JSON formatted prompt parameters, but not the full prompt, we need to delete it
$NAImetadataA = magick identify -format '%[Title]\n%[Description]\n%[Software]\n%[Source]\n%[Comment]' -verbose "$($_.FullName)" 2>$null #read novelai prompt, add linebreaks between tEXt tags
$NAIresolutionA = magick identify -format '%wx%h' "$($_.FullName)" #read novelai resolution
$NAIcommentA = $NAImetadataA -split "`n"
$NAIoutputA += $NAIcommentA[1] + "`n" #put prompt on first line of new output
$jsonDataA = (ConvertFrom-Json $NAIcommentA[4]) #parse that novelai JSON "comment"
$NAIoutputA += "Negative prompt: " + $jsonDataA.uc + "`n" #extract negative prompt
$NAIoutputA += "Steps: " + $jsonDataA.steps + ", " #extract steps
$samplerA = $jsonDataA.sampler #sampler handler, rewrites all 5 novelai sampler options to match webui metadata, ChatGPT actually insisted on the final "else", lol
if ($samplerA -eq "k_euler_ancestral") {
$NAIoutputA += "Sampler: Euler a, "
}
elseif ($samplerA -eq "k_euler") {
$NAIoutputA += "Sampler: Euler, "
}
elseif ($samplerA -eq "ddim") {
$NAIoutputA += "Sampler: DDIM, "
}
elseif ($samplerA -eq "k_lms") {
$NAIoutputA += "Sampler: LMS, "
}
elseif ($samplerA -eq "plms") {
$NAIoutputA += "Sampler: PLMS, "
}
else {
$NAIoutputA += "Sampler: " + $samplerA + ", "
}
#add the rest of the prompt, including the resolution we read from the file
#note - if you upscaled using novelai's "enhance", this won't be very helpful!
#I think changing their noise and strength options while using "enhance" technically changes the ENSD value
#if you still have the base, pre-"enhance" gen, KEEP IT, and use THAT image/prompt/seed for e.g. latent upscaling
#if you did NOT use enhance to upscale, but made a BASE generation at a higher resolution, then YOU SHOULD BE FINE
$NAIoutputA += "CFG scale: " + $jsonDataA.scale + ", Seed: " + $jsonDataA.seed + ", Size: " + $NAIresolutionA + ", "
$stableDiffA = $NAIcommentA[3].Split(" ")[2]
if ($stableDiffA -eq "1D44365E") {
$NAIoutputA += "Model hash: 1d4a34af, Model: animesfw-final-pruned"
}
elseif ($stableDiffA -eq "81274D13") {
$NAIoutputA += "Model hash: 925997e9, Model: animefull-final-pruned"
}
else { $NAIoutputA += "Model hash: Not specified, Model: Not specified" }
#see note beginning on line 65, ENSD value is hard coded, not calculated
$NAIoutputA += ", Clip skip: 2, ENSD: 31337"
$NAIoutputA | Out-File -LiteralPath "$($_.Directory)\$($_.BaseName).txt" -Encoding utf8
exiftool -P "-ExifIFD:UserComment<=$($_.Directory)\$($_.BaseName).txt" "$($_.Directory)\$($_.BaseName).jpg" -overwrite_original
$PNGA = Get-Item -LiteralPath "$($_.FullName)"
$JPGA = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGA.CreationTime = $PNGA.CreationTime
$JPGA.LastWriteTime = $PNGA.LastWriteTime
If ($Delete) {Remove-Item -LiteralPath "$($_.FullName)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.Directory)\$($_.BaseName).txt"}
If ($TXT) {$NAImetadata | Out-File -LiteralPath "$($_.Directory)\$($_.BaseName).nai.txt" -Encoding utf8}
}
elseif ($NAItitle) {
Write-Host -ForegroundColor Yellow -NoNewline $_ ; Write-Host -ForegroundColor Red " is a NovelAI File with Unicode in the PROOMPT"
Write-Host -ForegroundColor Green "Now trying exiftool Bodge Job. It's not any better...don't look at the code."
$exiftoolfilenameB = $($_.BaseName) -replace '[^\x30-\x39\x41-\x5A\x61-\x7A]+', ''
$exiftoolfilenameB += "." + $(Get-Random)
Add-Content -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt" -Value $_.FullName -Encoding utf8
$NAIutf = exiftool -charset filename=utf8 -@ "$($_.Directory)\$($exiftoolfilenameB).txt" "-*Description*"
Remove-Item -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt"
$NAIresolutionB = magick identify -format '%wx%h' "$($_.FullName)"
$NAImetadataB = magick identify -format '%[Title]\n\n%[Software]\n%[Source]\n%[Comment]' -verbose "$($_.FullName)" 2>$null
$NAIutf = $NAIutf -split "Description : "
$NAIoutputB = $NAIutf[1] + "`n"
$NAImetadataB = $NAImetadataB -split "`n"
$jsonDataB = (ConvertFrom-Json $NAImetadataB[4])
$NAIoutputB += "Negative prompt: " + $jsonDataB.uc + "`n"
$NAIoutputB += "Steps: " + $jsonDataB.steps + ", "
$samplerB = $jsonDataB.sampler
if ($samplerB -eq "k_euler_ancestral") {
$NAIoutputB += "Sampler: Euler a, "
}
elseif ($samplerB -eq "k_euler") {
$NAIoutputB += "Sampler: Euler, "
}
elseif ($samplerB -eq "ddim") {
$NAIoutputB += "Sampler: DDIM, "
}
elseif ($samplerB -eq "k_lms") {
$NAIoutputB += "Sampler: LMS, "
}
elseif ($samplerB -eq "plms") {
$NAIoutputB += "Sampler: PLMS, "
}
else {
$NAIoutputB += "Sampler: " + $samplerB + ", "
}
$NAIoutputB += "CFG scale: " + $jsonDataB.scale + ", Seed: " + $jsonDataB.seed + ", Size: " + $NAIresolutionB + ", "
$stableDiffB = $NAImetadataB[3].Split(" ")[2]
if ($stableDiffB -eq "1D44365E") {
$NAIoutputB += "Model hash: 1d4a34af, Model: animesfw-final-pruned"
}
elseif ($stableDiffB -eq "81274D13") {
$NAIoutputB += "Model hash: 925997e9, Model: animefull-final-pruned"
}
else { $NAIoutputB += "Model hash: Not specified, Model: Not specified" }
$NAIoutputB += ", Clip skip: 2, ENSD: 31337"
$NAIoutputB | Out-File -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt" -Encoding utf8
Rename-Item "$($_.Directory)\$($_.BaseName).jpg" "$($_.Directory)\$($exiftoolfilenameB).jpg"
mogrify -strip "$($_.Directory)\$($exiftoolfilenameB).jpg"
exiftool -P "-ExifIFD:UserComment<=$($_.Directory)\$($exiftoolfilenameB).txt" "$($_.Directory)\$($exiftoolfilenameB).jpg" -overwrite_original
Rename-Item "$($_.Directory)\$($exiftoolfilenameB).jpg" "$($_.Directory)\$($_.BaseName).jpg"
$PNGB = Get-Item -LiteralPath "$($_.FullName)"
$JPGB = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGB.CreationTime = $PNGB.CreationTime
$JPGB.LastWriteTime = $PNGB.LastWriteTime
If ($Delete) {Remove-Item -LiteralPath "$($_.FullName)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.Directory)\$($exiftoolfilenameB).txt"}
ElseIf ($TXT) {Rename-Item "$($_.Directory)\$($exiftoolfilenameB).txt" "$($_.Directory)\$($_.BaseName).txt"}
}
elseif (-not $NAItitle) {
Write-Host -ForegroundColor Red "Unicode Parsing Error For ASSUMED webui File " -NoNewline; Write-Host -ForegroundColor Yellow $_
Write-Host -ForegroundColor Green "Now trying exiftool Bodge Job. It's not any better...don't look at the code."
$exiftoolfilenameC = $($_.BaseName) -replace '[^\x30-\x39\x41-\x5A\x61-\x7A]+', ''
$exiftoolfilenameC += "." + $(Get-Random)
Add-Content -LiteralPath "$($_.Directory)\$($exiftoolfilenameC).txt" -Value $_.FullName -Encoding utf8
$webuiutf = exiftool -charset filename=utf8 -@ "$($_.Directory)\$($exiftoolfilenameC).txt" "-*parameters*"
$webuisplit = $webuiutf -split "Parameters : "
$webuineg = $webuisplit -split "Negative prompt: "
$webuisteps = $webuineg -split "Steps: "
$webuiout = $webuisteps[1] + "`n" + "Negative prompt: " + $webuisteps[2] + "`n" + "Steps: " + $webuisteps[3]
$webuiout | Out-File -LiteralPath "$($_.Directory)\$($exiftoolfilenameC).txt" -Encoding utf8
Rename-Item "$($_.Directory)\$($_.BaseName).jpg" "$($_.Directory)\$($exiftoolfilenameC).jpg"
exiftool -P "-ExifIFD:UserComment<=$($_.Directory)\$($exiftoolfilenameC).txt" "$($_.Directory)\$($exiftoolfilenameC).jpg" -overwrite_original
Rename-Item "$($_.Directory)\$($exiftoolfilenameC).jpg" "$($_.Directory)\$($_.BaseName).jpg"
$PNGC = Get-Item -LiteralPath "$($_.FullName)"
$JPGC = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGC.CreationTime = $PNGC.CreationTime
$JPGC.LastWriteTime = $PNGC.LastWriteTime
If ($Delete) {Remove-Item -LiteralPath "$($_.FullName)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.Directory)\$($exiftoolfilenameC).txt"}
ElseIf ($TXT) {Rename-Item "$($_.Directory)\$($exiftoolfilenameC).txt" "$($_.Directory)\$($_.BaseName).txt"}
}
else {Write-Host -ForegroundColor Red "HELLO LINK, I AM ERROR"}
}
#webui ansi prompt handling
elseif ($comments) {
Write-Host -ForegroundColor Green $_ "is a webui PNG with purely ANSI metadata."
$comments | Out-File -LiteralPath "$($_.FullName).txt" -Encoding utf8 #write prompt to txt for exiftool
exiftool -P "-ExifIFD:UserComment<=$($_.FullName).txt" "$($_.Directory)\$($_.BaseName).jpg" -overwrite_original #set exif comment
$PNGD = Get-Item -LiteralPath "$($_.FullName)"
$JPGD = Get-Item -LiteralPath "$($_.Directory)\$($_.BaseName).jpg"
$JPGD.CreationTime = $PNGD.CreationTime #set date created to match png
$JPGD.LastWriteTime = $PNGD.LastWriteTime #set date modified to match png
If ($Delete) {Remove-Item -LiteralPath "$($_.FullName)"}
If (-not $TXT) {Remove-Item -LiteralPath "$($_.FullName).txt"}
}
else {
#This exception will actually never be caught. I couldn't think of any other way to catch webui Unicode parameters. If you see actually see this error below, congratulations. You win!
Write-Host -ForegroundColor Red "Unspecified Error for File " -NoNewline; Write-Host -ForegroundColor Yellow $_
Write-Host -ForegroundColor DarkRed "Maybe it doesn't have metadata? Wait, this error is supposed to be impossible to trigger..."
Write-Host -ForegroundColor Green "Screw exiftool and ImageMagick anyways. And PowerShell. And everything. Why did I think this was a good idea?"
Rename-Item -LiteralPath $($_.Directory)\$($_.BaseName).jpg $($_.Directory)\Metadata-Error-$($_.BaseName).jpg
}
}
}
@vt-idiot
Copy link
Author

I have only tested this with:

  • PowerShell 7.3.2
  • ImageMagick 7.1.0-58
  • ExifTool 12.55
  • on Windows 10
  • with long filename support enabled...
  • with PowerShell explicitly set to use UTF-8

You need imagemagick in your PATH for this to work.

https://imagemagick.org/script/download.php#windows

image

You also need exiftool in your PATH.

https://exiftool.org/

image

You must rename it to exiftool.exe and make sure it's in your PATH. If you don't know what that means, put exiftool.exe in the C:\Program Files\ImageMagick-7.1.0-Q16-HDRI folder after you install it, it'll work.

If you are not using PowerShell 7.x, you must remove -Parallel from line 25.

There is no real error handling here.

I think I might've been better served learning some C or C++ and just using imagemagick that way, maybe I could've figured out how to read Unicode iTXt.

if it's stupid, but it works, it's not stupid

@vt-idiot
Copy link
Author

vt-idiot commented Jan 30, 2023

No filename collisions

Asks you to install PowerShell 7, will run fine otherwise

Halts immediately if exiftool and magick are not in $PATH

DISREGARD EVERYTHING BELOW

There are potential file name collision issues, but it's such an infinitesimally rare chance, and can only occur with -Parallel processing enabled. If you're not using PowerShell 7, you already have to remove -Parallel in order for the script to function.

Your images would have to:

  1. be from Novel AI
  2. use the same exact seed
  3. have non-ANSI characters or {curly braces} or [brackets] in the prompt
  4. end up with identical filenames once all the non-ANSI characters were stripped from the filename

So なほね s-12345.png and おやすみ s-12345.png would potentially result in one file overwriting the other (during the tag writing process) if they were processed simultaneously. Or {tokoyami towa} s-12345.png and {{tokoyami towa}} s-12345.png. Pretty sure I fixed that with some -LiteralPath. Don't take my word for it.

なほね s-12345.png and なほね s-12345 (1).png would not overwrite each other.

The chance is much lower for combinations like towa s-12345.png and {towa} s-12345.png (in a folder with more than 5 images between the two of them...) because the files are processed in order based on the original filenames and not the temporary "safe" filenames that are required...because exiftool can't parse Unicode from the command line in 2023. {... would be at the top of the list. t... would be towards the bottom. Capisce?

The chances of filename collisions are even smaller than infinitesimally small with only webui images, because of the default numbered filename prefix; there is no chance that 00000-12345-なほね.png and 00001-12345-おやすみ.png could ever overwrite each other!

There is also NO chance of collision if you're NOT using -Parallel - ZERO. So if you're worried about that, just delete -Parallel and deal with it processing images single threaded, one at a time, vs. 5 at a time.

Couldn't you fix it with a randomized temporary file name

It's a miracle this thing even works at all. Even if I assign a string like $random to GetRandom and prepend the temporary filename with $random, the very sloppy -Parallel bodge means that you'll instead just end up with it "forgetting" what the file it was working on was supposed to be called once it hits the next file that requires a random number.


ImageMagick is actually fixing identify and their other tools to properly handle Unicode PNG iTXT tags. https://github.com/ImageMagick/ImageMagick/discussions/6000#discussioncomment-4804761

If I can figure out how to write an EXIF comment using a magick... command then I can drop exiftool entirely (it's still used for writing the new metadata, Unicode or otherwise) and then there will be 0 chance of filename collisions regardless of -Parallel or what characters are in the input filenames. The last time I tried, I think I couldn't get it to place line breaks in them, which webui requires.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment