none
How to identify unique images in a RTF? RRS feed

  • Question

  • I am using VB 2017 in Windows 10. I have a richtextbox that a 16x16 .png image is inserted in several locations. Just before the image is inserted I place a unique ID number in the images' .tag property. When the image is clicked I can identify that it is an object (type matches image). What I am not being able to do is read the unique ID number. Any suggestions or does the rich text remove this? 
    Wednesday, May 31, 2017 1:28 AM

Answers

  • I like this approach. In fact I had this same idea that I was going to try. I also was looking at the other type of images, .BMP etc. I was going to load them into the RTF and then view the raw rich text to see how each type is embedded into it. 

    The only issues I have thought about is like you say it might change some of the color of the image. Since I have my image in a resource file I have better control over the original being overwritten.

    Thanks IronRazerz

     No problem.  8)

     Also,  i just updated my last post just in case you want to protect the images as i explained.  I thought of checking the RTF too but,  just had this in mind and figured i would share the idea since i knew it could be implemented quickly and easily.  I have not checked but,  there is ways to embed OLE objects using win32 api functions which may have a way to embed and retrieve an id of some sort to/from the OLE objects but,  it would probably be a long drawn out bunch of complex code to do it.  Have not tried it myself though.


    If you say it can`t be done then i`ll try it


    Hola Razerz. 5 mins till my library times up! ;)

    La vida loca

    • Marked as answer by G Owen B Tuesday, June 6, 2017 2:02 AM
    Friday, June 2, 2017 9:40 PM

