Eric White's Blog
Open XML, SharePoint, and Office
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");
}
}
}
}
}
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.
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.
[...] Read OpenXML Content Control and Replace Data [...]
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,
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.
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?
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.
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
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
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
Hi Eric,
Thanks for the reply. Learned a lot of tools/technqs.
So far badluck, I am unable fix the issue.
Rajesh
Hi Eric,
In your code –
SdtBlock cc = doc.MainDocumentPart.Document.Body.Descendants().FirstOrDefault(c =>
what does c reference in c => ??
Thanks,
Paul.
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