Add the WinRT assembly, and load the appropriate WinRT types

February 21, 2021 · View on GitHub

using namespace Windows.Storage using namespace Windows.Graphics.Imaging using namespace System.IO.WindowsRuntimeStreamExtensions using namespace System.IO.WindowsRuntimeStreamExtensions using namespace System.Text using namespace System.Text.Json

Add the WinRT assembly, and load the appropriate WinRT types

Add-Type -AssemblyName System.Runtime.WindowsRuntime Add-Type -AssemblyName System.Runtime.Serialization

null=[Windows.Storage.StorageFile,Windows.Storage,ContentType=WindowsRuntime]null = [Windows.Storage.StorageFile, Windows.Storage, ContentType = WindowsRuntime] null = [Windows.Media.Ocr.OcrEngine, Windows.Foundation, ContentType = WindowsRuntime] null=[Windows.Foundation.IAsyncOperation1,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]::TryCreateFromLanguage("en")

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,AsyncTask, ResultType)

$getAwaiterBaseMethod.
    MakeGenericMethod($ResultType).
    Invoke($null, @($AsyncTask)).
    GetResult()

}

$http = [System.Net.HttpListener]::new()

Hostname and port to listen on

$http.Prefixes.Add("http://+:80/")

Start the Http Server

$http.Start()

Add-Type -AssemblyName System.Web

Log ready message to terminal

if (http.IsListening) { write-host "HTTP Server Ready! " -f 'black' -b 'gre' write-host "($http.Prefixes)" -f 'y' }

while (http.IsListening) { # Get Request Url # When a request is made in a web browser the GetContext() method will return a request object # Our route examples below will use the request object properties to decide how to respond context = http.GetContext()if(http.GetContext() if (context.Request.HttpMethod -eq 'GET') { Context.Response.ContentType="text/html"Context.Response.ContentType = "text/html" buffer = [System.Text.Encoding]::UTF8.GetBytes("<input type=file onchange=""fetch('', {method: 'POST', body: this.files[0]}).then(r=>r.json()).then(console.log)"">") context.Response.OutputStream.Write(context.Response.OutputStream.Write(buffer, 0, buffer.Length)buffer.Length) Context.Response.Close() }

if ($context.Request.HttpMethod -eq 'POST') {

    # We can log the request to the terminal
    write-host "$($context.Request.UserHostAddress)  =>  $($context.Request.Url)" -f 'mag'
    $memStream = [System.IO.MemoryStream]::new()
    $context.Request.InputStream.CopyTo($memStream)

    $params = @{
        AsyncTask  = [BitmapDecoder]::CreateAsync([System.IO.WindowsRuntimeStreamExtensions]::AsRandomAccessStream($memStream))
        ResultType = [BitmapDecoder]
    }
    $bitmapDecoder = Await @params


    $params = @{ 
        AsyncTask = $bitmapDecoder.GetSoftwareBitmapAsync()
        ResultType = [SoftwareBitmap]
    }
    $softwareBitmap = Await @params

    # Run the OCR
    $result = Await $ocrEngine.RecognizeAsync($softwareBitmap) ([Windows.Media.Ocr.OcrResult])

    $Context.Response.ContentType = "application/json"
    $serialized = $result | ConvertTo-Json -Depth 5 -Compress
    $buffer = [System.Text.Encoding]::UTF8.GetBytes($serialized)
    $context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
    $Context.Response.Close()
}

}