Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inserting Image into DocX using OpenXML and setting the size

I am using OpenXML to insert an image into my document. The code provided by Microsoft works, but makes the image much smaller:

public static void InsertAPicture(string document, string fileName)
        {
            using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true))
            {
                MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart;

                ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);

                using (FileStream stream = new FileStream(fileName, FileMode.Open))
                {
                    imagePart.FeedData(stream);
                }

                AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart));
            }
        }
        private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId)
        {
            // Define the reference of the image.
            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 = relationshipId,
                                             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"
                     });

            // Append the reference to body, the element should be in a Run.
            wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
        }

I need to make the image its original size. How can I do this? (I have googled how to do this outside of this process, but that is not what I am looking for. I have to assume that there are some sort of size properties inside of the given code).

Edit: Updated Code (still not working)

public static void InsertAPicture(string document, string fileName)
{
    using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(document, true))
    {
        MainDocumentPart mainPart = wordprocessingDocument.MainDocumentPart;

        ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);

        using (FileStream stream = new FileStream(fileName, FileMode.Open))
        {
            imagePart.FeedData(stream);
        }

        AddImageToBody(wordprocessingDocument, mainPart.GetIdOfPart(imagePart), fileName);
    }
}
private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId, string fileName)
{

    var img = new BitmapImage(new Uri(fileName, UriKind.RelativeOrAbsolute));
    var widthPx = img.PixelWidth;
    var heightPx = img.PixelHeight;
    var horzRezDpi = img.DpiX;
    var vertRezDpi = img.DpiY;
    const int emusPerInch = 914400;
    const int emusPerCm = 360000;
    var maxWidthCm = 16.51;
    var widthEmus = (long)(widthPx / horzRezDpi * emusPerInch);
    var heightEmus = (long)(heightPx / vertRezDpi * emusPerInch);
    var maxWidthEmus = (long)(maxWidthCm * emusPerCm);
    if (widthEmus > maxWidthEmus)
    {
        var ratio = (heightEmus * 1.0m) / widthEmus;
        widthEmus = maxWidthEmus;
        heightEmus = (long)(widthEmus * ratio);
    }

    // Define the reference of the image.
    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 = relationshipId,
                                     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 = widthEmus, Cy = heightEmus }),
                                 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"
             });

    // Append the reference to body, the element should be in a Run.
    wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
}
like image 771
LunchMarble Avatar asked Nov 10 '11 16:11

LunchMarble


3 Answers

The sizes, in EMUs (English Metric Unit -- read this for a good explanation), are set in the Extents (the Cx and Cy). In order to get a pic into a DocX I usually do it like so:

  1. Get the image's dimensions and resolution
  2. Compute the image's width in EMUs: wEmu = imgWidthPixels / imgHorizontalDpi * emuPerInch
  3. Compute the image's height in EMUs: hEmu = imgHeightPixels / imgVerticalDpi * emuPerInch
  4. Compute the max page width in EMUs (I've found that if the image is too wide, it won't show)
  5. If the image's width in EMUs is greater than the max page width's, I scale the image's width and height so that the width of image is equal to that of the page (when I say page, I'm referring to the "usable" page, that is minus the margins):

    var ratio = hEmu / wEmu;
    wEmu = maxPageWidthEmu;
    hEmu = wEmu * ratio;

  6. I then use the width as the value of Cx and height as the value of Cy, both in the DW.Extent and in the A.Extents (of the A.Transform2D of the PIC.ShapeProperties).

Note that the emuPerInch value is 914400.
I have this running (in a service) but I don't have the code with me right now.

UPDATE

This is the code I use:

var img = new BitmapImage(new Uri(fileName, UriKind.RelativeOrAbsolute));
var widthPx = img.PixelWidth;
var heightPx = img.PixelHeight;
var horzRezDpi = img.DpiX;
var vertRezDpi = img.DpiY;
const int emusPerInch = 914400;
const int emusPerCm = 360000;
var widthEmus = (long)(widthPx / horzRezDpi * emusPerInch);
var heightEmus = (long)(heightPx / vertRezDpi * emusPerInch);
var maxWidthEmus = (long)(maxWidthCm * emusPerCm);
if (widthEmus > maxWidthEmus) {
  var ratio = (heightEmus * 1.0m) / widthEmus;
  widthEmus = maxWidthEmus;
  heightEmus = (long)(widthEmus * ratio);
}

In my case, my page's measures are in cm, hence the emusPerCm you see above.

UPDATE 2 (to answer @andw)

To have the file locked during the minimum possible time, open it with a FileStream and pass the resulting stream to the StreamSource property of the BitmapImage:

