简体   繁体   English

打开在C#中创建的OpenXML Word文档时未应用图像大小

[英]Image Size Not Applied when opening OpenXML Word Document Created in C#

I am creating an OpenXML Word Document inside a C# Web Application and am writing a Google Chart Image to it. 我正在C#Web应用程序内创建OpenXML Word文档,并向其中写入Google图表图像。 I'm specifying the dimensions of the image, it seems, correctly. 我正在正确指定图像的尺寸。 However, when I open the Word Document, the image is the right height, but not the right width. 但是,当我打开Word文档时,图像是正确的高度,而不是正确的宽度。 In fact, it is almost a square. 实际上,它几乎是一个正方形。

When I click on the image inside of Word and go to Size and Position, the correct dimensions are displayed. 当我单击Word内的图像并转到“大小和位置”时,将显示正确的尺寸。 In this case, it is 2.08" by 5.04". 在这种情况下,它是2.08“ x 5.04”。 When I click "OK" after changing nothing, the image stretches to the right size. 不做任何更改后单击“确定”时,图像会拉伸到正确的尺寸。

If I try to identify what size it originally appears as, it is fairly close to half the defined width, but that may be a coincidence. 如果我尝试确定最初显示的尺寸,则该尺寸非常接近定义宽度的一半,但这可能是一个巧合。

The native size of the image is actually 3.13" (h) by 7.55" (w), but that doesn't seem like it should matter. 图像的原始尺寸实际上是3.13英寸(h)x 7.55英寸(w),但这似乎并不重要。

I followed the following posts pretty closely: 我非常关注以下帖子:

I'm guessing I'm just missing a setting of some sort, but I don't know which one. 我猜我只是缺少某种设置,但我不知道哪个设置。 Does the Paragraph or the Run need to be sized to the entire width of the page? 是否需要将“段落”或“运行”的大小调整到页面的整个宽度? Does the width of the document itself need to be specified? 是否需要指定文件本身的宽度?

    public void AddImage(string imageName, byte[] imageData)
    {
        var img = System.Drawing.Image.FromStream(new MemoryStream(imageData));

        MainDocumentPart mainPart = doc.MainDocumentPart;

        ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Png);
        MemoryStream imageStream = new MemoryStream(imageData);
        imagePart.FeedData(imageStream);

        AddImageToBody(mainPart.GetIdOfPart(imagePart), img);
    }

    private void AddImageToBody(string relationshipId, System.Drawing.Image img)
    {
        var widthPx = img.Width;
        var heightPx = img.Height;
        var horzRezDpi = img.HorizontalResolution;
        var vertRezDpi = img.VerticalResolution;
        const int emusPerInch = 914400;
        var widthEmus = (long)(widthPx / horzRezDpi * emusPerInch);
        var heightEmus = (long)(heightPx / vertRezDpi * emusPerInch);
        var maxWidthEmus = (long)(6.5 * emusPerInch);
        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 = widthEmus, Cy = heightEmus }, // 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.
        var p = new Paragraph();

        doc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
    }

this is a pretty old question but I think it's worth answering anyway since this seems to come up a lot. 这是一个很老的问题,但是我认为还是值得回答,因为这似乎很多。

I also used the above sample and it works well, except that cx and cy are hard-coded and distort the image. 我还使用了上面的示例,并且效果很好,除了cx和cy是硬编码的并且会使图像失真。

I created a class to handle my image then I use it to add detail to the element which I then can use to either append to the document or append to a paragraph etc. 我创建了一个类来处理图像,然后使用它为元素添加细节,然后可以将其用于追加到文档或追加到段落等。

EDIT : I added an ID field in ImageDetails because when I added several images to the document I needed to update the Id. 编辑 :我在ImageDetails中添加了一个ID字段,因为当我向文档中添加多个图像时,我需要更新ID。 By creating collections and a CounterState class, I was able to track the Id and make sure it was unique. 通过创建集合和CounterState类,我能够跟踪ID并确保它是唯一的。 If anyone wants to see this implementation, let me know in the comments and I'll include it in this answer. 如果有人想看到此实现,请在评论中告诉我,并将其包含在此答案中。

So... The class is a little specific to what I required in my solution, but take what you need. 所以...该类是针对我在解决方案中需要的内容,但可以满足您的需求。

public class ImageDetails
{
    // required to set the image id which needs to be unique in the document
    // which is important if you're adding several images
    public UInt32 Id { get; set; } 

    public ImageDetails(string fileName)
    {
        this.ImageFile = fileName;
    }

    #region Properties
    private decimal _widthInCm;

    /// <summary>
    /// 
    /// </summary>
    /// <summary>
    /// Sets the width in cm (note this is a user set to calculate cx. Leave blank for the class to calculate the cx based on pixels)
    /// </summary>
    public decimal WidthInCm
    {
        set { _widthInCm = value; }
    }

