OpenXml Force image fit in parent container
Asked Answered
S

1

8

I'm parsing a piece of hmtl into a word document using the following code

//Need the following packages
//<package id="DocumentFormat.OpenXml" version="2.7.2" targetFramework="net471" />
//<package id = "HtmlToOpenXml.dll" version="2.0.1" targetFramework="net471" />

using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;

using DocumentFormat.OpenXml.Wordprocessing;
using HtmlToOpenXml;

namespace ConsoleAppHtmlParse
{
    class Program
    {
        static void Main(string[] args)
        {
            string fileName = @"C:\temp\myDoc.docx";

            using (WordprocessingDocument document = WordprocessingDocument.Create(fileName, WordprocessingDocumentType.Document))
            {
                document.AddMainDocumentPart();
                document.MainDocumentPart.Document = new Document(new Body());
                HtmlConverter conveter = new HtmlConverter(document.MainDocumentPart);

                var compositeElements = conveter.Parse(Html);

                Paragraph p = compositeElements[0] as Paragraph;
                p.ParagraphProperties = new ParagraphProperties();
                p.ParagraphProperties.FrameProperties = new FrameProperties();
                p.ParagraphProperties.FrameProperties.Width = new StringValue("3200");

                document.MainDocumentPart.Document.Body.Append(compositeElements);
            }
        }

        const string Html = "<p>SomeText<img  src=\"data:image/png;base64,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\" alt=\"Screenshot_3\" />moretext</p>";
    }
}

The above code sample produces something like this:
enter image description here
I'd like to "shrink" the image to something like this:
enter image description here

Can I do this if I know the "parent" container size?

Thanks

Shanaeshanahan answered 1/6, 2018 at 14:32 Comment(0)
G
7

Understanding the modifications for OpenXml:

The w:drawing element has two parts to manage the image size

  1. wp:extent node, child of the wp:inline, it determines the extent of the area of the document that will contain the image. It is not helping us here.

Note: It is essential for Libre Office

extent

  1. spPr node is used to define the shape properties which contains xfrm node, which applies the transform to an object. It defines offset and extent.

Note: It is essential for OpenXml - Google Documents, etc.

inline extent

I have written a program below with two modifications to your code.

  1. Define Page Width: Setting the PageSize and PageMargin: defines the available area that we need to fill with the image. In our case, the available area can be defined as below:

    Available Page Width = PageSize.Width - PageMargin.Left - PageMargin.Right

    // Define Constants for Page Width and Page Margin
    private const int PageWidth = 17000;
    private const int PageHeight = 10000;
    private const int PageMarginLeft = 1000;
    private const int PageMarginRight = 1000;
    private const int PageMarginTop = 1000;
    private const int PageMarginBottom = 1000;
    private const double DocumentSizePerPixel = 15;
    private const double EmuPerPixel = 9525;
    
    // Set Page Size and Page Margin so that we can place the image as desired.
    // Available Width = PageWidth - PageMarginLeft - PageMarginRight (= 17000 - 1000 - 1000 = 15000 for default values)
    var sectionProperties = new SectionProperties();
    sectionProperties.AppendChild(new PageSize { Width = PageWidth, Height = PageHeight });
    sectionProperties.AppendChild(new PageMargin { Left = PageMarginLeft, Bottom = PageMarginBottom, Top = PageMarginTop, Right = PageMarginRight });
    document.MainDocumentPart.Document.Body.AppendChild(sectionProperties);
    
  2. Update Image Width: Update the Extents with the updated value of width and height for the image

    1. Calculate the aspect ratio, useful in updating height for the image.

    2. Calculate the new width in Emu which is understood by word by using below

      15 width of Page = 1 width of image in pixel = 9525 EMUs per pixel

      Avalable page width = 15000 page width = 15000/ 15 pixels = 1000 pixels = 1000 * 9525 Emu = 9525000 Emu

    3. Update the width and height of the Page by using Extents in two separate places to be used by Google Documents and Libre Office, etc.

               // Search for Extents used by the word present in Drawing > Inline > Extent
              var inlineEnumerable = p.ChildElements.Where(e => e is DocumentFormat.OpenXml.Wordprocessing.Run)
                  .Where(r => r.GetFirstChild<Drawing>() != null).Select(r => r.GetFirstChild<Drawing>())
                  .Where(r => r.GetFirstChild<Inline>() != null).Select(r => r.GetFirstChild<Inline>());
      
              // Update Visible Extent
              var inlineChildren = inlineEnumerable as Inline[] ?? inlineEnumerable.ToArray();
              foreach (var inlineChild in inlineChildren)
              {
                  var inlineElement = inlineChild.Extent;
                  UpdateExtent(inlineElement);
              }
      
              // Search for Extents used by the word present in Drawing > Inline > Graphic > GraphicData > Picture > ShapeProperties > Transform2D > Extents
              var extentsEnumerable = inlineChildren
                  .Where(r => r.GetFirstChild<Graphic>() != null).Select(d => d.GetFirstChild<Graphic>())
                  .Where(r => r.GetFirstChild<GraphicData>() != null).Select(r => r.GetFirstChild<GraphicData>())
                  .Where(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.Picture>() != null)
                  .Select(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.Picture>())
                  .Where(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties>() != null)
                  .Select(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties>())
                  .Where(r => r.GetFirstChild<Transform2D>() != null).Select(r => r.GetFirstChild<Transform2D>())
                  .Where(r => r.GetFirstChild<Extents>() != null).Select(r => r.GetFirstChild<Extents>());
      
              // Modify all images in Extents to the desired size here, to be stretched out on available page width
              foreach (var extents in extentsEnumerable)
              {
                  // Set Image Size: We calculate Aspect Ratio of the image and then calculate the width and update the height as per aspect ratio
                  var inlineElement = extents;
      
                  UpdateExtent(inlineElement);
              }
      

Update Extent method to update the extent values:

    private static void UpdateExtent(dynamic inlineElement)
    {
        // Read Default Cx and Cy Values provided in Emu
        var extentCx = inlineElement.Cx;
        var extentCy = inlineElement.Cy;

        // Aspect ratio used to set image height after calculation of width
        double aspectRatioOfImage = (double)extentCy / extentCx;

        // We know 15 width of Page = 1 width of image in pixel = 9525 EMUs per pixel, and we convert document size to pixel and then to EMU
        // For Default Values Available page width = 15000 page width = 15000/ 15 pixels = 1000 pixels = 1000 * 9525 Emu = 9525000 Emu
        double newExtentCx = EmuPerPixel * ((PageWidth - PageMarginLeft - PageMarginRight) / DocumentSizePerPixel);
        // Maintain the Aspect Ratio for height
        double newExtentCy = aspectRatioOfImage * newExtentCx;

        // Update the values
        inlineElement.Cx = (long)Math.Round(newExtentCx);
        inlineElement.Cy = (long)Math.Round(newExtentCy);
    } 

Full Program:

namespace Solutions
{
    using System;
    using System.Linq;
    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Drawing;
    using DocumentFormat.OpenXml.Drawing.Wordprocessing;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Wordprocessing;
    using HtmlToOpenXml;

    using Paragraph = DocumentFormat.OpenXml.Wordprocessing.Paragraph;

    public class WordProcessorClass
    {
        const string Html = "<p>SomeText<img src=\"data:image/png;base64,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\" alt=\"Screenshot_3\" />moretext</p>";

        // Define Constants for Page Width and Page Margin
        private const int PageWidth = 17000;
        private const int PageHeight = 10000;
        private const int PageMarginLeft = 1000;
        private const int PageMarginRight = 1000;
        private const int PageMarginTop = 1000;
        private const int PageMarginBottom = 1000;
        private const double DocumentSizePerPixel = 15;
        private const double EmuPerPixel = 9525;

