1+ # Credits https://github.com/HumanEquivalentUnit/PowerShell-Misc/blob/master/Get-Win10OcrTextFromImage.ps1
2+
3+ function Get-OCR {
4+ <#
5+ . SYNOPSIS
6+ Runs Windows 10 OCR on an image.
7+
8+ . DESCRIPTION
9+ Takes a path to an image file, with some text on it.
10+ Runs Windows 10 OCR against the image.
11+ Returns an [OcrResult], hopefully with a .Text property containing the text
12+
13+ . PARAMETER -Path
14+ Path to an image file
15+
16+ . EXAMPLE
17+ Get-OCR -Path 'c:\test.bmp'
18+ #>
19+ [CmdletBinding ()]
20+ param (
21+ [Parameter (Mandatory = $true ,
22+ ValueFromPipeline = $true ,
23+ ValueFromPipelineByPropertyName = $true ,
24+ Position = 0 ,
25+ HelpMessage = ' Path to an image file, to run OCR on' )]
26+ [ValidateNotNullOrEmpty ()]
27+ $Path
28+ )
29+
30+ Begin {
31+ # Add the WinRT assembly, and load the appropriate WinRT types
32+ Add-Type - AssemblyName System.Runtime.WindowsRuntime
33+
34+ $null = [Windows.Storage.StorageFile , Windows.Storage , ContentType = WindowsRuntime ]
35+ $null = [Windows.Media.Ocr.OcrEngine , Windows.Foundation , ContentType = WindowsRuntime ]
36+ $null = [Windows.Foundation.IAsyncOperation ` 1 , Windows.Foundation , ContentType = WindowsRuntime ]
37+ $null = [Windows.Graphics.Imaging.SoftwareBitmap , Windows.Foundation , ContentType = WindowsRuntime ]
38+ $null = [Windows.Storage.Streams.RandomAccessStream , Windows.Storage.Streams , ContentType = WindowsRuntime ]
39+
40+ # [Windows.Media.Ocr.OcrEngine]::AvailableRecognizerLanguages
41+ $ocrEngine = [Windows.Media.Ocr.OcrEngine ]::TryCreateFromUserProfileLanguages()
42+
43+ # PowerShell doesn't have built-in support for Async operations,
44+ # but all the WinRT methods are Async.
45+ # This function wraps a way to call those methods, and wait for their results.
46+ $getAwaiterBaseMethod = [WindowsRuntimeSystemExtensions ].GetMember(' GetAwaiter' ).
47+ Where ({
48+ $PSItem.GetParameters ()[0 ].ParameterType.Name -eq ' IAsyncOperation`1'
49+ }, ' First' )[0 ]
50+
51+ Function Await {
52+ param ($AsyncTask , $ResultType )
53+
54+ $getAwaiterBaseMethod .
55+ MakeGenericMethod($ResultType ).
56+ Invoke($null , @ ($AsyncTask )).
57+ GetResult()
58+ }
59+ }
60+
61+ Process {
62+ foreach ($p in $Path ) {
63+ # From MSDN, the necessary steps to load an image are:
64+ # Call the OpenAsync method of the StorageFile object to get a random access stream containing the image data.
65+ # Call the static method BitmapDecoder.CreateAsync to get an instance of the BitmapDecoder class for the specified stream.
66+ # Call GetSoftwareBitmapAsync to get a SoftwareBitmap object containing the image.
67+ #
68+ # https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/imaging#save-a-softwarebitmap-to-a-file-with-bitmapencoder
69+
70+ # .Net method needs a full path, or at least might not have the same relative path root as PowerShell
71+ $p = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath ($p )
72+
73+ $params = @ {
74+ AsyncTask = [Windows.Storage.StorageFile ]::GetFileFromPathAsync($p )
75+ ResultType = [Windows.Storage.StorageFile ]
76+ }
77+ $storageFile = Await @params
78+
79+
80+ $params = @ {
81+ AsyncTask = $storageFile.OpenAsync ([Windows.Storage.FileAccessMode ]::Read)
82+ ResultType = [Windows.Storage.Streams.IRandomAccessStream ]
83+ }
84+ $fileStream = Await @params
85+
86+
87+ $params = @ {
88+ AsyncTask = [Windows.Graphics.Imaging.BitmapDecoder ]::CreateAsync($fileStream )
89+ ResultType = [Windows.Graphics.Imaging.BitmapDecoder ]
90+ }
91+ $bitmapDecoder = Await @params
92+
93+
94+ $params = @ {
95+ AsyncTask = $bitmapDecoder.GetSoftwareBitmapAsync ()
96+ ResultType = [Windows.Graphics.Imaging.SoftwareBitmap ]
97+ }
98+ $softwareBitmap = Await @params
99+
100+ # Run the OCR
101+ Await $ocrEngine.RecognizeAsync ($softwareBitmap ) ([Windows.Media.Ocr.OcrResult ])
102+ }
103+ }
104+ }
0 commit comments