Search code examples
c#asp.netms-wordexportexport-to-word

C# Open XML HTML to DOCX Spacing


I've been working on my site, and trying to create an Export to Word. The export works well, converting HTML string to DOCX.

I'm trying to figure out how I can adjust the Line Spacing. By Default Word is adding 8pt Spacing After and setting the Line Spacing to double. I would prefer 0 and Single.

Here is the Function I created to Save a Word Document:

private static void SaveDOCX(string fileName, string BodyText, bool isLandScape, double rMargin, double lMargin, double bMargin, double tMargin)
{
    string htmlSectionID = "Sect1";
    //Creating a word document using the the Open XML SDK 2.0
    WordprocessingDocument document = WordprocessingDocument.Create(fileName, WordprocessingDocumentType.Document);

    //create a paragraph
    MainDocumentPart mainDocumenPart = document.AddMainDocumentPart();
    mainDocumenPart.Document = new DocumentFormat.OpenXml.Wordprocessing.Document();
    Body documentBody = new Body();
    mainDocumenPart.Document.Append(documentBody);


    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("<html><head></head><body>" + BodyText + "</body></html>"));

    // Create alternative format import part.
    AlternativeFormatImportPart formatImportPart = mainDocumenPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html, htmlSectionID);

    //ms.Seek(0, SeekOrigin.Begin);

    // Feed HTML data into format import part (chunk).
    formatImportPart.FeedData(ms);
    AltChunk altChunk = new AltChunk();
    altChunk.Id = htmlSectionID;

    mainDocumenPart.Document.Body.Append(altChunk);

    /*
     inch equiv = 1440 (1 inch margin)
     */
    double width = 8.5 * 1440;
    double height = 11 * 1440;

    SectionProperties sectionProps = new SectionProperties();
    PageSize pageSize;
    if (isLandScape)
    {
        pageSize = new PageSize() { Width = (UInt32Value)height, Height = (UInt32Value)width, Orient = PageOrientationValues.Landscape };
    }
    else
    {
        pageSize = new PageSize() { Width = (UInt32Value)width, Height = (UInt32Value)height, Orient = PageOrientationValues.Portrait };
    }

    rMargin = rMargin * 1440;
    lMargin = lMargin * 1440;
    bMargin = bMargin * 1440;
    tMargin = tMargin * 1440;

    PageMargin pageMargin = new PageMargin() { Top = (Int32)tMargin, Right = (UInt32Value)rMargin, Bottom = (Int32)bMargin, Left = (UInt32Value)lMargin, Header = (UInt32Value)360U, Footer = (UInt32Value)360U, Gutter = (UInt32Value)0U };

    sectionProps.Append(pageSize);
    sectionProps.Append(pageMargin);
    mainDocumenPart.Document.Body.Append(sectionProps);

    //Saving/Disposing of the created word Document
    document.MainDocumentPart.Document.Save();
    document.Dispose();
}

In searching, I found this code:

SpacingBetweenLines spacing = new SpacingBetweenLines() { Line = "240", LineRule = LineSpacingRuleValues.Auto, Before = "0", After = "0" };

I've placed it many places in my function, but I can't seem to find the correct place to Append this setting.


Solution

  • I worked on the function trying to set the spacing in code, but wasn't able to remove the spacing. I decided to try creating a Template Word Document and setting the spacing in that document.

    I copy the template.docx file, creating the one I will use, then use the adjusted function below to add the HTML string:

    private static void SaveDOCX(string fileName, string BodyText, bool isLandScape, double rMargin, double lMargin, double bMargin, double tMargin)
    {
        WordprocessingDocument document = WordprocessingDocument.Open(fileName, true);
        MainDocumentPart mainDocumenPart = document.MainDocumentPart;
    
        //Place the HTML String into a MemoryStream Object
        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("<html><head></head><body>" + BodyText + "</body></html>"));
    
        //Assign an HTML Section for the String Text
        string htmlSectionID = "Sect1";
    
        // Create alternative format import part.
        AlternativeFormatImportPart formatImportPart = mainDocumenPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html, htmlSectionID);
    
        // Feed HTML data into format import part (chunk).
        formatImportPart.FeedData(ms);
        AltChunk altChunk = new AltChunk();
        altChunk.Id = htmlSectionID;
    
        //Clear out the Document Body and Insert just the HTML string.  (This prevents an empty First Line)
        mainDocumenPart.Document.Body.RemoveAllChildren();
        mainDocumenPart.Document.Body.Append(altChunk);
    
        /*
         Set the Page Orientation and Margins Based on Page Size
         inch equiv = 1440 (1 inch margin)
         */
        double width = 8.5 * 1440;
        double height = 11 * 1440;
    
        SectionProperties sectionProps = new SectionProperties();
        PageSize pageSize;
        if (isLandScape)
            pageSize = new PageSize() { Width = (UInt32Value)height, Height = (UInt32Value)width, Orient = PageOrientationValues.Landscape };
        else
            pageSize = new PageSize() { Width = (UInt32Value)width, Height = (UInt32Value)height, Orient = PageOrientationValues.Portrait };
    
        rMargin = rMargin * 1440;
        lMargin = lMargin * 1440;
        bMargin = bMargin * 1440;
        tMargin = tMargin * 1440;
    
        PageMargin pageMargin = new PageMargin() { Top = (Int32)tMargin, Right = (UInt32Value)rMargin, Bottom = (Int32)bMargin, Left = (UInt32Value)lMargin, Header = (UInt32Value)360U, Footer = (UInt32Value)360U, Gutter = (UInt32Value)0U };
    
        sectionProps.Append(pageSize);
        sectionProps.Append(pageMargin);
        mainDocumenPart.Document.Body.Append(sectionProps);
    
        //Saving/Disposing of the created word Document
        document.MainDocumentPart.Document.Save();
        document.Dispose();
    }
    

    By using the template file, the line spacing is correct.

    For those that might find this function useful, here is the code that calls the function:

    string filePath = "~/Content/Exports/Temp/";
    
    string WordTemplateFile = HttpContext.Current.Server.MapPath("/Content/Templates/WordTemplate.docx");
    string DestinationPath = HttpContext.Current.Server.MapPath(filePath);
    string NewFileName = DOCXFileName + ".docx";
    
    string destFile = System.IO.Path.Combine(DestinationPath, NewFileName);
    
    System.IO.File.Copy(WordTemplateFile, destFile, true);
    
    SaveDOCX(destFile, HTMLString, isLandScape, rMargin, lMargin, bMargin, tMargin);