        public static void Main1()
        {
            string fileName = @"f:\myDoc.docx";

            using (WordprocessingDocument document = WordprocessingDocument.Create(fileName, WordprocessingDocumentType.Document))
            {
                document.AddMainDocumentPart();
                document.MainDocumentPart.Document = new Document(new Body());

                HtmlConverter converter = new HtmlConverter(document.MainDocumentPart);
                var compositeElements = converter.Parse(Html);
                var p = compositeElements[0] as Paragraph;


                // Set Page Size and Page Margin so that we can place the image as desired.
                // Available Width = PageWidth - PageMarginLeft - PageMarginRight (= 17000 - 1000 - 1000 = 15000 for default values)
                var sectionProperties = new SectionProperties();
                sectionProperties.AppendChild(new PageSize { Width = PageWidth, Height = PageHeight });
                sectionProperties.AppendChild(new PageMargin { Left = PageMarginLeft, Bottom = PageMarginBottom, Top = PageMarginTop, Right = PageMarginRight });
                document.MainDocumentPart.Document.Body.AppendChild(sectionProperties);

                if (p != null)
                {
                    // Search for Extents used by the word present in Drawing > Inline > Extent
                    var inlineEnumerable = p.ChildElements.Where(e => e is DocumentFormat.OpenXml.Wordprocessing.Run)
                        .Where(r => r.GetFirstChild<Drawing>() != null).Select(r => r.GetFirstChild<Drawing>())
                        .Where(r => r.GetFirstChild<Inline>() != null).Select(r => r.GetFirstChild<Inline>());

                    // Update Visible Extent
                    var inlineChildren = inlineEnumerable as Inline[] ?? inlineEnumerable.ToArray();
                    foreach (var inlineChild in inlineChildren)
                    {
                        var inlineElement = inlineChild.Extent;
                        UpdateExtent(inlineElement);
                    }

                    // Search for Extents used by the word present in Drawing > Inline > Graphic > GraphicData > Picture > ShapeProperties > Transform2D > Extents
                    var extentsEnumerable = inlineChildren
                        .Where(r => r.GetFirstChild<Graphic>() != null).Select(d => d.GetFirstChild<Graphic>())
                        .Where(r => r.GetFirstChild<GraphicData>() != null).Select(r => r.GetFirstChild<GraphicData>())
                        .Where(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.Picture>() != null)
                        .Select(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.Picture>())
                        .Where(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties>() != null)
                        .Select(r => r.GetFirstChild<DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties>())
                        .Where(r => r.GetFirstChild<Transform2D>() != null).Select(r => r.GetFirstChild<Transform2D>())
                        .Where(r => r.GetFirstChild<Extents>() != null).Select(r => r.GetFirstChild<Extents>());

                    // Modify all images in Extents to the desired size here, to be stretched out on available page width
                    foreach (var extents in extentsEnumerable)
                    {
                        // Set Image Size: We calculate Aspect Ratio of the image and then calculate the width and update the height as per aspect ratio
                        var inlineElement = extents;

                        UpdateExtent(inlineElement);
                    }
                }

                document.MainDocumentPart.Document.Body.Append(compositeElements);
            }
        }

        private static void UpdateExtent(dynamic inlineElement)
        {
            // Read Default Cx and Cy Values provided in Emu
            var extentCx = inlineElement.Cx;
            var extentCy = inlineElement.Cy;

            // Aspect ratio used to set image height after calculation of width
            double aspectRatioOfImage = (double)extentCy / extentCx;

            // We know 15 width of Page = 1 width of image in pixel = 9525 EMUs per pixel, and we convert document size to pixel and then to EMU
            // For Default Values Available page width = 15000 page width = 15000/ 15 pixels = 1000 pixels = 1000 * 9525 Emu = 9525000 Emu
            double newExtentCx = EmuPerPixel * ((PageWidth - PageMarginLeft - PageMarginRight) / DocumentSizePerPixel);
            // Maintain the Aspect Ratio for height
            double newExtentCy = aspectRatioOfImage * newExtentCx;

            // Update the values
            inlineElement.Cx = (long)Math.Round(newExtentCx);
            inlineElement.Cy = (long)Math.Round(newExtentCy);
        }
    }
}

Output:

Libre Office

Libre Office Document

Google Document

Google Document

Reference: Output Document

Gurney answered 7/6, 2018 at 12:18 Comment(9)
Thanks for the answer.I tried playing with "extent" myself but didn't manage to make it work.I'll test it later today and get back to youShanaeshanahan
I hope it helps!Gurney
Have you tried your sample on MS Office or Libre office?I'm having some trouble even though Google Docs seem to workShanaeshanahan
Hi @GeorgeVovos, I haven't tried this sample on MS Office or Libre office. What is the issue?Gurney
it ignores the page size. Haven't had much time to test it though. I'll try to spend more time tomorrowShanaeshanahan
I can reproduce the issue and able to fix it as well. It seems Libre office doesn't follow Microsoft OpenXml Standards fully. I have modified the explanation in the above answer.Gurney
In short, adding the code in the w:drawing element for updating the extent for the wp:extent node (child of the wp:inline) did the trick. Hope it helps!Gurney
Great work vCillusion!Thanks for you time (Nice blog too)Shanaeshanahan
I am glad it helped. Thanks for checking out my blog.Gurney

© 2022 - 2024 — McMap. All rights reserved.