Add-Type -AssemblyName System.Runtime.WindowsRuntime $null = [Windows.Storage.StorageFile, Windows.Storage, ContentType=WindowsRuntime] $null = [Windows.Storage.Streams.IRandomAccessStream, Windows.Storage.Streams, ContentType=WindowsRuntime] $null = [Windows.Graphics.Imaging.BitmapDecoder, Windows.Graphics.Imaging, ContentType=WindowsRuntime] $null = [Windows.Graphics.Imaging.SoftwareBitmap, Windows.Graphics.Imaging, ContentType=WindowsRuntime] $null = [Windows.Media.Ocr.OcrEngine, Windows.Foundation, ContentType=WindowsRuntime] $null = [Windows.Media.Ocr.OcrResult, Windows.Foundation, ContentType=WindowsRuntime] $asyncMethod = [System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object { $_.Name -eq 'AsTask' -and $_.IsGenericMethod -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' } | Select-Object -First 1 function AwaitOperation($operation, $resultType) { $task = $asyncMethod.MakeGenericMethod($resultType).Invoke($null, @($operation)) $task.Wait() return $task.Result } $engine = [Windows.Media.Ocr.OcrEngine]::TryCreateFromUserProfileLanguages() if ($null -eq $engine) { throw 'OCR language unavailable' } $sourceRoot = (Resolve-Path 'work/trilium/phase3/doc_notes/en').Path $items = Get-ChildItem -LiteralPath $sourceRoot -Recurse -File | Where-Object {$_.Extension -in '.png','.jpg','.gif'} $results = [System.Collections.Generic.List[object]]::new() foreach ($entry in $items) { try { $file = AwaitOperation ([Windows.Storage.StorageFile]::GetFileFromPathAsync($entry.FullName)) ([Windows.Storage.StorageFile]) $stream = AwaitOperation ($file.OpenAsync([Windows.Storage.FileAccessMode]::Read)) ([Windows.Storage.Streams.IRandomAccessStream]) $decoder = AwaitOperation ([Windows.Graphics.Imaging.BitmapDecoder]::CreateAsync($stream)) ([Windows.Graphics.Imaging.BitmapDecoder]) $bitmap = AwaitOperation ($decoder.GetSoftwareBitmapAsync()) ([Windows.Graphics.Imaging.SoftwareBitmap]) $ocr = AwaitOperation ($engine.RecognizeAsync($bitmap)) ([Windows.Media.Ocr.OcrResult]) $latin = [regex]::Matches($ocr.Text,'[A-Za-z]{3,}').Count $results.Add([pscustomobject]@{file=$entry.FullName.Substring($sourceRoot.Length+1).Replace('\','/');latinWords=$latin;text=$ocr.Text;error=$null}) $bitmap.Dispose();$stream.Dispose() } catch { $results.Add([pscustomobject]@{file=$entry.FullName.Substring($sourceRoot.Length+1).Replace('\','/');latinWords=-1;text='';error=$_.Exception.Message}) } if ($results.Count % 30 -eq 0) { Write-Output ('OCR processed: '+$results.Count+'/'+$items.Count) } } $utf8 = New-Object System.Text.UTF8Encoding($false) [System.IO.File]::WriteAllText((Join-Path (Get-Location) 'work/trilium/help-image-ocr.json'),($results | ConvertTo-Json -Depth 5),$utf8) Write-Output ('OCR complete: '+$results.Count)