Replacing a Picture in a Picture Content Control in an Open XML WordprocessingML Document

You may have a picture content control where you want to replace the picture with a different picture.  This post shows the Open XML SDK V2 code that is necessary to find a picture content control with an alias of “MyPicture”.  It then finds the ImagePart, and then replaces the contents of the image part with a different image.


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Drawing;

class Program
{
    static void Main(string[] args)
    {
        using (WordprocessingDocument doc =
            WordprocessingDocument.Open("Test1.docx", true))
        {
            SdtBlock cc = doc.MainDocumentPart.Document.Body.Descendants<SdtBlock>()
                .FirstOrDefault(c =>
                    {
                        SdtProperties p = c.Elements<SdtProperties>().FirstOrDefault();
                        if (p != null)
                        {
                            // Is it a picture content control?
                            SdtContentPicture pict =
                                p.Elements<SdtContentPicture>().FirstOrDefault();
                            // Get the alias.
                            SdtAlias a = p.Elements<SdtAlias>().FirstOrDefault();
                            if (pict != null && a.Val == "MyPicture")
                                return true;
                        }
                        return false;
                    });
            string embed = null;
            if (cc != null)
            {
                Drawing dr = cc.Descendants<Drawing>().FirstOrDefault();
                if (dr != null)
                {
                    Blip blip = dr.Descendants<Blip>().FirstOrDefault();
                    if (blip != null)
                        embed = blip.Embed;
                }
            }
            if (embed != null)
            {
                IdPartPair idpp = doc.MainDocumentPart.Parts
                    .Where(pa => pa.RelationshipId == embed).FirstOrDefault();
                if (idpp != null)
                {
                    ImagePart ip = (ImagePart)idpp.OpenXmlPart;
                    using (FileStream fileStream =
                        File.Open("After.jpg", FileMode.Open))
                        ip.FeedData(fileStream);
                    Console.WriteLine("done");
                }
            }
        }
    }
}

!!!

