【C#】【OpenXML SDK】【Word】換表頭文與圖。讀取模版檔案Header->填值->為現有檔案換Header。Template Header。

  • 673
  • 0
  • 2022-06-10

換表頭

class:

/*
 參考來源:
 Copy header with image from a docx file to another using open xml and c#
 https://social.msdn.microsoft.com/Forums/Azure/en-US/7e34c135-361a-44cb-a9df-e6246f6ca781/copy-header-with-image-from-a-docx-file-to-another-using-open-xml-and-c?forum=oxmlsdk
*/

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

//因為Wordprocessing與Drawing有許多class同名,須指定namespace,所以分別給這兩個namespace別名:
using WPS = DocumentFormat.OpenXml.Wordprocessing;
using DRW = DocumentFormat.OpenXml.Drawing;

using System.IO;
using System.Web.Hosting;
using System.Text;
using System.Collections.Generic;

namespace DMS.WebMVC.ApplicationForm
{
    public class DocHeaderCopyer
    {
        HeaderPart _srcHeaderPart = null;
        ImagePart _srcHeaderImage = null;
        string _srcFilepath;
        Dictionary<string, string> _textToReplace;
        WordprocessingDocument _srcWordprocessingDocument, _dstWordprocessingDocument;

        public DocHeaderCopyer(string srcFilepath, string dstFilepath, Dictionary<string, string> textToReplace)
        {
            try
            {
                ReadSourceDocHeaderWithImg(srcFilepath);
                _srcFilepath = dstFilepath;
                _textToReplace = textToReplace;
            }
            catch (Exception err)
            {
                throw err;
            }
        }

        public bool Copy()
        {
            bool result = false;
            try
            {
                WriteDestinationDocHeaderWithImg(_srcFilepath);
                result = true;
            }
            catch (Exception err)
            {
                throw err;
            }
            finally
            {
                _srcWordprocessingDocument.Close();
            }

            return result;
        }

        private void ReadSourceDocHeaderWithImg(string srcFilepath)
        {
            try
            {
                //WordprocessingDocument srcWordprocessingDocument = WordprocessingDocument.Open(srcFilepath, false);
                _srcWordprocessingDocument = WordprocessingDocument.Open(srcFilepath, false);
                MainDocumentPart srcMainDocumentPart = _srcWordprocessingDocument.MainDocumentPart;
                WPS.Document srcDocument = srcMainDocumentPart.Document;
                WPS.SectionProperties srcSectionProperties = srcDocument.Descendants<WPS.SectionProperties>().FirstOrDefault();
                WPS.HeaderReference srcHeaderReference = srcSectionProperties.Descendants<WPS.HeaderReference>()
                    .Where(H => H.Type == WPS.HeaderFooterValues.Default)
                    .FirstOrDefault();
                _srcHeaderPart = srcMainDocumentPart.GetPartById(srcHeaderReference.Id) as HeaderPart;
                _srcHeaderImage = _srcHeaderPart.ImageParts.FirstOrDefault();
            }
            catch (Exception err)
            {
                throw err;
            }
        }

        private void WriteDestinationDocHeaderWithImg(string dstFilepath)
        {
            try
            {
                //WordprocessingDocument dstWordprocessingDocument = WordprocessingDocument.Open(dstFilepath, true);
                _dstWordprocessingDocument = WordprocessingDocument.Open(dstFilepath, true);
                MainDocumentPart dstMainDocumentPart = _dstWordprocessingDocument.MainDocumentPart;
                WPS.Document dstDocument = dstMainDocumentPart.Document;
                WPS.SectionProperties dstSectionProperties = dstDocument.Descendants<WPS.SectionProperties>().FirstOrDefault();
                WPS.HeaderReference dstHeaderReference = dstSectionProperties.Descendants<WPS.HeaderReference>()
                    .Where(H => H.Type == WPS.HeaderFooterValues.Default)
                    .FirstOrDefault();

                //若目的地檔案原有Header,刪掉它,新建一個
                if (dstHeaderReference != null)
                {
                    HeaderPart dstOldHeader = dstMainDocumentPart.GetPartById(dstHeaderReference.Id) as HeaderPart;
                    dstMainDocumentPart.DeletePart(dstOldHeader);

                    //把來源的Header(含圖)填入目的地檔案的Header
                    CreateAndFillNewHeaderPart(dstMainDocumentPart, dstHeaderReference);
                }
                else
                //若目的地檔案原沒有Header,新建一個
                {
                    //新建一個HeaderReference
                    dstHeaderReference = new WPS.HeaderReference() { Type = WPS.HeaderFooterValues.Default, Id = string.Empty };

                    //把來源的Header(含圖)填入目的地檔案的Header
                    CreateAndFillNewHeaderPart(dstMainDocumentPart, dstHeaderReference);

                    //把填好的新目的地檔案Header,加入到文件中
                    dstSectionProperties.Append(dstHeaderReference);
                }
            }
            catch (Exception err)
            {
                throw err;
            }
            finally
            {
                _dstWordprocessingDocument.Close();
            }
        }

