Search code examples
c#openxmlopenxml-sdk

Constructing an OpenXmlElement from bitmap picture to append into a Run instance


I have the following code:

string replaceValueString = parameterValue.ToString();
Run replaceRun = new Run();
replaceRun.Append(new Text(replaceValueString));
contentControl.InsertAfterSelf(replaceRun);

I need to add a similar logic, but instead of Text, I need to add Picture (or some other type of image instance), like that:

replaceRun.Append(new Picture(data));

I have a Bitmap class, I can also pass byte[] or Steam of the image. My only problem is, I found virtually no example how to construct this Picture class, inherited from OpenXmlCompositeElement.

Can someone provide me with some examples and guides, in order to convert from Bitmap/data[]/Steam image into DocumentFormat.OpenXml.Wordprocessing.Picture (or any other OpenXmlElement)?

So far I found only this example: https://learn.microsoft.com/en-us/office/open-xml/how-to-insert-a-picture-into-a-word-processing-document

...it creates a Drawing class instead of a picture, and it uses some DW SDK, which I don't have access to.


Solution

  • The example you have provided can seem daunting at first but it is very useable if you work through it...

    it uses some DW SDK, which I don't have access to.

    The DW is simply just an alias to some namespaces that you will no doubt have access to already. Make sure you include the following at the top of your class file:

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

    With that in mind. Let's start with your Bitmap. First, you want to use that to create an ImagePart. The following code may seem like it is adding an image straight to the main document, but it doesn't quite work like that. Don't worry, we will move it to your run later.

    MainDocumentPart mainDocumentPart = wordDoc.MainDocumentPart;
    ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Bmp);
    using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
    {
        image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
        stream.Position = 0;
        imagePart.FeedData(stream);
    }
    

    We need to get the ID of the image part, so that we can use that when creating the Drawing object.

    string imagePartId = mainDocumentPart.GetIdOfPart(imagePart);
    

    Next, we need to use that code that you didn't like from here.

    Let's just take everything we have so far and stick it into a function that will create a Drawing from a Bitmap.

    static Drawing ConvertBitmapToDrawing(WordprocessingDocument wordDoc, System.Drawing.Bitmap image)
    {
        MainDocumentPart mainDocumentPart = wordDoc.MainDocumentPart;
        ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Bmp);
        using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
        {
            image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
            stream.Position = 0;
            imagePart.FeedData(stream);
        }
    
        string imagePartId = mainDocumentPart.GetIdOfPart(imagePart);
    
        var element =
                 new Drawing(
                     new DW.Inline(
                         new DW.Extent() { Cx = 990000L, Cy = 792000L },
                         new DW.EffectExtent() { LeftEdge = 0L, TopEdge = 0L, 
                             RightEdge = 0L, BottomEdge = 0L },
                         new DW.DocProperties() { Id = (UInt32Value)1U, 
                             Name = "Picture 1" },
                         new DW.NonVisualGraphicFrameDrawingProperties(
                             new A.GraphicFrameLocks() { NoChangeAspect = true }),
                         new A.Graphic(
                             new A.GraphicData(
                                 new PIC.Picture(
                                     new PIC.NonVisualPictureProperties(
                                         new PIC.NonVisualDrawingProperties() 
                                            { Id = (UInt32Value)0U, 
                                                Name = "New Bitmap Image.jpg" },
                                         new PIC.NonVisualPictureDrawingProperties()),
                                     new PIC.BlipFill(
                                         new A.Blip(
                                             new A.BlipExtensionList(
                                                 new A.BlipExtension() 
                                                    { Uri = 
                                                        "{28A0092B-C50C-407E-A947-70E740481C1C}" })
                                         ) 
                                         { Embed = imagePartId, 
                                             CompressionState = 
                                             A.BlipCompressionValues.Print },
                                         new A.Stretch(
                                             new A.FillRectangle())),
                                     new PIC.ShapeProperties(
                                         new A.Transform2D(
                                             new A.Offset() { X = 0L, Y = 0L },
                                             new A.Extents() { Cx = 990000L, Cy = 792000L }),
                                         new A.PresetGeometry(
                                             new A.AdjustValueList()
                                         ) { Preset = A.ShapeTypeValues.Rectangle }))
                             ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
                     ) { DistanceFromTop = (UInt32Value)0U, 
                         DistanceFromBottom = (UInt32Value)0U, 
                         DistanceFromLeft = (UInt32Value)0U, 
                         DistanceFromRight = (UInt32Value)0U, EditId = "50D07946" });
    
        return element;
    }
    

    With this function, you can finally just do something like this:

    Drawing drawing = ConvertBitmapToDrawing(wordProcessingDocument, myBitmap);
    Run newRun = new Run(drawing);
    contentControl.InsertAfterSelf(newRun);