Problem with replacing Image

Hi,

I am trying to find a string and replace it with an image.

My keyword is SIGNATURE

In my document i have " By : SIGNATURE "

when i replace it with image, it’s inserting the image before “By” word rather than after it.

I am using the following replace callback. Please help.

private static class SearchAndReplaceImage implements IReplacingCallback {
    byte[] image;

    public void setImage(byte[] img) {
        this.image = img;
    }

    public int replacing(ReplacingArgs e) throws Exception {
        String is = e.getMatch().group();

        Document doc = (Document)e.getMatchNode().getDocument();
        DocumentBuilder builder = new DocumentBuilder(doc);
        builder.moveTo(e.getMatchNode());
        builder.insertImage(image);
        return ReplaceAction.REPLACE;
    }
}

Hi Rama,

Thanks for the inquiry. Please change your code snippet as described below:

DocumentBuilder builder = new DocumentBuilder(doc);
builder.moveTo(e.getMatchNode());
builder.insertImage(image);
e.setReplacement("");
return ReplaceAction.REPLACE;

I hope, this will help. In case of any ambiguity, please let us share input files for investigation purposes.

Hi,

May be i wasn’t clear of my problem. I want to replace a keyword with an image in the document.

builder.moveTo(e.getMatchNode()); gets to the Node Run of the matching text but i want the image to be placed right in place of the matching keyword but Node Run gives me the whole line of text. How do i move the cursor just before the matching keyword but not to the starting point of the Node? I am attaching the document for your furthur investigation.

Thanks

Hi Rama,

Thanks for the inquiry and sorry for delay response. In your case, I have changed the code snippet as below. Moreover, you can observe the attached document where it is inserting image after “By” word.

Document doc = (Document)e.getMatchNode().getDocument();
DocumentBuilder builder = new DocumentBuilder(doc);
Node currentNode = (Node)e.getMatchNode().getParentNode();
builder.moveTo(currentNode);
// builder.moveTo(e.getMatchNode());
builder.insertImage("c:/temp/signature.jpg");
return ReplaceAction.REPLACE;

I hope, this will help.

Hi Rama,

It is to update you that the above code does not cover all cases. Please follow up the following code snippet:

public class TextReplaceWithImage implements IReplacingCallback{
    public int replacing(ReplacingArgs e) throws Exception {

        // This is a Run node that contains either the beginning or the complete match. Node currentNode = e.getMatchNode(); 
        // The first (and may be the only) run can contain text before the match, // in this case it is necessary to split the run.
        if (e.getMatchOffset() > 0)
            currentNode = SplitRun((Run)currentNode, e.getMatchOffset());

        // This array is used to store all nodes of the match for further removing. ArrayList runs = new ArrayList(); 
        // Find all runs that contain parts of the match string. int remainingLength = e.getMatch().group().length();//.oz().cI(1).getValue().//..Value.Length; while (
        (remainingLength > 0) &&
                (currentNode != null) &&
                (currentNode.getText().length() <= remainingLength))
        {
            runs.add(currentNode);
            remainingLength = remainingLength - currentNode.getText().length();
            // Select the next Run node. // Have to loop because there could be other nodes such as BookmarkStart etc. do { currentNode = currentNode.getNextSibling(); } while ((currentNode != null) && (currentNode.getNodeType() != NodeType.RUN)); } 
            // Split the last run that contains the match if there is any text left. if ((currentNode != null) && (remainingLength > 0)) { SplitRun((Run)currentNode, remainingLength); runs.add(currentNode); }

            Document doc = (Document)e.getMatchNode().getDocument();
            DocumentBuilder builder = new DocumentBuilder(doc);
            builder.moveTo((Run)runs.get(runs.toArray().length - 1));
            builder.insertImage("c:/temp/test128/signature.jpg");
            return ReplaceAction.REPLACE;
        }
        private static Run SplitRun(Run run, int position) { Run afterRun = (Run)run.deepClone(true); afterRun.setText(run.getText().substring(position)); run.setText(run.getText().substring(0, position)); run.getParentNode().insertAfter(afterRun, run); return afterRun; }
    }
}

I hope this will help.

I have been trying to similarly use this technique to find and replace (with new nodes) multiple occurances of the same text, where the original text occurs within a run and needs to be split as in the sample code here. The problem I am running into is that regardless of whether or not I call setReplacement and return ReplaceAction.SKIP or ReplaceAction.REPLACE, the Range’s replacing mechanism seems to get confused and replacements after the first occurance end up in wrong and unpredictable locations. It seems that Range.replace is relly not intended to support replacing text with anything but new text? Or do you have any more complex examples to demonstrate how to replace multiple occurances of text with more complex groups of nodes?

Hi Tad,

Please accept my apologies for late response.

Thanks for your inquiry. It would be great if you please share your input document along with expected output document here for our reference. We will then provide you more information about your query along with code.

For the record I have attached a much simplified example input document. Everywhere there is a text surrounded by braces it would be repalced either with text or a complex table.

Since my original post I have gotten this to work, however the solution is rather complex code. I first use Range.replace to locate all of the nodes that I need to replace, then I make a second pass to replace the matched node(s) with simple text or complex tables. Per my original post, the two passes seem necessary because making the replacements during the first pass seem to confuse the positioning of the replace feature. Furthermore mimicking Word’s behavior for handling spacing when inserting new content for various circumstances (i.e. variables back-to-back, on lines by themselves, when the inserted tables follow empty paragraphs, etc.) required a lot of trial and error and learning the Aspose Document model. Aspose is a “life saving” tool even having to do all of the above. It would be nice if the replace feature was able to handle all of that for me.

-Tad

Hi Tad,

Thanks for sharing the input document. You can achieve your requirements by using Aspose.Words. If you want to replace simple text, please use the Document.Range.Replace method as shown in following code snippet. Please read following documentation link for your kind reference.
https://docs.aspose.com/words/java/find-and-replace/

Document doc = new Document(MyDir + "in.docx");
doc.Range.Replace("[CUSTOMER NAME]", "MY text", false, false);
doc.Range.Replace("[EFFECTIVE DATE]", "MY text", false, false);
doc.Save(MyDir + "out.docx");

If you want to do ‘Find and Replace’ with complex scenario, you can also achieve your requirement by implementing IReplacingCallback interface. Please use the same approach shared at following documentation link to achieve your requirements.
https://docs.aspose.com/words/net/find-and-replace/

If you still face problem, please manually create your expected Word document using Microsoft Word and attach it here for our reference. We will investigate, how you want your final Word output be generated like. We will then provide you more information on this along with code.

My solution is based on the examples that you reference, which are good starting points.

Hi Tad,

Thanks for your feedback. Please let us know if you face any issue while working with find and replace, we will be happy to help you.