Imports System.Threading
Imports System.Drawing.Imaging
Imports System.Drawing.Drawing2D

Public Class FormDemo

    Private cancel As Boolean

    Private Sub buttonSelectPicture_Click(sender As Object, e As EventArgs) Handles buttonSelectPicture.Click
        If openFileDialog.ShowDialog() = DialogResult.OK Then
            selection.Width = 0
            selection.Height = 0
            progressBar.Value = 0
            textBoxText.Clear()
            textBoxHtml.Clear()
            textBoxUnlv.Clear()
            pictureBoxRegions.Image = Nothing
            pictureBoxParagraphs.Image = Nothing
            pictureBoxTextLines.Image = Nothing
            pictureBoxWords.Image = Nothing
            pictureBoxComponents.Image = Nothing
            Try
                pictureBox.Image = Image.FromFile(openFileDialog.FileName)
                ocr.Picture = pictureBox.Image
                pictureBox.Cursor = Cursors.Cross
            Catch ex As Exception
                ocr.Picture = Nothing
                ocr.PictureFileName = openFileDialog.FileName
                pictureBox.Cursor = Cursors.Cross
            End Try

            If Not ocr.Active Then
                ocr.DataPath = AppDomain.CurrentDomain.BaseDirectory
                ocr.Active = True
            End If
            buttonRecognize.Enabled = True
        End If
    End Sub

    Private Sub buttonCancel_Click(sender As Object, e As EventArgs) Handles buttonCancel.Click
        cancel = True
    End Sub

    Delegate Sub OcrDelegate()

    Private Sub Start()
        ocr.Recognize()
        If InvokeRequired Then
            Dim invoke = New OcrDelegate(AddressOf OcrInvoke)
            Me.Invoke(invoke, Nothing)
        Else
            OcrInvoke()
        End If
    End Sub

    Private Sub buttonRecognize_Click(sender As Object, e As EventArgs) Handles buttonRecognize.Click
        buttonSelectPicture.Enabled = False
        Cursor.Current = Cursors.WaitCursor
        cancel = False
        buttonCancel.Visible = True
        textBoxText.Clear()
        textBoxHtml.Clear()
        textBoxUnlv.Clear()
        pictureBoxRegions.Image = Nothing
        pictureBoxParagraphs.Image = Nothing
        pictureBoxTextLines.Image = Nothing
        pictureBoxWords.Image = Nothing
        pictureBoxComponents.Image = Nothing

        Dim useSelection = selection.Width <> 0 And selection.Height <> 0
        If useSelection Then
            Dim left As Integer
            Dim top As Integer
            Dim right As Integer
            Dim bottom As Integer

            PictureBoxToImage(selection.Left, selection.Top, left, top)
            PictureBoxToImage(selection.Right, selection.Bottom, right, bottom)
            ocr.PictureLeft = left
            ocr.PictureTop = top
            ocr.PictureWidth = right - ocr.PictureLeft
            ocr.PictureHeight = bottom - ocr.PictureTop
        Else
            selection.X = selection.Y = ocr.PictureLeft = ocr.PictureTop = ocr.PictureWidth = ocr.PictureHeight = 0
        End If

        Dim thread = New Thread(AddressOf Start)
        thread.Start()
    End Sub

    Private Sub OcrInvoke()
        Try
            If Not cancel Then
                progressBar.Value = 100

                textBoxText.Text = ocr.Text.Replace(Chr(&HA), Chr(&HD) + Chr(&HA))
                textBoxHtml.Text = ocr.HtmlText.Replace(Chr(&HA), Chr(&HD) + Chr(&HA))
                textBoxUnlv.Text = ocr.UnlvText.Replace(Chr(&HA), Chr(&HD) + Chr(&HA))

                Using bitmap = New Bitmap(pictureBox.Image)
                    pictureBoxWords.Image = bitmap.Clone(New Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb)
                    If Not ocr.Words Is Nothing Then
                        Using g = Graphics.FromImage(pictureBoxWords.Image)
                            Dim pen = New Pen(Color.FromArgb(&H0, &H7F, &HFF))
                            For Each rectangle In ocr.Words
                                g.DrawRectangle(pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height)
                            Next
                        End Using
                    End If

                    pictureBoxRegions.Image = bitmap.Clone(New Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb)
                    If Not ocr.Regions Is Nothing Then
                        Using g = Graphics.FromImage(pictureBoxRegions.Image)
                            Dim pen = New Pen(Color.FromArgb(&H7F, &H0, &HFF))
                            For Each rectangle In ocr.Regions
                                g.DrawRectangle(pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height)
                            Next
                        End Using
                    End If

                    pictureBoxTextLines.Image = bitmap.Clone(New Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb)
                    If Not ocr.TextLines Is Nothing Then
                        Using g = Graphics.FromImage(pictureBoxTextLines.Image)
                            Dim pen = New Pen(Color.FromArgb(&H0, &HFF, &H7F))
                            For Each rectangle In ocr.TextLines
                                g.DrawRectangle(pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height)
                            Next
                        End Using
                    End If

                    pictureBoxComponents.Image = bitmap.Clone(New Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb)
                    If Not ocr.ConnectedComponents Is Nothing Then
                        Using g = Graphics.FromImage(pictureBoxComponents.Image)
                            Dim Pen = New Pen(Color.FromArgb(&HFF, &H7F, &H0))
                            For Each rectangle In ocr.ConnectedComponents
                                g.DrawRectangle(Pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height)
                            Next
                        End Using
                    End If

                    pictureBoxParagraphs.Image = bitmap.Clone(New Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb)
                    If Not ocr.Paragraphs Is Nothing Then
                        Using g = Graphics.FromImage(pictureBoxParagraphs.Image)
                            Dim pen = New Pen(Color.FromArgb(&H7F, &HFF, &H0))
                            For Each paragraph In ocr.Paragraphs
                                Dim rectangle = paragraph.Location
                                g.DrawRectangle(pen, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height)
                            Next
                        End Using
                    End If
                End Using
            Else
                progressBar.Value = 0
            End If
        Finally
            buttonCancel.Visible = False
            buttonSelectPicture.Enabled = True
            Cursor.Current = Cursors.Default
        End Try
    End Sub

    Delegate Sub ProgressDelegate(progress As Integer)

    Private Sub ProgressInvoke(progress As Integer)
        progressBar.Value = progress
    End Sub

    Private Sub ocr_Progress(sender As Object, e As Winsoft.Ocr.ProgressEventArgs) Handles ocr.Progress
        If progressBar.InvokeRequired Then
            Dim invoke = New ProgressDelegate(AddressOf ProgressInvoke)
            Me.Invoke(invoke, New Object() {e.Progress})
        Else
            ProgressInvoke(e.Progress)
            e.Cancel = cancel
        End If
    End Sub

    Private selecting As Boolean
    Private selection As Rectangle

    Private Sub pictureBox_Paint(sender As Object, e As PaintEventArgs) Handles pictureBox.Paint
        Using pen As New Pen(Color.Red)
            pen.DashStyle = DashStyle.Dash
            e.Graphics.DrawRectangle(pen, selection)
        End Using
    End Sub

    Private Sub pictureBox_MouseDown(sender As Object, e As MouseEventArgs) Handles pictureBox.MouseDown
        If pictureBox.Cursor = Cursors.Cross Then
            If e.Button = MouseButtons.Left Then
                selecting = True
                selection.X = e.X
                selection.Y = e.Y
                selection.Width = 0
                selection.Height = 0
                pictureBox.Refresh()
            End If
        End If
    End Sub

    Private Sub pictureBox_MouseMove(sender As Object, e As MouseEventArgs) Handles pictureBox.MouseMove
        If selecting Then
            selection.Width = e.X - selection.X
            selection.Height = e.Y - selection.Y
            pictureBox.Refresh()
        End If
    End Sub

    Private Sub pictureBox_MouseUp(sender As Object, e As MouseEventArgs) Handles pictureBox.MouseUp
        If selecting Then
            selecting = False
            selection.Width = e.X - selection.X
            selection.Height = e.Y - selection.Y
            pictureBox.Refresh()
        End If
    End Sub

    Private Sub pictureBox_Resize(sender As Object, e As EventArgs) Handles pictureBox.Resize
        selection.Width = 0
        selection.Height = 0
        pictureBox.Refresh()
    End Sub

    Private Sub PictureBoxToImage(x As Integer, y As Integer, ByRef imageX As Integer, ByRef imageY As Integer)
        Dim boxHeight = pictureBox.Height
        Dim boxWidth = pictureBox.Width
        Dim boxAspect = CDbl(boxWidth) / boxHeight

        Dim imageHeight = pictureBox.Image.Height
        Dim imageWidth = pictureBox.Image.Width
        Dim imageAspect = CDbl(imageWidth) / imageHeight

        If boxAspect >= imageAspect Then
            ' PictureBox is wider and shorter than image
            Dim zoom = CDbl(imageHeight) / boxHeight

            imageY = CInt(y * zoom) ' zoom height

            Dim boxDX = x - CDbl(boxWidth) / 2 ' calc distance from PictureBox center
            Dim imageDX = boxDX * zoom ' zoom distance
            imageX = CInt(imageDX + imageWidth / 2) ' convert distance back to coordinate
        Else
            ' PictureBox is taller and thinner than image
            Dim zoom = CDbl(imageWidth) / boxWidth

            imageX = CInt(x * zoom) ' zoom width

            Dim boxDY = y - CDbl(boxHeight) / 2 ' calc distance from PictureBox center
            Dim imageDY = boxDY * zoom ' zoom distance
            imageY = CInt(imageDY + CDbl(imageHeight) / 2) ' convert distance back to coordinate
        End If
    End Sub
End Class