简体   繁体   English

使用OpenXML将图像插入DocX并设置大小

[英]Inserting Image into DocX using OpenXML and setting the size

I am using OpenXML to insert an image into my document. 我正在使用OpenXML将图像插入到我的文档中。 The code provided by Microsoft works, but makes the image much smaller: Microsoft提供的代码可以工作,但会使图像更小:

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). (我已经用Google搜索了如何在此过程之外执行此操作,但这不是我要查找的内容。我必须假设在给定代码中存在某种大小属性)。

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)));
}

The sizes, in EMUs ( English Metric Unit -- read this for a good explanation ), are set in the Extents (the Cx and Cy). 动车组的尺寸( 英制公制单位 - 阅读此内容以获得更好的解释 ),在范围(Cx和Cy)中设置。 In order to get a pic into a DocX I usually do it like so: 为了将照片写入DocX,我通常会这样做:

  1. Get the image's dimensions and resolution 获取图像的尺寸和分辨率
  2. Compute the image's width in EMUs: wEmu = imgWidthPixels / imgHorizontalDpi * emuPerInch 在EMU中计算图像的宽度:wEmu = imgWidthPixels / imgHorizo​​ntalDpi * emuPerInch
  3. Compute the image's height in EMUs: hEmu = imgHeightPixels / imgVerticalDpi * emuPerInch 在EMU中计算图像的高度: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) 计算EMU中的最大页面宽度(我发现如果图像太宽,则不会显示)
  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): 如果EMU中图像的宽度大于最大页面宽度,我会缩放图像的宽度和高度,使图像的宽度等于页面的宽度(当我说页面时,我指的是“可用”页面,这是减去边际):

    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 ). 然后我使用宽度Cx的值和高度赛扬的值, 无论是在DW.Extent和在A.Extents (的A.Transform2D所述的PIC.ShapeProperties )。

Note that the emuPerInch value is 914400. 请注意,emuPerInch值为914400。
I have this running (in a service) but I don't have the code with me right now. 我有这个运行(在服务中),但我现在没有代码。

UPDATE 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. 就我而言,我的页面的度量单位是厘米,因此您在上面看到的是emusPerCm。

UPDATE 2 (to answer @andw) 更新2(回答@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 : 要在最短的时间内锁定文件,请使用FileStream打开它,并将结果流传递给BitmapImageStreamSource属性:

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;
...

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: 然后以这种方式 像素 转换EMU

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: CxCy替换为您的计算值,使其如下所示:

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. 然后你的图像是原始大小,希望这有助于某人。

This code works for me. 这段代码适合我。

Source: http://msdn.microsoft.com/en-us/library/office/bb497430(v=office.15).aspx 资料来源: 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;
    }

Since this is one of the first hits when searching for images and OpenXml, and the world has turned a bit further I'd like to share @ssarabando's solution for calculating the EMUs adapted for .net core where System.Drawing is not available, using ImageSharp (still beta as of nov 2018): 由于这是搜索图像和OpenXml时的首次点击之一,并且世界已经进一步发展,我想分享@ssarabando的计算适用于.net核心的EMU的解决方案,其中System.Drawing不可用,使用ImageSharp(从2018年开始仍是测试版):

const int emusPerInch = 914400;
const int emusPerCm = 360000;

long widthEmus;
long heightEmus;
Image<Rgba32> img = Image.Load(sourceStream, new PngDecoder());

switch (img.MetaData.ResolutionUnits)
{
    case PixelResolutionUnit.PixelsPerCentimeter :
        widthEmus = (long)(img.Width / img.MetaData.HorizontalResolution * emusPerCm);
        heightEmus = (long)(img.Height / img.MetaData.VerticalResolution * emusPerCm);
        break;
    case PixelResolutionUnit.PixelsPerInch:
        widthEmus = (long)(img.Width / img.MetaData.HorizontalResolution * emusPerInch);
        heightEmus = (long)(img.Height / img.MetaData.VerticalResolution * emusPerInch);
        break;
    case PixelResolutionUnit.PixelsPerMeter:
        widthEmus = (long)(img.Width / img.MetaData.HorizontalResolution * emusPerCm * 100);
        heightEmus = (long)(img.Height / img.MetaData.VerticalResolution * emusPerCm * 100);
        break;
    default:
        widthEmus = 2000000;
        heightEmus = 2000000;
        break;
}

Hope it will save someone's time. 希望它能节省一些人的时间。

This is what works for me in Net Core and implemented here . 这对Net Core有用,并在这里实现。

long iWidth = 0;
long iHeight = 0;
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullPathToImageFile))
{
    iWidth = bmp.Width;
    iHeight = bmp.Height;
}            

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

double maxWidthCm = 17.4; // Our current margins gives us 17.4cm of space
const int emusPerCm = 360000;
long maxWidthEmus = (long)(maxWidthCm * emusPerCm);
if (iWidth > maxWidthEmus) {
    var ratio = (iHeight * 1.0m) / iWidth;
    iWidth = maxWidthEmus;
    iHeight = (long)(iWidth * ratio);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM