How to stick some text on an Image via a Label?

Jean-Luc Coudret 21 Reputation points
2021-05-18T17:06:01.083+00:00

Hi all,

In short: I am trying to add a text via a label on an image placed in a picturebox.
My code below is working in some case, but not always. I am using a weird number (3.16) which help most of the case, but I don't really understand why.

What I am looking for is:
1- To stick the text of the label over my Image
2- The label (coming from the class TGlass) displayed over my Image must appeared exactly as it is displayed on the screen (in my picturebox "pbCheckImage01" 400x266px)
3- My image can change in term of pixels (example: 6016x4000 or 2256x1504 or 317x212 ... with always the same ratio 1.5)
4- The size of the label can change via a personalised and limited FontDialog (size 48 to 108)

Any ideas, corrections, improvements are welcome. Hope my explanations were clear enough.

I tried with the method DrawToBitmap, but it doesn't work as I am losing pixels.
I also tried with the method MeasureString without success, but it is maybe the way to go.

Below is the code I am using to stick my label on my image.

            Dim myBitmap As Bitmap = Nothing
            Using fs As New System.IO.FileStream(myPath, System.IO.FileMode.Open, System.IO.FileAccess.Read)
                'Dim img2 As Image = Image.FromStream(fs)
                Dim img2 As Bitmap = CType(Bitmap.FromStream(fs), Bitmap)
                pbCheckImage01.BackgroundImage = img2
                Dim g As Graphics = Graphics.FromImage(img2)
                ' Text position of Label TGlass
                Dim topleft As Point
                topleft = New Point(TGlass.Left, TGlass.Top)
                ' Text content of Label TGlass
                Dim strCalendar As String = TGlass.Text
                ' Rectangle layout for the selected font
                Dim layout As New Rectangle(topleft, TGlass.Size)
                ' Rectangle position with respect of the image
                layout.X = CInt(layout.X * (img2.Height / pbCheckImage01.Height))
                layout.Y = CInt(layout.Y * (img2.Width / pbCheckImage01.Width))
                ' Text First Page
                Dim myFontSize As Integer
                myFontSize = CInt(TGlass.Font.Size * (img2.Width / pbCheckImage01.Width) / 3.16)
                Dim myFont As New Font(TGlass.Font.FontFamily, myFontSize, TGlass.Font.Style)
                Dim myBrush As New SolidBrush(TGlass.ForeColor)
                ' Drawing on Image
                g.DrawString(strCalendar, myFont, myBrush, layout.X, layout.Y)
                ' Remove the TextWindow class
                ckbYear.Checked = False
                myBitmap = img2
            End Using
            ' Update the new image on FirstPage
            pb00.BackgroundImage = myBitmap
            pb00.BackgroundImageLayout = ImageLayout.Stretch
            pb00.Size = fSizeTransfer(myBitmap.Width, myBitmap.Height, 120)
            ' Save (Replace) the Image in the right folder
            myBitmap.Save(myPath, System.Drawing.Imaging.ImageFormat.Jpeg)

And here the code of the TextWindow class TGlass.

Public Class cTextWindow

    Inherits Label ' Control Text
    ' Variable initialisation
    Dim a As Integer
    Dim b As Integer
    Dim newPoint As Point
    Public bClick As Boolean

    Public Sub New()
        ' Initialisation
        Me.Cursor = Cursors.SizeAll
        bClick = True
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        ' Draw the border of the label
        Try
            If bClick = True Then
                e.Graphics.DrawRectangle(New Pen(Brushes.Blue, 4), Me.ClientRectangle)
            Else
                e.Graphics.DrawRectangle(New Pen(Brushes.Transparent, 4), Me.ClientRectangle)
            End If
            MyBase.OnPaint(e)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
        ' Find the position of the label
        Try
            a = MousePosition.X - Me.Location.X
            b = MousePosition.Y - Me.Location.Y
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
        ' Update the position of the label
        Try
            ' New location
            If e.Button = MouseButtons.Left Then
                newPoint = MousePosition
                newPoint.X -= a
                newPoint.Y -= b
                Me.Location = newPoint
            End If
            ' Raise the MouseMove event
            MyBase.OnMouseMove(e)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
        ' Control the position of the label
        Try
            ' Keep it inside the main PictureBox
            If Me.Location.X < 0 Then Me.Location = New Point(0, Me.Location.Y)
            If Me.Location.Y < 0 Then Me.Location = New Point(Me.Location.X, 0)
            If Me.Location.X + Me.Width > frmECalendar.pbCheckImage01.Width Then Me.Location = New Point(frmECalendar.pbCheckImage01.Width - Me.Width, Me.Location.Y)
            If Me.Location.Y + Me.Height > frmECalendar.pbCheckImage01.Height Then Me.Location = New Point(Me.Location.X, frmECalendar.pbCheckImage01.Height - Me.Height)
            ' Control to be redrawn
            'Me.Invalidate()
            Me.Update()
            ' Raise the Move event
            MyBase.OnMove(e)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    Protected Overrides Sub OnMousedoubleClick(e As MouseEventArgs)
        ' Display the label frame with a mouse click 
        Try
            bClick = Not bClick
            ' Raise the MouseClick event
            MyBase.OnMouseDoubleClick(e)
            Refresh()
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

