diff --git a/OfficeIMO.Tests/Documents/ExampleTemplate.dotx b/OfficeIMO.Tests/Documents/ExampleTemplate.dotx new file mode 100644 index 0000000..87f95e8 Binary files /dev/null and b/OfficeIMO.Tests/Documents/ExampleTemplate.dotx differ diff --git a/OfficeIMO.Tests/Word.Converter.cs b/OfficeIMO.Tests/Word.Converter.cs new file mode 100644 index 0000000..e3621ed --- /dev/null +++ b/OfficeIMO.Tests/Word.Converter.cs @@ -0,0 +1,20 @@ +using OfficeIMO.Word; +using Xunit; + +namespace OfficeIMO.Tests; + +public partial class Word { + [Fact] + public void Test_ConvertDotXtoDocX() { + string filePath = Path.Combine(_directoryDocuments, "ExampleTemplate.dotx"); + string outFilePath = Path.Combine(_directoryWithFiles, "ExampleTemplate.docx"); + WordHelpers.ConvertDotXtoDocX(filePath, outFilePath); + + Assert.True(File.Exists(outFilePath)); + + using (WordDocument document = WordDocument.Load(filePath)) { + Assert.True(document.Paragraphs.Count == 57); + Assert.Contains(document.Paragraphs[56].Text, "Feel free to use and share the file according to the license above."); + } + } +} diff --git a/OfficeIMO.Word/Helpers.Cloners.cs b/OfficeIMO.Word/Helpers.Cloners.cs index 594051f..c79af01 100644 --- a/OfficeIMO.Word/Helpers.Cloners.cs +++ b/OfficeIMO.Word/Helpers.Cloners.cs @@ -1,37 +1,91 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; +namespace OfficeIMO.Word; +/// +/// Provides helper methods for stream and file operations. +/// +public static partial class Helpers { + /// + /// Reads all bytes from a file and writes them to a MemoryStream. + /// + /// The path of the file to read. + /// A MemoryStream containing the file's bytes. + public static MemoryStream ReadAllBytesToMemoryStream(string path) { + byte[] buffer = File.ReadAllBytes(path); + var destStream = new MemoryStream(buffer.Length); + destStream.Write(buffer, 0, buffer.Length); + destStream.Seek(0, SeekOrigin.Begin); + return destStream; + } -namespace OfficeIMO.Word { - public static partial class Helpers { - public static MemoryStream ReadAllBytesToMemoryStream(string path) { - byte[] buffer = File.ReadAllBytes(path); - var destStream = new MemoryStream(buffer.Length); - destStream.Write(buffer, 0, buffer.Length); - destStream.Seek(0, SeekOrigin.Begin); - return destStream; - } + /// + /// Copies the contents of a file stream to a MemoryStream. + /// + /// The path of the file to read. + /// A MemoryStream containing the file's contents. + public static MemoryStream CopyFileStreamToMemoryStream(string path) { + FileStream sourceStream = File.OpenRead(path); + var destStream = new MemoryStream((int)sourceStream.Length); + sourceStream.CopyTo(destStream); + destStream.Seek(0, SeekOrigin.Begin); + return destStream; + } + + /// + /// Copies the contents of one file stream to another file stream. + /// + /// The path of the source file. + /// The path of the destination file. + /// A FileStream for the destination file. + public static FileStream CopyFileStreamToFileStream(string sourcePath, string destPath) { + FileStream sourceStream = File.OpenRead(sourcePath); + FileStream destStream = File.Create(destPath); + sourceStream.CopyTo(destStream); + destStream.Seek(0, SeekOrigin.Begin); + return destStream; + } - public static MemoryStream CopyFileStreamToMemoryStream(string path) { - FileStream sourceStream = File.OpenRead(path); + /// + /// Copies a file and opens a file stream for the copied file. + /// + /// The path of the source file. + /// The path of the destination file. + /// A FileStream for the copied file. + public static FileStream CopyFileAndOpenFileStream(string sourcePath, string destPath) { + File.Copy(sourcePath, destPath, true); + return new FileStream(destPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); + } + + /// + /// Reads the contents of a file into a MemoryStream. + /// + /// The path of the file to read. + /// A MemoryStream containing the file's contents. + public static MemoryStream ReadFileToMemoryStream(string path) { + using (Stream sourceStream = File.OpenRead(path)) { var destStream = new MemoryStream((int)sourceStream.Length); - sourceStream.CopyTo(destStream); + CopyStream(sourceStream, destStream); destStream.Seek(0, SeekOrigin.Begin); return destStream; } + } - public static FileStream CopyFileStreamToFileStream(string sourcePath, string destPath) { - FileStream sourceStream = File.OpenRead(sourcePath); - FileStream destStream = File.Create(destPath); - sourceStream.CopyTo(destStream); - destStream.Seek(0, SeekOrigin.Begin); - return destStream; - } + /// + /// Copies the contents of one stream to another stream. + /// + /// The source stream. + /// The target stream. + public static void CopyStream(Stream source, Stream target) { + if (source != null) { + MemoryStream mstream = source as MemoryStream; + if (mstream != null) { + mstream.WriteTo(target); + } else { + byte[] buffer = new byte[2048]; + int length = buffer.Length, size; - public static FileStream CopyFileAndOpenFileStream(string sourcePath, string destPath) { - File.Copy(sourcePath, destPath, true); - return new FileStream(destPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); + while ((size = source.Read(buffer, 0, length)) != 0) { + target.Write(buffer, 0, size); + } + } } } } diff --git a/OfficeIMO.Word/WordDocument.cs b/OfficeIMO.Word/WordDocument.cs index 000faf3..9e11975 100644 --- a/OfficeIMO.Word/WordDocument.cs +++ b/OfficeIMO.Word/WordDocument.cs @@ -683,15 +683,8 @@ public static WordDocument Load(string filePath, bool readOnly = false, bool aut word._fileStream.CopyTo(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); - // Save the memoryStream to a file for inspection - using (var fileStream = new FileStream("debug_output.docx", FileMode.Create, FileAccess.Write)) { - memoryStream.CopyTo(fileStream); - memoryStream.Seek(0, SeekOrigin.Begin); - } - var wordDocument = WordprocessingDocument.Open(memoryStream, !readOnly, openSettings); - InitialiseStyleDefinitions(wordDocument, readOnly); word.FilePath = filePath; diff --git a/OfficeIMO.Word/WordHelpers.Converters.cs b/OfficeIMO.Word/WordHelpers.Converters.cs new file mode 100644 index 0000000..9a81fdc --- /dev/null +++ b/OfficeIMO.Word/WordHelpers.Converters.cs @@ -0,0 +1,18 @@ +using DocumentFormat.OpenXml.Packaging; + +namespace OfficeIMO.Word { + public partial class WordHelpers { + /// + /// Given a document name, remove all of the headers and footers from the document. + /// + /// + public static void RemoveHeadersAndFooters(string filename) { + using (WordprocessingDocument doc = WordprocessingDocument.Open(filename, true)) { + WordHeader.RemoveHeaders(doc); + WordFooter.RemoveFooters(doc); + // save document + doc.MainDocumentPart.Document.Save(); + } + } + } +} diff --git a/OfficeIMO.Word/WordHelpers.HeadersAndFooters.cs b/OfficeIMO.Word/WordHelpers.HeadersAndFooters.cs index 29b95ca..1f30bc4 100644 --- a/OfficeIMO.Word/WordHelpers.HeadersAndFooters.cs +++ b/OfficeIMO.Word/WordHelpers.HeadersAndFooters.cs @@ -1,21 +1,42 @@ -using System; -using System.Collections.Generic; -using System.Text; using DocumentFormat.OpenXml.Packaging; namespace OfficeIMO.Word { public partial class WordHelpers { /// - /// Given a document name, remove all of the headers and footers from the document. + /// Converts a DOTX template to a DOCX document. + /// + /// Based on: https://github.com/onizet/html2openxml/wiki/Convert-.dotx-to-.docx /// - /// - public static void RemoveHeadersAndFooters(string filename) { - using (WordprocessingDocument doc = WordprocessingDocument.Open(filename, true)) { - WordHeader.RemoveHeaders(doc); - WordFooter.RemoveFooters(doc); - // save document - doc.MainDocumentPart.Document.Save(); + /// The path to the DOTX template file. + /// The path where the converted DOCX file will be saved. + public static void ConvertDotXtoDocX(string templatePath, string outputPath) { + // Read the DOTX template file into a MemoryStream + MemoryStream documentStream = Helpers.ReadFileToMemoryStream(templatePath); + + // Open the WordprocessingDocument from the MemoryStream + using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true)) { + // Change the document type from template to document + template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document); + + // Get the main document part + MainDocumentPart mainPart = template.MainDocumentPart; + + // Ensure the DocumentSettingsPart exists + if (mainPart.DocumentSettingsPart == null) { + mainPart.AddNewPart(); + } + + // Add an external relationship to the template + mainPart.DocumentSettingsPart.AddExternalRelationship( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate", + new Uri(templatePath, UriKind.Absolute)); + + // Save the changes to the main document part + mainPart.Document.Save(); } + + // Write the MemoryStream contents to the output file + File.WriteAllBytes(outputPath, documentStream.ToArray()); } } }