    private decimal _heightInCm;
    /// <summary>
    /// Sets the height in cm (note this is a user set to calculate cy. Leave blank for the class to calculate the cy based on pixels)
    /// </summary>
    public decimal HeightInCm
    {
        set { _heightInCm = value; }
    }


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

    /// <summary>
    /// Returns the width in EMUS (English Metric Units)
    /// </summary>
    public long cx
    {
        get
        {
            if (_widthInCm > 0)
                return (long)Math.Round(_widthInCm * emusPerCm);
            else if (_image.Width > 0)
                return (long)Math.Round((_image.Width / _image.HorizontalResolution) * emusPerInch);
            else
            {
                throw new InvalidDataException("WidthInCm/WidthInPx has not been set");
            }
        }
    }

    /// <summary>
    /// Returns the height in EMUS (English Metric Units)
    /// </summary>
    public long cy
    {
        get
        {
            if (_heightInCm > 0)
                return (long)decimal.Round(_heightInCm * emusPerCm);
            else if (_image.Height > 0)
                return (long)Math.Round((_image.Height / _image.VerticalResolution) * emusPerInch);
            else
            {
                throw new InvalidDataException("HeightInCm/HeightInPx has not been set");
            }
        }
    }

    public int WidthInPx
    {
        get { return _image.Width; }
    }


    public int HeightInPx
    {
        get { return _image.Height; }
    }



    private string _imageFileName;
    private Image _image;

    /// <summary>
    /// Sets the Image file name and loads the Image object for later use
    /// </summary>
    public string ImageFile
    {
        get { return _imageFileName; }
        set
        {
            _imageFileName = value;
            // Limiting the time the image file is open in case others require it
            using (var fs = new FileStream(value, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                _image = Image.FromStream(fs);
            }

        }
    }

    /// <summary>
    /// Allows direct read/write access to the internal Image Object
    /// </summary>
    public Image ImageObject
    {
        get { return _image; }
        set { _image = value; }
    }

    #endregion


    /// <summary>
    /// This method resizes the image and replaces the internal Drawing.Image object with the new size
    /// </summary>
    /// <param name="targetWidth">New target width in px. The aspect ratio is maintained</param>
    public  void ResizeImage(int targetWidth)
    {
        if (_image == null)
            throw new InvalidOperationException("The Image has not been referenced. Add an image first using .ImageFile or .ImageObject");

        double percent = (double)_image.Width / targetWidth;
        int destWidth = (int)(_image.Width / percent);
        int destHeight = (int)(_image.Height / percent);

        Bitmap b = new Bitmap(destWidth, destHeight);
        Graphics g = Graphics.FromImage((Image)b);
        try
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
            g.CompositingQuality = CompositingQuality.HighQuality;

            g.DrawImage(_image, 0, 0, destWidth, destHeight);
        }
        finally
        {
            g.Dispose();
        }

        _image = (Image)b;
    }
}

If you need to resize the image beforehand, just call: 如果您需要预先调整图像大小,只需致电:

ImageDetails image = new ImageDetails("image.png");
image.Resize(45); // set new image to a width of 45px. Height is automatically adjusted

I have then used this in the image method: 然后,我在图像方法中使用了此方法:

     private Drawing CreateImageElement(WordprocessingDocument wordDoc, string relationshipId, ImageDetails image)
    {
        // Define the reference of the image.
        return
             new Drawing(
                 new DW.Inline(
                     new DW.Extent() { Cx = image.cx, Cy = image.cy},
                     new DW.EffectExtent()
                     {
                         LeftEdge = 0L,
                         TopEdge = 0L,
                         RightEdge = 0L,
                         BottomEdge = 0L
                     },
                     new DW.DocProperties()
                     {
                         Id = image.Id,
                         Name = FileManipulation.GetFileName(image.ImageFile) 
                     },
                     new DW.NonVisualGraphicFrameDrawingProperties(
                         new A.GraphicFrameLocks() { NoChangeAspect = true }),
                     new A.Graphic(
                         new A.GraphicData(
                             new PIC.Picture(
                                 new PIC.NonVisualPictureProperties(
                                     new PIC.NonVisualDrawingProperties()
                                     {
                                         Id = image.Id,
                                         Name = Path.GetFileName(image.ImageFile)
                                     },
                                     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 = image.cx, Cy = image.cy}),
                                     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"
                 });


    }

Hope this helps someone. 希望这对某人有帮助。

According to Your code, you have to set Cx and Cy values for both Extent properties. 根据您的代码,您必须为两个Extent属性设置CxCy值。

new DW.Extent() { Cx = widthEmus, Cy = heightEmus }

First one for Inline and second for Transform2D . 第一个用于Inline ,第二个用于Transform2D

Oops. 哎呀。 There are two places where the size is set. 设置大小有两个地方。 I missed the second. 我错过了第二个。

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

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