Site icon [<Developer>]

Open XML – Setting multiple Picture Content Controls by Tag name, without going crazy

For a project I was working on I had to generate some documents on the server. Not wanting to install Microsoft Word on the server because, well let’s not go there, I’ll have to use bad words; I decided to use Open XML. I started a little C# project to see how this stuff works. At first you frown a little, some cursing and yelling occur; maybe you shed some tears because some simple things turn out to be not that simple, like setting a Picture Content Control. Normally you just fire up Google and look for examples. I did that just that but sadly all examples did something but not just what I wanted: setting multiple Picture Content Controls by Tag name. I found this blog post of Erik White but that code changed all picture content controls when you changed one. That’s because initially a Picture Content Control has some resource Id that points to the same (‘blank’) image in the resources of your document. In another thread some guy Jinesh replied with some code that almost did what I wanted. I used that and added some of my magic to solve this should-be-simple-it’s-2012 problem.

Ok let’s start; first add some using statements and, to prevent some ambiguous (*sigh*) classes, add some aliases.

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;

In this example I’ll use a Bitmap object, this enables me to resize the placeholder using the image dimensions. First I’ll use the Tag name to select the element containing the Picture Content Control, which is a block element. Then I’ll get the Blip element which has a reference to the picture.

Bitmap image = new Bitmap(@"F:insert_me.jpg");
SdtElement controlBlock = _mainDocumentPart.Document.Body
    .Descendants()
        .Where
        (r => 
            r.SdtProperties.GetFirstChild().Val == tagName
        ).SingleOrDefault();
// Find the Blip element of the content control.
A.Blip blip = controlBlock.Descendants().FirstOrDefault();

The next step is to load the image into the document and assign the resource Id of that image to the Blip.Embed property.

// Add image and change embeded id.
ImagePart imagePart = _mainDocumentPart
    .AddImagePart(ImagePartType.Jpeg);
using (MemoryStream stream = new MemoryStream())
{
    image.Save(stream, ImageFormat.Jpeg);
    stream.Position = 0;
    imagePart.FeedData(stream);
}
blip.Embed = _mainDocumentPart.GetIdOfPart(imagePart);

Yes, it’s that simple. You’ve probably seen a lot of different, not working, solutions on the web which had a lot more code. Now the code for the resizing, I suspect there should be an easier way, but for now this will do.

// set image dimensions in the document
DW.Inline inline = controlBlock
    .Descendants().FirstOrDefault();
// 9525 = pixels to points
inline.Extent.Cy = image.Size.Height * 9525; 
inline.Extent.Cx = image.Size.Width * 9525;
PIC.Picture pic = inline
    .Descendants().FirstOrDefault();
pic.ShapeProperties.Transform2D.Extents.Cy 
    = image.Size.Height * 9525;
pic.ShapeProperties.Transform2D.Extents.Cx 
    = image.Size.Width * 9525;
Exit mobile version