Search code examples
vb.nettimerocr.net-4.8

How to avoid text to flicker using Windows.media.ocr and timer control


I'm scanning some text in the screen using Windows.Media.Ocr under a timer control, firing the tick event every 200 ms. I'm then displaying the output in a richtextbox that is unfortunately flickering..

I made a gif to show the issue ( the ocr is on purpose scanning just the values with M)

enter image description here

is there any way to stop this behavior? Thanks

The code I'm using inside of the timer is:

 Dim softwareBmp As Windows.Graphics.Imaging.SoftwareBitmap
        Using bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
            Using g As Graphics = Graphics.FromImage(bmp)
                Dim pt As Point = Me.PointToScreen(New Point(PictureBox1.Left, PictureBox1.Top))
                g.CopyFromScreen(pt.X, pt.Y, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy)
                Using memStream = New Windows.Storage.Streams.InMemoryRandomAccessStream()
                    bmp.Save(memStream.AsStream(), System.Drawing.Imaging.ImageFormat.Bmp)
                    Dim decoder As Windows.Graphics.Imaging.BitmapDecoder = Await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(memStream)
                    softwareBmp = Await decoder.GetSoftwareBitmapAsync(decoder.BitmapPixelFormat, BitmapAlphaMode.Ignore)
                End Using
            End Using
        End Using
        Dim ocrEng = OcrEngine.TryCreateFromLanguage(New Windows.Globalization.Language("en-US"))
        Dim languages As IReadOnlyList(Of Windows.Globalization.Language) = ocrEng.AvailableRecognizerLanguages
        For Each language In languages
            Console.WriteLine(language.LanguageTag)
        Next
        Dim r = ocrEng.RecognizerLanguage
        Dim n = ocrEng.MaxImageDimension
        Dim ocrResult = Await ocrEng.RecognizeAsync(softwareBmp)

        RichTextBox1.Clear()

        Dim wordList As List(Of cText) = New List(Of cText)()
        Dim lines As IReadOnlyList(Of OcrLine) = ocrResult.Lines
        For Each line In lines
            For Each word In line.Words
                Dim nY As Double = CLng(word.BoundingRect.Bottom / 10) * 10
                wordList.Add(New cText() With {.Text = word.Text, .LocY = nY, .LocX = word.BoundingRect.Left})
            Next
        Next

        wordList.Sort(New WordComparer())

        Dim oldLocY As Double = 0
        For Each item As cText In wordList
            If (item.LocY > oldLocY And oldLocY <> 0) Then
                RichTextBox1.Text += Environment.NewLine
            End If
            RichTextBox1.Text += (item.Text + " ") 
            oldLocY = item.LocY
        Next

Solution

  • I solved using WM_SETREDRAW

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
         Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
         End Function
        
         Public Const WM_SETREDRAW As Integer = &HB
    

    Before adding lines (before RichTextBox1.Clear())

      If (RichTextBox1.IsHandleCreated) Then
                 SendMessage(RichTextBox1.Handle, WM_SETREDRAW, 0, IntPtr.Zero)
             End If
    

    After lines have been added :

     If (RichTextBox1.IsHandleCreated) Then
                 SendMessage(RichTextBox1.Handle, WM_SETREDRAW, 1, IntPtr.Zero)
                 RichTextBox1.Invalidate()
             End If