none
How can I replace Image with Text in Word, using VB? RRS feed

  • Question

  • Hello,

     

    I cant seem to find the correct code in other topics, but I apologize if I ask something that has already been answered somewhere else.

     

    I am working on a script to replace certain elements in a Word-document, so it can be transferred to a plain txt file. I need this to post data on wikidot.com and they use flat text files and alternate coding.

     

    I have managed to replace style-elements with plain txt-coding, but now I am trying to replace all the images in the document with a text block, in the best case a unique text for every image.

     

    Let's say I want the images in the document replaced by "[[image uniquenr.jpg]]", how do I do that?

     

    I would really appreciate your help.

    • Moved by Cindy Meister MVPModerator Friday, September 9, 2011 11:13 AM Word-specific issue (From:Visual Studio Tools for Office)
    Friday, September 9, 2011 9:32 AM

Answers

  • Hi Peter

    Yes, theres a ConvertToInlineShape method. That would certainly simplify things :-)

    <<On the other hand, it's not my intention to copy the layout of the document literally. So if a Shape is (let's say) always aligned on the right, maybe I should just accept that. Re-aligning an image by hand afterwards it's not that much work.>>

    InlineShapes will align according to paragraph formatting (usually left) and not to what formatting the Shape might have had. But you could certainly pick up that information from the Shape before converting then apply that to the paragraph.

    My recommendation would be to look at a couple of documents in the Word UI. See what happens when you convert a Shape to an InlineShape, just to get a "feel" for how Word works. (The object model is very close to the UI in so many respects that that does help).

    When you've got an InlineShape, replacing it with text is dead simple:
      Word.InlineShape ils = oShape.ConvertToInlineShape();
      ils.Range.Text = "the text"; 
      //at this point, the shape is gone because the content of the range has been replace

    Note please, however, that there are some kinds of Shapes that cannot be converted to InlineShapes (drawing objects, for example). So that does bring us full loop in figuring out the Anchor point if you need to support these.


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:57 AM
    Friday, September 9, 2011 11:12 AM
    Moderator
  • Hi Peter

    <<Can I do something with loops and counters? So the counter-value acts as part of the plain-text?>>

    Sure. You need to loop the collections, anyway, either using For Each or For...Next. In the first case, you can increment a counter, in the second, the counter is already part of the loop structure.

    For each shp in theDocument.Shapes vs. For counter = 1 to theDocument.Shapes.Count

    Actually, since you'll be removing things from the collection, the best approach is probably:

    For counter = theDoc.Shapes.Count to 1, Step -1

    meaning you'd work backwards through the collection. That's safest when you're removing items from it.


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:56 AM
    Friday, September 9, 2011 2:19 PM
    Moderator
  • Hi Peter

    Ah, yes, I'd forgotten about Find.Text = "^g".

    You'll want to test thoroghly whether this finds ALL graphic types. Now that you've jogged my memory, I seem to recall there are some kinds of graphics it doesn't "see".

    Also, the same "problem" remains about where the text actually turns up IF the graphic had text wrapping. You'll also want to see whether the result is satisfactory.

    As to the "uniqueness": you've got a loop, but I'm not sure it's going to actually loop as you intend. You need to call Find again within the loop. And you want to change the following : .Wrap = wdFindContinue to wdFindStop.


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:56 AM
    Saturday, September 10, 2011 11:33 AM
    Moderator
  • If you leave it as wdFindContinue, the code will (probably) go into a continuous loop and never stop.  With wdFindStop on the other hand, when it gets to the end of the document, it will stop.

     


    Doug Robbins - Word MVP dkr[atsymbol]mvps[dot]org
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:56 AM
    Sunday, September 11, 2011 12:30 AM

