Windows-F# 및 표준 기능을 사용하여 영역을 선택하는 OCR

33078 단어 WindowsF#tech

개요


화면 캡처 촬영 프로그램'캡처 & 스케치[1]'와'윈도s.Media.Ocr[2]'를 조합하여 F#로 선택한 영역의 텍스트를 읽는 프로그램을 만든다.
전역 핫키 시작 영역 선택을 통해 읽은 텍스트를 클립보드에 저장하는 작업 트레이 상주 응용 프로그램입니다.

환경 만들기


대상
릴리즈
Windows
20H2 (19042.928)
.NET SDK
5.0.202

설치 예


※'커팅 & 스케치'설정'자동 클립보드로 복사'를 엽니다.
.fsproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
    <RootNamespace>プロジェクト名</RootNamespace>
    <UseWindowsForms>true</UseWindowsForms>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>

</Project>

Program.fs
open System

let await (i: Windows.Foundation.IAsyncOperation<'TResult>) =
    i.AsTask() |> Async.AwaitTask


let startScreenclip () =
    let cmd = new System.Diagnostics.ProcessStartInfo "cmd"
    cmd.Arguments <- @"/c start ms-screenclip:"
    cmd.UseShellExecute <- true
    cmd.WindowStyle <- System.Diagnostics.ProcessWindowStyle.Hidden

    let cmdProcess = System.Diagnostics.Process.Start cmd
    cmdProcess.WaitForExit()

    let processArray = System.Diagnostics.Process.GetProcessesByName "ScreenClippingHost"
    processArray.[0].WaitForExit()


let getClipboardBitmap () =
    let bitmapSource = System.Windows.Clipboard.GetImage()

    if bitmapSource <> null then
        let bitmapFrame = System.Windows.Media.Imaging.BitmapFrame.Create bitmapSource

        let encoder = new System.Windows.Media.Imaging.BmpBitmapEncoder()
        encoder.Frames.Add bitmapFrame

        use memoryStream = new System.IO.MemoryStream()
        encoder.Save memoryStream

        let byteArray = memoryStream.ToArray()

        use randomAccessStream = new Windows.Storage.Streams.InMemoryRandomAccessStream()
        use outputStream = randomAccessStream.GetOutputStreamAt(uint64 0)
        use dataWriter = new Windows.Storage.Streams.DataWriter(outputStream)
        dataWriter.WriteBytes byteArray

        async {
            let! _ = await <| dataWriter.StoreAsync()
            let! _ = await <| outputStream.FlushAsync()

            let! decoder = await <| Windows.Graphics.Imaging.BitmapDecoder.CreateAsync randomAccessStream
            let! softwareBitmap = await <| decoder.GetSoftwareBitmapAsync(Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8, Windows.Graphics.Imaging.BitmapAlphaMode.Premultiplied)

            return softwareBitmap
        }
        |> Async.RunSynchronously
    else
        null


let startOCR bitmap =
    let ocrEngine = Windows.Media.Ocr.OcrEngine.TryCreateFromUserProfileLanguages()

    if bitmap <> null then
        async {
            let! ocrResult = await <| ocrEngine.RecognizeAsync bitmap
            return ocrResult.Text
        }
        |> Async.RunSynchronously
    else
        ""


let createIcon () =
    let toolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(Text = "&終了")
    toolStripMenuItem.Click.Add(fun e -> System.Windows.Forms.Application.Exit())

    let contextMenuStrip = new System.Windows.Forms.ContextMenuStrip()
    contextMenuStrip.Items.Add toolStripMenuItem |> ignore

    new System.Windows.Forms.NotifyIcon(
        Icon = new System.Drawing.Icon @".\icon.ico",
        Visible = true,
        Text = "TestApp",
        ContextMenuStrip = contextMenuStrip
    )


[<System.Runtime.InteropServices.DllImport("user32.dll")>]
extern int RegisterHotKey(IntPtr HWnd, int ID, int MOD_KEY, int KEY)

[<System.Runtime.InteropServices.DllImport("user32.dll")>]
extern int UnregisterHotKey(IntPtr HWnd, int ID)


type HotkeyForm () as this =
    inherit System.Windows.Forms.Form()

    let icon = createIcon()

    do
        RegisterHotKey(this.Handle, 0x0000, 0x0001 ||| 0x0008, int System.Windows.Forms.Keys.C) |> ignore

        System.Windows.Forms.Application.ApplicationExit.Add(fun e ->
            UnregisterHotKey(this.Handle, 0x0000) |> ignore
        )

    override this.WndProc m =
        base.WndProc(&m)

        if m.Msg = 0x0312 && int m.WParam = 0x0000 then
            startScreenclip()
            System.Windows.Clipboard.SetText(startOCR <| getClipboardBitmap())

    interface IDisposable with
        member this.Dispose() =
            icon.Dispose()


[<STAThread>]
do
    use form = new HotkeyForm()
    System.Windows.Forms.Application.Run()

해설


커팅 & 스케치


[잘라내기 & 스케치] 클립보드에 선택 영역의 이미지를 저장하는 기능을 사용합니다.
let startScreenclip () =

    // コマンドプロンプト
    let cmd = new System.Diagnostics.ProcessStartInfo "cmd"

    // 「ms-screenclip:」新規切り取りを開始する URI スキーム
    cmd.Arguments <- @"/c start ms-screenclip:"

    cmd.UseShellExecute <- true
    cmd.WindowStyle <- System.Diagnostics.ProcessWindowStyle.Hidden

    // 「切り取り&スケッチ」の起動
    let cmdProcess = System.Diagnostics.Process.Start cmd
    cmdProcess.WaitForExit()

    // 「切り取り&スケッチ」の終了待機
    let processArray = System.Diagnostics.Process.GetProcessesByName "ScreenClippingHost"
    processArray.[0].WaitForExit()

클립보드에서 이미지 가져오기


let getClipboardBitmap () =

    // WPF の機能を利用

    let bitmapSource = System.Windows.Clipboard.GetImage()

    if bitmapSource <> null then

        // 以下「Windows.Media.Ocr」が認識できる SoftwareBitmap に変換する処理

        let bitmapFrame = System.Windows.Media.Imaging.BitmapFrame.Create bitmapSource

        let encoder = new System.Windows.Media.Imaging.BmpBitmapEncoder()
        encoder.Frames.Add bitmapFrame

        use memoryStream = new System.IO.MemoryStream()
        encoder.Save memoryStream

        let byteArray = memoryStream.ToArray()

        use randomAccessStream = new  Windows.Storage.Streams.InMemoryRandomAccessStream()
        use outputStream = randomAccessStream.GetOutputStreamAt(uint64 0)
        use dataWriter = new Windows.Storage.Streams.DataWriter(outputStream)
        dataWriter.WriteBytes byteArray

        async {
            let! _ = await <| dataWriter.StoreAsync()
            let! _ = await <| outputStream.FlushAsync()

            let! decoder = await <| Windows.Graphics.Imaging.BitmapDecoder.CreateAsync randomAccessStream
            let! softwareBitmap = await <| decoder.GetSoftwareBitmapAsync(Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8, Windows.Graphics.Imaging.BitmapAlphaMode.Premultiplied)

            return softwareBitmap
        }
        |> Async.RunSynchronously
    else
        null

Windows.Media.Ocr


https://zenn.dev/shikatan/articles/451245de0f5dd70d28be

글로벌 핫키


https://zenn.dev/shikatan/articles/f6c4c52c134b61

역사를 갱신하다


일자
컨텐트
2021/04/26
'커팅 & 스케치' 관련 내용을 추가합니다.

end


각주
'Windows 10 옥토버 2018 업데이트'에 표준으로 탑재된다.↩︎
Windows 10에 표준으로 설치됩니다.↩︎

좋은 웹페이지 즐겨찾기