End Class
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,625 questions
{count} votes

Accepted answer
  1. Xingyu Zhao-MSFT 5,356 Reputation points
    2021-05-28T03:07:23.433+00:00

    Hi @Jean-Luc Coudret ,

    especially about these numbers 3 or 4 depending of the way I do it.

    *(intRenderer.Width / PictureBox1.Width) * img.Width* cannot be used as font size.
    In 'Button4_Click', you set TGlass.Font = New Font("Arial", 80, FontStyle.Bold)
    So consider :

                Dim WidthRate = img.Width / PictureBox1.Width  
                Dim myFontSize = CInt(WidthRate * 80)  
    

    Best Regards,
    Xingyu Zhao
    *
    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. Xingyu Zhao-MSFT 5,356 Reputation points
    2021-05-26T03:37:41.667+00:00

    Hi @Jean-Luc Coudret ,
    You can consider drawing a string directly on a PictureBox image.
    For example:

            Dim bmp As Bitmap = New Bitmap("image path")  
            Using g As Graphics = Graphics.FromImage(bmp)  
                TextRenderer.DrawText(g, "Hello", New Font("Arial", 76, FontStyle.Bold), New Point(5, 75), Color.Red)  
            End Using  
            bmp.Save("image path")  
    

    Result of my test:
    99697-img4.jpg
    Also check:

    1. Custom AntiAliasing with GDI+
    2. Drawing smooth text and pictures on the extended glass area of your WinForm in Windows Vista

    Hope them could be helpful.

    Best Regards,
    Xingyu Zhao
    *
    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

  2. Jean-Luc Coudret 21 Reputation points
    2021-05-23T15:49:21.553+00:00

    Hi,

    And thanks for your help.
    I did a short version of what I want to achieved in a small Apps, but I was not able to attach the zipped file.
    Then, I added the main code I used in my small Apps below. The TGlass class I used is already shared in the previous post.

    Note it will create a Test folder on your desktop with the various images.
    Click BTN01 or BTN02, BTN04 (you can move the label) and finally BTN05 and check the created images N_img1 and N_img2 in the Test folder.
    Target: I would like to have the text on the N_image in the folder as it appeared on the picturebox. It worked a bit (not perfectly) with img1, but not with img2 (text too small).

    img1 size: W=6016px, H=4000px
    img2 size: W=995px, H=661px

    If you prefer, I can share it on Google Drive, but I will need your email address.

    Public Class Form1
    
        Private ReadOnly TGlass As New cTextWindow
        Private myPath As String
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            myPath = System.IO.Path.Combine(System.IO.Path.Combine(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop))), "Test")
            If (Not (System.IO.Directory.Exists(myPath))) Then
                System.IO.Directory.CreateDirectory(myPath)
                My.Resources.img1.Save(myPath & "\img1.jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
                My.Resources.img2.Save(myPath & "\img2.jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
            End If
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            PictureBox1.BackgroundImage = Nothing
            Dim bmp As Bitmap = New Bitmap(My.Resources.img1, PictureBox1.Size)
            PictureBox1.BackgroundImage = bmp
            'PictureBox1.Image = My.Resources.img1
            PictureBox1.BackgroundImageLayout = ImageLayout.Stretch
            Label1.Text = "W: " & My.Resources.img1.Width & " x H: " & My.Resources.img1.Height
            Label2.Text = "img1"
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            PictureBox1.BackgroundImage = Nothing
            Dim bmp As Bitmap = New Bitmap(My.Resources.img2, PictureBox1.Size)
            PictureBox1.BackgroundImage = bmp
            'PictureBox1.Image = My.Resources.img2
            PictureBox1.BackgroundImageLayout = ImageLayout.Stretch
            Label1.Text = "W: " & My.Resources.img2.Width & " x H: " & My.Resources.img2.Height
            Label2.Text = "img2"
        End Sub
    
        Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
            PictureBox1.Controls.Remove(TGlass)
            TGlass.BackColor = Color.Transparent
            TGlass.ForeColor = Color.Red
            TGlass.AutoSize = True
            TGlass.Text = "Hello"
            TGlass.Font = New Font("Arial", 76, FontStyle.Bold)
            TGlass.Location = New Point(5, 75)
            PictureBox1.Controls.Add(TGlass)
        End Sub
    
        Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
            Dim myBitmap As Bitmap = Nothing
            Using fs As New System.IO.FileStream(myPath & "\" & Label2.Text & ".jpg", System.IO.FileMode.Open, System.IO.FileAccess.Read)
                Dim img As Bitmap = CType(Bitmap.FromStream(fs), Bitmap)
                PictureBox1.BackgroundImage = img
                Dim g As Graphics = Graphics.FromImage(img)
                ' Text position of Label TGlass
                Dim topleft As Point
                topleft = New Point(TGlass.Left, TGlass.Top)
                ' Text content of Label TGlass
                Dim strCalendar As String = TGlass.Text
                ' Rectangle layout for the selected font
                Dim layout As New Rectangle(topleft, TGlass.Size)
                ' Rectangle position with respect of the image
                layout.X = CInt(layout.X * (img.Height / PictureBox1.Height))
                layout.Y = CInt(layout.Y * (img.Width / PictureBox1.Width))
    
    
                ' Text First Page
                Dim myFontSize As Integer
                myFontSize = CInt(TGlass.Font.Size * (img.Width / PictureBox1.Width) / 3.16)
    
    
                Dim myFont As New Font(TGlass.Font.FontFamily, myFontSize, TGlass.Font.Style)
                Dim myBrush As New SolidBrush(TGlass.ForeColor)
                ' Drawing on Image
                g.DrawString(strCalendar, myFont, myBrush, layout.X, layout.Y)
                myBitmap = img
            End Using
            ' Save (Replace) the Image in the right folder
            myBitmap.Save(myPath & "\N_" & Label2.Text & ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
            PictureBox1.Controls.Remove(TGlass)
        End Sub
    
    End Class
    

    Thanks,
    Jean-Luc


  3. Jean-Luc Coudret 21 Reputation points
    2021-05-26T22:07:26.563+00:00

    Hi,

    I followed your advice (also with the help of this link).
    It is much better, but not perfect. But I don't think now it is possible to have something perfect because of the conversion pixels to points, need to consider dpi, screen resolution... (or maybe I am wrong).
    Anyway, below is the code I am using now. Note there is still something I don't understand as I need to divide by 3 or 4 (depending of the code I used) in the formula calculating myFontSize. If someone understand why, do not hesitate to tell me.

        Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
            Dim myBitmap As Bitmap = Nothing
            Using fs As New System.IO.FileStream(myPath & "\" & Label2.Text & ".jpg", System.IO.FileMode.Open, System.IO.FileAccess.Read)
                Dim img As Bitmap = CType(Bitmap.FromStream(fs), Bitmap)
                PictureBox1.BackgroundImage = img
                Dim g As Graphics = Graphics.FromImage(img)
    
                ' Text position of Label TGlass
                Dim topleft As Point
                topleft = New Point(TGlass.Left, TGlass.Top)
                ' Text content of Label TGlass
                Dim strCalendar As String = TGlass.Text
                ' Text ForeColor
                Dim myColor As Color
                myColor = TGlass.ForeColor
                ' Rectangle layout for the selected font
                Dim layout As New Rectangle(topleft, TGlass.Size)
                ' Rectangle position with respect of the image
                layout.X = CInt(layout.X * (img.Height / PictureBox1.Height))
                layout.Y = CInt(layout.Y * (img.Width / PictureBox1.Width))
    
                ' Text First Page
                Dim intRenderer As SizeF
                Dim myFontSize As Integer
                'intRenderer = TextRenderer.MeasureText(strCalendar, New Font(TGlass.Font.FontFamily, TGlass.Font.Size, TGlass.Font.Style, GraphicsUnit.Pixel))
                'myFontSize = CInt((intRenderer.Width / PictureBox1.Width) * img.Width / 3)
                intRenderer = TextRenderer.MeasureText(strCalendar, TGlass.Font)
                myFontSize = CInt((intRenderer.Width / PictureBox1.Width) * img.Width / 4)
                ' New Font for Text applied on Image
                Dim myFont As New Font(TGlass.Font.FontFamily, myFontSize, TGlass.Font.Style)
                ' Drawing on Image
                TextRenderer.DrawText(g, strCalendar, myFont, New Point(layout.X, layout.Y), myColor)
    
                myBitmap = img
            End Using
            ' Save (Replace) the Image in the right folder
            myBitmap.Save(myPath & "\N_" & Label2.Text & ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
            PictureBox1.Controls.Remove(TGlass)
        End Sub