diff --git a/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.csproj b/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.csproj index 37ce84a67b..902dc26e6d 100644 --- a/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.csproj +++ b/src/EPPlus.Export.Pdf.Tests/EPPlus.Export.Pdf.Tests.csproj @@ -17,6 +17,7 @@ + diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs index 6ce9e4da3e..71424c9d46 100644 --- a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs +++ b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs @@ -11,6 +11,10 @@ Date Author Change 10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0 *************************************************************************************************/ using EPPlus.Export.Pdf.Settings; +using OfficeOpenXml; +using OfficeOpenXml.Export.PdfExport; +using System.Diagnostics; +using System.Text; using OfficeOpenXml.Export.PdfExport; using EPPlus.Export.Pdf.Settings.PdfPageSizes; using EPPlus.Export.Pdf; @@ -26,142 +30,488 @@ namespace EPPlusTest.PDF [TestClass] public class PdfTests : TestBase { - /* BIG PDF TODO - * - * Missing Features: - * Embedding pictures as drawings - * Embedding pictures as cell content - * Embedding pictures as header/footer - * Number formatting - * Scaling document - * Conditional Formatting icons - * Vertical text - * Equations - * Pivot tables - * Shapes - * Charts - * 3D models - * Compression - * - * Bugs: - * Merged cell uses full width/height even when columns/rows are hidden. - * Conditional formatting not worksing 100% of the time. - * Table could sometimes select wrong style - * - * Other - * Cells: Remove stroke from solid fill and adjust size and position of cell more precise and only use fill command. - * Gradients: Make diamond gradients instead of radial gradtient in from corner and center gradient - * Text: Set up to use back up techniques when not embedding font - * Borders: Adjust and make border look better - * - */ - - /// - /// Old Test - /// - //[TestMethod] - //public void TestWritePdf() - //{ - // using var p = OpenTemplatePackage("PDFTest.xlsx"); - // //using var p = OpenTemplatePackage("PdfGrids\\PdfTextTest.xlsx"); - // //using var p = OpenTemplatePackage("PdfGrids\\PdfPageBreakTest.xlsx"); - // //using var p = OpenTemplatePackage("PDFTest - Copy (2).xlsx"); - // //using var p = OpenTemplatePackage("PdfBorders.xlsx"); - // //using var p = OpenTemplatePackage("PdfGrids\\3 2 Page Crazy Cells.xlsx"); - // //using var p = OpenTemplatePackage("PdfGrids\\3 2 Page Crazy Cells Merged.xlsx"); - // //using var p = OpenTemplatePackage("Gradient.xlsx"); - // //using var p = OpenTemplatePackage("PatternFill.xlsx"); - // var ws = p.Workbook.Worksheets[0]; - // //var ws = p.Workbook.Worksheets[1]; - // PdfPageSettings pageSettings = new PdfPageSettings(); - // pageSettings.ShowGridLines = true; - // pageSettings.PageSize = PdfPageSize.A4; - // pageSettings.Orientation = Orientations.Portrait; - // pageSettings.Margins = PdfMargins.Normal; - // pageSettings.ShowGridLines = true; - // pageSettings.CenterOnPageHorizontally = true; - // pageSettings.CenterOnPageVertically = true; - // pageSettings.ShowHeadings = true; - // pageSettings.CommentsAndNotes = CommentsAndNotes.AtEndOfSheet; - // //Debug Flags - // pageSettings.Debug = true; - // pageSettings.PrintAsText = true; - - // ExcelPdf pedeef = new ExcelPdf(ws, pageSettings); - // pedeef.CreatePdf("c:\\epplustest\\pdf\\FullPageTest49.pdf"); - //} - - /// - /// Old Test - /// - //[TestMethod] - //public void TestWritePdf2() - //{ - // using var p = OpenTemplatePackage("PDFTest2.xlsx"); - // PdfPageSettings pageSettings = new PdfPageSettings(); - // pageSettings.ShowGridLines = true; - // pageSettings.PageSize = PdfPageSize.A4; - // pageSettings.Orientation = Orientations.Portrait; - // pageSettings.Margins = PdfMargins.Normal; - // pageSettings.ShowGridLines = true; - // //Debug Flags - // pageSettings.Debug = true; - // pageSettings.PrintAsText = true; - - // ExcelPdf pedeef = new ExcelPdf(p.Workbook.Worksheets.First(), pageSettings); - // pedeef.CreatePdf("c:\\epplustest\\pdf\\EmojiTest.pdf"); - //} - - [TestMethod] - public void ReadPrintAreas() - { - //using var p = OpenTemplatePackage("PdfPrintAreas.xlsx"); - using var p = OpenTemplatePackage("PDFTest.xlsx"); - //using var p = OpenTemplatePackage("PDFTest_old.xlsx"); - //using var p = OpenTemplatePackage("DoubleBorder.xlsx"); - var ws = p.Workbook.Worksheets[0]; - PdfPageSettings pageSettings = new PdfPageSettings(); - pageSettings.CommentsAndNotes = CommentsAndNotes.AtEndOfSheet; - pageSettings.CellErrors = CellErrors.NA; - pageSettings.Debug = true; - pageSettings.PrintAsText = true; - pageSettings.ShowGridLines = true; - pageSettings.ShowHeadings = true; - PdfCatalog catlog = new PdfCatalog(pageSettings, ws, "C:\\epplustest\\pdf\\FullPageTest58.pdf"); + private static void AssertLooksLikePdf(byte[] bytes) + { + Assert.IsTrue(bytes.Length > 0, "PDF output is empty."); + string head = Encoding.ASCII.GetString(bytes, 0, Math.Min(8, bytes.Length)); + Assert.IsTrue(head.StartsWith("%PDF-"), $"Missing PDF header. Got: '{head}'"); + int tailLen = Math.Min(8, bytes.Length); + string tail = Encoding.ASCII.GetString(bytes, bytes.Length - tailLen, tailLen); + Assert.IsTrue(tail.Contains("%%EOF"), "Missing %%EOF trailer marker."); + } - //line breaks - //wrap comments - //text placement - //alignment - //vertical + private static long ParseStartXref(byte[] bytes, int pdfStart) + { + string text = Encoding.ASCII.GetString(bytes, pdfStart, bytes.Length - pdfStart); + int idx = text.LastIndexOf("startxref", StringComparison.Ordinal); + Assert.IsTrue(idx >= 0, "startxref keyword not found."); + int i = idx + "startxref".Length; + while (i < text.Length && (text[i] == '\n' || text[i] == '\r' || text[i] == ' ')) i++; + int start = i; + while (i < text.Length && char.IsDigit(text[i])) i++; + return long.Parse(text.Substring(start, i - start)); } + protected static string pdfPath = _worksheetPath + "\\PDF\\"; + [TestMethod] - public void PerfTest() + public void SaveWorksheetAsPdfTest1() { - var sw = new Stopwatch(); - Console.WriteLine("Starting..."); - sw.Start(); - using var p = OpenTemplatePackage("Aico_0105_S_ALR_87011990_AICO_ASSET_ITE_2025-04_BS.xlsx"); - Console.WriteLine($"Read package time elapsed: {sw.ElapsedMilliseconds} ms"); - sw.Restart(); + using var p = OpenTemplatePackage("PDFTest.xlsx"); var ws = p.Workbook.Worksheets[0]; - var dun = ws.Dimension; - var pageSettings = new PdfPageSettings + string path = pdfPath + "WorksheetTest1.pdf"; + ws.SaveAsPdf(path); + Assert.IsTrue(File.Exists(path), "PDF file was not created."); + AssertLooksLikePdf(File.ReadAllBytes(path)); + } + + [TestMethod] + public void SaveWorksheetAsPdfTest2() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + ws.PrinterSettings.Orientation = eOrientation.Landscape; + ws.PrinterSettings.ShowGridLines = false; + ws.PrinterSettings.ShowHeaders = false; + ws.PrinterSettings.PaperSize = ePaperSize.A3; + string path = pdfPath + "WorksheetTest2.pdf"; + ws.SaveAsPdf(path); + Assert.IsTrue(File.Exists(path), "PDF file was not created."); + AssertLooksLikePdf(File.ReadAllBytes(path)); + } + + [TestMethod] + public void SaveRangeAsPdfTest1() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var range = p.Workbook.Worksheets[0].Cells["D3:F6"]; + string path = pdfPath + "RangeTest1.pdf"; + range.SaveAsPdf(path); + Assert.IsTrue(File.Exists(path), "PDF file was not created."); + AssertLooksLikePdf(File.ReadAllBytes(path)); + } + + [TestMethod] + public void SaveWorkbookAsPdfTest1() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + string path = pdfPath + "WorkbookTest1.pdf"; + wb.SaveAsPdf(path); + Assert.IsTrue(File.Exists(path), "PDF file was not created."); + AssertLooksLikePdf(File.ReadAllBytes(path)); + } + + [TestMethod] + public void SaveWorksheetsAsPdfTest2() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws0 = wb.Worksheets[0]; + var ws1 = wb.Worksheets[1]; + var ws2 = wb.Worksheets[2]; + string path = pdfPath + "WorksheetsTest2.pdf"; + wb.SaveAsPdf(path, ws0, ws1, ws2); + Assert.IsTrue(File.Exists(path), "PDF file was not created."); + AssertLooksLikePdf(File.ReadAllBytes(path)); + } + + [TestMethod] + public void SaveWorksheetsAsPdfTest1() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws0 = wb.Worksheets[0]; + var ws2 = wb.Worksheets[2]; + string path = pdfPath + "WorksheetsTest1.pdf"; + wb.SaveAsPdf(path, ws0, ws2); + Assert.IsTrue(File.Exists(path), "PDF file was not created."); + AssertLooksLikePdf(File.ReadAllBytes(path)); + } + + [TestMethod] + public void SaveRangesAsPdfTest1() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws = wb.Worksheets[0]; + var r1 = ws.Cells["D3:F6"]; + var r2 = ws.Cells["B36:F39"]; + var r3 = ws.Cells["K49:Q58"]; + var r4 = ws.Cells["L142:Q147"]; + string path = pdfPath + "RangesTest1.pdf"; + wb.SaveAsPdf(path, r1, r2, r3, r4); + Assert.IsTrue(File.Exists(path), "PDF file was not created."); + AssertLooksLikePdf(File.ReadAllBytes(path)); + } + + [TestMethod] + public async Task SaveWorkbookAsPdfAsyncTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + string tempFile = Path.GetTempFileName(); + try { - CommentsAndNotes = CommentsAndNotes.AtEndOfSheet, - CellErrors = CellErrors.NA, - Debug = true, - PrintAsText = true, - ShowGridLines = false, - ShowHeadings = true - }; - PdfCatalog catalog = new PdfCatalog(pageSettings, ws, "C:\\epplustest\\pdf\\OutputTest1.3.pdf"); - Console.WriteLine($"workbook exported time elapsed: {sw.ElapsedMilliseconds} ms"); + await wb.SaveAsPdfAsync(tempFile); + AssertLooksLikePdf(File.ReadAllBytes(tempFile)); + } + finally + { + if (File.Exists(tempFile)) File.Delete(tempFile); + } } + [TestMethod] + public async Task SaveWorksheetsAsPdfAsyncTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws0 = wb.Worksheets[0]; + var ws2 = wb.Worksheets[2]; + string tempFile = Path.GetTempFileName(); + try + { + await wb.SaveAsPdfAsync(tempFile, ws0, ws2); + AssertLooksLikePdf(File.ReadAllBytes(tempFile)); + } + finally + { + if (File.Exists(tempFile)) File.Delete(tempFile); + } + } + + [TestMethod] + public async Task SaveWorksheetsAsPdfAsyncWithTokenTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws0 = wb.Worksheets[0]; + var ws2 = wb.Worksheets[2]; + string tempFile = Path.GetTempFileName(); + try + { + await wb.SaveAsPdfAsync(tempFile, CancellationToken.None, ws0, ws2); + AssertLooksLikePdf(File.ReadAllBytes(tempFile)); + } + finally + { + if (File.Exists(tempFile)) File.Delete(tempFile); + } + } + + [TestMethod] + public async Task SaveRangesAsPdfAsyncTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws = wb.Worksheets[0]; + var r1 = ws.Cells["D3:F6"]; + var r2 = ws.Cells["B36:F39"]; + string tempFile = Path.GetTempFileName(); + try + { + await wb.SaveAsPdfAsync(tempFile, r1, r2); + AssertLooksLikePdf(File.ReadAllBytes(tempFile)); + } + finally + { + if (File.Exists(tempFile)) File.Delete(tempFile); + } + } + + [TestMethod] + public async Task SaveRangesAsPdfAsyncWithTokenTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws = wb.Worksheets[0]; + var r1 = ws.Cells["D3:F6"]; + var r2 = ws.Cells["B36:F39"]; + string tempFile = Path.GetTempFileName(); + try + { + await wb.SaveAsPdfAsync(tempFile, CancellationToken.None, r1, r2); + AssertLooksLikePdf(File.ReadAllBytes(tempFile)); + } + finally + { + if (File.Exists(tempFile)) File.Delete(tempFile); + } + } + + [TestMethod] + public async Task SaveWorkbookAsPdfAsyncWithCanceledTokenThrowsTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + string tempFile = Path.GetTempFileName(); + try + { + using var cts = new CancellationTokenSource(); + cts.Cancel(); + + await Assert.ThrowsExactlyAsync( + () => wb.SaveAsPdfAsync(tempFile, cts.Token)); + } + finally + { + if (File.Exists(tempFile)) File.Delete(tempFile); + } + } + + [TestMethod] + public void SaveWorkbookAsPdfToStreamTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + using var ms = new MemoryStream(); + wb.SaveAsPdf(ms); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public void SaveWorksheetsAsPdfToStreamTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws0 = wb.Worksheets[0]; + var ws2 = wb.Worksheets[2]; + using var ms = new MemoryStream(); + wb.SaveAsPdf(ms, ws0, ws2); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public void SaveRangesAsPdfToStreamTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + var ws = wb.Worksheets[0]; + var r1 = ws.Cells["D3:F6"]; + var r2 = ws.Cells["B36:F39"]; + using var ms = new MemoryStream(); + wb.SaveAsPdf(ms, r1, r2); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public async Task SaveWorkbookAsPdfToStreamAsyncTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + using var ms = new MemoryStream(); + await wb.SaveAsPdfAsync(ms); + AssertLooksLikePdf(ms.ToArray()); + } - [TestMethod] + [TestMethod] + public async Task SaveAsPdfAsyncWithCanceledTokenThrowsTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + using var ms = new MemoryStream(); + using var cts = new CancellationTokenSource(); + cts.Cancel(); + await Assert.ThrowsExactlyAsync(() => wb.SaveAsPdfAsync(ms, cts.Token)); + } + + [TestMethod] + public void SaveAsPdfToStreamLeavesStreamOpenTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + using var ms = new MemoryStream(); + wb.SaveAsPdf(ms); + Assert.IsTrue(ms.CanWrite, "Stream was closed by the export."); + Assert.IsTrue(ms.CanRead, "Stream was closed by the export."); + Assert.IsTrue(ms.Length > 0, "Nothing was written to the stream."); + } + + [TestMethod] + public void StreamOffsetsAreRelativeToPdfStartTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + using var ms = new MemoryStream(); + // Pre-fill the stream so the PDF does not start at offset 0. + byte[] preamble = Encoding.ASCII.GetBytes("LEADING BYTES THAT ARE NOT PART OF THE PDF"); + ms.Write(preamble, 0, preamble.Length); + int pdfStart = (int)ms.Position; + wb.SaveAsPdf(ms); + byte[] all = ms.ToArray(); + // The PDF itself still starts with the header at the captured position. + string header = Encoding.ASCII.GetString(all, pdfStart, 5); + Assert.AreEqual("%PDF-", header, "PDF was not written at the stream's current position."); + // startxref must point at the xref table relative to the PDF start. + long startXref = ParseStartXref(all, pdfStart); + string atOffset = Encoding.ASCII.GetString(all, pdfStart + (int)startXref, 4); + Assert.AreEqual("xref", atOffset, "startxref offset is not relative to the PDF start."); + } + + [TestMethod] + public void FileAndStreamProduceSamePdfLengthTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + string tempFile = Path.GetTempFileName(); + try + { + wb.SaveAsPdf(tempFile); + long fileLength = new FileInfo(tempFile).Length; + using var ms = new MemoryStream(); + wb.SaveAsPdf(ms); + Assert.AreEqual(fileLength, ms.Length, "Stream output length differs from file output length."); + } + finally + { + if (File.Exists(tempFile)) File.Delete(tempFile); + } + } + + [TestMethod] + public void SaveWorksheetToStreamViaCatalogTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + var pageSettings = new PdfPageSettings(ws.Workbook.RenderContext.FontEngine); + using var ms = new MemoryStream(); + _ = new PdfCatalog(ms, pageSettings, ws); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public void SaveAsPdfToNonWritableStreamThrowsTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var wb = p.Workbook; + using var readOnly = new MemoryStream(new byte[16], writable: false); + Assert.ThrowsExactly(() => wb.SaveAsPdf(readOnly)); + } + + [TestMethod] + public void SaveWorksheetAsPdfToStreamTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + using var ms = new MemoryStream(); + ws.SaveAsPdf(ms); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public async Task SaveWorksheetAsPdfToStreamAsyncTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + using var ms = new MemoryStream(); + await ws.SaveAsPdfAsync(ms); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public void SaveWorksheetAsPdfToStreamLeavesStreamOpenTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + using var ms = new MemoryStream(); + ws.SaveAsPdf(ms); + Assert.IsTrue(ms.CanWrite, "Stream was closed by the export."); + Assert.IsTrue(ms.CanRead, "Stream was closed by the export."); + Assert.IsTrue(ms.Length > 0, "Nothing was written to the stream."); + } + + [TestMethod] + public async Task SaveWorksheetAsPdfAsyncToStreamWithCanceledTokenThrowsTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + using var ms = new MemoryStream(); + using var cts = new CancellationTokenSource(); + cts.Cancel(); + await Assert.ThrowsExactlyAsync(() => ws.SaveAsPdfAsync(ms, cts.Token)); + } + + [TestMethod] + public void SaveWorksheetToStreamOffsetsAreRelativeToPdfStartTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + using var ms = new MemoryStream(); + byte[] preamble = Encoding.ASCII.GetBytes("LEADING BYTES THAT ARE NOT PART OF THE PDF"); + ms.Write(preamble, 0, preamble.Length); + int pdfStart = (int)ms.Position; + ws.SaveAsPdf(ms); + byte[] all = ms.ToArray(); + string header = Encoding.ASCII.GetString(all, pdfStart, 5); + Assert.AreEqual("%PDF-", header, "PDF was not written at the stream's current position."); + long startXref = ParseStartXref(all, pdfStart); + string atOffset = Encoding.ASCII.GetString(all, pdfStart + (int)startXref, 4); + Assert.AreEqual("xref", atOffset, "startxref offset is not relative to the PDF start."); + } + + [TestMethod] + public void SaveWorksheetToNonWritableStreamThrowsTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + using var readOnly = new MemoryStream(new byte[16], writable: false); + Assert.ThrowsExactly(() => ws.SaveAsPdf(readOnly)); + } + + [TestMethod] + public void SaveRangeAsPdfToStreamTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var range = p.Workbook.Worksheets[0].Cells["D3:F6"]; + using var ms = new MemoryStream(); + range.SaveAsPdf(ms); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public async Task SaveRangeAsPdfToStreamAsyncTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var range = p.Workbook.Worksheets[0].Cells["D3:F6"]; + using var ms = new MemoryStream(); + await range.SaveAsPdfAsync(ms); + AssertLooksLikePdf(ms.ToArray()); + } + + [TestMethod] + public void SaveRangeAsPdfToStreamLeavesStreamOpenTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var range = p.Workbook.Worksheets[0].Cells["D3:F6"]; + using var ms = new MemoryStream(); + range.SaveAsPdf(ms); + Assert.IsTrue(ms.CanWrite, "Stream was closed by the export."); + Assert.IsTrue(ms.CanRead, "Stream was closed by the export."); + Assert.IsTrue(ms.Length > 0, "Nothing was written to the stream."); + } + + [TestMethod] + public async Task SaveRangeAsPdfAsyncToStreamWithCanceledTokenThrowsTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var range = p.Workbook.Worksheets[0].Cells["D3:F6"]; + using var ms = new MemoryStream(); + using var cts = new CancellationTokenSource(); + cts.Cancel(); + await Assert.ThrowsExactlyAsync(() => range.SaveAsPdfAsync(ms, cts.Token)); + } + + [TestMethod] + public void SaveRangeToNonWritableStreamThrowsTest() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var range = p.Workbook.Worksheets[0].Cells["D3:F6"]; + using var readOnly = new MemoryStream(new byte[16], writable: false); + Assert.ThrowsExactly(() => range.SaveAsPdf(readOnly)); + } + + [TestMethod] // works as expected. //[DataRow("PDFTest.xlsx", "C:\\epplustest\\pdf\\FullPageTest56.pdf", "Sheet1")] [DataRow("Aico_0105_S_ALR_87011990_AICO_ASSET_ITE_2025-04_BS.xlsx", "C:\\epplustest\\pdf\\OutputTest1.1.pdf", "SAP Data")] @@ -189,7 +539,7 @@ public void WorkbookTests(string sourceFile, string outputPath, string wsName) var d = ws.Dimension; var d2 = ws.DimensionByValue; - PdfPageSettings pageSettings = new PdfPageSettings(); + PdfPageSettings pageSettings = new PdfPageSettings(ws.Workbook.RenderContext.FontEngine); pageSettings.CommentsAndNotes = CommentsAndNotes.AtEndOfSheet; pageSettings.CellErrors = CellErrors.Displayed; @@ -198,95 +548,94 @@ public void WorkbookTests(string sourceFile, string outputPath, string wsName) pageSettings.ShowGridLines = false; pageSettings.ShowHeadings = false; - PdfCatalog catalog = new PdfCatalog(pageSettings, ws, outputPath); - } - - /// - /// This test we can make somehing of. - /// - //[TestMethod] - //public void CalculatePages() - //{ - // using var p = new ExcelPackage(); - // var ws = p.Workbook.Worksheets.Add("Sheet 1"); - // PdfPageSettings pageSettings = new PdfPageSettings(); - // pageSettings.ShowHeadings = true; - // PdfWorksheet pws = new PdfWorksheet(); - // pws.Worksheet = ws; - // pws.ZeroCharWidth = PdfWorksheet.GetThemeFont0Width(ws); - // pws.ToRow = 256; - // PdfRange range = new PdfRange(); - // range.TotalWidth = 800; - // range.TotalHeight = 1600; - - // var result = PdfLayout.GetNumberOfPages(pageSettings, pws, ref range); - //} - - /// - /// Old Test - /// - //[TestMethod] - //public void TestWrapText() - //{ - // using var p = OpenTemplatePackage("PDFTest.xlsx"); - // var cell = p.Workbook.Worksheets[0].Cells["P118"]; - - // List TextFragments = GetTextFragments(cell.RichText).Cast().ToList(); - - - // var layout = OpenTypeFonts.GetTextLayoutEngineForFont((IFontFormatBase)TextFragments[0].RichTextOptions); - - // var TextLines = layout.WrapRichTextLineCollection(TextFragments, 51d); - //} - - //private static List GetTextFragments(ExcelRichTextCollection RichTextCollection, PdfCellStyle cellStyle = null) - //{ - // var textFragments = new List(); - // bool bold = false, italic = false, underline = false, strike = false; - // ExcelUnderLineType underLineType = ExcelUnderLineType.None; - // if (cellStyle != null && cellStyle.dxfFont != null) - // { - // bold = cellStyle.dxfFont.Bold != null ? (bool)cellStyle.dxfFont.Bold : false; - // italic = cellStyle.dxfFont.Italic != null ? (bool)cellStyle.dxfFont.Italic : false; - // strike = cellStyle.dxfFont.Strike != null ? (bool)cellStyle.dxfFont.Strike : false; - // underline = cellStyle.dxfFont.Underline != null; - // underLineType = cellStyle.dxfFont.Underline != null ? (ExcelUnderLineType)cellStyle.dxfFont.Underline : ExcelUnderLineType.None; - // } - // for (int i = 0; i < RichTextCollection.Count; i++) - // { - // var rt = RichTextCollection[i]; - // var textFrag = new TextFragment(); - // textFrag.Text = rt.Text; - - // textFrag.Font.Family = rt.FontName; - // textFrag.Font.Size = rt.Size; - - // textFrag.RichTextOptions.Bold = rt.Bold || bold; - // textFrag.RichTextOptions.Italic = rt.Italic || italic; - // //underline - // //none : 12 - // //single : 13 - // //Double : 4 - // //accouting does not exsist - // textFrag.RichTextOptions.UnderlineType = 12; - // textFrag.RichTextOptions.UnderlineType = rt.UnderLineType == ExcelUnderLineType.Single ? 13 : textFrag.RichTextOptions.UnderlineType; - // textFrag.RichTextOptions.UnderlineType = rt.UnderLineType == ExcelUnderLineType.Double ? 4 : textFrag.RichTextOptions.UnderlineType; - // textFrag.RichTextOptions.StrikeType = rt.Strike || strike ? 2 : 1; - // textFrag.RichTextOptions.SuperScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Superscript; - // textFrag.RichTextOptions.SubScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Subscript; - // textFrag.RichTextOptions.FontColor = rt.Color; - - // //Should no longer be neccesary - // //textFrag.Font.Style = (textFrag.RichTextOptions.Bold ? MeasurementFontStyles.Bold : 0) | - // // (textFrag.RichTextOptions.Italic ? MeasurementFontStyles.Italic : 0) | - // // (textFrag.RichTextOptions.UnderlineType != 12 ? MeasurementFontStyles.Underline : 0) | - // // (textFrag.RichTextOptions.StrikeType > 1 ? MeasurementFontStyles.Strikeout : 0); - - - // textFragments.Add(textFrag); - // } - - // return textFragments; - //} + PdfCatalog catalog = new PdfCatalog(outputPath, pageSettings, ws); + + } + + [TestMethod] + public void EPPlusToPdf() + { + string[][] pixels = + { + new[] { "#805840", "#805840", "#805840", "#C0A070", "#C0A070", "#C0A070", "#402820", "#402820", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#805840", "#402820", "#000000", "#000000", "#805840", "#402820", "#402820", "#000000", "#402820", "#402820" }, + new[] { "#805840", "#805840", "#C0A070", "#C0A070", "#402820", "#805840", "#805840", "#402820", "#402820", "#C0A070", "#C0A070", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#805840", "#402820", "#000000", "#805840", "#402820", "#000000", "#402820", "#402820", "#402820" }, + new[] { "#805840", "#805840", "#C0A070", "#C0A070", "#C0A070", "#402820", "#A87850", "#A87850", "#402820", "#402820", "#C0A070", "#C0A070", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#805840", "#402820", "#402820", "#402820", "#000000", "#402820", "#402820", "#402820", "#402820" }, + new[] { "#E0C8A0", "#E0C8A0", "#A87850", "#C0A070", "#C0A070", "#402820", "#402820", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#805840", "#805840", "#805840", "#000000", "#402820", "#402820", "#402820", "#000000" }, + new[] { "#E0C8A0", "#E0C8A0", "#E0C8A0", "#A87850", "#C0A070", "#805840", "#402820", "#402820", "#C0A070", "#A87850", "#805840", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#402820", "#402820", "#805840", "#805840", "#000000", "#406850", "#000000", "#000000", "#384038" }, + new[] { "#402820", "#402820", "#E0C8A0", "#E0C8A0", "#A87850", "#805840", "#402820", "#402820", "#A87850", "#C0A070", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#402820", "#402820", "#402820", "#406850", "#406850", "#406850", "#406850", "#000000", "#384038", "#384038" }, + new[] { "#70A070", "#70A070", "#000000", "#000000", "#E0C8A0", "#805840", "#805840", "#402820", "#A87850", "#C0A070", "#C0A070", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#402820", "#384038", "#384038", "#384038", "#406850", "#406850", "#406850", "#406850", "#000000", "#384038", "#384038" }, + new[] { "#70A070", "#70A070", "#70A070", "#70A070", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#384038", "#384038", "#384038", "#384038", "#384038", "#384038", "#384038", "#406850", "#406850", "#406850", "#000000", "#384038", "#384038", "#384038" }, + new[] { "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#384038", "#384038", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#384038", "#384038", "#384038", "#384038", "#384038", "#384038", "#384038", "#406850", "#406850", "#406850", "#000000", "#384038", "#384038", "#384038" }, + new[] { "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#384038", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#384038", "#384038", "#384038", "#384038", "#384038", "#384038", "#384038", "#406850", "#406850", "#384038", "#000000", "#384038", "#384038", "#384038" }, + new[] { "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#384038", "#384038", "#384038", "#384038", "#384038", "#000000", "#000000", "#384038", "#384038", "#384038", "#000000", "#406850", "#384038", "#384038" }, + new[] { "#384038", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#384038", "#384038", "#384038", "#384038", "#384038", "#000000", "#000000", "#406850", "#406850", "#406850", "#406850", "#406850", "#384038", "#384038" }, + new[] { "#70A070", "#384038", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#384038", "#384038", "#384038", "#384038", "#000000", "#000000", "#406850", "#406850", "#406850", "#406850", "#406850", "#384038", "#384038" }, + new[] { "#70A070", "#70A070", "#384038", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#384038", "#384038", "#384038", "#384038", "#000000", "#384038", "#406850", "#406850", "#406850", "#406850", "#384038", "#384038", "#384038" }, + new[] { "#406850", "#406850", "#406850", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#384038", "#384038", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#384038", "#384038", "#384038", "#000000", "#384038", "#406850", "#406850", "#406850", "#406850", "#384038", "#384038", "#384038", "#384038" }, + new[] { "#000000", "#406850", "#406850", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#384038", "#384038", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#384038", "#384038", "#000000", "#000000", "#384038", "#406850", "#406850", "#406850", "#406850", "#406850", "#384038", "#384038", "#000000", "#000000" }, + new[] { "#000000", "#406850", "#406850", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#70A070", "#384038", "#384038", "#384038", "#384038", "#406850", "#406850", "#000000", "#000000", "#384038", "#000000", "#000000", "#000000", "#384038", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#406850", "#406850", "#406850", "#70A070", "#70A070", "#70A070", "#70A070", "#406850", "#000000", "#406850", "#406850", "#406850", "#000000", "#384038", "#000000", "#406850", "#406850", "#406850", "#406850", "#384038", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#70A070", "#70A070", "#406850", "#000000", "#406850", "#406850", "#406850", "#000000", "#384038", "#000000", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000" }, + new[] { "#000000", "#000000", "#402820", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#805840", "#805840" }, + new[] { "#000000", "#000000", "#402820", "#402820", "#000000", "#B8A898", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#805840", "#805840", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#805840", "#C0A070", "#805840" }, + new[] { "#000000", "#000000", "#000000", "#805840", "#805840", "#000000", "#B8A898", "#B8A898", "#000000", "#000000", "#000000", "#000000", "#402820", "#E0C8A0", "#E0C8A0", "#402820", "#402820", "#000000", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#805840", "#C0A070", "#C0A070", "#805840" }, + new[] { "#000000", "#000000", "#000000", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#805840", "#000000", "#000000", "#000000", "#000000", "#000000", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#402820", "#402820", "#000000", "#000000", "#402820", "#402820", "#402820", "#402820", "#402820", "#805840", "#805840", "#805840", "#805840", "#C0A070", "#C0A070", "#805840", "#805840" }, + new[] { "#000000", "#000000", "#000000", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#805840", "#805840", "#805840", "#C0A070", "#C0A070", "#402820", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#805840", "#805840", "#A87850", "#000000", "#000000", "#402820", "#402820", "#402820", "#402820", "#805840", "#805840", "#805840", "#C0A070", "#C0A070", "#C0A070", "#805840", "#000000" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#E0C8A0", "#C0A070", "#805840", "#E0C8A0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#805840", "#805840", "#A87850", "#805840", "#000000", "#000000", "#402820", "#805840", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#805840", "#000000", "#805840" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#E0C8A0", "#C0A070", "#805840", "#E0C8A0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#805840", "#A87850", "#A87850", "#A87850", "#805840", "#000000", "#402820", "#805840", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#805840", "#000000", "#805840" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#C0A070", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#E0C8A0", "#805840", "#FFF0E0", "#E0C8A0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#805840", "#A87850", "#A87850", "#A87850", "#805840", "#805840", "#000000", "#000000", "#402820", "#402820", "#C0A070", "#C0A070", "#402820", "#000000", "#000000", "#000000", "#805840" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#C0A070", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#805840", "#A87850", "#A87850", "#A87850", "#A87850", "#805840", "#805840", "#402820", "#402820", "#402820", "#C0A070", "#402820", "#000000", "#000000", "#805840", "#805840", "#805840" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#000000", "#C0A070", "#C0A070", "#FFF0E0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#402820", "#A87850", "#A87850", "#A87850", "#C0A070", "#805840", "#805840", "#402820", "#402820", "#402820", "#402820", "#000000", "#000000", "#805840", "#805840", "#E0C8A0", "#A87850" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#E0C8A0", "#E0C8A0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#402820", "#A87850", "#A87850", "#C0A070", "#C0A070", "#805840", "#805840", "#402820", "#402820", "#000000", "#000000", "#000000", "#805840", "#805840", "#E0C8A0", "#E0C8A0", "#A87850" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#FFF0E0", "#E0C8A0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#A87850", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#402820", "#A87850", "#A87850", "#402820", "#402820", "#A87850", "#A87850", "#805840", "#805840", "#000000", "#000000", "#000000", "#805840", "#E0C8A0", "#E0C8A0", "#E0C8A0", "#A87850" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#FFF0E0", "#E0C8A0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#A87850", "#A87850", "#402820", "#402820", "#000000", "#000000", "#000000", "#A87850", "#A87850", "#A87850", "#A87850", "#A87850", "#000000", "#402820", "#402820", "#E0C8A0", "#C0A070", "#C0A070", "#E0C8A0", "#E0C8A0" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#FFF0E0", "#E0C8A0", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#A87850", "#402820", "#000000", "#000000", "#000000", "#A87850", "#A87850", "#A87850", "#402820", "#402820", "#402820", "#000000", "#805840", "#805840", "#C0A070", "#C0A070", "#C0A070", "#E0C8A0", "#E0C8A0" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#A87850", "#FFF0E0", "#E0C8A0", "#FFF0E0", "#A87850", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#000000", "#000000", "#A87850", "#A87850", "#A87850", "#805840", "#000000", "#000000", "#402820", "#000000", "#805840", "#A87850", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#402820" }, + new[] { "#000000", "#000000", "#000000", "#000000", "#70A070", "#70A070", "#402820", "#FFF0E0", "#E0C8A0", "#FFF0E0", "#000000", "#805840", "#805840", "#402820", "#000000", "#000000", "#805840", "#805840", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#000000", "#000000", "#A87850", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#402820" }, + new[] { "#000000", "#000000", "#000000", "#70A070", "#70A070", "#70A070", "#406850", "#000000", "#E0C8A0", "#FFF0E0", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#C0A070", "#C0A070", "#C0A070", "#C0A070", "#402820", "#A87850" }, + new[] { "#000000", "#000000", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#E0C8A0", "#FFF0E0", "#000000", "#000000", "#000000", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#805840", "#805840", "#805840", "#805840", "#000000", "#000000", "#000000", "#000000", "#C0A070", "#E0C8A0", "#C0A070", "#402820", "#A87850", "#A87850" }, + new[] { "#000000", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#402820", "#A87850", "#805840", "#000000", "#FFF0E0", "#FFF0E0", "#A87850", "#A87850", "#A87850", "#A87850", "#805840", "#805840", "#805840", "#805840", "#402820", "#402820", "#000000", "#000000", "#E0C8A0", "#E0C8A0", "#C0A070", "#402820", "#A87850", "#A87850" }, + new[] { "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#A87850", "#805840", "#E0C8A0", "#E0C8A0", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#805840", "#805840", "#805840", "#000000", "#000000", "#E0C8A0", "#E0C8A0", "#402820", "#A87850", "#A87850", "#384038" }, + new[] { "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#805840", "#A87850", "#402820", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#805840", "#402820", "#000000", "#000000", "#E0C8A0", "#000000", "#000000", "#A87850", "#384038", "#384038" }, + new[] { "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#402820", "#E0C8A0", "#402820", "#402820", "#E0C8A0", "#E0C8A0", "#E0C8A0", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#C0A070", "#000000", "#000000", "#000000", "#A87850", "#000000", "#406850" }, + new[] { "#384038", "#384038", "#384038", "#384038", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#402820", "#A87850", "#E0C8A0", "#E0C8A0", "#E0C8A0", "#E0C8A0", "#E0C8A0", "#A87850", "#000000", "#000000", "#000000", "#000000", "#000000", "#805840", "#000000", "#C0A070", "#000000", "#000000", "#000000", "#000000", "#406850", "#406850" }, + new[] { "#70A070", "#406850", "#406850", "#384038", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#402820", "#A87850", "#A87850", "#E0C8A0", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#A87850", "#000000", "#000000", "#000000", "#000000", "#000000", "#805840", "#805840", "#000000", "#000000", "#000000", "#000000", "#406850", "#406850", "#406850" }, + new[] { "#70A070", "#70A070", "#406850", "#000000", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#A87850", "#A87850", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#000000", "#000000", "#000000", "#000000", "#805840", "#805840", "#000000", "#000000", "#000000", "#000000", "#406850", "#406850", "#406850", "#406850" }, + new[] { "#70A070", "#70A070", "#70A070", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#A87850", "#000000", "#A87850", "#FFF0E0", "#FFF0E0", "#FFF0E0", "#E0C8A0", "#000000", "#000000", "#000000", "#000000", "#805840", "#000000", "#000000", "#402820", "#000000", "#406850", "#406850", "#406850", "#406850", "#406850" }, + new[] { "#000000", "#000000", "#70A070", "#384038", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#A87850", "#000000", "#402820", "#402820", "#402820", "#402820", "#402820", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#000000", "#406850", "#406850", "#406850", "#000000", "#000000" }, + new[] { "#384038", "#384038", "#70A070", "#70A070", "#384038", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#000000", "#A87850", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#000000", "#406850", "#384038", "#000000", "#000000", "#000000", "#000000" }, + new[] { "#384038", "#384038", "#000000", "#70A070", "#406850", "#406850", "#406850", "#406850", "#000000", "#000000", "#000000", "#000000", "#A87850", "#A87850", "#A87850", "#A87850", "#A87850", "#000000", "#000000", "#000000", "#000000", "#000000", "#000000", "#402820", "#402820", "#000000", "#406850", "#384038", "#000000", "#000000", "#000000", "#000000" }, + }; + var p = new ExcelPackage(); + var ws = p.Workbook.Worksheets.Add("Snake"); + const double rowHeightPts = 15; + double columnWidth = rowHeightPts * (96.0 / 72.0) / 7.0; + ws.Column(1).Width = columnWidth; + ws.Cells["A1"].Value = "SOLID"; + ws.Cells["AE50"].Value = "SNAKE"; + //ws.Cells["AF51"].Value = " "; + const int startRow = 2; + const int startCol = 1; // D + for (int y = 0; y < pixels.Length; y++) + { + for (int x = 0; x < pixels[y].Length; x++) + { + var cell = ws.Cells[startRow + y, startCol + x]; + var color = System.Drawing.ColorTranslator.FromHtml(pixels[y][x]); + cell.Style.Fill.PatternType = ExcelFillStyle.Solid; + cell.Style.Fill.BackgroundColor.SetColor(color); + ws.Column(startCol + x).Width = columnWidth; + } + ws.Row(startRow + y).Height = 15; + } + ws.PrinterSettings.TopMargin = 0.1d; + ws.PrinterSettings.BottomMargin = 0.1d; + ws.PrinterSettings.LeftMargin = 0.1d; + ws.PrinterSettings.RightMargin = 0.1d; + ws.PrinterSettings.HorizontalCentered = true; + ws.PrinterSettings.VerticalCentered = true; + p.Workbook.SaveAsPdf(pdfPath + "Snake.Pdf"); + p.SaveAs(pdfPath + "Snake.xlsx"); + } } } diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontStream.cs b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontStream.cs index c3112d256e..b4a82f4c9b 100644 --- a/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontStream.cs +++ b/src/EPPlus.Export.Pdf/DocumentObjects/Fonts/PdfFontStream.cs @@ -38,14 +38,6 @@ internal override void RenderDictionary(BinaryWriter bw) WriteAscii(bw, $"<< /Length {fontBytes.Length} >>\nstream\n"); bw.Write(fontBytes); WriteAscii(bw, "\nendstream"); - - using (var fs = new FileStream("c:\\epplustest\\pdf\\ExportedFont.ttf", FileMode.Create, FileAccess.Write)) - { - using (var bw2 = new BinaryWriter(fs, Encoding.ASCII)) - { - bw2.Write(fontBytes); - } - } } } } diff --git a/src/EPPlus.Export.Pdf/ExcelPdf.cs b/src/EPPlus.Export.Pdf/ExcelPdf.cs index d9d1834d56..2c03a03def 100644 --- a/src/EPPlus.Export.Pdf/ExcelPdf.cs +++ b/src/EPPlus.Export.Pdf/ExcelPdf.cs @@ -16,6 +16,7 @@ Date Author Change using EPPlus.Export.Pdf.Resources; using EPPlus.Export.Pdf.Settings; using EPPlus.Graphics; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -228,6 +229,33 @@ private PdfInfoObject AddInfoObject(string workBookName = "") internal void CreatePdf(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Transform layout, string fileName) { + //Write the PDF to the file. The Stream overload does the actual work and + //populates _debugString. + using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) + { + CreatePdf(pageSettings, dictionaries, layout, fs); + } + //Write pdf as txt for debug. + if (_pageSettings.Debug && _pageSettings.PrintAsText) + { + using (var fs = new FileStream(fileName + ".txt", FileMode.Create, FileAccess.Write)) + { + using (var wr = new StreamWriter(fs)) + { + wr.Write(_debugString); + } + } + } + } + + internal void CreatePdf(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Transform layout, Stream stream) + { + if (stream == null) throw new ArgumentNullException(nameof(stream)); + if (!stream.CanWrite) throw new ArgumentException("The stream must be writable.", nameof(stream)); + //The cross-reference table stores byte offsets that the PDF reader uses to + //seek to each object, so the target stream has to support querying its position. + if (!stream.CanSeek) throw new ArgumentException("The stream must be seekable, because the PDF cross-reference table requires byte offsets.", nameof(stream)); + _pageSettings = pageSettings; _dictionaries = dictionaries; var catalog = AddCatalog(2); @@ -249,42 +277,33 @@ internal void CreatePdf(PdfPageSettings pageSettings, PdfDictionaries dictionari pages.pageObjectNumbers.Add(page.objectNumber); } var info = AddInfoObject(); - string debugString = ""; + _debugString = ""; //write to pdf PdfCrossRefTable crossRefTable = new PdfCrossRefTable(); - //start wring pdf binary - using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) + //Cross-reference offsets are relative to the start of the PDF. A freshly created + //FileStream starts at position 0, but a caller-supplied stream may already hold + //data, so capture the starting position and make every offset relative to it. + long start = stream.Position; + //start writing pdf binary. leaveOpen: true so a caller-supplied stream is not closed. + using (var bw = new BinaryWriter(stream, Encoding.ASCII, true)) { - using (var bw = new BinaryWriter(fs, Encoding.ASCII)) + //Write header + bw.Write(Encoding.ASCII.GetBytes(Header)); + _debugString += Header; + //Write body + foreach (var pdfobj in _document) { - //Write header - bw.Write(Encoding.ASCII.GetBytes(Header)); - debugString += Header; - //Write body - foreach (var pdfobj in _document) - { - crossRefTable.AddPosition(fs.Position); - pdfobj.ToPdfBytes(bw); - debugString += pdfobj.ToPdfString(); - } - //Write CrossReference - crossRefTable.Write(bw, fs.Position, _document.Count); - debugString += crossRefTable.WriteString(_document.Count); - // Write trailer - PdfTrailer.Write(bw, _document.Count, catalog.objectNumber, info.objectNumber, crossRefTable.StartPosition); - debugString += PdfTrailer.WriteString(_document.Count, catalog.objectNumber, info.objectNumber, crossRefTable.StartPosition); - } - } - //Write pdf as txt for debug. - if (_pageSettings.Debug && _pageSettings.PrintAsText) - { - using (var fs = new FileStream(fileName + ".txt", FileMode.Create, FileAccess.Write)) - { - using (var wr = new StreamWriter(fs)) - { - wr.Write(debugString); - } + crossRefTable.AddPosition(stream.Position - start); + pdfobj.ToPdfBytes(bw); + _debugString += pdfobj.ToPdfString(); } + //Write CrossReference + crossRefTable.Write(bw, stream.Position - start, _document.Count); + _debugString += crossRefTable.WriteString(_document.Count); + // Write trailer + PdfTrailer.Write(bw, _document.Count, catalog.objectNumber, info.objectNumber, crossRefTable.StartPosition); + _debugString += PdfTrailer.WriteString(_document.Count, catalog.objectNumber, info.objectNumber, crossRefTable.StartPosition); + bw.Flush(); } } } diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs index d5fdf6486a..5416f18870 100644 --- a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs @@ -31,26 +31,6 @@ public OpenTypeFontEngine FontEngine { get { - if(_fontEngine == null) - { - _fontEngine = new OpenTypeFontEngine(x => - { - if(FontDirectories != null && FontDirectories.Any()) - { - foreach(var dir in FontDirectories) - { - if (!System.IO.Directory.Exists(dir)) - { - throw new System.IO.DirectoryNotFoundException($"Font directory not found: {dir}"); - } - x.FontDirectories.Add(dir); - } - x.SearchSystemDirectories = SearchSystemDirectories; - - } - - }); - } return _fontEngine; } } @@ -95,6 +75,16 @@ public OpenTypeFontEngine FontEngine /// public bool ShowHeadings = false; + /// + /// Set to true for to only use black and white. + /// + public bool BlackAndWhite = false; + + /// + /// Set to true for to make a draft. + /// + public bool Draft = false; + /// /// Set the range to repeat at the top of the page. /// @@ -105,6 +95,11 @@ public OpenTypeFontEngine FontEngine /// public string ColumnsToRepeatAtLeft = null; + /// + /// Specific range to print. + /// + public string PrintArea = null; + /// /// Set if comments and notes should be included. /// @@ -132,19 +127,23 @@ public PdfPageSize PageSize } set { - _pageSize = new PdfPageSize(value.Height, value.Width); - if (value.Height > value.Width) + var size = new PdfPageSize(value.Width, value.Height); // store as authored, no transpose + if (_orientationExplicitlySet) { - _orientation = Orientations.Portrait; + size = ApplyOrientation(size, _orientation); } else { - _orientation = Orientations.Landscape; + _orientation = size.Height >= size.Width + ? Orientations.Portrait + : Orientations.Landscape; } - ContentBounds.CalculateBounds(Margins, PageSize); + _pageSize = size; + ContentBounds.CalculateBounds(Margins, _pageSize); } } + private bool _orientationExplicitlySet = false; private Orientations _orientation = Orientations.Portrait; /// /// Set the orientation of the pages. @@ -157,22 +156,10 @@ public Orientations Orientation } set { - if (value == Orientations.Portrait) - { - if (_pageSize.Height < _pageSize.Width) - { - _pageSize = new PdfPageSize(_pageSize.Height, _pageSize.Width); - _orientation = value; - } - } - if (value == Orientations.Landscape) - { - if (_pageSize.Height > _pageSize.Width) - { - _pageSize = new PdfPageSize(_pageSize.Height, _pageSize.Width); - _orientation = value; - } - } + _orientation = value; + _orientationExplicitlySet = true; + _pageSize = ApplyOrientation(_pageSize, value); + ContentBounds.CalculateBounds(Margins, _pageSize); } } @@ -215,6 +202,20 @@ public PdfScaling Scaling //DEBUG internal bool Debug = false; internal bool PrintAsText = false; + + public PdfPageSettings(OpenTypeFontEngine fontEngine) + { + _fontEngine = fontEngine; + } + + private static PdfPageSize ApplyOrientation(PdfPageSize size, Orientations orientation) + { + bool isPortrait = size.Height >= size.Width; + bool wantPortrait = orientation == Orientations.Portrait; + return isPortrait == wantPortrait + ? size + : new PdfPageSize(size.Height, size.Width); // swap (ctor is width, height) + } } /// @@ -257,13 +258,13 @@ public enum CommentsAndNotes /// None, /// - /// Comments and Notes will be displayed on a seprate page at the end. + /// Notes will be displayed on the sheet. (Comments will not be shown.) /// - AtEndOfSheet, + AsDisplayedOnSheet, /// - /// Notes will be displayed on the sheet. (Comments will not be shown.) + /// Comments and Notes will be displayed on a seprate page at the end. /// - AsDisplayedOnSheet + AtEndOfSheet, } /// diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfMargins.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfMargins.cs index 1fee87bf8e..e0de44473e 100644 --- a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfMargins.cs +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfMargins.cs @@ -39,7 +39,7 @@ public PdfMargins() FooterPu = UnitConversion.MmToPoints(Footer); } - public PdfMargins(double Top, double Left, double Right, double Bottom, double Header, double Footer) + public PdfMargins(double Top, double Bottom, double Left, double Right, double Header, double Footer) { this.Top = Top; this.Left = Left; diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfPageSize.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfPageSize.cs index 8dce84bc52..359075daa3 100644 --- a/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfPageSize.cs +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSizes/PdfPageSize.cs @@ -35,8 +35,65 @@ public PdfPageSize(double width, double height) public static PdfPageSize B5 => new PdfPageSize(182d, 257d); public static PdfPageSize B4 => new PdfPageSize(257d, 364d); public static PdfPageSize Letter => new PdfPageSize(215.9d, 279.4d); //(612, 792); + public static PdfPageSize LetterSmall => new PdfPageSize(215.9d, 279.4d); public static PdfPageSize Legal => new PdfPageSize(215.9d, 355.6d); //(612, 1008); public static PdfPageSize Statement => new PdfPageSize(139.7d, 215.9d); public static PdfPageSize Executive => new PdfPageSize(184.2d, 266.7d); + public static PdfPageSize Tabloid => new PdfPageSize(279.4d, 431.8d); + public static PdfPageSize Ledger => new PdfPageSize(431.84d, 279.4d); + public static PdfPageSize A4Small => new PdfPageSize(210d, 297d); + public static PdfPageSize Folio => new PdfPageSize(215.9d, 330.2d); // 8.5 x 13 in + public static PdfPageSize Quarto => new PdfPageSize(215d, 275d); + public static PdfPageSize Standard10_14 => new PdfPageSize(254d, 355.6d); // 10 x 14 in + public static PdfPageSize Standard11_17 => new PdfPageSize(279.4d, 431.8d); // 11 x 17 in + public static PdfPageSize Note => new PdfPageSize(215.9d, 279.4d); // 8.5 x 11 in + public static PdfPageSize Envelope9 => new PdfPageSize(98.425d, 225.425d); // 3.875 x 8.875 in + public static PdfPageSize Envelope10 => new PdfPageSize(104.775d, 241.3d); // 4.125 x 9.5 in + public static PdfPageSize Envelope11 => new PdfPageSize(114.3d, 263.525d); // 4.5 x 10.375 in + public static PdfPageSize Envelope12 => new PdfPageSize(120.65d, 279.4d); // 4.75 x 11 in + public static PdfPageSize Envelope14 => new PdfPageSize(127d, 292.1d); // 5 x 11.5 in + public static PdfPageSize C => new PdfPageSize(431.8d, 558.8d); // 17 x 22 in + public static PdfPageSize D => new PdfPageSize(558.8d, 863.6d); // 22 x 34 in + public static PdfPageSize E => new PdfPageSize(863.6d, 1117.6d); // 34 x 44 in + public static PdfPageSize DLEnvelope => new PdfPageSize(110d, 220d); + public static PdfPageSize C5Envelope => new PdfPageSize(162d, 229d); + public static PdfPageSize C3Envelope => new PdfPageSize(324d, 458d); + public static PdfPageSize C4Envelope => new PdfPageSize(229d, 324d); + public static PdfPageSize C6Envelope => new PdfPageSize(114d, 162d); + public static PdfPageSize C65Envelope => new PdfPageSize(114d, 229d); + public static PdfPageSize B4Envelope => new PdfPageSize(250d, 353d); + public static PdfPageSize B5Envelope => new PdfPageSize(176d, 250d); + public static PdfPageSize B6Envelope => new PdfPageSize(176d, 125d); + public static PdfPageSize ItalyEnvelope => new PdfPageSize(110d, 230d); + public static PdfPageSize MonarchEnvelope => new PdfPageSize(98.425d, 190.5d); // 3.875 x 7.5 in + public static PdfPageSize Six3_4Envelope => new PdfPageSize(92.075d, 165.1d); // 3.625 x 6.5 in + public static PdfPageSize USStandard => new PdfPageSize(377.825d, 279.4d); // 14.875 x 11 in + public static PdfPageSize GermanStandard => new PdfPageSize(215.9d, 304.8d); // 8.5 x 12 in + public static PdfPageSize GermanLegal => new PdfPageSize(215.9d, 330.2d); // 8.5 x 13 in + public static PdfPageSize ISOB4 => new PdfPageSize(250d, 353d); + public static PdfPageSize JapaneseDoublePostcard => new PdfPageSize(200d, 148d); + public static PdfPageSize Standard9 => new PdfPageSize(228.6d, 279.4d); // 9 x 11 in + public static PdfPageSize Standard10 => new PdfPageSize(254d, 279.4d); // 10 x 11 in + public static PdfPageSize Standard15 => new PdfPageSize(381d, 279.4d); // 15 x 11 in + public static PdfPageSize InviteEnvelope => new PdfPageSize(220d, 220d); + public static PdfPageSize LetterExtra => new PdfPageSize(235.585d, 304.8d); // 9.275 x 12 in + public static PdfPageSize LegalExtra => new PdfPageSize(235.585d, 381d); // 9.275 x 15 in + public static PdfPageSize TabloidExtra => new PdfPageSize(296.926d, 457.2d); // 11.69 x 18 in + public static PdfPageSize A4Extra => new PdfPageSize(236d, 322d); + public static PdfPageSize LetterTransverse => new PdfPageSize(210.185d, 279.4d); // 8.275 x 11 in + public static PdfPageSize A4Transverse => new PdfPageSize(210d, 297d); + public static PdfPageSize LetterExtraTransverse => new PdfPageSize(235.585d, 304.8d); // 9.275 x 12 in + public static PdfPageSize SuperA => new PdfPageSize(227d, 356d); + public static PdfPageSize SuperB => new PdfPageSize(305d, 487d); + public static PdfPageSize LetterPlus => new PdfPageSize(215.9d, 322.326d); // 8.5 x 12.69 in + public static PdfPageSize A4Plus => new PdfPageSize(210d, 330d); + public static PdfPageSize A5Transverse => new PdfPageSize(148d, 210d); + public static PdfPageSize JISB5Transverse => new PdfPageSize(182d, 257d); + public static PdfPageSize A3Extra => new PdfPageSize(322d, 445d); + public static PdfPageSize A5Extra => new PdfPageSize(174d, 235d); + public static PdfPageSize ISOB5 => new PdfPageSize(201d, 276d); + public static PdfPageSize A2 => new PdfPageSize(420d, 594d); + public static PdfPageSize A3Transverse => new PdfPageSize(297d, 420d); + public static PdfPageSize A3ExtraTransverse => new PdfPageSize(322d, 445d); } } \ No newline at end of file diff --git a/src/EPPlus.Fonts.OpenType/OpenTypeFontEngine.cs b/src/EPPlus.Fonts.OpenType/OpenTypeFontEngine.cs index 383263859a..4de8871caf 100644 --- a/src/EPPlus.Fonts.OpenType/OpenTypeFontEngine.cs +++ b/src/EPPlus.Fonts.OpenType/OpenTypeFontEngine.cs @@ -105,7 +105,7 @@ public OpenTypeFontEngine(Action configure) // ----------------------------------------------------------------------------------------- // Public API // ----------------------------------------------------------------------------------------- - + /// /// When true, GetTextShaper throws if the requested font cannot be resolved to an exact match, /// even though a fallback was found. Default is false: rendering trusts the fallback chain diff --git a/src/EPPlus.Graphics/Units/UnitConversion.cs b/src/EPPlus.Graphics/Units/UnitConversion.cs index f13e067581..76031a1e82 100644 --- a/src/EPPlus.Graphics/Units/UnitConversion.cs +++ b/src/EPPlus.Graphics/Units/UnitConversion.cs @@ -52,5 +52,10 @@ public static double ExcelRowHeightToPoints(double rowHeight) { return rowHeight; //These values are guessed. } + + public static double ToMillimeters(double inches) + { + return inches * 25.4; + } } } diff --git a/src/EPPlus/EPPlus.csproj b/src/EPPlus/EPPlus.csproj index 6fe3f55ef0..1930351ed6 100644 --- a/src/EPPlus/EPPlus.csproj +++ b/src/EPPlus/EPPlus.csproj @@ -6,7 +6,8 @@ 8.6.1 true - $(TargetsForTfmSpecificBuildOutput);IncludeReferencedProjectsInPackage + + $(TargetsForTfmSpecificBuildOutput);IncludeReferencedProjectsInPackage https://epplussoftware.com EPPlus Software AB license.md @@ -23,8 +24,10 @@ EPPlus 8.6.1 IMPORTANT NOTICE! - From version 5 EPPlus changes the license model using a dual license, Polyform Non Commercial / Commercial license. - EPPlus will still have the source available, but for non Polyform NC compliant projects, EPPlus will provide a commercial license. + From version 5 EPPlus changes the license model using a dual license, Polyform Non + Commercial / Commercial license. + EPPlus will still have the source available, but for non Polyform NC compliant projects, + EPPlus will provide a commercial license. Commercial licenses can be purchased from https://epplussoftware.com This applies to EPPlus version 5 and later. Earlier versions are still licensed LGPL. @@ -36,7 +39,8 @@ ## Version 8.6.0 * New functions: * GROUPBY, PIVOTBY, TRIMRANGE, WRAPROWS, WRAPCOLS, USDOLLAR, CODE, ENCODEURL, ISFORMULA - * Support for [Trim reference operator](https://github.com/EPPlusSoftware/EPPlus/wiki/Trim-reference-operator). + * Support for [Trim reference + operator](https://github.com/EPPlusSoftware/EPPlus/wiki/Trim-reference-operator). * Minor bug fixes. ## Version 8.5.4 @@ -54,7 +58,8 @@ ## Version 8.5.0 * Added ´CancellationToken´ option to the Calculate method. - * Added property ´ValueFromCellsRange´ and the ´SetValueFromCellsRange´ method to data labels on chart series. + * Added property ´ValueFromCellsRange´ and the ´SetValueFromCellsRange´ method to data + labels on chart series. * Minor bug fixes. ## Version 8.4.2 @@ -71,7 +76,8 @@ Minor bug fixes. ## Version 8.3.0 - * Support for adding, updating and removing external connections and query tables. See https://github.com/EPPlusSoftware/EPPlus/wiki/External-Connections-and-Query-Tables + * Support for adding, updating and removing external connections and query tables. See + https://github.com/EPPlusSoftware/EPPlus/wiki/External-Connections-and-Query-Tables * Support for adding pivot tables with external connections as data source. * Added three new functions * Minor bug fixes. @@ -80,7 +86,8 @@ * Minor bug fixes. ## Version 8.2.1 - * Support for 8 LAMBDA functions when calculating workbooks. See https://github.com/EPPlusSoftware/EPPlus/wiki/Using-LAMBDA-functions + * Support for 8 LAMBDA functions when calculating workbooks. See + https://github.com/EPPlusSoftware/EPPlus/wiki/Using-LAMBDA-functions * LAMBDA * MAKEARRAY * SCAN @@ -98,7 +105,8 @@ ## Version 8.1.0 * Add Shapes and Pictures to charts. * An new interface for styling headers and footers more easily. - * If copying a worksheet or a range to a new workbook, the relevant defined names are also copied. + * If copying a worksheet or a range to a new workbook, the relevant defined names are + also copied. * Minor bug fixes. ## Version 8.0.8 @@ -163,7 +171,8 @@ ## Version 7.5.2 * Pivot tables could crash - * Reading linked images was failed if a relation attribute existed but did not have a value. + * Reading linked images was failed if a relation attribute existed but did not have a + value. * Support for in-cell checkboxes. * Interfaces to integrate EPPlus with the MIP API to handle sensibility labels. * Minor features and bug fixes. @@ -181,7 +190,8 @@ * Minor features and bug fixes. ## Version 7.4.1 - * Updated for vulnerability in System.Text.Json - Microsoft.Extensions.Configuration.Json 8.0.0 -> 8.0.1 + * Updated for vulnerability in System.Text.Json - + Microsoft.Extensions.Configuration.Json 8.0.0 -> 8.0.1 ## Version 7.4.0 * Conditional formatting in Pivot Tables. @@ -208,10 +218,12 @@ ## Version 7.2.0 * Pivot table calculation - * Fetch calculated data via the GetPivotData method or the CalculatedData property on the ExcelPivotData. + * Fetch calculated data via the GetPivotData method or the CalculatedData property on + the ExcelPivotData. * Support for the GetPivotData function. * Import/Export of fixed width text files. - * Html export now supports all conditional formattings (Added support for Icon sets and Data bars in 7.2). + * Html export now supports all conditional formattings (Added support for Icon sets and + Data bars in 7.2). * Copy of drawings. * Transpose functionality added to many Copy, Import and Export function. * Bug fixes @@ -228,7 +240,8 @@ ## Version 7.1.0 * The html export now supports most conditional formattings. * Updated performance for rich text handling on ranges. - * Improvments in sort order and cell formatting of the ExcelRangeBase.LoadFromCollection method + * Improvments in sort order and cell formatting of the ExcelRangeBase.LoadFromCollection + method * Bug fixes ## Version 7.0.10 @@ -262,7 +275,8 @@ * Bug fixes ## Version 7.0.0 - * Calculation engine update to support array formulas. https://epplussoftware.com/en/Developers/EPPlus7 + * Calculation engine update to support array formulas. + https://epplussoftware.com/en/Developers/EPPlus7 * Support for calculating legacy / dynamic array formulas. * Support for intersect operator. * Support for implicit intersection. @@ -271,7 +285,9 @@ * Better handling of circular references * 90 new functions * Faster optimized calculation engine with configurable expression caching. - * Breaking changes: Updated calculation engine, See [Breaking Changes in EPPlus 7](https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-7) for more information. + * Breaking changes: Updated calculation engine, See [Breaking Changes in EPPlus + 7](https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-7) for more + information. * Conditional Formatting improvements * Improved performance, xml is now read and written on load and save. * Cross worksheet support formula support. @@ -299,7 +315,8 @@ * Bug fixes. ## Version 6.2.6 - * Updated System.Security.Cryptography.Pkcs for security vulnerability in .NET 6 and 7. See https://github.com/dotnet/runtime/issues/87498 + * Updated System.Security.Cryptography.Pkcs for security vulnerability in .NET 6 and 7. + See https://github.com/dotnet/runtime/issues/87498 * Bug fixes. ## Version 6.2.5 @@ -318,7 +335,8 @@ * Bug fixes. ## Version 6.2.0 - * Improved performance and better support for cross-worksheet references in data validations. + * Improved performance and better support for cross-worksheet references in data + validations. * Bug fixes. ## Version 6.1.3 @@ -333,10 +351,14 @@ * Bug fixes. https://epplussoftware.com/Developers/MinorFeaturesAndIssues ## Version 6.1.0 - * Support for the Agile and V3 VBA signing. - https://github.com/EPPlusSoftware/EPPlus/wiki/VBA - * ExcelRange.ToCollection method - to map ranges and tables to an collection of T - https://github.com/EPPlusSoftware/EPPlus/wiki/ToCollection - * New methods to group, ungroup, collapse and expand rows and columns - https://github.com/EPPlusSoftware/EPPlus/wiki/Grouping-and-Ungrouping-Rows-and-Columns - * New overloads of Drawings.AddPicture that reads the signature of the image from stream to identify the type of image. + * Support for the Agile and V3 VBA signing. - + https://github.com/EPPlusSoftware/EPPlus/wiki/VBA + * ExcelRange.ToCollection method - to map ranges and tables to an collection of T - + https://github.com/EPPlusSoftware/EPPlus/wiki/ToCollection + * New methods to group, ungroup, collapse and expand rows and columns - + https://github.com/EPPlusSoftware/EPPlus/wiki/Grouping-and-Ungrouping-Rows-and-Columns + * New overloads of Drawings.AddPicture that reads the signature of the image from stream + to identify the type of image. * AddPicture(string, Stream) * AddPicture(string, Stream, Uri) These overloads has been has been deprecated @@ -366,10 +388,12 @@ * Json Export - https://github.com/EPPlusSoftware/EPPlus/wiki/JSON-Export * 32 new functions. * Support for new image types: Svg, WebP and Ico. - * Removed direct references to System.Drawing.Common, see https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-6 + * Removed direct references to System.Drawing.Common, see + https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-6 * Bug fixes. - To see the new export in action, visit our new Web Sample Site: https://samples.epplussoftware.com + To see the new export in action, visit our new Web Sample Site: + https://samples.epplussoftware.com See https://epplussoftware.com/Developers/EPPlus6 for more details. @@ -407,14 +431,14 @@ ## Version 5.8.0 * ExcelWorksheetView.SplitPanes method added * ExcelRangeBase Fill method added - * FillNumber - * FillDateTime - * FillList + * FillNumber + * FillDateTime + * FillList * New collection properties for Rows and Columns - * ExcelWorksheet.Rows - * ExcelWorksheet.Columns - * ExcelRangeBase.EntireRow - * ExcelRangeBase.EntireColum + * ExcelWorksheet.Rows + * ExcelWorksheet.Columns + * ExcelRangeBase.EntireRow + * ExcelRangeBase.EntireColum * Support for formatting and deleting individual Chart Legend Entries. * Range.Copy improvments. * Bug fixes @@ -457,14 +481,14 @@ ## Version 5.6.0 * Custom table styles. - * Create and modify custom table styles that can be applied to tables and pivot tables. - * Create and modify custom slicer styles + * Create and modify custom table styles that can be applied to tables and pivot tables. + * Create and modify custom slicer styles * Pivot table styling using pivot areas to style individual areas within a pivot table. * Enhanced table styling * Added three new style properties to the ExcelTable and ExcelTableColumn - * HeaderRowStyle - * DataStyle - * TotalsRowStyle + * HeaderRowStyle + * DataStyle + * TotalsRowStyle * Bug fixes. ## Version 5.5.5 @@ -485,17 +509,19 @@ ## Version 5.5.0 * Form Controls - * Buttons - * Drop-Downs - * List Boxes - * Check Boxes - * Radio Buttons - * Spin Buttons - * Scroll Bars - * Labels - * Group Boxes - * Group/Ungroup drawing object via the ExcelDrawing.Group and ExcelDrawing.Ungroup methods - * New attribute support for LoadFromCollection. See https://github.com/EPPlusSoftware/EPPlus/wiki/LoadFromCollection-using-Attributes + * Buttons + * Drop-Downs + * List Boxes + * Check Boxes + * Radio Buttons + * Spin Buttons + * Scroll Bars + * Labels + * Group Boxes + * Group/Ungroup drawing object via the ExcelDrawing.Group and ExcelDrawing.Ungroup + methods + * New attribute support for LoadFromCollection. See + https://github.com/EPPlusSoftware/EPPlus/wiki/LoadFromCollection-using-Attributes * 20 new functions * Bug fixes @@ -505,18 +531,20 @@ ## Version 5.4.1 # Features - * WriteProtection added to Workbook.Protection. Allows to set a workbook to read-only with a password. + * WriteProtection added to Workbook.Protection. Allows to set a workbook to read-only + with a password. * ToDataTable method added to ExcelRange * Bug fixes ## Version 5.4.0 ### Features * Pivot tables filters - * Item filters - Filters on individual items in row/column or page fields. - * Caption filters (label filters) - Filters for text on row and column fields. - * Date, numeric and string filters - Filters using various operators such as Equals, NotBetween, GreaterThan, etc. - * Top 10 filters - Filters using top or bottom criterias for percent, count or value. - * Dynamic filters - Filters using various date- and average criterias. + * Item filters - Filters on individual items in row/column or page fields. + * Caption filters (label filters) - Filters for text on row and column fields. + * Date, numeric and string filters - Filters using various operators such as Equals, + NotBetween, GreaterThan, etc. + * Top 10 filters - Filters using top or bottom criterias for percent, count or value. + * Dynamic filters - Filters using various date- and average criterias. * Add calculated fields to pivot tables. * Support for pivot table shared caches via the new overload for PivotTables.Add. * Support for pivot table slicers @@ -533,19 +561,22 @@ * Bug fixes New features in version 5.3.0: - * Support for Threaded Comments with mentions. See https://github.com/EPPlusSoftware/EPPlus/wiki/Threaded-comments + * Support for Threaded Comments with mentions. See + https://github.com/EPPlusSoftware/EPPlus/wiki/Threaded-comments * New functions MAXIFS and MINIFS * Bug fixes New features in version 5.2.1: - * New method ExcelRange.LoadFromDictionary. Support for Dynamics in LoadFromCollection (ExpandoObject). + * New method ExcelRange.LoadFromDictionary. Support for Dynamics in LoadFromCollection + (ExpandoObject). * Zip64 support in packaging to enable larger packages. * Bug fixes. New features in version 5.2: * Support for extended chart types and stock charts: - * Four types of stock charts: High-Low-Close, Open-High-Low-Close, Volume-High-Low-Close and Volume-Open-High-Low-Close + * Four types of stock charts: High-Low-Close, Open-High-Low-Close, Volume-High-Low-Close + and Volume-Open-High-Low-Close * Sunburst Chart * Treemap Chart * Histogram Chart @@ -554,7 +585,8 @@ * Waterfall Chart * Box & Whisker Chart * Region Map Chart. - * Support for 49 new functions in the formula calc engine, mainly finance and engineering. + * Support for 49 new functions in the formula calc engine, mainly finance and + engineering. * Bug fixes New features in version 5.0 and 5.1: @@ -568,153 +600,172 @@ * Insert/Delete in ranges and tables. Breaking Changes - * LoadFromCollection changes the data type of parameter 'TableStyle' from 'TableStyles' to 'TableStyles?'. The default value, if omitted, changes from 'TableStyles.None' to null. 'TableStyles.None', if supplied will create a table with style None. - * The default behavior for the Worksheet collection base in .NET Framework has changed from 1 to 0. This is the same default behavior as in .NET core today. - * Pictures have changed the behavior as the oneCellAnchor tag is used instead of the twoCellAnchor tag with the editAs="oneCell". + * LoadFromCollection changes the data type of parameter 'TableStyle' from 'TableStyles' + to 'TableStyles?'. The default value, if omitted, changes from 'TableStyles.None' to + null. 'TableStyles.None', if supplied will create a table with style None. + * The default behavior for the Worksheet collection base in .NET Framework has changed + from 1 to 0. This is the same default behavior as in .NET core today. + * Pictures have changed the behavior as the oneCellAnchor tag is used instead of the + twoCellAnchor tag with the editAs="oneCell". * Pivot tables will always refresh on load. * Adding and inserting table row will now copy styles from the row above. - * ...and more, see https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-8 + * ...and more, see + https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-8 Worksheets collection behavior in .NET Framework - The default behavior for the Worksheet collection base in .NET Framework has changed from 1 to 0. This is the same behavior as in .NET Core. - For backward compatibility the property IsWorksheets1Based can be set to true, to have the same behavior as in previous version of EPPlus. This property can also be set in the app.config. - For more details see https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-8 - A list of fixed issues can be found here https://epplussoftware.com/docs/8.6/articles/fixedissues.html + The default behavior for the Worksheet collection base in .NET Framework has changed + from 1 to 0. This is the same behavior as in .NET Core. + For backward compatibility the property IsWorksheets1Based can be set to true, to have + the same behavior as in previous version of EPPlus. This property can also be set in the + app.config. + For more details see + https://github.com/EPPlusSoftware/EPPlus/wiki/Breaking-Changes-in-EPPlus-8 + A list of fixed issues can be found here + https://epplussoftware.com/docs/8.6/articles/fixedissues.html Version history - 8.6.1 20260616 3 new functions. Minor bug fixes. See https://epplussoftware.com/Developers/MinorFeaturesAndIssues - 8.6.0 20260529 9 new functions. Support for trim Reference operator. - 8.5.4 20260430 Minor bug fixes. - 8.5.3 20260416 Updated .NET 8 references incorrectly update to 9.x to 8.x. - 8.5.2 20260416 Minor bug fixes. - 8.5.1 20260330 Minor bug fixes. - 8.5.0 20260306 Minor features and bug fixes. - 8.4.2 20260204 Minor bug fixes. - 8.4.1 20260112 Minor bug fixes. - 8.4.0 20251212 Updated target frameworks. Minor bug fixes. - 8.3.1 20251128 Minor bug fixes. - 8.3.0 20251120 Connections and query tables support. Minor features and bug fixes. - 8.2.1 20251012 Minor bug fixes. - 8.2.0 20250924 LAMBDA functions support. Minor bug fixes. - 8.1.1 20250909 Minor bug fixes. - 8.1.0 20250815 Shapes in Charts. Header/footer styling interface. - 8.0.8 20250722 Minor bug fixes. - 8.0.7 20250702 Minor bug fixes. - 8.0.6 20250619 Minor bug fixes. - 8.0.5 20250515 Fix for external links issue in 8.0.4. - 8.0.4 20250514 Minor bug fixes. - 8.0.3 20250430 Minor bug fixes. - 8.0.2 20250415 Minor bug fixes. - 7.7.1 20250414 Minor bug fixes. - 8.0.1 20250328 Digital Signatures, Ole objects, in-cell pictures. - 8.0.0-rc 20250321 Digital Signatures, Ole objects, in-cell pictures. - 7.7.0 20250317 Fixed referenced packages versioning. Minor bug fixes. - 8.0.0-beta 20250214 Digital Signatures, Ole objects, in-cell pictures. - 7.6.1 20250304 Minor bug fixes. - 7.6.0 20250206 Updated target frameworks. Minor features and bug fixes. - 7.5.3 20250116 Minor features and bug fixes. - 7.5.2 20241209 Minor features and bug fixes. - 7.5.1 20241121 Minor features and bug fixes. - 7.5.0 20241115 Signed dll's and nuget package. Minor features and bug fixes. - 7.4.2 20241028 Minor features and bug fixes. - 7.4.1 20241011 Updated System.Text.Json - 7.4.0 20241002 Conditional Formatting's in Pivot tables. Linked image files in Pictures. - 7.3.2 20240917 Minor features and bug fixes. - 7.3.1 20240905 Minor features and bug fixes. - 7.3.0 20240820 Precision as displayed support in formula calculation. - 7.2.2 20240724 Minor features and bug fixes. - 7.2.1 20240702 Minor bug fixes. - 7.2.0 20240618 Pivot table calculation. Import/Export of fixed width text files. Improvment export of Conditional formatting. Copy of drawings. Transpose functionality. - 7.1.3 20240528 Minor bug fixes. - 7.1.2 20240423 Minor bug fixes. - 7.1.1 20240408 Minor bug fixes. - 7.1.0 20240328 Html export of Conditional formatting, Performance RichText, LoadFromCollection Enhancements. - 7.0.10 20240311 Minor bug fixes. - 7.0.9 20240215 Minor bug fixes. - 7.0.8 20240124 Minor bug fixes. - 7.0.7 20240119 Minor bug fixes. - 7.0.6 20240110 Minor bug fixes. - 7.0.5 20231222 Minor bug fixes. - 7.0.4 20231215 Minor bug fixes. - 7.0.3 20231205 Minor bug fixes. - 7.0.2 20231123 Minor bug fixes. - 7.0.1 20231109 Minor bug fixes. - 7.0.0 20231026 Calculation engine update for array formulas. https://epplussoftware.com/en/Developers/EPPlus7 - 6.2.13 20231123 Minor bug fixes.See https://epplussoftware.com/Developers/MinorFeaturesAndIssues - 6.2.12 20231026 Minor bug fixes. - 6.2.11 20231023 Minor bug fixes. - 7.0.0-rc 1 20231002 Calculation engine update for array formulas. - 6.2.10 20231002 Minor bug fixes.See - 7.0.0-beta 1 20230912 Calculation engine update for array formulas. - 6.2.9 20230908 Minor bug fixes. - 6.2.8 20230815 Minor bug fixes. - 6.2.7 20230719 Minor bug fixes. - 7.0.0-preview 2 20230719 Calculation engine update for array formulas. - 6.2.6 20230615 Minor bug fixes. - 6.2.5 20230614 Minor bug fixes. - 7.0.0-preview 1 20230519 Calculation engine update for array formulas. - 6.2.4 20230515 Minor bug fixes. - 6.2.3 20230502 Minor bug fixes. - 6.2.2 20230417 Minor bug fixes. - 6.2.1 20230406 Minor bug fixes. - 6.2.0 20230324 Performance update to data validation. Minor bug fixes. - 6.1.3 20230224 Minor bug fixes. - 6.1.2 20230119 Minor bug fixes. - 6.1.1 20221121 Minor bug fixes. See https://epplussoftware.com/Developers/MinorFeaturesAndIssues - 6.1.0 20221103 Newer types of VBA signatures, ToCollection method, Methods for Grouping rows and columns. - 6.0.8 20220921 Minor bug fixes. - 5.8.14 20220921 Minor bug fixes. - 6.0.7 20220830 Minor bug fixes. - 5.8.13 20220830 Minor bug fixes. - 6.0.6 20220708 Minor bug fixes. - 5.8.12 20220708 Minor bug fixes. - 6.0.5 20220610 Minor bug fixes. - 5.8.11 20220610 Minor bug fixes. - 6.0.4 20220512 Minor bug fixes. - 5.8.10 20220512 Minor bug fixes. - 6.0.3 20220412 Html and JSON export. New drawing handling. https://epplussoftware.com/Developers/EPPlus6 - 5.8.9 20220411 Minor bug fixes. - 5.8.8 20220322 Minor bug fixes. - 6.0.1 20220310 Beta 2 - 6.0.0 20220307 Beta 1 - 5.8.7 20220301 Minor bug fixes. - 5.8.6 20220203 Minor bug fixes. - 5.8.5 20220113 Minor features and bug fixes. - 5.8.4 20211214 Minor features and bug fixes. - 5.8.3 20211119 Minor bug fixes. - 5.8.2 20211029 Minor bug fixes. - 5.8.1 20211026 Minor bug fixes. - 5.8.0 20211021 Range.Fill methods, Range Rows and Column Collection, Range.Copy improvments and Worksheet Split Panes. - 5.7.5 20210921 Minor bug fixes. - 5.7.4 20210826 Minor bug fixes. - 5.7.3 20210810 Minor bug fixes. - 5.7.2 20210722 Minor bug fixes. - 5.7.1 20210706 Minor bug fixes. - 5.7.0 20210617 External links. Better sorting support. Pivot table ShowAs - 5.6.4 20210512 Minor bug fixes. - 5.6.3 20210416 Minor bug fixes. - 5.6.2 20210407 Minor bug fixes. - 5.6.1 20210322 Minor bug fixes. - 5.6.0 20210315 Custom table styles. Pivot table styling. Table styling enhancements. - 5.5.5 20210223 Minor bug fixes. - 5.5.4 20210216 Minor bug fixes. - 5.5.3 20210206 Minor bug fixes. - 5.5.2 20210118 Minor bug fixes. - 5.5.1 20210111 Minor features and bug fixes. - 5.5.0 20201218 Form Controls. - 5.4.2 20201119 Minor features and bug fixes. - 5.4.1 20201105 Minor features and bug fixes. - 5.4.0 20201008 Table- and Pivot Table- Slicers. Pivot Table Filters. - 5.3.2 20200914 Bug fixes. - 5.3.1 20200902 Minor features and bug fixes. - 5.3.0 20200819 Support for threaded comment with mentions. Minor feature and bug fixes. - 5.2.1 20200722 Minor features and bug fixes. - 5.2.0 20200623 Support for 12 new chart types. Minor features and bug fixes. - 5.1.2 20200513 Minor features and bug fixes. - 5.1.1 20200427 Minor bug fixes. - 5.1.0 20200401 Insert, Delete in Ranges and Tables. Minor bug fixes. - 5.0.4 20200310 Minor bug fixes. - 5.0.3 20200308 Initial release EPPlus 5 + 8.6.1 20260616 3 new functions. Minor bug fixes. See + https://epplussoftware.com/Developers/MinorFeaturesAndIssues + 8.6.0 20260529 9 new functions. Support for trim Reference operator. + 8.5.4 20260430 Minor bug fixes. + 8.5.3 20260416 Updated .NET 8 references incorrectly update to 9.x to 8.x. + 8.5.2 20260416 Minor bug fixes. + 8.5.1 20260330 Minor bug fixes. + 8.5.0 20260306 Minor features and bug fixes. + 8.4.2 20260204 Minor bug fixes. + 8.4.1 20260112 Minor bug fixes. + 8.4.0 20251212 Updated target frameworks. Minor bug fixes. + 8.3.1 20251128 Minor bug fixes. + 8.3.0 20251120 Connections and query tables support. Minor features and bug fixes. + 8.2.1 20251012 Minor bug fixes. + 8.2.0 20250924 LAMBDA functions support. Minor bug fixes. + 8.1.1 20250909 Minor bug fixes. + 8.1.0 20250815 Shapes in Charts. Header/footer styling interface. + 8.0.8 20250722 Minor bug fixes. + 8.0.7 20250702 Minor bug fixes. + 8.0.6 20250619 Minor bug fixes. + 8.0.5 20250515 Fix for external links issue in 8.0.4. + 8.0.4 20250514 Minor bug fixes. + 8.0.3 20250430 Minor bug fixes. + 8.0.2 20250415 Minor bug fixes. + 7.7.1 20250414 Minor bug fixes. + 8.0.1 20250328 Digital Signatures, Ole objects, in-cell pictures. + 8.0.0-rc 20250321 Digital Signatures, Ole objects, in-cell pictures. + 7.7.0 20250317 Fixed referenced packages versioning. Minor bug fixes. + 8.0.0-beta 20250214 Digital Signatures, Ole objects, in-cell pictures. + 7.6.1 20250304 Minor bug fixes. + 7.6.0 20250206 Updated target frameworks. Minor features and bug fixes. + 7.5.3 20250116 Minor features and bug fixes. + 7.5.2 20241209 Minor features and bug fixes. + 7.5.1 20241121 Minor features and bug fixes. + 7.5.0 20241115 Signed dll's and nuget package. Minor features and bug fixes. + 7.4.2 20241028 Minor features and bug fixes. + 7.4.1 20241011 Updated System.Text.Json + 7.4.0 20241002 Conditional Formatting's in Pivot tables. Linked image files in Pictures. + 7.3.2 20240917 Minor features and bug fixes. + 7.3.1 20240905 Minor features and bug fixes. + 7.3.0 20240820 Precision as displayed support in formula calculation. + 7.2.2 20240724 Minor features and bug fixes. + 7.2.1 20240702 Minor bug fixes. + 7.2.0 20240618 Pivot table calculation. Import/Export of fixed width text files. + Improvment export of Conditional formatting. Copy of drawings. Transpose functionality. + 7.1.3 20240528 Minor bug fixes. + 7.1.2 20240423 Minor bug fixes. + 7.1.1 20240408 Minor bug fixes. + 7.1.0 20240328 Html export of Conditional formatting, Performance RichText, + LoadFromCollection Enhancements. + 7.0.10 20240311 Minor bug fixes. + 7.0.9 20240215 Minor bug fixes. + 7.0.8 20240124 Minor bug fixes. + 7.0.7 20240119 Minor bug fixes. + 7.0.6 20240110 Minor bug fixes. + 7.0.5 20231222 Minor bug fixes. + 7.0.4 20231215 Minor bug fixes. + 7.0.3 20231205 Minor bug fixes. + 7.0.2 20231123 Minor bug fixes. + 7.0.1 20231109 Minor bug fixes. + 7.0.0 20231026 Calculation engine update for array formulas. + https://epplussoftware.com/en/Developers/EPPlus7 + 6.2.13 20231123 Minor bug fixes.See + https://epplussoftware.com/Developers/MinorFeaturesAndIssues + 6.2.12 20231026 Minor bug fixes. + 6.2.11 20231023 Minor bug fixes. + 7.0.0-rc 1 20231002 Calculation engine update for array formulas. + 6.2.10 20231002 Minor bug fixes.See + 7.0.0-beta 1 20230912 Calculation engine update for array formulas. + 6.2.9 20230908 Minor bug fixes. + 6.2.8 20230815 Minor bug fixes. + 6.2.7 20230719 Minor bug fixes. + 7.0.0-preview 2 20230719 Calculation engine update for array formulas. + 6.2.6 20230615 Minor bug fixes. + 6.2.5 20230614 Minor bug fixes. + 7.0.0-preview 1 20230519 Calculation engine update for array formulas. + 6.2.4 20230515 Minor bug fixes. + 6.2.3 20230502 Minor bug fixes. + 6.2.2 20230417 Minor bug fixes. + 6.2.1 20230406 Minor bug fixes. + 6.2.0 20230324 Performance update to data validation. Minor bug fixes. + 6.1.3 20230224 Minor bug fixes. + 6.1.2 20230119 Minor bug fixes. + 6.1.1 20221121 Minor bug fixes. See + https://epplussoftware.com/Developers/MinorFeaturesAndIssues + 6.1.0 20221103 Newer types of VBA signatures, ToCollection method, Methods for Grouping + rows and columns. + 6.0.8 20220921 Minor bug fixes. + 5.8.14 20220921 Minor bug fixes. + 6.0.7 20220830 Minor bug fixes. + 5.8.13 20220830 Minor bug fixes. + 6.0.6 20220708 Minor bug fixes. + 5.8.12 20220708 Minor bug fixes. + 6.0.5 20220610 Minor bug fixes. + 5.8.11 20220610 Minor bug fixes. + 6.0.4 20220512 Minor bug fixes. + 5.8.10 20220512 Minor bug fixes. + 6.0.3 20220412 Html and JSON export. New drawing handling. + https://epplussoftware.com/Developers/EPPlus6 + 5.8.9 20220411 Minor bug fixes. + 5.8.8 20220322 Minor bug fixes. + 6.0.1 20220310 Beta 2 + 6.0.0 20220307 Beta 1 + 5.8.7 20220301 Minor bug fixes. + 5.8.6 20220203 Minor bug fixes. + 5.8.5 20220113 Minor features and bug fixes. + 5.8.4 20211214 Minor features and bug fixes. + 5.8.3 20211119 Minor bug fixes. + 5.8.2 20211029 Minor bug fixes. + 5.8.1 20211026 Minor bug fixes. + 5.8.0 20211021 Range.Fill methods, Range Rows and Column Collection, Range.Copy + improvments and Worksheet Split Panes. + 5.7.5 20210921 Minor bug fixes. + 5.7.4 20210826 Minor bug fixes. + 5.7.3 20210810 Minor bug fixes. + 5.7.2 20210722 Minor bug fixes. + 5.7.1 20210706 Minor bug fixes. + 5.7.0 20210617 External links. Better sorting support. Pivot table ShowAs + 5.6.4 20210512 Minor bug fixes. + 5.6.3 20210416 Minor bug fixes. + 5.6.2 20210407 Minor bug fixes. + 5.6.1 20210322 Minor bug fixes. + 5.6.0 20210315 Custom table styles. Pivot table styling. Table styling enhancements. + 5.5.5 20210223 Minor bug fixes. + 5.5.4 20210216 Minor bug fixes. + 5.5.3 20210206 Minor bug fixes. + 5.5.2 20210118 Minor bug fixes. + 5.5.1 20210111 Minor features and bug fixes. + 5.5.0 20201218 Form Controls. + 5.4.2 20201119 Minor features and bug fixes. + 5.4.1 20201105 Minor features and bug fixes. + 5.4.0 20201008 Table- and Pivot Table- Slicers. Pivot Table Filters. + 5.3.2 20200914 Bug fixes. + 5.3.1 20200902 Minor features and bug fixes. + 5.3.0 20200819 Support for threaded comment with mentions. Minor feature and bug fixes. + 5.2.1 20200722 Minor features and bug fixes. + 5.2.0 20200623 Support for 12 new chart types. Minor features and bug fixes. + 5.1.2 20200513 Minor features and bug fixes. + 5.1.1 20200427 Minor bug fixes. + 5.1.0 20200401 Insert, Delete in Ranges and Tables. Minor bug fixes. + 5.0.4 20200310 Minor bug fixes. + 5.0.3 20200308 Initial release EPPlus 5 true OpenOfficeXml.snk @@ -730,10 +781,14 @@ - - - - + + + + @@ -743,8 +798,9 @@ so the correct per-target-framework output is picked up in the multi-target build. --> - WithMetadataValue('Extension', '.dll'))" + Condition="'%(FileName)' == 'EPPlus.DrawingRenderer' Or '%(FileName)' == 'EPPlus.Export.Pdf' Or '%(FileName)' == 'EPPlus.Fonts.OpenType' Or '%(FileName)' == 'EPPlus.Graphics'" /> @@ -802,7 +858,8 @@ - + diff --git a/src/EPPlus/ExcelPrinterSettings.cs b/src/EPPlus/ExcelPrinterSettings.cs index 40b4090e96..a844557968 100644 --- a/src/EPPlus/ExcelPrinterSettings.cs +++ b/src/EPPlus/ExcelPrinterSettings.cs @@ -319,6 +319,46 @@ public enum ePageOrder /// OverThenDown } + /// + /// Specifies how comments and notes will be displayed + /// + public enum eCellComments + { + /// + /// Comments will not be dispalyed + /// + None, + /// + /// Notes will be displyed in a box next to the cell + /// + AsDisplayed, + /// + /// Adds pages at the end containing notes and commnets + /// + AtEnd + } + /// + /// Specifies how to display errors + /// + public enum ePrintError + { + /// + /// Show error as it is + /// + Displayed, + /// + /// Show eror as blank + /// + Blank, + /// + /// Show error as a dash + /// + Dash, + /// + /// Show error as N/A + /// + NA + } #endregion /// /// Printer settings @@ -342,7 +382,7 @@ public double LeftMargin { get { - return GetXmlNodeDouble(_leftMarginPath); + return GetXmlNodeDouble(_leftMarginPath, 0.7480d); } set { @@ -358,7 +398,7 @@ public double RightMargin { get { - return GetXmlNodeDouble(_rightMarginPath); + return GetXmlNodeDouble(_rightMarginPath, 0.7480d); } set { @@ -374,7 +414,7 @@ public double TopMargin { get { - return GetXmlNodeDouble(_topMarginPath); + return GetXmlNodeDouble(_topMarginPath, 0.7480d); } set { @@ -390,7 +430,7 @@ public double BottomMargin { get { - return GetXmlNodeDouble(_bottomMarginPath); + return GetXmlNodeDouble(_bottomMarginPath, 0.7480d); } set { @@ -406,7 +446,7 @@ public double HeaderMargin { get { - return GetXmlNodeDouble(_headerMarginPath); + return GetXmlNodeDouble(_headerMarginPath, 0.315d); } set { @@ -422,7 +462,7 @@ public double FooterMargin { get { - return GetXmlNodeDouble(_footerMarginPath); + return GetXmlNodeDouble(_footerMarginPath, 0.315d); } set { @@ -439,7 +479,8 @@ public eOrientation Orientation { get { - return (eOrientation)Enum.Parse(typeof(eOrientation), GetXmlNodeString(_orientationPath), true); + var orientation = GetXmlNodeString(_orientationPath); + return string.IsNullOrEmpty( orientation) ? eOrientation.Portrait : (eOrientation)Enum.Parse(typeof(eOrientation), orientation, true); } set { @@ -806,6 +847,90 @@ public ePaperSize PaperSize SetXmlNodeString(_paperSizePath, ((int)value).ToString()); } } + const string _commentPath = "d:pageSetup/@cellComments"; + /// + /// Specifies how cell comments are printed. + /// + public eCellComments CellComments + { + get + { + return GetXmlNodeString(_commentPath) switch + { + "asDisplayed" => eCellComments.AsDisplayed, + "atEnd" => eCellComments.AtEnd, + _ => eCellComments.None + }; + } + set + { + var xmlValue = value switch + { + eCellComments.AsDisplayed => "asDisplayed", + eCellComments.AtEnd => "atEnd", + _ => "none" + }; + SetXmlNodeString(_commentPath, xmlValue == "none" ? null : xmlValue, true); + } + } + const string _errorPath = "d:pageSetup/@errors"; + /// + /// Specifies how cell error values are printed. + /// + public ePrintError Errors + { + get + { + return GetXmlNodeString(_errorPath) switch + { + "blank" => ePrintError.Blank, + "dash" => ePrintError.Dash, + "NA" => ePrintError.NA, + _ => ePrintError.Displayed + }; + } + set + { + var xmlValue = value switch + { + ePrintError.Blank => "blank", + ePrintError.Dash => "dash", + ePrintError.NA => "NA", + _ => "displayed" + }; + SetXmlNodeString(_errorPath, xmlValue == "displayed" ? null : xmlValue, true); + } + } + const string _firstPageNumberPath = "d:pageSetup/@firstPageNumber"; + const string _useFirstPageNumberPath = "d:pageSetup/@useFirstPageNumber"; + /// + /// The page number to use for the first printed page. + /// Set to 1 or less to revert to automatic page numbering. + /// Setting this also controls the useFirstPageNumber attribute automatically. + /// + public int FirstPageNumber + { + get + { + if (!GetXmlNodeBool(_useFirstPageNumberPath)) + return 1; // automatic — return the default + return GetXmlNodeInt(_firstPageNumberPath); + } + set + { + if (value <= 1) + { + // Revert to automatic — remove both attributes + DeleteNode(_firstPageNumberPath); + DeleteNode(_useFirstPageNumberPath); + } + else + { + SetXmlNodeString(_firstPageNumberPath, value.ToString()); + SetXmlNodeBool(_useFirstPageNumberPath, true, true); + } + } + } /// /// All or none of the margin attributes must exist. Create all att ones. /// diff --git a/src/EPPlus/ExcelRangeBase.cs b/src/EPPlus/ExcelRangeBase.cs index d11c845020..5e55aebba4 100644 --- a/src/EPPlus/ExcelRangeBase.cs +++ b/src/EPPlus/ExcelRangeBase.cs @@ -17,6 +17,8 @@ Date Author Change using OfficeOpenXml.Core.Worksheet; using OfficeOpenXml.DataValidation; using OfficeOpenXml.Export.HtmlExport.Interfaces; +using OfficeOpenXml.Export.PdfExport; +using OfficeOpenXml.Export.PdfExport.Settings; using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; @@ -32,6 +34,9 @@ Date Author Change using System.Collections; using System.Collections.Generic; using System.Globalization; +using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace OfficeOpenXml { @@ -1133,6 +1138,58 @@ public IExcelHtmlRangeExporter CreateHtmlExporter() return new OfficeOpenXml.Export.HtmlExport.Exporters.ExcelHtmlRangeExporter(this); } + /// + /// Save range to PDF. + /// + /// Name of file. + public void SaveAsPdf(string fileName) + { + var setttings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Worksheet.Workbook, this.Worksheet.PrinterSettings); + PdfCatalog catalog = new PdfCatalog(fileName, setttings, this); + } + + /// + /// Save range to PDF asynchronously. + /// + /// Name of file. + /// Token to cancel the operation. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken = default) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Worksheet.Workbook, this.Worksheet.PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(fileName, settings, this); + }, cancellationToken); + } + + /// + /// Save range to PDF, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + public void SaveAsPdf(Stream stream) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Worksheet.Workbook, this.Worksheet.PrinterSettings); + PdfCatalog catalog = new PdfCatalog(stream, settings, this); + } + + /// + /// Save range to PDF asynchronously, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Token to cancel the operation. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken = default) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Worksheet.Workbook, this.Worksheet.PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(stream, settings, this); + }, cancellationToken); + } + //public ExcelHtmlRangeExporter CreateHtmlExporter() //{ // return new ExcelHtmlRangeExporter(this); diff --git a/src/EPPlus/ExcelWorkbook.cs b/src/EPPlus/ExcelWorkbook.cs index 6157d386d6..f52be370f8 100644 --- a/src/EPPlus/ExcelWorkbook.cs +++ b/src/EPPlus/ExcelWorkbook.cs @@ -24,6 +24,11 @@ Date Author Change using OfficeOpenXml.Drawing.Theme; using OfficeOpenXml.Export.HtmlExport.Exporters; using OfficeOpenXml.Export.HtmlExport.Interfaces; +using OfficeOpenXml.Export.PdfExport; +using OfficeOpenXml.Export.PdfExport.Settings; +using OfficeOpenXml.ExternalReferences; +using OfficeOpenXml.FormulaParsing; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.ExternalReferences; using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; @@ -48,6 +53,8 @@ Date Author Change using System.IO; using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; using System.Xml; namespace OfficeOpenXml @@ -735,6 +742,206 @@ public IExcelHtmlRangeExporter CreateHtmlExporter(params ExcelRangeBase[] ranges return new ExcelHtmlWorkbookExporter(ranges); } + /// + /// Export workbook to PDF. + /// + /// Name of file. + public void SaveAsPdf(string fileName) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, Worksheets[View.ActiveTab].PrinterSettings); + PdfCatalog catalog = new PdfCatalog(fileName, settings, this); + } + + /// + /// Export selected worksheets to PDF. + /// + /// Name of File. + /// Worksheets to export. + public void SaveAsPdf(string fileName, params ExcelWorksheet[] worksheets) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, worksheets[0].PrinterSettings); + PdfCatalog catalog = new PdfCatalog(fileName, settings, worksheets); + } + + /// + /// Export selected ranges to PDF. + /// + /// Name of file. + /// Ranges to export. + public void SaveAsPdf(string fileName, params ExcelRangeBase[] ranges) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, ranges[0].Worksheet.PrinterSettings); + PdfCatalog catalog = new PdfCatalog(fileName, settings, ranges); + } + + /// + /// Export workbook to PDF asynchronously. + /// + /// Name of file. + /// Token to cancel the operation. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken = default) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, Worksheets[View.ActiveTab].PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(fileName, settings, this); + }, cancellationToken); + } + + /// + /// Export selected worksheets to PDF asynchronously. + /// + /// Name of file. + /// Worksheets to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(string fileName, params ExcelWorksheet[] worksheets) + => SaveAsPdfAsync(fileName, CancellationToken.None, worksheets); + + /// + /// Export selected worksheets to PDF asynchronously. + /// + /// Name of file. + /// Token to cancel the operation. + /// Worksheets to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken, params ExcelWorksheet[] worksheets) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, worksheets[0].PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(fileName, settings, worksheets); + }, cancellationToken); + } + + /// + /// Export selected ranges to PDF asynchronously. + /// + /// Name of file. + /// Ranges to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(string fileName, params ExcelRangeBase[] ranges) + => SaveAsPdfAsync(fileName, CancellationToken.None, ranges); + + /// + /// Export selected ranges to PDF asynchronously. + /// + /// Name of file. + /// Token to cancel the operation. + /// Ranges to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken, params ExcelRangeBase[] ranges) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, ranges[0].Worksheet.PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(fileName, settings, ranges); + }, cancellationToken); + } + + /// + /// Export workbook to PDF, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + public void SaveAsPdf(Stream stream) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, Worksheets[View.ActiveTab].PrinterSettings); + PdfCatalog catalog = new PdfCatalog(stream, settings, this); + } + + /// + /// Export selected worksheets to PDF, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Worksheets to export. + public void SaveAsPdf(Stream stream, params ExcelWorksheet[] worksheets) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, worksheets[0].PrinterSettings); + PdfCatalog catalog = new PdfCatalog(stream, settings, worksheets); + } + + /// + /// Export selected ranges to PDF, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Ranges to export. + public void SaveAsPdf(Stream stream, params ExcelRangeBase[] ranges) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, ranges[0].Worksheet.PrinterSettings); + PdfCatalog catalog = new PdfCatalog(stream, settings, ranges); + } + + /// + /// Export workbook to PDF asynchronously, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Token to cancel the operation. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken = default) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, Worksheets[View.ActiveTab].PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(stream, settings, this); + }, cancellationToken); + } + + /// + /// Export selected worksheets to PDF asynchronously, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Worksheets to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(Stream stream, params ExcelWorksheet[] worksheets) + => SaveAsPdfAsync(stream, CancellationToken.None, worksheets); + + /// + /// Export selected worksheets to PDF asynchronously, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Token to cancel the operation. + /// Worksheets to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken, params ExcelWorksheet[] worksheets) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, worksheets[0].PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(stream, settings, worksheets); + }, cancellationToken); + } + + /// + /// Export selected ranges to PDF asynchronously, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Ranges to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(Stream stream, params ExcelRangeBase[] ranges) + => SaveAsPdfAsync(stream, CancellationToken.None, ranges); + + /// + /// Export selected ranges to PDF asynchronously, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Token to cancel the operation. + /// Ranges to export. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken, params ExcelRangeBase[] ranges) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, ranges[0].Worksheet.PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(stream, settings, ranges); + }, cancellationToken); + } + //public ExcelHtmlRangeExporter CreateHtmlExporter(params ExcelRangeBase[] ranges) //{ // foreach (var range in ranges) @@ -1492,7 +1699,7 @@ internal RenderContext RenderContext /// A callback that configures the font settings for this workbook. /// /// The configuration is applied when this workbook first renders a drawing. Call this before - /// rendering. The font engine is per workbook — configuring one workbook does not affect any + /// rendering. The font engine is per workbook � configuring one workbook does not affect any /// other workbook or any global state. /// public void ConfigureFonts(Action configure) @@ -1505,7 +1712,7 @@ public void ConfigureFonts(Action configure) /// /// Supplies a pre-built font engine for this workbook's rendering. Intended for advanced - /// scenarios and testing where a specific engine instance must be used. Per workbook — never + /// scenarios and testing where a specific engine instance must be used. Per workbook � never /// global. /// /// The font engine to use for this workbook. diff --git a/src/EPPlus/ExcelWorksheet.cs b/src/EPPlus/ExcelWorksheet.cs index e4543bcc19..28f394c33c 100644 --- a/src/EPPlus/ExcelWorksheet.cs +++ b/src/EPPlus/ExcelWorksheet.cs @@ -15,23 +15,22 @@ Date Author Change using OfficeOpenXml.Constants; using OfficeOpenXml.Core; using OfficeOpenXml.Core.CellStore; -using OfficeOpenXml.Core.RangeQuadTree; using OfficeOpenXml.Core.RichValues; using OfficeOpenXml.Core.Worksheet; using OfficeOpenXml.Core.Worksheet.XmlWriter; -using OfficeOpenXml.Data.Connection.IOHandlers; using OfficeOpenXml.Data.QueryTable; using OfficeOpenXml.DataValidation; using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Interfaces; using OfficeOpenXml.Drawing.Vml; +using OfficeOpenXml.Export.PdfExport; +using OfficeOpenXml.Export.PdfExport.Settings; using OfficeOpenXml.Filter; using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.Packaging; using OfficeOpenXml.Packaging.Ionic.Zip; using OfficeOpenXml.RichData; -using OfficeOpenXml.RichData.RichValues.WebImages; using OfficeOpenXml.Sorting; using OfficeOpenXml.Sparkline; using OfficeOpenXml.Style; @@ -51,8 +50,9 @@ Date Author Change using System.Globalization; using System.IO; using System.Linq; -using System.Security.Permissions; using System.Text; +using System.Threading; +using System.Threading.Tasks; using System.Xml; namespace OfficeOpenXml @@ -3029,8 +3029,8 @@ private ExcelRangeBase GetDimension(bool byVisibility) CheckSheetTypeAndNotDisposed(); if (_values.GetDimension(out int fr, out int fc, out int tr, out int tc)) { - var fvc = FirstValueCell; - var lvc = LastValueCell; + var fvc = Cells[fr, fc]; + var lvc = Cells[tr, tc]; // Row range comes from values only — styling never extends the height. var fromRow = fvc._fromRow; var toRow = lvc._toRow; @@ -3091,10 +3091,10 @@ private ExcelRangeBase GetDimension(bool byVisibility) { for (int c = fc; c <= tc; c++) { - if (c >= fromCol && c <= toCol) - { - continue; // already inside the range - } + //if (c >= fromCol && c <= toCol) + //{ + // continue; // already inside the range + //} for (int r = fromRow; r <= toRow; r++) { if (HasVisibleStyle(r, c)) @@ -3745,6 +3745,58 @@ internal bool IsDisposed } } + /// + /// Export worksheet to PDF. + /// + /// Name of file. + public void SaveAsPdf(string fileName) + { + var setttings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Workbook, PrinterSettings); + PdfCatalog catalog = new PdfCatalog(fileName, setttings, this); + } + + /// + /// Export worksheet to PDF asynchronously. + /// + /// Name of file. + /// Token to cancel the operation. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken = default) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Workbook, PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(fileName, settings, this); + }, cancellationToken); + } + + /// + /// Export worksheet to PDF, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + public void SaveAsPdf(Stream stream) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Workbook, PrinterSettings); + PdfCatalog catalog = new PdfCatalog(stream, settings, this); + } + + /// + /// Export worksheet to PDF asynchronously, writing to a stream. + /// + /// Stream to write the PDF to. The stream is not closed; the caller owns it. + /// Token to cancel the operation. + /// A task representing the asynchronous operation. + public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken = default) + { + var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Workbook, PrinterSettings); + return Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + _ = new PdfCatalog(stream, settings, this); + }, cancellationToken); + } + ExcelPackage IPictureRelationDocument.Package { get { return _package; } } Dictionary _hashes = new Dictionary(); diff --git a/src/EPPlus/Export/PdfExport/PdfCatalog.cs b/src/EPPlus/Export/PdfExport/PdfCatalog.cs index 5b8cc13199..2bfb60d0ab 100644 --- a/src/EPPlus/Export/PdfExport/PdfCatalog.cs +++ b/src/EPPlus/Export/PdfExport/PdfCatalog.cs @@ -10,6 +10,10 @@ Date Author Change ************************************************************************************************* 27/11/2025 EPPlus Software AB EPPlus 9 *************************************************************************************************/ +using EPPlus.Export.Pdf; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Graphics; using EPPlus.Graphics; using EPPlus.Export.Pdf; using EPPlus.Export.Pdf.Settings; @@ -19,6 +23,10 @@ Date Author Change using OfficeOpenXml.Export.PdfExport.RowResize; using OfficeOpenXml.Export.PdfExport.TextMapping; using OfficeOpenXml.Export.PdfExport.TextShaping; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -30,53 +38,100 @@ internal class PdfCatalog internal PdfDictionaries _dictionaries = new PdfDictionaries(); private bool _addTextForHeadings = true; + public PdfCatalog() { } + // // CONSTRUCTORS FOR MULTIPLE WORKSHEETS AS INPUT // - public PdfCatalog() { } - public PdfCatalog(PdfPageSettings pageSettings, ExcelWorkbook workbook) + public PdfCatalog(string fileName, PdfPageSettings pageSettings, ExcelWorkbook workbook) + { + HandleWorksheetCollection(pageSettings, workbook.Worksheets.ToArray(), WriteToFile(pageSettings, fileName)); + } + + public PdfCatalog(string fileName, PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) { - HandleWorksheetCollection(pageSettings, workbook.Worksheets.ToArray()); + HandleWorksheetCollection(pageSettings, worksheets, WriteToFile(pageSettings, fileName)); } - public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) + public PdfCatalog(string fileName, PdfPageSettings pageSettings, List worksheets) + { + HandleWorksheetCollection(pageSettings, worksheets.ToArray(), WriteToFile(pageSettings, fileName)); + } + + + public PdfCatalog(Stream stream, PdfPageSettings pageSettings, ExcelWorkbook workbook) { - HandleWorksheetCollection(pageSettings, worksheets); + HandleWorksheetCollection(pageSettings, workbook.Worksheets.ToArray(), WriteToStream(pageSettings, stream)); } - public PdfCatalog(PdfPageSettings pageSettings, List worksheets) + public PdfCatalog(Stream stream, PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) { - HandleWorksheetCollection(pageSettings, worksheets.ToArray()); + HandleWorksheetCollection(pageSettings, worksheets, WriteToStream(pageSettings, stream)); } - private void HandleWorksheetCollection(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) + public PdfCatalog(Stream stream, PdfPageSettings pageSettings, List worksheets) { - var pdfSheets = GetPdfWorksheets(pageSettings, worksheets); - foreach (var pdfSheet in pdfSheets) + HandleWorksheetCollection(pageSettings, worksheets.ToArray(), WriteToStream(pageSettings, stream)); + } + + private void HandleWorksheetCollection(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets, Action writePdf) + { + // Match the single-worksheet path: resolve the default font before building. + pageSettings.defaultFontName = worksheets[0].Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; + + PdfWorksheet[] pdfSheets = null; + try { - ShapeTextInPdfWorksheet(pageSettings, pdfSheet); - PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); + // Collect text for every worksheet. + pdfSheets = GetPdfWorksheets(pageSettings, worksheets); + + // Shape text and auto-fit rows per sheet. + foreach (var pdfSheet in pdfSheets) + { + ShapeTextInPdfWorksheet(pageSettings, pdfSheet); + PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); + } + + // One layout spanning all sheets and their ranges. + var layout = GetLayout(pageSettings, pdfSheets); + + // Write the PDF document. + writePdf(layout); + } + finally + { + // Clean up the temporary comments/notes worksheet created for each sheet, + // so the source workbook isn't permanently mutated by the PDF export. + if (pdfSheets != null) + { + foreach (var pdfSheet in pdfSheets) + { + if (pdfSheet != null && pdfSheet.CommentsAndNotesSheet != null) + { + pdfSheet.Worksheet.Workbook.Worksheets.Delete(pdfSheet.CommentsAndNotesSheet); + pdfSheet.CommentsAndNotesSheet = null; + } + } + } } - var Layout = GetLayout(pageSettings, pdfSheets); - //send Layout to pdf export here. } // // CONSTRUCTORS FOR SINGLE WORKSHEET AS INPUT // - public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet worksheet, string fileName) + public PdfCatalog(string fileName, PdfPageSettings pageSettings, ExcelWorksheet worksheet) { - BuildPdf(pageSettings, worksheet, fileName); + BuildPdf(pageSettings, worksheet, WriteToFile(pageSettings, fileName)); } - //public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet worksheet, Stream stream) - //{ - // BuildPdf(pageSettings, worksheet); - //} + public PdfCatalog(Stream stream, PdfPageSettings pageSettings, ExcelWorksheet worksheet) + { + BuildPdf(pageSettings, worksheet, WriteToStream(pageSettings, stream)); + } - private void BuildPdf(PdfPageSettings pageSettings, ExcelWorksheet worksheet, string fileName) + private void BuildPdf(PdfPageSettings pageSettings, ExcelWorksheet worksheet, Action writePdf) { //pageSettings.defaultFontName = worksheet.Workbook.ThemeManager.CurrentTheme.FontScheme.MinorFont[0].Typeface; pageSettings.defaultFontName = worksheet.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; @@ -114,8 +169,7 @@ private void BuildPdf(PdfPageSettings pageSettings, ExcelWorksheet worksheet, st sw.Start(); //Write Pdf Document - ExcelPdf excelPdf = new ExcelPdf(); - excelPdf.CreatePdf(pageSettings, _dictionaries, layout, fileName); + writePdf(layout); sw.Stop(); var CreatePdfTime = sw.ElapsedMilliseconds; sw.Reset(); @@ -136,13 +190,94 @@ private void BuildPdf(PdfPageSettings pageSettings, ExcelWorksheet worksheet, st // CONSTRUCTORS FOR RANGE AS INPUT // - public PdfCatalog(PdfPageSettings pageSettings, ExcelRangeBase range) + public PdfCatalog(string fileName, PdfPageSettings pageSettings, ExcelRangeBase range) { - PdfWorksheet pdfSheet = GetPdfWorksheet(pageSettings, range); - ShapeTextInPdfWorksheet(pageSettings, pdfSheet); - PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); - var Layout = GetLayout(pageSettings, pdfSheet); - //send Layout to pdf export here. + BuildPdfFromRange(pageSettings, range, WriteToFile(pageSettings, fileName)); + } + + public PdfCatalog(Stream stream, PdfPageSettings pageSettings, ExcelRangeBase range) + { + BuildPdfFromRange(pageSettings, range, WriteToStream(pageSettings, stream)); + } + + private void BuildPdfFromRange(PdfPageSettings pageSettings, ExcelRangeBase range, Action writePdf) + { + pageSettings.defaultFontName = range.Worksheet.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; + + PdfWorksheet pdfSheet = null; + try + { + pdfSheet = GetPdfWorksheet(pageSettings, range); + ShapeTextInPdfWorksheet(pageSettings, pdfSheet); + PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); + var layout = GetLayout(pageSettings, pdfSheet); // single-sheet GetLayout overload + + writePdf(layout); + } + finally + { + if (pdfSheet != null && pdfSheet.CommentsAndNotesSheet != null) + { + pdfSheet.Worksheet.Workbook.Worksheets.Delete(pdfSheet.CommentsAndNotesSheet); + pdfSheet.CommentsAndNotesSheet = null; + } + } + } + + public PdfCatalog(string fileName, PdfPageSettings pageSettings, ExcelRangeBase[] ranges) + { + HandleRangeCollection(pageSettings, ranges, WriteToFile(pageSettings, fileName)); + } + + public PdfCatalog(string fileName, PdfPageSettings pageSettings, List ranges) + { + HandleRangeCollection(pageSettings, ranges.ToArray(), WriteToFile(pageSettings, fileName)); + } + + public PdfCatalog(Stream stream, PdfPageSettings pageSettings, ExcelRangeBase[] ranges) + { + HandleRangeCollection(pageSettings, ranges, WriteToStream(pageSettings, stream)); + } + + public PdfCatalog(Stream stream, PdfPageSettings pageSettings, List ranges) + { + HandleRangeCollection(pageSettings, ranges.ToArray(), WriteToStream(pageSettings, stream)); + } + + private void HandleRangeCollection(PdfPageSettings pageSettings, ExcelRangeBase[] ranges, Action writePdf) + { + pageSettings.defaultFontName = ranges[0].Worksheet.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; + + PdfWorksheet[] pdfSheets = null; + try + { + // One PdfWorksheet per worksheet, each carrying all of its ranges. + pdfSheets = GetPdfWorksheets(pageSettings, ranges); + + foreach (var pdfSheet in pdfSheets) + { + ShapeTextInPdfWorksheet(pageSettings, pdfSheet); + PdfCalculateRowHeight.ResizeRowHeights(pdfSheet); + } + + var layout = GetLayout(pageSettings, pdfSheets); + + writePdf(layout); + } + finally + { + if (pdfSheets != null) + { + foreach (var pdfSheet in pdfSheets) + { + if (pdfSheet != null && pdfSheet.CommentsAndNotesSheet != null) + { + pdfSheet.Worksheet.Workbook.Worksheets.Delete(pdfSheet.CommentsAndNotesSheet); + pdfSheet.CommentsAndNotesSheet = null; + } + } + } + } } internal PdfCellCollection GetCellCollectionFromRange(PdfPageSettings pageSettings, ExcelRangeBase range) @@ -155,6 +290,15 @@ internal PdfCellCollection GetCellCollectionFromRange(PdfPageSettings pageSettin //Private Methods + private Action WriteToFile(PdfPageSettings pageSettings, string fileName) + { + return layout => new ExcelPdf().CreatePdf(pageSettings, _dictionaries, layout, fileName); + } + + private Action WriteToStream(PdfPageSettings pageSettings, Stream stream) + { + return layout => new ExcelPdf().CreatePdf(pageSettings, _dictionaries, layout, stream); + } //Create Layout Methods @@ -254,6 +398,53 @@ private PdfWorksheet GetPdfWorksheet(PdfPageSettings pageSettings, ExcelRangeBas return pdfSheet; } + private PdfWorksheet[] GetPdfWorksheets(PdfPageSettings pageSettings, ExcelRangeBase[] ranges) + { + // Group ranges by worksheet, preserving input order. + var sheetOrder = new List(); + var rangesBySheet = new Dictionary>(); + foreach (var range in ranges) + { + var ws = range.Worksheet; + if (!rangesBySheet.TryGetValue(ws, out var list)) + { + list = new List(); + rangesBySheet[ws] = list; + sheetOrder.Add(ws); + } + list.Add(range); + } + + var pdfSheets = new PdfWorksheet[sheetOrder.Count]; + for (int i = 0; i < sheetOrder.Count; i++) + { + var ws = sheetOrder[i]; + pdfSheets[i] = GetPdfWorksheet(pageSettings, ws, rangesBySheet[ws]); + } + return pdfSheets; + } + + private PdfWorksheet GetPdfWorksheet(PdfPageSettings pageSettings, ExcelWorksheet worksheet, List ranges) + { + PdfWorksheet pdfSheet = new PdfWorksheet(); + pdfSheet.Worksheet = worksheet; + pdfSheet.Ranges = new List(); + foreach (var range in ranges) + { + pdfSheet.Ranges.Add(new PdfRange(range, false)); + } + + if (pageSettings.ShowHeadings && _addTextForHeadings) + _dictionaries.AddFont(pageSettings, pdfSheet.NormalStyle.Style.Font.Name, pdfSheet.GetSubFamilyFromNormalStyle, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); + _addTextForHeadings = false; + + GetMaps(pageSettings, pdfSheet, pdfSheet.Ranges); + GetPrintTitles(pageSettings, pdfSheet); + GetHeaderFooter(pageSettings, pdfSheet); + GetCommentsAndNotes(pageSettings, pdfSheet); + return pdfSheet; + } + private List GetRanges(ExcelWorksheet worksheet) { List ranges = new List(); @@ -267,7 +458,7 @@ private List GetRanges(ExcelWorksheet worksheet) } else { - var range = worksheet.DimensionByValue; + var range = worksheet.DimensionByVisibility; var pdfRange = new PdfRange(range, true); pdfRange.ExtendColumns = true; ranges.Add(pdfRange); @@ -369,7 +560,7 @@ private void GetCommentsAndNotes(PdfPageSettings pageSettings, PdfWorksheet pdfS { if (pageSettings.CommentsAndNotes == CommentsAndNotes.AtEndOfSheet && pdfSheet.CommentsAndNotesCollections.Count > 0) { - var cnPageSettings = new PdfPageSettings(); + var cnPageSettings = new PdfPageSettings(pdfSheet.Worksheet.Workbook.RenderContext.FontEngine); cnPageSettings.CommentsAndNotes = CommentsAndNotes.None; cnPageSettings.ShowHeadings = false; pdfSheet.CommentsAndNotesSheet = PdfCommentsAndNotes.CreateCommentAndNotesPages(pdfSheet.CommentsAndNotesCollections, pdfSheet.Worksheet); diff --git a/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs b/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs new file mode 100644 index 0000000000..571ee41e0f --- /dev/null +++ b/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs @@ -0,0 +1,199 @@ +/************************************************************************************************* + Required Notice: Copyright (C) EPPlus Software AB. + This software is licensed under PolyForm Noncommercial License 1.0.0 + and may only be used for noncommercial purposes + https://polyformproject.org/licenses/noncommercial/1.0.0/ + + A commercial license to use this software can be purchased at https://epplussoftware.com + ************************************************************************************************* + Date Author Change + ************************************************************************************************* + 27/11/2025 EPPlus Software AB EPPlus 9 + *************************************************************************************************/ +using EPPlus.Export.Pdf.Settings; +using EPPlus.Export.Pdf.Settings.PdfPageSizes; +using EPPlus.Graphics.Units; +using System; + +namespace OfficeOpenXml.Export.PdfExport.Settings +{ + internal static class GetPdfSettings + { + internal static PdfPageSettings GetPdfSettingsFromPrinterSettings(ExcelWorkbook workbook, ExcelPrinterSettings eps) + { + var settings = new PdfPageSettings(workbook.RenderContext.FontEngine); + var leftMargin = UnitConversion.ToMillimeters(eps.LeftMargin); + var rightMargin = UnitConversion.ToMillimeters(eps.RightMargin); + var topMargin = UnitConversion.ToMillimeters(eps.TopMargin); + var bottomMargin = UnitConversion.ToMillimeters(eps.BottomMargin); + var headerMargin = UnitConversion.ToMillimeters(eps.HeaderMargin); + var footerMargin = UnitConversion.ToMillimeters(eps.FooterMargin); + settings.Margins = new PdfMargins(topMargin, bottomMargin, leftMargin, rightMargin, headerMargin, footerMargin); + settings.Orientation = (Orientations)eps.Orientation; + //Scaling is not yet implemented. + settings.Scaling = new PdfScaling(eps.Scale); + settings.ShowHeadings = eps.ShowHeaders; + settings.RowsToRepeatAtTop = eps.RepeatRows != null ? eps.RepeatRows.Address : null; + settings.ColumnsToRepeatAtLeft = eps.RepeatColumns != null ? eps.RepeatColumns.Address : null; + //Print area is implemented and uses the defined name instead of this setting. this setting should override the print area defined name. + settings.PrintArea = eps.PrintArea != null ? eps.PrintArea.Address : null; + settings.ShowGridLines = eps.ShowGridLines; + //Centering is not implemented. + settings.CenterOnPageHorizontally = eps.HorizontalCentered; + settings.CenterOnPageVertically = eps.VerticalCentered; + settings.PageOrders = (PageOrders)eps.PageOrder; + //Black and white is not yet implemented. + settings.BlackAndWhite = eps.BlackAndWhite; + //Draft is not implemtened. + settings.Draft = eps.Draft; + settings.PageSize = GetPageSize(eps.PaperSize); + settings.CommentsAndNotes = (CommentsAndNotes)eps.CellComments; + settings.CellErrors = (CellErrors)eps.Errors; + settings.FirstPageNumber = eps.FirstPageNumber; + return settings; + } + + private static PdfPageSize GetPageSize(ePaperSize PaperSize) + { + switch (PaperSize) + { + case ePaperSize.Letter: + return PdfPageSize.Letter; + case ePaperSize.LetterSmall: + return PdfPageSize.LetterSmall; + case ePaperSize.Tabloid: + return PdfPageSize.Tabloid; + case ePaperSize.Ledger: + return PdfPageSize.Ledger; + case ePaperSize.Legal: + return PdfPageSize.Legal; + case ePaperSize.Statement: + return PdfPageSize.Statement; + case ePaperSize.Executive: + return PdfPageSize.Executive; + case ePaperSize.A3: + return PdfPageSize.A3; + case ePaperSize.A4: + return PdfPageSize.A4; + case ePaperSize.A4Small: + return PdfPageSize.A4Small; + case ePaperSize.A5: + return PdfPageSize.A5; + case ePaperSize.B4: + return PdfPageSize.B4; + case ePaperSize.B5: + return PdfPageSize.B5; + case ePaperSize.Folio: + return PdfPageSize.Folio; + case ePaperSize.Quarto: + return PdfPageSize.Quarto; + case ePaperSize.Standard10_14: + return PdfPageSize.Standard10_14; + case ePaperSize.Standard11_17: + return PdfPageSize.Standard11_17; + case ePaperSize.Note: + return PdfPageSize.Note; + case ePaperSize.Envelope9: + return PdfPageSize.Envelope9; + case ePaperSize.Envelope10: + return PdfPageSize.Envelope10; + case ePaperSize.Envelope11: + return PdfPageSize.Envelope11; + case ePaperSize.Envelope12: + return PdfPageSize.Envelope12; + case ePaperSize.Envelope14: + return PdfPageSize.Envelope14; + case ePaperSize.C: + return PdfPageSize.C; + case ePaperSize.D: + return PdfPageSize.D; + case ePaperSize.E: + return PdfPageSize.E; + case ePaperSize.DLEnvelope: + return PdfPageSize.DLEnvelope; + case ePaperSize.C5Envelope: + return PdfPageSize.C5Envelope; + case ePaperSize.C3Envelope: + return PdfPageSize.C3Envelope; + case ePaperSize.C4Envelope: + return PdfPageSize.C4Envelope; + case ePaperSize.C6Envelope: + return PdfPageSize.C6Envelope; + case ePaperSize.C65Envelope: + return PdfPageSize.C65Envelope; + case ePaperSize.B4Envelope: + return PdfPageSize.B4Envelope; + case ePaperSize.B5Envelope: + return PdfPageSize.B5Envelope; + case ePaperSize.B6Envelope: + return PdfPageSize.B6Envelope; + case ePaperSize.ItalyEnvelope: + return PdfPageSize.ItalyEnvelope; + case ePaperSize.MonarchEnvelope: + return PdfPageSize.MonarchEnvelope; + case ePaperSize.Six3_4Envelope: + return PdfPageSize.Six3_4Envelope; + case ePaperSize.USStandard: + return PdfPageSize.USStandard; + case ePaperSize.GermanStandard: + return PdfPageSize.GermanStandard; + case ePaperSize.GermanLegal: + return PdfPageSize.GermanLegal; + case ePaperSize.ISOB4: + return PdfPageSize.ISOB4; + case ePaperSize.JapaneseDoublePostcard: + return PdfPageSize.JapaneseDoublePostcard; + case ePaperSize.Standard9: + return PdfPageSize.Standard9; + case ePaperSize.Standard10: + return PdfPageSize.Standard10; + case ePaperSize.Standard15: + return PdfPageSize.Standard15; + case ePaperSize.InviteEnvelope: + return PdfPageSize.InviteEnvelope; + case ePaperSize.LetterExtra: + return PdfPageSize.LetterExtra; + case ePaperSize.LegalExtra: + return PdfPageSize.LegalExtra; + case ePaperSize.TabloidExtra: + return PdfPageSize.TabloidExtra; + case ePaperSize.A4Extra: + return PdfPageSize.A4Extra; + case ePaperSize.LetterTransverse: + return PdfPageSize.LetterTransverse; + case ePaperSize.A4Transverse: + return PdfPageSize.A4Transverse; + case ePaperSize.LetterExtraTransverse: + return PdfPageSize.LetterExtraTransverse; + case ePaperSize.SuperA: + return PdfPageSize.SuperA; + case ePaperSize.SuperB: + return PdfPageSize.SuperB; + case ePaperSize.LetterPlus: + return PdfPageSize.LetterPlus; + case ePaperSize.A4Plus: + return PdfPageSize.A4Plus; + case ePaperSize.A5Transverse: + return PdfPageSize.A5Transverse; + case ePaperSize.JISB5Transverse: + return PdfPageSize.JISB5Transverse; + case ePaperSize.A3Extra: + return PdfPageSize.A3Extra; + case ePaperSize.A5Extra: + return PdfPageSize.A5Extra; + case ePaperSize.ISOB5: + return PdfPageSize.ISOB5; + case ePaperSize.A2: + return PdfPageSize.A2; + case ePaperSize.A3Transverse: + return PdfPageSize.A3Transverse; + case ePaperSize.A3ExtraTransverse: + return PdfPageSize.A3ExtraTransverse; + default: + //should return custom paper size instead. + throw new ArgumentOutOfRangeException(nameof(PaperSize), PaperSize, "Unsupported paper size."); + } + + } + } +}