All replies

  • I am using VB 2017 in Windows 10. I have a richtextbox that a 16x16 .png image is inserted in several locations. Just before the image is inserted I place a unique ID number in the images' .tag property. When the image is clicked I can identify that it is an object (type matches image). What I am not being able to do is read the unique ID number. Any suggestions or does the rich text remove this? 

    If you are inserting a .Net object then you can retrieve that object and check the tag property.  If you are inserting an image, then there is no tag property - it is not part of the image and it is not retrieved when the image is retrieved. 

    So it all depends on how you are doing the insert, and exactly what you mean by 'type matches image'.

    Wednesday, May 31, 2017 1:37 AM
  • I am using VB 2017 in Windows 10. I have a richtextbox that a 16x16 .png image is inserted in several locations. Just before the image is inserted I place a unique ID number in the images' .tag property. When the image is clicked I can identify that it is an object (type matches image). What I am not being able to do is read the unique ID number. Any suggestions or does the rich text remove this? 

    At the point that it becomes Rich Text Format, it turns everything (images included) into text in a special format.

    I don't know if the same image would generate the same RTF or not, but none of that is anything built into the dotNET framework.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, May 31, 2017 1:32 PM
  • G,

    Maybe can you explain a little bit (with code) how you insert that 16x16 image. The RTF is just a string of characters which has code include to identify the (fysical) objects used. 

    However, maybe you have even simply put that data inside a document using a keyboard.


    Success
    Cor


    Wednesday, May 31, 2017 3:59 PM
  • My guess is you could add a PictureBox to the RichTextBox and handle the Click Event:

    The problem is the picturebox is located above the text... so you need to handle the scrolling and position of the PictureBox yourself to simulate a document with text and images.... but that's another question...

    Private WithEvents aPicturebox As New PictureBox
        Private WithEvents aPicturebox2 As New PictureBox
    
        Private Sub aPicturebox_Click(sender As Object, e As EventArgs) Handles aPicturebox.Click
            Me.RichTextBox1.AppendText("                                                                                     Image1 clicked" & Environment.NewLine)
        End Sub
    
        Private Sub aPicturebox2_Click(sender As Object, e As EventArgs) Handles aPicturebox2.Click
            Me.RichTextBox1.AppendText("                                                                                     Image2 clicked" & Environment.NewLine)
        End Sub
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Load text
            RichTextBox1.AppendText("This is first line" & Environment.NewLine)
            
            'Load PictureBox into RTB
    
            aPicturebox.Image = My.Resources.Capture
            aPicturebox.Tag = "Link?"
            aPicturebox.SizeMode = PictureBoxSizeMode.StretchImage
            aPicturebox.Size = New Size(New Point(100, 100))
            aPicturebox.Location = Me.RichTextBox1.GetPositionFromCharIndex(Me.RichTextBox1.TextLength)
            'Addind the PictureBox to the RTB
            Me.RichTextBox1.Controls.Add(aPicturebox)
    
            aPicturebox2.Image = My.Resources.Capture2
            aPicturebox2.Tag = "Link2"
            aPicturebox2.SizeMode = PictureBoxSizeMode.StretchImage
            aPicturebox2.Size = New Size(New Point(100, 100))
            aPicturebox2.Location = aPicturebox.Location + New Point(0, 150)
            'Addind the PictureBox to the RTB
            Me.RichTextBox1.Controls.Add(aPicturebox2)
            
        End Sub
    
    End Class

    Wednesday, May 31, 2017 5:44 PM
  • Hi G Owen B,

    Please try to the code below to detect the images in RTF.

      Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If OpenFileDialog1.ShowDialog = DialogResult.OK Then
                Dim img As Image = Image.FromFile(OpenFileDialog1.FileName)
                Clipboard.SetImage(img)
                RichTextBox1.Paste()
            End If
        End Sub
    
        Private Sub Form24_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            MsgBox("contains image: " & RichTextBox1.Rtf.Contains("\pict\wmetafile8\"))
        End Sub

    it searches the richtextbox inner code, "\pict\wmetafile8\" is the pic tag.

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, June 1, 2017 6:12 AM
    Moderator
  • Hi G Owen B,

    Please try to the code below to detect the images in RTF.

      Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If OpenFileDialog1.ShowDialog = DialogResult.OK Then
                Dim img As Image = Image.FromFile(OpenFileDialog1.FileName)
                Clipboard.SetImage(img)
                RichTextBox1.Paste()
            End If
        End Sub
    
        Private Sub Form24_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            MsgBox("contains image: " & RichTextBox1.Rtf.Contains("\pict\wmetafile8\"))
        End Sub

    it searches the richtextbox inner code, "\pict\wmetafile8\" is the pic tag.

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Cherry,

    I was curious if it would go. However this was the result.


    Success
    Cor

    Thursday, June 1, 2017 10:26 AM

  • Cherry,

    I was curious if it would go. However this was the result.


    Success
    Cor

    As it turns out, it *might* be in there but there's no promise of it.

    When I was reading more about the RTF specification yesterday, they made it clear that the writer of the RTF has a lot of latitude in just how it's written, so long as it follows certain guidelines so that it can be rendered correctly then it's fine.

    If you use, for example, MS Word to create the RTF, the file's name will be in there but if you use another writer - it might not be in there.

    As an example: Take the document to PDF then to RTF and it won't be in there. The PDF doesn't need it so the image's file name isn't in the source at all.


    "A problem well stated is a problem half solved.” - Charles F. Kettering


    Thursday, June 1, 2017 11:54 AM
  • First let me say I'm sorry for not responding sooner, wife was taken to hospital. Second thanks for all the replies and suggestions. 

    To give more detail on the programs usage, a user will be able to read a RTF in a RichTextBox control in VB. I want to allow them to make a note and indicate in the file that there is a note attached to the current text. My approach is when the user selects "Insert Note" I bring up another form with a RichTextBox so they can write the note. When they select "Save" the note will be written into an Access DB and I then place the .png image into the RTF at the location that they selected. In the image I need then to be able to insert the Access record number. They can do this several times in a document. Later when they or someone else looks at the document they should be able to click on any one of the images and I will display the note. 

    My first approach was to insert the image with the Clipboard. Hers is my code.

     ' get image from the resource file
                Dim Picture As Image = CType(My.Resources.ResourceManager.GetObject("Note"), Image)
                ' place the unique Note ID in the Access DB
                Picture.Tag = "Note:" & NoteNameID.ToString
                ' get the data in the Clickboard to restore later
                Dim cboard As Object = Clipboard.GetData(System.Windows.Forms.DataFormats.Text)
                ' load image into the Clipboard
                Clipboard.SetImage(Picture)
                Dim PictureFormat As DataFormats.Format = DataFormats.GetFormat(DataFormats.Bitmap)
                ' paste into RTF if allowed
                If rtb.CanPaste(PictureFormat) Then
                    rtb.Paste(PictureFormat)
                End If
                ' clear data and restore previous in the Clipboard
                Clipboard.Clear()
                Clipboard.SetText(cboard)

    This has the effect that I need and the images are embedded in the RTF and scrolls with the text. But retrieving the .Tag information that has the Access record number is where I fail.

    Next I tried attaching a PictureBox to the RichTextBox as a control but the picturebox does not scroll. Here was that code.

     Dim Picture As Image = CType(My.Resources.ResourceManager.GetObject("Note"), Image)
                Dim pb As New PictureBox With {.Image = Picture} 
                pb.SizeMode = PictureBoxSizeMode.AutoSize
                'AddHandler pb.MouseClick, AddressOf Clicked
                rtb.Controls.Add(pb)

    Has anyone used the OLE method of adding to a RichTextBox and will it scroll if added this way?

    Thursday, June 1, 2017 3:40 PM
  • Maybe somebody can help you with this using RTF

    But otherwise it is a perfect description why HTML was made as document language. 

    https://en.wikipedia.org/wiki/HTML


    Success
    Cor


    Thursday, June 1, 2017 3:55 PM
  •  You could take the approach of changing the color of 2 pixels in your "Note" image before adding it to the RichTextBox.  In the example below i change the Green and Blue channel values of the first two pixel of my "Note" image before pasting it into the selected index of the RichTextBox.  The 4 values i change in the 2 pixels are set by the 4 Byte values i get from the ID integer number.

     This may be more noticeable in the png image depending on the colors in it and how high the ID values go for the notes.  If there are 1 to maybe 50 or 60 notes,  you probably would note really notice the pixel color change if you use two black pixels where the ID number is set.  Notice my image has a black border and with and id of 1 or 2, there is no difference to the naked eye.

    Public Class Form1
        Private Notes As New Dictionary(Of Integer, String)
    
        Private Sub Button_InsertNote_Click(sender As Object, e As EventArgs) Handles Button_InsertNote.Click
            If RichTextBox_Note.Text.Trim <> "" Then
                Dim IdBts() As Byte = BitConverter.GetBytes(CInt(NumericUpDown_Id.Value)) 'get the 4 bytes from the ID Integer number
                Notes.Add(CInt(NumericUpDown_Id.Value), RichTextBox_Note.Text) 'i am adding the text note to a Dictionary using the ID number. You can insert it into your DataBase instead.
                Using bm As New Bitmap(My.Resources.NoteImage)
                    bm.SetPixel(0, 0, Color.FromArgb(255, 0, IdBts(0), IdBts(1))) 'set the 1st pixel`s Green channel to the 1st byte value, and the Blue to the 2nd byte
                    bm.SetPixel(1, 0, Color.FromArgb(255, 0, IdBts(2), IdBts(3))) 'set the 2nd pixel`s Green channel to the 3rd byte value, and the Blue to the 4th byte
                    Clipboard.SetImage(bm) 'copy the bitmap to the clipboard
                End Using
                RichTextBox1.Paste() 'paste it into the RichTextBox at the currently selected index
            End If
        End Sub
    
        Private Sub RichTextBox1_SelectionChanged(sender As Object, e As EventArgs) Handles RichTextBox1.SelectionChanged
            If RichTextBox1.SelectionType = RichTextBoxSelectionTypes.Object Then 'if it is an object that is selected..
                RichTextBox1.Copy() 'copy the object to the clipboard
                If Clipboard.ContainsImage Then 'if the clipboard object is an image...
                    Using bm As New Bitmap(Clipboard.GetImage)
                        'get the Green and Blue channel values from the first two pixels into a Byte array of 4 bytes
                        Dim IdBts() As Byte = New Byte() {bm.GetPixel(0, 0).G, bm.GetPixel(0, 0).B, bm.GetPixel(1, 0).G, bm.GetPixel(1, 0).B}
                        Dim id As Integer = BitConverter.ToInt32(IdBts, 0) 'get the ID Integer value from the 4 bytes
    
                        ''I get the note from the Dictionary using the note's ID. You can get the note from your DataBase using the ID number.
                        MessageBox.Show(Notes.Item(id), "Note Id: " & id.ToString) 'just to show you the ID and the text note...
                    End Using
                End If
            End If
        End Sub
    End Class
     

     Here is an example of how my example is set up and how i used it....

     

     Note that there are several spin-offs of this same technique that you could use for setting the ID into the color channel values of some of the image pixels.  So,  this is just one example.

     

     EDIT:  Below is the 16x16 .png image i used for the example if someone needs it to test the example with.  Right click on it and save it to your hard drive.  Then add it to the applications resources.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Thursday, June 1, 2017 8:39 PM
    Thursday, June 1, 2017 7:51 PM
  •  You could also set the image as protected so that it can not be deleted or removed from the text by the user without using a Button or maybe a ContextMenuStrip Item to call some code to un-protect it and remove it.  Here is how i added that functionality to the prior example.  Note that you will need to get the ID of the selected image and remove that note from your database.

    Public Class Form1
        Private Notes As New Dictionary(Of Integer, String)

        Private Sub Button_InsertNote_Click(sender As Object, e As EventArgs) Handles Button_InsertNote.Click
            If RichTextBox_Note.Text.Trim <> "" Then
                Dim IdBts() As Byte = BitConverter.GetBytes(CInt(NumericUpDown_Id.Value)) 'get the 4 bytes from the ID Integer number
                Notes.Add(CInt(NumericUpDown_Id.Value), RichTextBox_Note.Text) 'i am adding the text note to a Dictionary using the ID number. You can insert it into your DataBase instead.
                Using bm As New Bitmap(My.Resources.NoteImage)
                    bm.SetPixel(0, 0, Color.FromArgb(255, 0, IdBts(0), IdBts(1))) 'set the 1st pixel`s Green channel to the 1st byte value, and the Blue to the 2nd byte
                    bm.SetPixel(1, 0, Color.FromArgb(255, 0, IdBts(2), IdBts(3))) 'set the 2nd pixel`s Green channel to the 3rd byte value, and the Blue to the 4th byte
                    Clipboard.SetImage(bm) 'copy the bitmap to the clipboard
                End Using
                RichTextBox1.Paste() 'paste it into the RichTextBox at the currently selected index

                RemoveHandler RichTextBox1.SelectionChanged, AddressOf RichTextBox1_SelectionChanged
                RichTextBox1.Select(RichTextBox1.SelectionStart - 1, 1)
                RichTextBox1.SelectionProtected = True
                RichTextBox1.Select(RichTextBox1.SelectionStart + 1, 0)
                AddHandler RichTextBox1.SelectionChanged, AddressOf RichTextBox1_SelectionChanged
            End If
        End Sub

        Private Sub RichTextBox1_SelectionChanged(sender As Object, e As EventArgs) Handles RichTextBox1.SelectionChanged
            Dim id As Integer = GetNoteIdFromSelectedImage()
            If id > -1 Then
                ''I get the note from the Dictionary using the note's ID. You can get the note from your DataBase using the ID number.
                MessageBox.Show(Notes.Item(id), "Note Id: " & id.ToString)
            End If
        End Sub

        Private Sub Button_DeleteSelectedNote_Click(sender As Object, e As EventArgs) Handles Button_DeleteSelectedNote.Click
            Dim id As Integer = GetNoteIdFromSelectedImage()
            If id > -1 Then
                Notes.Remove(id) 'remove the note with this id from the Dictionary or your Database
                RichTextBox1.SelectionProtected = False
                RichTextBox1.SelectedText = ""
            End If
        End Sub

        Private Function GetNoteIdFromSelectedImage() As Integer
            Dim id As Integer = -1
            If RichTextBox1.SelectionType = RichTextBoxSelectionTypes.Object Then 'if it is an object that is selected..
                RichTextBox1.Copy() 'copy the object to the clipboard
                If Clipboard.ContainsImage Then 'if the clipboard object is an image...
                    Using bm As New Bitmap(Clipboard.GetImage)
                        'get the Green and Blue channel values from the first two pixels into a Byte array of 4 bytes
                        Dim IdBts() As Byte = New Byte() {bm.GetPixel(0, 0).G, bm.GetPixel(0, 0).B, bm.GetPixel(1, 0).G, bm.GetPixel(1, 0).B}
                        id = BitConverter.ToInt32(IdBts, 0) 'get the ID Integer value from the 4 bytes
                    End Using
                End If
            End If
            Return id
        End Function
    End Class


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Thursday, June 1, 2017 8:57 PM
    Thursday, June 1, 2017 8:45 PM
  • I like this approach. In fact I had this same idea that I was going to try. I also was looking at the other type of images, .BMP etc. I was going to load them into the RTF and then view the raw rich text to see how each type is embedded into it. 

    The only issues I have thought about is like you say it might change some of the color of the image. Since I have my image in a resource file I have better control over the original being overwritten.

    Thanks IronRazerz

    Thursday, June 1, 2017 8:55 PM
  • I like this approach. In fact I had this same idea that I was going to try. I also was looking at the other type of images, .BMP etc. I was going to load them into the RTF and then view the raw rich text to see how each type is embedded into it. 

    The only issues I have thought about is like you say it might change some of the color of the image. Since I have my image in a resource file I have better control over the original being overwritten.

    Thanks IronRazerz

     No problem.  8)

     Also,  i just updated my last post just in case you want to protect the images as i explained.  I thought of checking the RTF too but,  just had this in mind and figured i would share the idea since i knew it could be implemented quickly and easily.  I have not checked but,  there is ways to embed OLE objects using win32 api functions which may have a way to embed and retrieve an id of some sort to/from the OLE objects but,  it would probably be a long drawn out bunch of complex code to do it.  Have not tried it myself though.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Thursday, June 1, 2017 9:07 PM
    Thursday, June 1, 2017 9:06 PM
  • Just a 2c here: there has been a lot of efforts previously to create an "enhanced" RichTextBox.

    For example this one: https://www.codeproject.com/Tips/868653/EXTENDED-Version-of-Extended-Rich-Text-Box-RichTex

    Good programming technique is "steal, reuse and recycle"...

    Friday, June 2, 2017 9:31 AM
  • I like this approach. In fact I had this same idea that I was going to try. I also was looking at the other type of images, .BMP etc. I was going to load them into the RTF and then view the raw rich text to see how each type is embedded into it. 

    The only issues I have thought about is like you say it might change some of the color of the image. Since I have my image in a resource file I have better control over the original being overwritten.

    Thanks IronRazerz

    Well if you copy the image displayed into a rich text box and save it to a file does it then have tag information in the file it is saved to? And the if the RTF is saved and re-displayed in a RichTextBox can the image be copied to a file and provide the tag info? My PC is broke so I can't test any of that. However it may be possible to create a multi layered image, I don't know if you can do that for a RichTextBox, which peeps know how to do and make the second (bottom layer) have something on it to denote it somehow.

    Just like when peeps use code to get all the frames of an animated gif to display singly but I don't have access to Visual Studio or a PC so I can't test anything. Anyhow the bottom frame could have 16x16 pixels of info defining something. Or it could be all transparent perhaps except if the number was for example 19241 then the first pixel could be A000, R192, G41, B000 or I suppose even just binary for the number you would want since binary would fit in the 255 max of ARGB. A100, R101, G100, B101, A001, R000, G000, B000 the bolded being 19241 but perhaps that would be difficult to do or maybe make everything after the binary 2's. Of course that's if a 2 frame image can be stored in RTF for display in a RTB.

    19241 = 10010110010100122222222222222222222222222222222222222222222222222222222....to a total of 256 pixels and the binary starts at 0,0 to 0,13 and 2's go from 0,14 to15,15 I suppose for 16x16. Binary conversion code available but I don't remember it.


    La vida loca


    Friday, June 2, 2017 9:38 PM
  • I like this approach. In fact I had this same idea that I was going to try. I also was looking at the other type of images, .BMP etc. I was going to load them into the RTF and then view the raw rich text to see how each type is embedded into it. 

    The only issues I have thought about is like you say it might change some of the color of the image. Since I have my image in a resource file I have better control over the original being overwritten.

    Thanks IronRazerz

     No problem.  8)

     Also,  i just updated my last post just in case you want to protect the images as i explained.  I thought of checking the RTF too but,  just had this in mind and figured i would share the idea since i knew it could be implemented quickly and easily.  I have not checked but,  there is ways to embed OLE objects using win32 api functions which may have a way to embed and retrieve an id of some sort to/from the OLE objects but,  it would probably be a long drawn out bunch of complex code to do it.  Have not tried it myself though.


    If you say it can`t be done then i`ll try it


    Hola Razerz. 5 mins till my library times up! ;)

    La vida loca

    • Marked as answer by G Owen B Tuesday, June 6, 2017 2:02 AM
    Friday, June 2, 2017 9:40 PM