We're sorry Aspose doesn't work properply without JavaScript enabled.

Free Support Forum - aspose.com

Cannot replace image in doc file when disable loading external resources

Hi Aspose,
I want to replace all images in this sample.zip (38.8 KB). I use ImageData.SetImage(), but the image returned is difference.
My current version is Aspose.Words 22.3
Here is my current code:

public class ExternalResourceHandler : IResourceLoadingCallback
{
    public ResourceLoadingAction ResourceLoading(ResourceLoadingArgs args)
    {
        return ResourceLoadingAction.Skip;
    }
}

using (var inStream = new FileStream(sampleFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    var loadOptions = new LoadOptions
    {
        ResourceLoadingCallback = new ExternalResourceHandler()
    };
    Document doc = new Document(inStream, loadOptions);
    var shapes = doc.GetChildNodes(NodeType.Shape, true).ToArray();
    foreach (var shape in shapes)
    {
        var currentShape = shape as Shape;
        if (currentShape.HasImage)
        {
            currentShape.ImageData.SetImage(@"E:\Downloads\image.png");
            currentShape.ImageData.Save(@"E:\Downloads\tmp_out.png");
        }
    }
}

Please investigate. Thanks!

@dunghnguyen The problem occurs because ExternalResourceHandler is called when you use ImageData.SetImage(@"C:\Temp\image.png"). Ans image is skipped.
So to resolve the problem you should either not use ExternalResourceHandler, or use it while loading the document, but do not use it after loading:

var loadOptions = new LoadOptions
{
    ResourceLoadingCallback = new ExternalResourceHandler()
};
Document doc = new Document(inStream, loadOptions);
doc.ResourceLoadingCallback = null;

@alexey.noskov
I want to disable loading external resources and replace the image in sample file by my local image.
And I tried to not use ExternalResourceHandler after loading document, but after I assign null to doc.ResourceLoadingCallback, the external images will be loaded.
Is there any way to use ImageData.SetImage while using ExternalResourceHandle ?

Below is my code and sample.zip (6.2 KB)

var loadOptions = new LoadOptions
{
    ResourceLoadingCallback = new ExternalResourceHandler()
};
Document doc = new Document(inStream, loadOptions);
var shapes = doc.GetChildNodes(NodeType.Shape, true).ToArray();
foreach (var shape in shapes)
{
    var currentShape = shape as Shape;
    if (currentShape.HasImage)
    {
        currentShape.ImageData.Save(@"E:\Downloads\tmp_out1.png");
        doc.ResourceLoadingCallback = null;
        currentShape.ImageData.Save(@"E:\Downloads\tmp_out2.png");
        doc.ResourceLoadingCallback = new ExternalResourceHandler();
        currentShape.ImageData.Save(@"E:Downloads\tmp_out3.png");
    }
}

@dunghnguyen Yes, you can set the image data using IResourceLoadingCallback. For example see the following code:

private class ExternalResourceHandler : IResourceLoadingCallback
{
    public ResourceLoadingAction ResourceLoading(ResourceLoadingArgs args)
    {
        if (args.ResourceType == ResourceType.Image)
        {
            args.SetData(File.ReadAllBytes(@"C:\Temp\image.png"));
            return ResourceLoadingAction.UserProvided;
        }

        return ResourceLoadingAction.Default;
    }
}

However, in your case image in your document is inserted using INCLUDEPICTURE field. In this code external resource is not loaded. It is loaded on demand when you open the document in MS Word or if your render the document (Save to PDF or any other fixed page format).

You can detect such shapes using ImageData.IsLinkOnly property. For example you can replace such image using code like the following:

// Reset resource loading callback
doc.ResourceLoadingCallback = null;

NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
foreach (Shape s in shapes)
{
    if (s.HasImage && s.ImageData.IsLinkOnly)
    {
        string imagePath = @"C:\Temp\image.png";
        s.ImageData.SetImage(imagePath);
        s.ImageData.SourceFullName = imagePath;
    }
}