var img = new BitmapImage();
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
    img.BeginInit();
    img.StreamSource = fs;
    img.EndInit();
}
// The file is now unlocked
var widthPx = img.PixelWidth;
...
like image 143
ssarabando Avatar answered Oct 20 '22 05:10

ssarabando


You can give to the image its original size this way:

First you get the width and height of the file:

int iWidth = 0;
int iHeight = 0;
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap("yourFilePath"))
{
     iWidth = bmp.Width;
     iHeight = bmp.Height;
}

Then convert the pixels to EMUs this way:

iWidth = (int)Math.Round((decimal)iWidth * 9525);
iHeight = (int)Math.Round((decimal)iHeight * 9525);

And finally give the values when opening your file, I mean in this line of your code:

new DW.Extent() { Cx = 990000L, Cy = 792000L },

replace Cx and Cy with your calculated values so it looks like this:

new DW.Extent() { Cx = iWidth, Cy = iHeight },

Notice there is two lines in your code where you have to give the calculated values.

Then you have your image in its original size, hope this helps someone.

like image 21
JCO9 Avatar answered Oct 20 '22 07:10

JCO9


This code works for me.

Source: http://msdn.microsoft.com/en-us/library/office/bb497430(v=office.15).aspx

    public static void Do()
    {
        string filename = @"c:\temp\m.docx";
        byte[] reportData = GetWordReport();
       // File.WriteAllBytes(filename, reportData);
        //MessageBox.Show("File " + filename + " created");
    }

    private static byte[] GetWordReport()
    {
       // using (MemoryStream stream = new MemoryStream())
       // {
            //var template = GetTemplateData();
            //stream.Write(template, 0, template.Length);
            using (WordprocessingDocument docx = WordprocessingDocument.Open(@"c:\temp\m.docx", true))
            {
                // Some changes on docx
                docx.MainDocumentPart.Document = GenerateMainDocumentPart(6,4);

                var imagePart = docx.MainDocumentPart.AddNewPart<ImagePart>("image/jpeg", "rIdImagePart1");
                GenerateImagePart(imagePart);
            }
          //  stream.Seek(0, SeekOrigin.Begin);
           // return stream.ToArray();
       // }
        return null;
    }

    private static byte[] GetTemplateData()
    {
        using (MemoryStream targetStream = new MemoryStream())
        using (BinaryReader sourceReader = new BinaryReader(File.Open(@"c:\temp\m_2.docx", FileMode.Open)))
        {
            byte[] buffer = new byte[4096];

            int num = 0;
            do
            {
                num = sourceReader.Read(buffer, 0, 4096);
                if (num > 0)
                    targetStream.Write(buffer, 0, num);
            }
            while (num > 0);
            targetStream.Seek(0, SeekOrigin.Begin);
            return targetStream.ToArray();
        }
    }

    private static void GenerateImagePart(OpenXmlPart part)
    {
        using (Stream imageStream = File.Open(@"c:\temp\image002.jpg", FileMode.Open))
        {
            part.FeedData(imageStream);
        }
    }

    private static Document GenerateMainDocumentPart(int cx,int cy)
    {
        long LCX = cx*261257L;
        long LCY = cy*261257L;




        var element =
            new Document(
                new Body(
                    new Paragraph(
                        new Run(
                            new RunProperties(
                                new NoProof()),
                            new Drawing(
                                new wp.Inline(
                                    new wp.Extent() { Cx = LCX, Cy = LCY },
                                    new wp.EffectExtent() { LeftEdge = 0L, TopEdge = 19050L, RightEdge = 0L, BottomEdge = 0L },
                                    new wp.DocProperties() { Id = (UInt32Value)1U, Name = "Picture 0", Description = "Forest Flowers.jpg" },
                                    new wp.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 = "Forest Flowers.jpg" },
                                                    new pic.NonVisualPictureDrawingProperties()),
                                                new pic.BlipFill(
                                                    new a.Blip() { Embed = "rIdImagePart1", 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 = LCX, Cy = LCY }),
                                                    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 }))
                    ) { RsidParagraphAddition = "00A2180E", RsidRunAdditionDefault = "00EC4DA7" },
                    new SectionProperties(
                        new PageSize() { Width = (UInt32Value)11906U, Height = (UInt32Value)16838U },
                        new PageMargin() { Top = 1440, Right = (UInt32Value)1800U, Bottom = 1440, Left = (UInt32Value)1800U, Header = (UInt32Value)851U, Footer = (UInt32Value)992U, Gutter = (UInt32Value)0U },
                        new Columns() { Space = ((UInt32Value)425U).ToString() },
                        new DocGrid() { Type = DocGridValues.Lines, LinePitch = 312 }
                    ) { RsidR = "00A2180E", RsidSect = "00A2180E" }));
        return element;
    }
like image 2
safriend Avatar answered Oct 20 '22 06:10

safriend