Public/media/Get-OCR.ps1
# Credits https://github.com/HumanEquivalentUnit/PowerShell-Misc/blob/master/Get-Win10OcrTextFromImage.ps1 function Get-OCR { <# .SYNOPSIS Runs Windows 10 OCR on an image. .DESCRIPTION Takes a path to an image file, with some text on it. Runs Windows 10 OCR against the image. Returns an [OcrResult], hopefully with a .Text property containing the text .PARAMETER -Path Path to an image file .EXAMPLE Get-OCR -Path 'c:\test.bmp' #> [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0, HelpMessage = 'Path to an image file, to run OCR on')] [ValidateNotNullOrEmpty()] $Path ) Begin { # Add the WinRT assembly, and load the appropriate WinRT types Add-Type -AssemblyName System.Runtime.WindowsRuntime $null = [Windows.Storage.StorageFile, Windows.Storage, ContentType = WindowsRuntime] $null = [Windows.Media.Ocr.OcrEngine, Windows.Foundation, ContentType = WindowsRuntime] $null = [Windows.Foundation.IAsyncOperation`1, Windows.Foundation, ContentType = WindowsRuntime] $null = [Windows.Graphics.Imaging.SoftwareBitmap, Windows.Foundation, ContentType = WindowsRuntime] $null = [Windows.Storage.Streams.RandomAccessStream, Windows.Storage.Streams, ContentType = WindowsRuntime] # [Windows.Media.Ocr.OcrEngine]::AvailableRecognizerLanguages $ocrEngine = [Windows.Media.Ocr.OcrEngine]::TryCreateFromUserProfileLanguages() # PowerShell doesn't have built-in support for Async operations, # but all the WinRT methods are Async. # This function wraps a way to call those methods, and wait for their results. $getAwaiterBaseMethod = [WindowsRuntimeSystemExtensions].GetMember('GetAwaiter'). Where({ $PSItem.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' }, 'First')[0] Function Await { param($AsyncTask, $ResultType) $getAwaiterBaseMethod. MakeGenericMethod($ResultType). Invoke($null, @($AsyncTask)). GetResult() } } Process { foreach ($p in $Path) { # From MSDN, the necessary steps to load an image are: # Call the OpenAsync method of the StorageFile object to get a random access stream containing the image data. # Call the static method BitmapDecoder.CreateAsync to get an instance of the BitmapDecoder class for the specified stream. # Call GetSoftwareBitmapAsync to get a SoftwareBitmap object containing the image. # # https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/imaging#save-a-softwarebitmap-to-a-file-with-bitmapencoder # .Net method needs a full path, or at least might not have the same relative path root as PowerShell $p = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p) $params = @{ AsyncTask = [Windows.Storage.StorageFile]::GetFileFromPathAsync($p) ResultType = [Windows.Storage.StorageFile] } $storageFile = Await @params $params = @{ AsyncTask = $storageFile.OpenAsync([Windows.Storage.FileAccessMode]::Read) ResultType = [Windows.Storage.Streams.IRandomAccessStream] } $fileStream = Await @params $params = @{ AsyncTask = [Windows.Graphics.Imaging.BitmapDecoder]::CreateAsync($fileStream) ResultType = [Windows.Graphics.Imaging.BitmapDecoder] } $bitmapDecoder = Await @params $params = @{ AsyncTask = $bitmapDecoder.GetSoftwareBitmapAsync() ResultType = [Windows.Graphics.Imaging.SoftwareBitmap] } $softwareBitmap = Await @params # Run the OCR Await $ocrEngine.RecognizeAsync($softwareBitmap) ([Windows.Media.Ocr.OcrResult]) } } } |