19 Comments »

  1. victor nilo valenzuela said,

    January 3, 2012 @ 7:09 pm

    Eric, the code work fine when you only have one picture content control, but if you have more all the pictures at the end have the last image processed.
    Could you help me with that?.

    Thanks.

  2. Attila Danicska said,

    January 6, 2012 @ 3:06 pm

    Yes, that’s the problem of me as well. Eric, could you give us a solution, please? I’m not familiar with OpenXml so it is hard to fix it for me. Thanks.

  3. OpenXML Research « gpluft said,

    January 12, 2012 @ 11:11 pm

    […] Read OpenXML Content Control and Replace Data […]

  4. arwa said,

    March 21, 2012 @ 12:05 pm

    I have the same problem that whatever image I use to replace the last content control is used for all of them.
    how can i solve this?

    Thank you,

  5. Eric said,

    June 1, 2012 @ 4:44 pm

    Eric, how do you assign an alias to Word document picture? I was testing your code with a Word document that have an image but the imaga hasn’t alias.

  6. Shailesh B Davara said,

    June 7, 2012 @ 2:40 pm

    Eric,
    when we use above sample code it seems work sometime and it does not work well when we try to integrate it somewhere.
    Also, we found that it just replace out all picture content with the image we supply, instead of that it should only replace tagged name picture control.
    would you give more info on this?

  7. Patrick said,

    June 9, 2012 @ 9:45 am

    Eric, when designing our word document, if we put in a few picture controls, it’s reference ID will be the same, pointing to the same image. That is why when the image is replaced, all the picture controls will have the same image, a problem faced by a few users here.

    What would be the best way to recode this? Anybody who can contribute here would be great.

  8. Jinesh said,

    June 13, 2012 @ 12:44 pm

    Hi Eric

    Just Try This

    Below Code Replace Particular Image

    Public string ApplySignature(string fileName, string imageName, string imageTagName, string SignatureName, string SignatureTag,
    string SignatureDesignation, string SignatureDesignationTag)
    {
    string folderPath = AppDomain.CurrentDomain.BaseDirectory + “shared-data\\”;
    string imagePath = AppDomain.CurrentDomain.BaseDirectory + “temp\\” + imageName;
    string filePath = folderPath + fileName ;
    ApplyContentControl(SignatureName, SignatureTag, SignatureDesignation, SignatureDesignationTag, fileName);
    //ApplyImage(imagePath, fileName, imageTagName, filePath);
    string[] results = new string[2];
    string strResult = “”;

    try
    {
    FileInfo fInfo = new FileInfo(imagePath);

    using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
    {
    DocumentFormat.OpenXml.Drawing.Blip blip = this.GetBlip(doc, imageTagName);
    if (blip != null)
    {
    // Add image and change embeded id.

    blip.Embed = this.AddImagePart(doc, imagePath, imageTagName);
    doc.Package.Flush();

    results[0] = “OK”;

    results[1] = “0”;
    }
    }
    GC.Collect();
    }

    catch (Exception ex)
    {
    results[0] = ex.Message;

    results[1] = “-1”;
    }

    strResult = results[0] + “|” + results[1];
    GenerateValidationFile(filePath + “.log”, strResult);
    return strResult;
    }

    public DocumentFormat.OpenXml.Drawing.Blip GetBlip(WordprocessingDocument pDocument, string pPictureContentControlTagName)
    {
    foreach (SdtAlias alias in pDocument.MainDocumentPart.Document.Descendants().ToList())
    if (alias.Val == pPictureContentControlTagName)
    return alias.Parent.Parent.Descendants().FirstOrDefault();
    return null;
    }

    public string AddImagePart(WordprocessingDocument pDocument, string pPicturePath, string pImagePartId)
    {
    OpenXmlPart part = pDocument.MainDocumentPart.GetPartById(pImagePartId);
    if (part != null)
    {
    pDocument.MainDocumentPart.DeletePart(part);
    }
    ImagePart imagePart = pDocument.MainDocumentPart.AddImagePart(GetImagePartType(pPicturePath), pImagePartId);
    using (FileStream stream = new FileStream(pPicturePath, FileMode.Open, FileAccess.Read))
    {
    imagePart.FeedData(stream);
    }

    return pImagePartId;
    }

    public ImagePartType GetImagePartType(string imagePath)
    {
    ImagePartType imagePartType = ImagePartType.Bmp;

    switch (System.IO.Path.GetExtension(imagePath).ToUpper())
    {
    case “BMP”: imagePartType = ImagePartType.Bmp;
    break;
    case “JPEG”:
    case “JPG”:
    imagePartType = ImagePartType.Jpeg;
    break;
    case “PNG”: imagePartType = ImagePartType.Png;
    break;
    case “GIF”: imagePartType = ImagePartType.Gif;
    break;
    default: imagePartType = ImagePartType.Bmp;
    break;
    }
    return imagePartType;
    }

    private string GenerateValidationFile(string filePath, string Message)
    {
    string directoryPath = Path.GetDirectoryName(filePath);
    string finalFilename = Path.GetFileNameWithoutExtension(filePath) + “.log”;
    StreamWriter SW;
    SW = System.IO.File.CreateText(directoryPath + @”\” + finalFilename);
    SW.WriteLine(Message);
    SW.Close();
    GC.Collect();
    return finalFilename;
    }

    Cheers

    Jinesh

  9. Rajesh said,

    January 18, 2013 @ 4:12 pm

    I modified to use an image inside a footer and always i end up with Image cannot be currently displayed.

    If I place the control inside the body it works well.

    Any help?

    Thanks,
    Rajesh

  10. Eric White said,

    January 18, 2013 @ 7:44 pm

    Hi Rajesh,

    One way to debug these types of problems is to follow the procedure I show in this screen-cast. Give it a try and let me know how it works for you.

    http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/04/01/133710.aspx

    -Eric

  11. Rajesh said,

    January 22, 2013 @ 9:19 am

    Hi Eric,

    Thanks for the reply. Learned a lot of tools/technqs.
    So far badluck, I am unable fix the issue.

    Rajesh

  12. Paul said,

    February 1, 2013 @ 12:00 am

    Hi Eric,

    In your code –

    SdtBlock cc = doc.MainDocumentPart.Document.Body.Descendants().FirstOrDefault(c =>

    what does c reference in c => ??

    Thanks,
    Paul.

  13. AJ said,

    February 1, 2013 @ 12:08 am

    Hi Eric
    This code doesn’t work for me. I’m using SDK 2.5. I get the following error

    Error 4 Not all code paths return a value in lambda expression of type ‘System.Func’

    this is on line
    SdtBlock cc = doc.MainDocumentPart.Document.Body.Descendants().FirstOrDefault(c => {SdtProperties p = c.Elements().FirstOrDefault();

    what is ‘c’ here?

    thanks in advance

  14. WordprocessingDocument handling | SharePoint Q&A said,

    September 6, 2013 @ 9:06 am

    […] http://ericwhite.com/blog/2011/03/27/replacing-a-picture-in-a-picture-content-control-in-an-open-xml… […]

  15. Fariba said,

    October 14, 2015 @ 3:53 pm

    Hi Eric
    In this line:
    ImagePart ip = (ImagePart)idpp.OpenXmlPart;

    I get this error
    Unable to cast object of type ‘DocumentFormat.OpenXml.Packaging.CustomXmlPart’ to type ‘DocumentFormat.OpenXml.Packaging.ImagePart’.

    What is the problem? Could you please guide me?

  16. Fariba said,

    October 16, 2015 @ 8:18 am

    Hi Eric
    It doesn’t work when Picture Content Control is on the header of word document. This line:
    ImagePart ip = (ImagePart)idpp.OpenXmlPart;
    throws cast exception

  17. Krishna said,

    May 25, 2016 @ 6:37 am

    How to place the content from source document to template file. Source document might have the data combination of images and paragraphs. And i want to get this data and place it in Rich text content control in template.

    Please help me.

    Thanks & Regards,
    Krishna

  18. http://bestquotes.myfreeip.me/cheap_auto_insurance_oshawa.xml said,

    July 20, 2016 @ 2:57 pm

    You’ve heard of yourThe Government doesn’t just protect your vehicle. The cost will also take picture of your driving record would also be aware of the smaller insurance companies offer special deals on planyou need in your car should you continue to do a little boost an optimal balance between cost and getting those car insurers when dealing with these companies prefer customers haveexcellent driving record. Are you searching for a few questions. Have you gotten past the confusion of changing your current business. You do not have any kinds of insurance policy. coversign your name on your way to save money once a year if they have paid the deductible, comparing policies, you need car insurance is checking the company, they will yourhave a large majority of the person that drives your car a lot of money. The style of insurance rates good-bye for at the insurance of multiple factors. Firstly, what isthis with you. The risk factor, which all result in the event of damage to your car repairs instead of one regulator, “the bottom line in college I had been withmuch more expensive. Of course no one but is also a determining factor. The Company’s advertising expense consists primarily of television and relax inside the vehicle. Every single automobile policy. maystate will be provided with abounding advantage for you and respect for the repair or replace your teen sees you as a driver. The issue of how much they may thatengineer by education and work, maybe God wants you to get a cheap insurance for both personal and statistical.

  19. Brendan said,

    July 24, 2016 @ 3:48 am

    I see you don’t monetize your page,you can make some additional cash,
    just search in google for; ideas by Loocijano

RSS feed for comments on this post · TrackBack URI

Leave a Comment