From 8ed5636c7328bb1cd4b44362de75ca1cb3602528 Mon Sep 17 00:00:00 2001 From: "Karl-Julius v. Keudell" Date: Thu, 16 Apr 2020 13:58:09 +0200 Subject: [PATCH] =?UTF-8?q?Projektdateien=20hinzuf=C3=BCgen.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyStuff2Docx.sln | 25 +++ MyStuff2Docx/Models/MyStuffCategory.cs | 124 +++++++++++++ MyStuff2Docx/Models/MyStuffImage.cs | 13 ++ MyStuff2Docx/Models/MyStuffItemInfo.cs | 28 +++ MyStuff2Docx/MyStuff2Docx.csproj | 14 ++ MyStuff2Docx/MyStuffHandler.cs | 50 ++++++ MyStuff2Docx/ProcessingMessage.cs | 58 +++++++ MyStuff2Docx/Program.cs | 230 +++++++++++++++++++++++++ MyStuff2Docx/WordCreator.cs | 188 ++++++++++++++++++++ 9 files changed, 730 insertions(+) create mode 100644 MyStuff2Docx.sln create mode 100644 MyStuff2Docx/Models/MyStuffCategory.cs create mode 100644 MyStuff2Docx/Models/MyStuffImage.cs create mode 100644 MyStuff2Docx/Models/MyStuffItemInfo.cs create mode 100644 MyStuff2Docx/MyStuff2Docx.csproj create mode 100644 MyStuff2Docx/MyStuffHandler.cs create mode 100644 MyStuff2Docx/ProcessingMessage.cs create mode 100644 MyStuff2Docx/Program.cs create mode 100644 MyStuff2Docx/WordCreator.cs diff --git a/MyStuff2Docx.sln b/MyStuff2Docx.sln new file mode 100644 index 0000000..1ffabe3 --- /dev/null +++ b/MyStuff2Docx.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30002.166 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyStuff2Docx", "MyStuff2Docx\MyStuff2Docx.csproj", "{1E660EB5-519D-4959-95A6-603CEC277CF6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1E660EB5-519D-4959-95A6-603CEC277CF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E660EB5-519D-4959-95A6-603CEC277CF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E660EB5-519D-4959-95A6-603CEC277CF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E660EB5-519D-4959-95A6-603CEC277CF6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E82253D9-72CD-44A7-9C13-01F467709E37} + EndGlobalSection +EndGlobal diff --git a/MyStuff2Docx/Models/MyStuffCategory.cs b/MyStuff2Docx/Models/MyStuffCategory.cs new file mode 100644 index 0000000..1f9de05 --- /dev/null +++ b/MyStuff2Docx/Models/MyStuffCategory.cs @@ -0,0 +1,124 @@ +using CsvHelper; +using DocumentFormat.OpenXml.Packaging; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.IO.Compression; +using System.Linq; + +namespace MyStuff2Docx.Models { + class MyStuffCategory : IDisposable { + private ZipArchive categoryZipArchive; + public ZipArchive CategoryZipArchive => categoryZipArchive ??= ZipFile.OpenRead(LocalZipFilePath); + + + public string TempImagesPath { get; set; } + public string LocalZipFilePath { get; set; } + public string ZipFileName { get; set; } + public string Name { get; set; } + public bool Selected { get; set; } = false; + + + private List itemInfos; + public List ItemInfos => itemInfos ??= getItemInfos(); + + private List images; + public List Images => images ??= getImages(); + + + + private List getItemInfos() { + var result = new List(); + + var infoCsvFile = CategoryZipArchive.Entries.SingleOrDefault(e => e.Name.Equals($"{Name}.csv")); + if (infoCsvFile != null) { + using (var rawCsvReader = new StreamReader(infoCsvFile.Open())) { + using (var csv = new CsvReader(rawCsvReader, CultureInfo.InvariantCulture)) { + csv.Read(); + csv.ReadHeader(); + while (csv.Read()) { + var newItemInfo = new MyStuffItemInfo() { + Id = csv.GetField("item id"), + ItemLocation = csv.GetField("item location"), + Images = csv.GetField("item images").Split("|").Where(x => !string.IsNullOrEmpty(x)).ToArray(), + Attachments = csv.GetField("item attachments").Split("|").Where(x => !string.IsNullOrEmpty(x)).ToArray() + }; + + try { + newItemInfo.ItemUpdated = DateTime.ParseExact(csv.GetField("item updated"), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + } + catch (Exception) { } + try { + newItemInfo.ItemCreated = DateTime.ParseExact(csv.GetField("item created"), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + } + catch (Exception) { } + + newItemInfo.AdditionalProperties ??= new Dictionary { }; + foreach (var header in csv.Context.HeaderRecord) { + newItemInfo.AdditionalProperties.TryAdd(header, csv.TryGetField(header, out string value) ? value : string.Empty); + } + + result.Add(newItemInfo); + } + } + } + } + + return result; + } + private List getImages() { + var result = new List(); + + foreach (var compressedImage in CategoryZipArchive.Entries) { + var imageInfo = new MyStuffImage(); + + switch (Path.GetExtension(compressedImage.Name)) { + case ".jpg": + case ".jpeg": + imageInfo.ImageType = ImagePartType.Jpeg; + break; + case ".png": + imageInfo.ImageType = ImagePartType.Png; + break; + case ".bmp": + imageInfo.ImageType = ImagePartType.Bmp; + break; + case ".gif": + imageInfo.ImageType = ImagePartType.Gif; + break; + case ".tiff": + imageInfo.ImageType = ImagePartType.Tiff; + break; + default: + continue; + } + + imageInfo.ImageFileName = compressedImage.Name; + imageInfo.PathInCategory = compressedImage.FullName; + imageInfo.ImageId = Path.GetFileNameWithoutExtension(compressedImage.Name); + imageInfo.ItemId = compressedImage.FullName.Split('\\', '/').FirstOrDefault(); + imageInfo.TempImagePath = TempImagesPath + "Temp_Image_" + Guid.NewGuid() + ".tmp"; + + using (var compressedImageStream = compressedImage.Open()) { + using (var tempImageStream = File.Open(imageInfo.TempImagePath, FileMode.OpenOrCreate)) { + compressedImageStream.CopyTo(tempImageStream); + } + } + + result.Add(imageInfo); + } + + + return result; + } + + + public void Dispose() { + if (categoryZipArchive != null) { + categoryZipArchive.Dispose(); + categoryZipArchive = null; + } + } + } +} diff --git a/MyStuff2Docx/Models/MyStuffImage.cs b/MyStuff2Docx/Models/MyStuffImage.cs new file mode 100644 index 0000000..c2f1049 --- /dev/null +++ b/MyStuff2Docx/Models/MyStuffImage.cs @@ -0,0 +1,13 @@ +using DocumentFormat.OpenXml.Packaging; + +namespace MyStuff2Docx.Models { + class MyStuffImage { + public string PathInCategory { get; set; } + public string ImageFileName { get; set; } + public string ItemId { get; set; } + public string ImageId { get; set; } + public ImagePartType ImageType { get; set; } + + public string TempImagePath { get; set; } + } +} diff --git a/MyStuff2Docx/Models/MyStuffItemInfo.cs b/MyStuff2Docx/Models/MyStuffItemInfo.cs new file mode 100644 index 0000000..acc1303 --- /dev/null +++ b/MyStuff2Docx/Models/MyStuffItemInfo.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MyStuff2Docx.Models { + class MyStuffItemInfo { + public string Id { get; set; } + public string ItemLocation { get; set; } + + public Dictionary AdditionalProperties { get; set; } + + public string[] Images { get; set; } + public string[] Attachments { get; set; } + public DateTime ItemUpdated { get; set; } + public DateTime ItemCreated { get; set; } + + public bool AdditionalPropertyFilter(KeyValuePair property) { + var conditions = new List { + !property.Key.Equals("item id"), + !property.Key.Equals("item barcode"), + !property.Key.Equals("item images"), + !property.Key.Equals("item attachments") + }; + + return conditions.All(c => c); + } + } +} diff --git a/MyStuff2Docx/MyStuff2Docx.csproj b/MyStuff2Docx/MyStuff2Docx.csproj new file mode 100644 index 0000000..201d9e7 --- /dev/null +++ b/MyStuff2Docx/MyStuff2Docx.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + diff --git a/MyStuff2Docx/MyStuffHandler.cs b/MyStuff2Docx/MyStuffHandler.cs new file mode 100644 index 0000000..fc459e6 --- /dev/null +++ b/MyStuff2Docx/MyStuffHandler.cs @@ -0,0 +1,50 @@ +using MyStuff2Docx.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; + +namespace MyStuff2Docx { + class MyStuffHandler : IDisposable { + public string BaseZipArchiveTempPath { get; private set; } + public string TempImagesPath { get; private set; } + public string TempDocxPath { get; private set; } + + + public List Categories { get; private set; } + + + public MyStuffHandler(string path) { + BaseZipArchiveTempPath = Path.GetTempPath() + "MyStuff2Docx_ZipFiles_" + Guid.NewGuid() + Path.DirectorySeparatorChar; + TempImagesPath = Path.GetTempPath() + "MyStuff2Docx_Images_" + Guid.NewGuid() + Path.DirectorySeparatorChar; + TempDocxPath = Path.GetTempPath() + "MyStuff2Docx_DocxFiles_" + Guid.NewGuid() + Path.DirectorySeparatorChar; + Directory.CreateDirectory(BaseZipArchiveTempPath); + Directory.CreateDirectory(TempImagesPath); + Directory.CreateDirectory(TempDocxPath); + + ZipFile.ExtractToDirectory(path, BaseZipArchiveTempPath); + + Categories ??= new List(); + foreach (var compressedCategory in Directory.GetFiles(BaseZipArchiveTempPath, "*.zip")) { + var newCategory = new MyStuffCategory() { + ZipFileName = Path.GetFileName(compressedCategory), + Name = Path.GetFileNameWithoutExtension(compressedCategory), + TempImagesPath = TempImagesPath, + LocalZipFilePath = compressedCategory + }; + + Categories.Add(newCategory); + } + } + + public void Dispose() { + foreach (var category in Categories ?? new List { }) { + category.Dispose(); + } + + Directory.Delete(BaseZipArchiveTempPath, true); + Directory.Delete(TempImagesPath, true); + Directory.Delete(TempDocxPath, true); + } + } +} diff --git a/MyStuff2Docx/ProcessingMessage.cs b/MyStuff2Docx/ProcessingMessage.cs new file mode 100644 index 0000000..d24181b --- /dev/null +++ b/MyStuff2Docx/ProcessingMessage.cs @@ -0,0 +1,58 @@ +using System; +using System.Diagnostics; + +namespace MyStuff2Docx { + class ProcessingMessage : IDisposable { + private const string PROCESSING_MESSAGE = "Processing..."; + private const string DONE_MESSAGE = "Done"; + private const string ERROR_MESSAGE = "Error!"; + private const ConsoleColor PROCESSING_COLOR = ConsoleColor.Yellow; + private const ConsoleColor DONE_COLOR = ConsoleColor.Green; + private const ConsoleColor ERROR_COLOR = ConsoleColor.Red; + + private int CursorXPosition; + private int CursorYPosition; + + public bool HasError { get; set; } = false; + + public ProcessingMessage(string text) { + lock (Program._CONSOLE_WRITE_LOCK) { + var currentConsoleColor = Console.ForegroundColor; + + Console.Write($"{text} --> "); + Console.ForegroundColor = PROCESSING_COLOR; + Console.Write($"{PROCESSING_MESSAGE}"); + Console.ForegroundColor = currentConsoleColor; + + CursorXPosition = Console.CursorLeft; + CursorYPosition = Console.CursorTop; + Console.WriteLine(); + } + } + + public void Dispose() { + lock (Program._CONSOLE_WRITE_LOCK) { + var currentXPosition = Console.CursorLeft; + var currentYPosition = Console.CursorTop; + var currentConsoleColor = Console.ForegroundColor; + + try { + Console.SetCursorPosition(CursorXPosition - PROCESSING_MESSAGE.Length, CursorYPosition); + } + finally { + if (HasError) { + Console.ForegroundColor = ERROR_COLOR; + Console.Write(ERROR_MESSAGE.PadRight(PROCESSING_MESSAGE.Length)); + } + else { + Console.ForegroundColor = DONE_COLOR; + Console.Write(DONE_MESSAGE.PadRight(PROCESSING_MESSAGE.Length)); + } + + Console.SetCursorPosition(currentXPosition, currentYPosition); + Console.ForegroundColor = currentConsoleColor; + } + } + } + } +} diff --git a/MyStuff2Docx/Program.cs b/MyStuff2Docx/Program.cs new file mode 100644 index 0000000..d3b6917 --- /dev/null +++ b/MyStuff2Docx/Program.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace MyStuff2Docx { + class Program { + private const string DEV_BASE_ZIP_PATH = null; + private const string DEV_TARGET_DIR_PATH = null; + + public static object _CONSOLE_WRITE_LOCK = new object(); + + static void Main(string[] args) { + Console.Title = "MyStuff2Docx"; + MyStuffHandler myStuffHandler = null; + + #region GetMyStuffHandler + renderHeadline(); + while (myStuffHandler == null) { + lock (_CONSOLE_WRITE_LOCK) { + var zipFilePath = string.Empty; + + if (string.IsNullOrEmpty(DEV_BASE_ZIP_PATH)) { + Console.WriteLine(); + Console.WriteLine("Please enter the complete path of the exported MyStuff .zip file:"); + Console.Write(" >> "); + zipFilePath = Console.ReadLine(); + } + else + zipFilePath = DEV_BASE_ZIP_PATH; + + zipFilePath = zipFilePath.Trim('"'); + + try { + myStuffHandler = new MyStuffHandler(zipFilePath); + } + catch (FileNotFoundException) { + Console.WriteLine("The file could not be found. Please try again."); + } + catch (Exception) { + Console.WriteLine("An unknown error has occurred. Please try again and make sure that you have read access to the file."); + } + } + } + #endregion + + using (myStuffHandler) { + + #region GetSelection + var selectedPage = 1; + var maxPages = Math.Ceiling((double)myStuffHandler.Categories.Count / 9); + + do { + lock (_CONSOLE_WRITE_LOCK) { + renderHeadline(); + + var index = 1; + foreach (var category in myStuffHandler.Categories.Skip(9 * (selectedPage - 1)).Take(9)) { + Console.Write(category.Selected ? "[X] " : "[ ] "); + Console.Write($"{index} {category.Name}"); + Console.WriteLine(); + + index++; + } + Console.WriteLine(); + Console.WriteLine($" -- Page {selectedPage}/{maxPages} --"); + Console.WriteLine(); + Console.WriteLine(" (1-9 -> select | w -> up | s -> down | a -> toogle all | x -> cancel | b -> save)"); + Console.WriteLine(); + Console.Write(" >> "); + var rawInput = Console.ReadKey(); + + if (rawInput.Key == ConsoleKey.W && selectedPage < maxPages) + selectedPage++; + else if (rawInput.Key == ConsoleKey.S && selectedPage > 1) + selectedPage--; + else if (rawInput.Key == ConsoleKey.A) { + var newValue = !myStuffHandler.Categories?.FirstOrDefault()?.Selected ?? false; + myStuffHandler.Categories.ForEach(cat => cat.Selected = newValue); + } + else if (int.TryParse(rawInput.KeyChar.ToString(), out int selectedOption) && selectedOption > 0 && selectedOption <= 9) { + var selectedItem = myStuffHandler.Categories.ElementAtOrDefault(selectedOption + (9 * (selectedPage - 1)) - 1); + if (selectedItem != null) { + selectedItem.Selected = !selectedItem.Selected; + } + } + else if (rawInput.Key == ConsoleKey.X) + return; + else if (rawInput.Key == ConsoleKey.B) + break; + } + } while (true); + #endregion + + #region GetFolderForExportAndExportType + renderHeadline(); + var exportFolderPath = string.Empty; + var multipleFiles = true; + + do { + lock (_CONSOLE_WRITE_LOCK) { + if (string.IsNullOrEmpty(DEV_TARGET_DIR_PATH)) { + Console.WriteLine(); + Console.WriteLine("Please enter the complete path for the created documents:"); + Console.Write(" >> "); + exportFolderPath = Console.ReadLine(); + } + else + exportFolderPath = DEV_TARGET_DIR_PATH; + + exportFolderPath = exportFolderPath.Trim('"'); + exportFolderPath = exportFolderPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + + if (!string.IsNullOrWhiteSpace(exportFolderPath) && Directory.Exists(exportFolderPath)) + break; + else + Console.WriteLine("This is not a valid directory. Please try again."); + } + } while (true); + + do { + lock (_CONSOLE_WRITE_LOCK) { + Console.WriteLine(); + Console.WriteLine("Would you like to have one document for all categories (not recommended),"); + Console.WriteLine("or rather one document per category (recommended)?"); + Console.WriteLine("Please note: Word documents that are larger than 500 mb"); + Console.WriteLine("or have more than 1000 pages are sometimes difficult or impossible to open."); + Console.WriteLine(" (o -> one document | m -> many documents)"); + Console.Write(" >> "); + var rawInput = Console.ReadKey(); + + if (rawInput.Key == ConsoleKey.O) { + multipleFiles = false; + break; + } + else if (rawInput.Key == ConsoleKey.M) { + multipleFiles = true; + break; + } + } + } while (true); + #endregion + + #region ExportCategories + renderHeadline(); + if (multipleFiles) { + var processingMessages = new Dictionary { }; + var generationTasks = new List { }; + + foreach (var selectedCategory in myStuffHandler.Categories.Where(cat => !cat.Selected)) { + selectedCategory.Dispose(); + } + + foreach (var selectedCategory in myStuffHandler.Categories.Where(cat => cat.Selected)) { + processingMessages.Add($"{selectedCategory.Name}_GeneratingAndCombiningPages", new ProcessingMessage($"Generating and combining \"{selectedCategory.Name}\"")); + + var newTask = Task.Factory.StartNew(() => { + var wordCreator = new WordCreator(); + var exportFilePath = @$"{exportFolderPath}\MyStuff2Docx_{selectedCategory.Name}_Export_{Guid.NewGuid()}.docx"; + + try { + foreach (var itemInfo in selectedCategory.ItemInfos) { + wordCreator.AddPage(itemInfo, selectedCategory, myStuffHandler.TempDocxPath); + } + + wordCreator.CombinePages(exportFilePath); + } + catch (Exception) { processingMessages[$"{selectedCategory.Name}_GeneratingAndCombiningPages"].HasError = true; } + finally { processingMessages[$"{selectedCategory.Name}_GeneratingAndCombiningPages"].Dispose(); } + + processingMessages.Remove($"{selectedCategory.Name}_GeneratingAndCombiningPages"); + selectedCategory.Dispose(); + }); + + generationTasks.Add(newTask); + } + + Task.WaitAll(generationTasks.ToArray()); + } + else { + var wordCreator = new WordCreator(); + var exportFilePath = @$"{exportFolderPath}\MyStuff2Docx_Export_{Guid.NewGuid()}.docx"; + + foreach (var selectedCategory in myStuffHandler.Categories.Where(cat => cat.Selected)) { + using (var pm = new ProcessingMessage($"\"{selectedCategory.Name}\"")) { + try { + foreach (var itemInfo in selectedCategory.ItemInfos) { + wordCreator.AddPage(itemInfo, selectedCategory, myStuffHandler.TempDocxPath); + } + } + catch (Exception) { pm.HasError = true; } + } + + selectedCategory.Dispose(); + } + + Console.WriteLine(); + using (var pm = new ProcessingMessage($"Combining all pages")) { + try { + wordCreator.CombinePages(exportFilePath); + } + catch (Exception) { pm.HasError = true; } + } + } + #endregion + + GC.Collect(); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine("The program has run through. Please press any button to exit."); + Console.ReadKey(); + } + } + + + private static void renderHeadline(bool clearBefore = true) { + lock (_CONSOLE_WRITE_LOCK) { + if (clearBefore) { + Console.Clear(); + } + + Console.WriteLine("=================================="); + Console.WriteLine("========== MyStuff2Docx =========="); + Console.WriteLine("=================================="); + Console.WriteLine(); + } + } + } +} diff --git a/MyStuff2Docx/WordCreator.cs b/MyStuff2Docx/WordCreator.cs new file mode 100644 index 0000000..035560c --- /dev/null +++ b/MyStuff2Docx/WordCreator.cs @@ -0,0 +1,188 @@ +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using MyStuff2Docx.Models; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using A = DocumentFormat.OpenXml.Drawing; +using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing; +using PIC = DocumentFormat.OpenXml.Drawing.Pictures; + +namespace MyStuff2Docx { + class WordCreator { + public const int IMAGE_WIDTH = 990000; + + private List pagePaths = new List(); + + public void AddPage(MyStuffItemInfo itemInfo, in MyStuffCategory category, string tempDocxPath) { + var pagePath = tempDocxPath + "MyStuff2Docx_" + Guid.NewGuid() + ".docx"; + + using (var baseDoc = WordprocessingDocument.Create(pagePath, WordprocessingDocumentType.Document)) { + baseDoc.AddMainDocumentPart(); + baseDoc.MainDocumentPart.Document = new Document(); + baseDoc.MainDocumentPart.Document.Body = new Body(); + + #region TableProperties + var tableProperties = new TableProperties( + new TableBorders( + new TopBorder() { Val = new EnumValue(BorderValues.BasicThinLines), Size = 2 }, + new BottomBorder() { Val = new EnumValue(BorderValues.BasicThinLines), Size = 2 }, + new LeftBorder() { Val = new EnumValue(BorderValues.BasicThinLines), Size = 2 }, + new RightBorder() { Val = new EnumValue(BorderValues.BasicThinLines), Size = 2 }, + new InsideHorizontalBorder() { Val = new EnumValue(BorderValues.BasicThinLines), Size = 2 }, + new InsideVerticalBorder() { Val = new EnumValue(BorderValues.BasicThinLines), Size = 2 } + ), + new TableWidth() { + Width = "5000", + Type = TableWidthUnitValues.Pct + } + ); + #endregion + + var table = new Table(tableProperties); + + #region Add CategoryName + table.AppendChild(new TableRow( + new TableCell(new Paragraph(new Run(new Text("Category")))), + new TableCell(new Paragraph(new Run(new Text(category.Name)))) + )); + #endregion + + #region Adding AdditionalProperties + foreach (var property in itemInfo.AdditionalProperties.Where(itemInfo.AdditionalPropertyFilter)) { + table.AppendChild(new TableRow( + new TableCell(new Paragraph(new Run(new Text(property.Key)))), + new TableCell(new Paragraph(new Run(new Text(property.Value)))) + )); + } + #endregion + + #region Adding Images + var imagesForThisItem = category.Images.Where(i => itemInfo.Images.Contains(i.PathInCategory)); + + var readyImages = new List { }; + foreach (var imageForThisItem in imagesForThisItem) { + readyImages.Add(getImageElement(baseDoc, imageForThisItem)); + } + + table.AppendChild(new TableRow( + new TableCell(new Paragraph(new Run(new Text("Images")))), + new TableCell(new Paragraph(new Run(readyImages))) + )); + #endregion + + + baseDoc.MainDocumentPart.Document.Body.AppendChild(table); + baseDoc.MainDocumentPart.Document.Body.AppendChild(new Break() { Type = BreakValues.Page }); + + baseDoc.Close(); + } + + pagePaths.Add(pagePath); + } + + public void CombinePages(string targetFilePath) { + using (var baseDoc = WordprocessingDocument.Create(targetFilePath, WordprocessingDocumentType.Document)) { + baseDoc.AddMainDocumentPart(); + baseDoc.MainDocumentPart.Document = new Document(); + baseDoc.MainDocumentPart.Document.Body = new Body(); + + + for (int i = 0; i < pagePaths.Count; i++) { + var chunk = baseDoc.MainDocumentPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, "AltChunkId" + i); + using (var fileStream = File.Open(pagePaths[i], FileMode.Open)) { + chunk.FeedData(fileStream); + } + var altChunk = new AltChunk() { + Id = "AltChunkId" + i + }; + baseDoc.MainDocumentPart.Document.Body.AppendChild(new Break() { Type = BreakValues.Page }); + baseDoc.MainDocumentPart.Document.Body.AppendChild(altChunk); + } + + + baseDoc.Close(); + } + } + + + private Drawing getImageElement(WordprocessingDocument baseDoc, MyStuffImage image) { + var imagePart = baseDoc.MainDocumentPart.AddImagePart(image.ImageType); + + if (!getImageDimensions(image.TempImagePath, out int width, out int height)) { + width = IMAGE_WIDTH; + height = 792000; + } + else { + var proportionMultiplier = (double)width / IMAGE_WIDTH; + width = IMAGE_WIDTH; + height = (int)Math.Ceiling(height / proportionMultiplier); + } + + using (FileStream stream = new FileStream(image.TempImagePath, FileMode.Open)) { + imagePart.FeedData(stream); + } + + // Define the reference of the image. + var element = new Drawing( + new DW.Inline( + new DW.Extent() { Cx = width, Cy = height }, + new DW.EffectExtent() { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L }, + new DW.DocProperties() { Id = 1U, Name = image.ImageId }, + new DW.NonVisualGraphicFrameDrawingProperties(new A.GraphicFrameLocks() { NoChangeAspect = true }), + new A.Graphic( + new A.GraphicData( + new PIC.Picture( + new PIC.NonVisualPictureProperties( + new PIC.NonVisualDrawingProperties() { Id = 0U, Name = image.ImageFileName }, + new PIC.NonVisualPictureDrawingProperties()), + new PIC.BlipFill( + new A.Blip( + new A.BlipExtensionList( + new A.BlipExtension() { + Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}" + } + ) + ) { + Embed = baseDoc.MainDocumentPart.GetIdOfPart(imagePart), + 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 = width, Cy = height }), + new A.PresetGeometry( + new A.AdjustValueList() + ) { Preset = A.ShapeTypeValues.Rectangle })) + ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) + ) { + DistanceFromTop = 0U, + DistanceFromBottom = 0U, + DistanceFromLeft = 0U, + DistanceFromRight = 0U, + EditId = "50D07946" + }); + + return element; + } + + private bool getImageDimensions(string path, out int width, out int height) { + try { + using (var img = Image.FromFile(path)) { + width = img.Width; + height = img.Height; + } + return true; + } + catch (Exception) { + width = 0; + height = 0; + return false; + } + } + } +}