        /// <summary>
        /// 把來源的Header的內容(含圖)填入目的地檔案的Header
        /// </summary>
        private void CreateAndFillNewHeaderPart(MainDocumentPart dstMainDocumentPart, WPS.HeaderReference dstHeaderReference)
        {
            try
            {
                HeaderPart newHeaderPart = dstMainDocumentPart.AddNewPart<HeaderPart>();
                if (_srcHeaderPart != null && _srcHeaderImage != null)
                {
                    //不修改內容文字的話,用這個存到目的地檔案Header
                    //newHeaderPart.FeedData(_srcHeaderPart.GetStream());

                    #region change text
                    //換表頭內的文字(Header)
                    string headerText;
                    using (StreamReader reader = new StreamReader(_srcHeaderPart.GetStream()))
                    {
                        headerText = reader.ReadToEnd();
                    }

                    foreach (var item in _textToReplace)
                    {
                        headerText = headerText.Replace(item.Key, item.Value);
                    }

                    // convert string to stream, 存到目的地檔
                    byte[] byteArray = Encoding.UTF8.GetBytes(headerText);
                    using (MemoryStream stream = new MemoryStream(byteArray))
                    {
                        newHeaderPart.FeedData(stream);
                    }
                    #endregion

                    ImagePart newImagePart = newHeaderPart.AddImagePart(ImagePartType.Png);
                    newImagePart.FeedData(_srcHeaderImage.GetStream());

                    string newImageId = newHeaderPart.GetIdOfPart(newImagePart);
                    WPS.Header newHeader = newHeaderPart.Header;
                    WPS.Paragraph newParagraph = newHeader.Descendants<WPS.Paragraph>().FirstOrDefault();
                    WPS.Run newRun = newParagraph.Descendants<WPS.Run>().First();
                    WPS.Drawing newDrawing = newRun.Descendants<WPS.Drawing>().First();
                    DRW.GraphicData newGraphicData = newDrawing.Inline.Graphic.GraphicData;
                    Picture newPicture = newGraphicData.Descendants<Picture>().FirstOrDefault();
                    BlipFill newBlipFill = newPicture.Descendants<BlipFill>().FirstOrDefault();
                    newBlipFill.Blip.Embed = newImageId;

                    dstHeaderReference.Id = dstMainDocumentPart.GetIdOfPart(newHeaderPart);
                }
                else
                {
                    throw (new Exception("沒有來源檔案的Header"));
                }
            }
            catch (Exception err)
            {
                throw err;
            }
        }
    }
}

use:

        //testChangeWordHeader.aspx.cs
		
		public string CopyFromTemplateHeader()
        {
            string strResult;
            string serverPath = HostingEnvironment.MapPath("~/Docs");
            string srcFilepath = Path.Combine(serverPath, "TemplateHeader.docx");
            string dstFilepath = Path.Combine(serverPath, "Destination.docx");
            Dictionary<string, string> textToReplace = new Dictionary<string, string>()
            {
                ["-SN-"] = "12345",
                ["-Author-"] = "李小白",
                ["-Version-"] = "2.0",
                ["-ChineseTitle-"] = "月亮",
                ["-EnglishTitle-"] = "Moon",
            };

            DocHeaderCopyer copyer = new DocHeaderCopyer(srcFilepath, dstFilepath, textToReplace);
            bool boolResult = copyer.Copy();
            strResult = boolResult ? "換表頭完成" : "換表頭失敗";
            return strResult;
        }