All replies

  • Hi Peter

    It might be best if I move this to the Word for Developers forum, as this doesn't seem to be an issue with the VSTO technology?

    The tricky thing with Word is that there are two collections for graphics: Shapes and InlineShapes. The former are the kind that have text flow (text wrapping around the graphic). The latter are treated like text characters.

    Doing what you want would be simplest with InlineShapes, but I suspect you'd need to allow for both kinds?

    The issue with Shapes is that, once you insert "plain text" it's not going to be in the same position on the page. So you need to think about how you want to handle that. A Shape has an Anchor property that refers to a RANGE object - the position in the text with which the graphic is associated. Thing is, that might not be what you want or expect.

    so you need to give this some thought before we can start discussing code samples :-)


    Cindy Meister, VSTO/Word MVP
    Friday, September 9, 2011 9:38 AM
    Moderator
  • Hi Cindy,

     

    Thank you for your quick reply. I think it will probably be better if this tread is moved to the other form. Can you easily do that?

     

    Regarding your answer: yes, I need to allow both kinds of shapes as I think it's harder to educate the users than to program both cases :)

    I think I understand what you are saying about the two types. Is it possible to convert Shapes to InlineShapes? Maybe that's a helpfull step in de process. 

    On the other hand, it's not my intention to copy the layout of the document literally. So if a Shape is (let's say) always aligned on the right, maybe I should just accept that. Re-aligning an image by hand afterwards it's not that much work.


    Friday, September 9, 2011 11:06 AM
  • Hi Peter

    Yes, theres a ConvertToInlineShape method. That would certainly simplify things :-)

    <<On the other hand, it's not my intention to copy the layout of the document literally. So if a Shape is (let's say) always aligned on the right, maybe I should just accept that. Re-aligning an image by hand afterwards it's not that much work.>>

    InlineShapes will align according to paragraph formatting (usually left) and not to what formatting the Shape might have had. But you could certainly pick up that information from the Shape before converting then apply that to the paragraph.

    My recommendation would be to look at a couple of documents in the Word UI. See what happens when you convert a Shape to an InlineShape, just to get a "feel" for how Word works. (The object model is very close to the UI in so many respects that that does help).

    When you've got an InlineShape, replacing it with text is dead simple:
      Word.InlineShape ils = oShape.ConvertToInlineShape();
      ils.Range.Text = "the text"; 
      //at this point, the shape is gone because the content of the range has been replace

    Note please, however, that there are some kinds of Shapes that cannot be converted to InlineShapes (drawing objects, for example). So that does bring us full loop in figuring out the Anchor point if you need to support these.


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:57 AM
    Friday, September 9, 2011 11:12 AM
    Moderator
  • Great! I must admit that I am not a very experienced VB-scripter, but I am trying to get the hang of things. Looking at some documents and just see how things react is always good advice. Makes me a better scripter too :)

     

    In my first post I also hoped for a solution to this: I am trying to replace all the images in the document with a text block, in the best case a unique text for every image.

    Can I do something with loops and counters? So the counter-value acts as part of the plain-text?

     

    You're a great help so far!

    Friday, September 9, 2011 11:32 AM
  • Hi Peter

    <<Can I do something with loops and counters? So the counter-value acts as part of the plain-text?>>

    Sure. You need to loop the collections, anyway, either using For Each or For...Next. In the first case, you can increment a counter, in the second, the counter is already part of the loop structure.

    For each shp in theDocument.Shapes vs. For counter = 1 to theDocument.Shapes.Count

    Actually, since you'll be removing things from the collection, the best approach is probably:

    For counter = theDoc.Shapes.Count to 1, Step -1

    meaning you'd work backwards through the collection. That's safest when you're removing items from it.


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:56 AM
    Friday, September 9, 2011 2:19 PM
    Moderator
  • For 'the fun of it' I took another approach (see below), but not yet with the unique-value in it. I will add this later.

    It seems to work, but am I doing the right thing?

     

    Private Sub ConvertImages()
        ActiveDocument.Select
        
        With Selection.Find
            .ClearFormatting
            .Text = "^g"
            .Format = True
            .MatchCase = False
            .MatchWholeWord = False
            .MatchWildcards = False
            .MatchSoundsLike = False
            .MatchAllWordForms = False
            
            .Forward = True
            .Wrap = wdFindContinue
            
            Do While .Execute
                With Selection
                    If InStr(1, .Text, vbCr) Then
                        ' Just process the chunk before any newline characters
                        .Collapse
                        .MoveEndUntil vbCr
                    End If
                                           
                    If Not .Text = vbCr Then
                        .Text = "[[image NEW]]"
                    End If
                End With
            Loop
        End With
    End Sub
    


     




    • Edited by PeterJongsma Saturday, September 10, 2011 11:33 AM
    Saturday, September 10, 2011 11:24 AM
  • Hi Peter

    Ah, yes, I'd forgotten about Find.Text = "^g".

    You'll want to test thoroghly whether this finds ALL graphic types. Now that you've jogged my memory, I seem to recall there are some kinds of graphics it doesn't "see".

    Also, the same "problem" remains about where the text actually turns up IF the graphic had text wrapping. You'll also want to see whether the result is satisfactory.

    As to the "uniqueness": you've got a loop, but I'm not sure it's going to actually loop as you intend. You need to call Find again within the loop. And you want to change the following : .Wrap = wdFindContinue to wdFindStop.


    Cindy Meister, VSTO/Word MVP
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:56 AM
    Saturday, September 10, 2011 11:33 AM
    Moderator
  • Can you explain this one to me?

    And you want to change the following : .Wrap = wdFindContinue to wdFindStop

     


     


    Saturday, September 10, 2011 12:13 PM
  • If you leave it as wdFindContinue, the code will (probably) go into a continuous loop and never stop.  With wdFindStop on the other hand, when it gets to the end of the document, it will stop.

     


    Doug Robbins - Word MVP dkr[atsymbol]mvps[dot]org
    • Marked as answer by Liliane Teng Wednesday, September 21, 2011 8:56 AM
    Sunday, September 11, 2011 12:30 AM
  • Inline Shapes are straightforward; floating ones, a tad trickier. This will convert all Shapes to InlineShapes and then replace all inline shapes with text; it should get you started.
     
        With ActiveDocument
            Do While ..Shapes.Count > 0
                ..Shapes(1).ConvertToInlineShape
            Loop
            Do While ..InlineShapes.Count > 0
                Count = Count + 1
                ..InlineShapes(1).Range.Text = " [[image number" & Count & ".jpg]] "
            Loop
        End With

    Enjoy,
    Tony
    www.WordArticles.com
    Thursday, September 15, 2011 2:24 PM
  • Grrrr!! Please ignore my post - I have just discovered that most of this thread was not visible to me because it has been moved, and that my post was unnecessary (and inadequate!).

     


    Enjoy,
    Tony
    www.WordArticles.com
    Thursday, September 15, 2011 3:31 PM