diff --git a/src/EPPlus.Export.Pdf.Tests/MeasurementRenderWidthParityTests.cs b/src/EPPlus.Export.Pdf.Tests/MeasurementRenderWidthParityTests.cs index 9c0f5b494..060b68f27 100644 --- a/src/EPPlus.Export.Pdf.Tests/MeasurementRenderWidthParityTests.cs +++ b/src/EPPlus.Export.Pdf.Tests/MeasurementRenderWidthParityTests.cs @@ -125,7 +125,7 @@ public void MeasuredWidth_MatchesRenderedWidth_ForKernedText() private static double GetMeasuredWidth(PdfPageSettings settings, ExcelRangeBase range) { - var catalog = new PdfCatalog(); + var catalog = new EPPlusToPdfWriter(); var cells = catalog.GetCellCollectionFromRange(settings, range); return cells[range.Start.Row, range.Start.Column].TotalTextLength; } @@ -134,7 +134,7 @@ private static byte[] RenderToBytes(PdfPageSettings settings, ExcelWorksheet she { using (var stream = new MemoryStream()) { - new PdfCatalog(settings, sheet).Save(stream); + new EPPlusToPdfWriter(settings, sheet).Save(stream); return stream.ToArray(); } } diff --git a/src/EPPlus.Export.Pdf.Tests/MultipleSubstitutionReproTests.cs b/src/EPPlus.Export.Pdf.Tests/MultipleSubstitutionReproTests.cs index 1d05cb028..9c3abbd5c 100644 --- a/src/EPPlus.Export.Pdf.Tests/MultipleSubstitutionReproTests.cs +++ b/src/EPPlus.Export.Pdf.Tests/MultipleSubstitutionReproTests.cs @@ -161,7 +161,7 @@ public void MultipleSubstitution_Roboto_ReproSheet() // rather than silently writing an unreadable file. using (var stream = new MemoryStream()) { - new PdfCatalog(settings, sheet).Save(stream); + new EPPlusToPdfWriter(settings, sheet).Save(stream); AssertLooksLikePdf(stream.ToArray()); } diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs b/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs index 1f2991db2..d2e7101db 100644 --- a/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs +++ b/src/EPPlus.Export.Pdf.Tests/PdfTestBase.cs @@ -31,7 +31,7 @@ protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName, params ExcelRange protected void SaveAsPdf(byte[] pdfBytes, string pdfFileName) { - if(!Directory.Exists(_worksheetPath)) + if (!Directory.Exists(_worksheetPath)) { Assert.Inconclusive("Pdf Path not available in this environment"); } @@ -39,11 +39,11 @@ protected void SaveAsPdf(byte[] pdfBytes, string pdfFileName) { File.WriteAllBytes(Path.Combine(_pdfPath, pdfFileName), pdfBytes); } - catch(Exception ex) + catch (Exception ex) { Assert.Inconclusive("Could not write pdf file: " + ex.Message); } - + } /// @@ -56,8 +56,16 @@ protected void SaveAsPdf(byte[] pdfBytes, string pdfFileName) /// protected void SaveAsPdf(ExcelWorksheet sheet, string pdfFileName, PdfPageSettings settings) { - string path = GetPdfFilePath(pdfFileName); - new PdfCatalog(settings, sheet).Save(path); + if (!pdfFileName.ToLower().EndsWith(".pdf")) + { + pdfFileName += ".pdf"; + } + if (Directory.Exists(_pdfPath) == false) + { + Directory.CreateDirectory(_pdfPath); + } + var path = Path.Combine(_pdfPath, pdfFileName); + new EPPlusToPdfWriter(settings, sheet).Save(path); } /// @@ -66,8 +74,12 @@ protected void SaveAsPdf(ExcelWorksheet sheet, string pdfFileName, PdfPageSettin /// protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName, PdfPageSettings settings) { - string path = GetPdfFilePath(pdfFileName); - new PdfCatalog(settings, wb).Save(path); + if (!pdfFileName.ToLower().EndsWith(".pdf")) + { + pdfFileName += ".pdf"; + } + var path = Path.Combine(_pdfPath, pdfFileName); + new EPPlusToPdfWriter(settings, wb).Save(path); } /// @@ -78,9 +90,9 @@ protected void SaveAsPdf(ExcelWorkbook wb, string pdfFileName, PdfPageSettings s { string path = GetPdfFilePath(pdfFileName); if (ranges.Count() > 1) - new PdfCatalog(settings, ranges).Save(path); + new EPPlusToPdfWriter(settings, ranges).Save(path); else - new PdfCatalog(settings, ranges[0]).Save(path); + new EPPlusToPdfWriter(settings, ranges[0]).Save(path); } private static string GetPdfFilePath(string pdfFileName) { diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs index 806ec1df2..ac4da4f1c 100644 --- a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs +++ b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs @@ -376,7 +376,7 @@ public void SaveWorksheetToStreamViaCatalogTest() var ws = p.Workbook.Worksheets[0]; var pageSettings = new PdfPageSettings(ws.Workbook.RenderContext.FontEngine); using var ms = new MemoryStream(); - var pdfCatalog = new PdfCatalog(pageSettings, ws); + var pdfCatalog = new EPPlusToPdfWriter(pageSettings, ws); pdfCatalog.Save(ms); AssertLooksLikePdf(ms.ToArray()); } @@ -674,7 +674,7 @@ public void WorkbookTests(string sourceFile, string outputPath, string wsName) pageSettings.ShowGridLines = false; pageSettings.ShowHeadings = false; - var pdfCatalog = new PdfCatalog(pageSettings, ws); + var pdfCatalog = new EPPlusToPdfWriter(pageSettings, ws); pdfCatalog.Save(outputPath); } @@ -813,7 +813,7 @@ public void EachWorksheetUsesItsOwnOrientation() byte[] pdf; using (var ms = new MemoryStream()) { - var pdfCatalog = new PdfCatalog(settings, package.Workbook); + var pdfCatalog = new EPPlusToPdfWriter(settings, package.Workbook); pdfCatalog.Save(ms); pdf = ms.ToArray(); } @@ -880,7 +880,7 @@ public void EachWorksheetUsesItsOwnPaperSize() byte[] pdf; using (var ms = new MemoryStream()) { - var pdfCatalog = new PdfCatalog(settings, package.Workbook); + var pdfCatalog = new EPPlusToPdfWriter(settings, package.Workbook); pdfCatalog.Save(ms); pdf = ms.ToArray(); } @@ -978,7 +978,7 @@ public void headerFooterImage() { using var p = OpenTemplatePackage("EPPlus Sample 3.xlsx"); var ws = p.Workbook.Worksheets[0]; - string path = _pdfPath + "EPPlus Sample 3.pdf"; + string path = _pdfPath + "EPPlus Sample 3 hf1.pdf"; ws.SaveAsPdf(path); } @@ -987,7 +987,7 @@ public void headerFooterImage2() { using var p = CreateWorkbook(); var ws = p.Workbook.Worksheets[0]; - string path = _pdfPath + "EPPlus Sample 4.pdf"; + string path = _pdfPath + "EPPlus Sample 3 hf2.pdf"; ws.SaveAsPdf(path); } public ExcelPackage CreateWorkbook() @@ -1129,6 +1129,184 @@ public void PngTransparentTest() } [TestMethod] + public void ScalingTests() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + ws.PrinterSettings.Scale = 50; + string path = _pdfPath + "ScalingTest1.pdf"; + ws.SaveAsPdf(path); + } + + [TestMethod] + public void ScalingTestFitToPage() + { + using var p = OpenTemplatePackage("PDFTest.xlsx"); + var ws = p.Workbook.Worksheets[0]; + ws.PrinterSettings.RepeatRows = new ExcelAddress("1:2"); + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToWidth = 2; + ws.PrinterSettings.FitToHeight = 3; + string path = _pdfPath + "ScalingTest2.pdf"; + ws.SaveAsPdf(path); + } + + + private static int CountPdfPages(string path) + { + var text = Encoding.ASCII.GetString(File.ReadAllBytes(path)); + return Regex.Matches(text, @"/Type\s*/Page\b").Count; + } + + private static ExcelWorksheet AddGrid(ExcelPackage p, int rows, int cols, string name = "Sheet1") + { + var ws = p.Workbook.Worksheets.Add(name); + for (int r = 1; r <= rows; r++) + for (int c = 1; c <= cols; c++) + ws.Cells[r, c].Value = $"R{r}C{c}"; + ws.PrinterSettings.PaperSize = ePaperSize.A4; + ws.PrinterSettings.Orientation = eOrientation.Portrait; + return ws; + } + + private static int SaveAndCount(ExcelWorksheet ws, string name) + { + string path = _pdfPath + name + ".pdf"; + ws.SaveAsPdf(path); + return CountPdfPages(path); + } + + [TestMethod] + public void Percentage_ChangesPageCount() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 120, cols: 20); // multi-page both directions + + ws.PrinterSettings.Scale = 100; int at100 = SaveAndCount(ws, "pct_100"); + ws.PrinterSettings.Scale = 50; int at50 = SaveAndCount(ws, "pct_50"); + ws.PrinterSettings.Scale = 200; int at200 = SaveAndCount(ws, "pct_200"); + + Assert.IsTrue(at100 > 1, "sheet should be multi-page at 100%"); + Assert.IsTrue(at50 < at100, $"50% ({at50}) should use fewer pages than 100% ({at100})"); + Assert.IsTrue(at200 > at100, $"200% ({at200}) should use more pages than 100% ({at100})"); + } + + [TestMethod] + public void Fit_WidthBudget_Exact() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 3, cols: 60); + Assert.IsTrue(SaveAndCount(ws, "fitw_base") > 2, "sheet should span >2 page-columns at 100%"); + + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToHeight = 0; + ws.PrinterSettings.FitToWidth = 1; + Assert.AreEqual(1, SaveAndCount(ws, "fitw_1")); + + ws.PrinterSettings.FitToWidth = 2; + Assert.AreEqual(2, SaveAndCount(ws, "fitw_2")); + } + + [TestMethod] + public void Fit_HeightBudget_Exact() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 300, cols: 3); + Assert.IsTrue(SaveAndCount(ws, "fith_base") > 3); + + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToWidth = 0; + ws.PrinterSettings.FitToHeight = 3; + Assert.AreEqual(3, SaveAndCount(ws, "fith_3")); + + ws.PrinterSettings.FitToHeight = 1; + Assert.AreEqual(1, SaveAndCount(ws, "fith_1")); + } + + [TestMethod] + public void Fit_OneByOne_SinglePage() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 200, cols: 30); + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToWidth = 1; + ws.PrinterSettings.FitToHeight = 1; + Assert.AreEqual(1, SaveAndCount(ws, "fit_1x1")); + } + + [TestMethod] + public void Fit_DoesNotEnlargeSmallSheet() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 3, cols: 3); + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToWidth = 2; + ws.PrinterSettings.FitToHeight = 2; + Assert.AreEqual(1, SaveAndCount(ws, "fit_small")); + } + + [TestMethod] + public void Fit_IgnoresManualPageBreaks() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 300, cols: 3); + ws.Row(150).PageBreak = true; + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToWidth = 0; + ws.PrinterSettings.FitToHeight = 2; + Assert.AreEqual(2, SaveAndCount(ws, "fit_break")); + } + + [TestMethod] + public void Fit_WithHeadings_HonorsBudget() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 300, cols: 3); + ws.PrinterSettings.ShowHeaders = true; + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToWidth = 0; + ws.PrinterSettings.FitToHeight = 3; + Assert.AreEqual(3, SaveAndCount(ws, "fit_headings")); + } + + [TestMethod] + public void Fit_WithPrintTitles_HonorsBudget() + { + using var p = new ExcelPackage(); + var ws = AddGrid(p, rows: 300, cols: 3); + ws.PrinterSettings.RepeatRows = new ExcelAddress("1:2"); + ws.PrinterSettings.FitToPage = true; + ws.PrinterSettings.FitToWidth = 0; + ws.PrinterSettings.FitToHeight = 3; + Assert.AreEqual(3, SaveAndCount(ws, "fit_titles")); + } + + [TestMethod] + public void MultiSheet_PerSheetScaling_IsIsolated() + { + using var p = new ExcelPackage(); + var plain = AddGrid(p, rows: 300, cols: 3, name: "Plain"); + var scaled = AddGrid(p, rows: 300, cols: 3, name: "Scaled"); + + int plainAlone = SaveAndCount(plain, "multi_plain"); + int scaledUnscaled = SaveAndCount(scaled, "multi_scaled_off"); + + scaled.PrinterSettings.FitToPage = true; + scaled.PrinterSettings.FitToWidth = 1; + scaled.PrinterSettings.FitToHeight = 1; + int scaledAlone = SaveAndCount(scaled, "multi_scaled_on"); + + Assert.AreEqual(1, scaledAlone, "fit 1x1 should put the scaled sheet on one page"); + Assert.IsTrue(scaledUnscaled > scaledAlone, "scaling should actually reduce the scaled sheet"); + + string combinedPath = _pdfPath + "multi_combined.pdf"; + p.Workbook.SaveAsPdf(combinedPath); + int combined = CountPdfPages(combinedPath); + + Assert.AreEqual(plainAlone + scaledAlone, combined, + $"combined ({combined}) should equal plain ({plainAlone}) + scaled ({scaledAlone}) - " + + "per-sheet scaling must stay isolated"); + } public void TableDxfStyleTest() { using var p = OpenTemplatePackage("TableDxfStylePdf1.xlsx"); diff --git a/src/EPPlus.Export.Pdf.Tests/VariationSequenceReproTests.cs b/src/EPPlus.Export.Pdf.Tests/VariationSequenceReproTests.cs index 1f24b5e6a..188cf9835 100644 --- a/src/EPPlus.Export.Pdf.Tests/VariationSequenceReproTests.cs +++ b/src/EPPlus.Export.Pdf.Tests/VariationSequenceReproTests.cs @@ -88,7 +88,7 @@ public void VariationSequence_BizUdGothic_ReproSheet() // rather than silently writing an unreadable file. using (var stream = new MemoryStream()) { - new PdfCatalog(settings, sheet).Save(stream); + new EPPlusToPdfWriter(settings, sheet).Save(stream); AssertLooksLikePdf(stream.ToArray()); } diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs index d6b6b833a..9b12b8912 100644 --- a/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs @@ -47,6 +47,14 @@ public void AddCommand(string command) commands.Add(command); } + public void AddContentScale(double scale, double anchorX, double anchorY) + { + if (scale == 1d) return; + double e = (1d - scale) * anchorX; + double f = (1d - scale) * anchorY; + commands.Add($"{scale.ToPdfString()} 0 0 {scale.ToPdfString()} {e.ToPdfString()} {f.ToPdfString()} cm"); + } + public void AddCellLayout(PdfCellLayout cell, string label) { if (cell.Size.X <= 0d || cell.Size.Y <= 0d) return; @@ -486,8 +494,8 @@ public void AddMarginClipping(PdfPageLayout pageLayout, PdfPageSettings pageSett left = System.Math.Min(left, System.Math.Min(line.X1, line.X2)); right = System.Math.Max(right, System.Math.Max(line.X1, line.X2)); } - right = System.Math.Min(right, pageSettings.PageSize.WidthPu); - bottom = System.Math.Max(bottom, 0d); + //right = System.Math.Min(right, pageSettings.PageSize.WidthPu); + //bottom = System.Math.Max(bottom, 0d); var pad = GridLine.Width * 4; var x = left + pl.HeadingWidth + pl.PrintTitleWidth - pad; var y = bottom - pad; diff --git a/src/EPPlus.Export.Pdf/ExcelPdf.cs b/src/EPPlus.Export.Pdf/ExcelPdf.cs index 0db79f7c2..6da361832 100644 --- a/src/EPPlus.Export.Pdf/ExcelPdf.cs +++ b/src/EPPlus.Export.Pdf/ExcelPdf.cs @@ -178,6 +178,9 @@ private PdfCatalog AddCatalog(int pagesObjectNumber) private void AddContent(PdfPageLayout pageLayout, PdfPage page) { var pageSettings = pageLayout.Settings; + double contentScale = pageSettings.ContentScale; + double scaleAnchorX = pageSettings.ContentBounds.Left; + double scaleAnchorY = pageSettings.ContentBounds.Top; var cells = pageLayout.ChildObjects.Where(t => (t is PdfCellLayout || t is PdfCellContentLayout || t is PdfCellBorderLayout) && !(t is PdfCellLayout cc && (cc.IsHeading || cc.IsPrintTitle)) && @@ -190,6 +193,7 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) contentStream.AddCommand($"% {pageLayout.Name} start"); //Start page content clipping rectangle. contentStream.AddCommand("q"); + contentStream.AddContentScale(contentScale, scaleAnchorX, scaleAnchorY); contentStream.AddMarginClipping((PdfPageLayout)pageLayout, pageSettings); if (pageSettings.ShowGridLines) { @@ -221,6 +225,8 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) contentStream.AddCommand("Q"); contentStream.AddCommand($"% Margin Clip End"); //Add headings + contentStream.AddCommand("q"); + contentStream.AddContentScale(contentScale, scaleAnchorX, scaleAnchorY); foreach (var heading in headingLayouts) { contentStream.AddCommand($"% HEADING : {heading.Name}"); @@ -234,11 +240,15 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) contentStream.AddBorderLayout(borderLayout); break; } } + contentStream.AddCommand("Q"); //Add outer gridlines if (pageSettings.ShowGridLines || pageSettings.ShowHeadings) { + contentStream.AddCommand("q"); + contentStream.AddContentScale(contentScale, scaleAnchorX, scaleAnchorY); contentStream.AddOuterGridBorder(pageLayout); contentStream.AddPrintTitleGridLines(pageLayout); + contentStream.AddCommand("Q"); } //Add header and footer. foreach (var hf in headerFooterLayouts) @@ -254,6 +264,8 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) if (PdfImageXObject.ProducesSoftMask(image.ImageBytes)) page.HasTransparency = true; } //Add print titles + contentStream.AddCommand("q"); + contentStream.AddContentScale(contentScale, scaleAnchorX, scaleAnchorY); foreach (var titleCell in printTitleLayouts) { contentStream.AddCommand($"% PRINT TITLE : {titleCell.Name}"); @@ -267,6 +279,7 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) contentStream.AddBorderLayout(borderLayout); break; } } + contentStream.AddCommand("Q"); _document.Add(contentStream); page.contentObjectNumbers.Add(contentStream.objectNumber); contentStream.AddCommand($"% {pageLayout.Name} end"); diff --git a/src/EPPlus.Export.Pdf/Layout/PdfCellLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfCellLayout.cs index 59774822d..c0967c411 100644 --- a/src/EPPlus.Export.Pdf/Layout/PdfCellLayout.cs +++ b/src/EPPlus.Export.Pdf/Layout/PdfCellLayout.cs @@ -137,7 +137,10 @@ public void UpdateShadingPositionMatrix(PdfPageSettings pageSettings) CellFillData.GradientFillData.coords = [0, 0, 1, 0]; break; } - CellFillData.GradientFillData.matrix = [Size.X, 0, 0, Size.Y, LocalPosition.X, LocalPosition.Y]; + double s = pageSettings.ContentScale; + double ax = pageSettings.ContentBounds.Left; + double ay = pageSettings.ContentBounds.Top; + CellFillData.GradientFillData.matrix = [Size.X * s, 0, 0, Size.Y * s, LocalPosition.X * s + (1d - s) * ax, LocalPosition.Y * s + (1d - s) * ay]; } else if (CellFillData.GradientFillData.GradientType == ExcelFillGradientType.Path) { @@ -170,7 +173,10 @@ public void UpdateShadingPositionMatrix(PdfPageSettings pageSettings) { CellFillData.GradientFillData.coords = [0.5, 0.5, 0, 0.5, 0.5, r]; } - CellFillData.GradientFillData.matrix = [Size.X, 0, 0, Size.Y, LocalPosition.X, LocalPosition.Y]; + double s = pageSettings.ContentScale; + double ax = pageSettings.ContentBounds.Left; + double ay = pageSettings.ContentBounds.Top; + CellFillData.GradientFillData.matrix = [Size.X * s, 0, 0, Size.Y * s, LocalPosition.X * s + (1d - s) * ax, LocalPosition.Y * s + (1d - s) * ay]; } } } diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs index c951d559c..24e1bad2d 100644 --- a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs @@ -196,6 +196,23 @@ public PdfScaling Scaling } } + private double _resolvedFitScale = 1d; + internal void SetResolvedFitScale(double s) { _resolvedFitScale = s; } + + internal double ContentScale + { + get + { + if (_scaling == null) + return 1d; + if (_scaling.ScalingMode == ScalingMode.AdjustToNormalSize) + return _scaling.Scale > 0d ? _scaling.Scale : 1d; + return _resolvedFitScale; + } + } + internal double EffectiveContentWidth => ContentBounds.Width / ContentScale; + internal double EffectiveContentHeight => ContentBounds.Height / ContentScale; + /// /// GSUB (glyph substitution) features to request when shaping text for this export, e.g. /// ligatures and contextual alternates. Defaults to | diff --git a/src/EPPlus/ExcelHeaderFooter.cs b/src/EPPlus/ExcelHeaderFooter.cs index a7ac0f6cd..894ecd352 100644 --- a/src/EPPlus/ExcelHeaderFooter.cs +++ b/src/EPPlus/ExcelHeaderFooter.cs @@ -435,7 +435,7 @@ public bool ScaleWithDocument { get { - return GetXmlNodeBool(scaleWithDocPath); + return GetXmlNodeBool(scaleWithDocPath, true); } set { diff --git a/src/EPPlus/ExcelRangeBase.cs b/src/EPPlus/ExcelRangeBase.cs index 652054336..4c44a0cdf 100644 --- a/src/EPPlus/ExcelRangeBase.cs +++ b/src/EPPlus/ExcelRangeBase.cs @@ -1146,7 +1146,7 @@ public IExcelHtmlRangeExporter CreateHtmlExporter() public void SaveAsPdf(string fileName) { var setttings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Worksheet.Workbook, this.Worksheet.PrinterSettings); - var pdfCatalog = new PdfCatalog(setttings, this); + var pdfCatalog = new EPPlusToPdfWriter(setttings, this); pdfCatalog.Save(fileName); } @@ -1162,7 +1162,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(fileName); }, cancellationToken); } @@ -1174,7 +1174,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken public void SaveAsPdf(Stream stream) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Worksheet.Workbook, this.Worksheet.PrinterSettings); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(stream); } @@ -1190,7 +1190,7 @@ public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken = return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(stream); }, cancellationToken); } diff --git a/src/EPPlus/ExcelWorkbook.cs b/src/EPPlus/ExcelWorkbook.cs index 16b5b2cef..70608281c 100644 --- a/src/EPPlus/ExcelWorkbook.cs +++ b/src/EPPlus/ExcelWorkbook.cs @@ -750,7 +750,7 @@ public IExcelHtmlRangeExporter CreateHtmlExporter(params ExcelRangeBase[] ranges public void SaveAsPdf(string fileName) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, Worksheets[View.ActiveTab].PrinterSettings); - PdfCatalog catalog = new PdfCatalog(settings, this); + EPPlusToPdfWriter catalog = new EPPlusToPdfWriter(settings, this); catalog.Save(fileName); } @@ -762,7 +762,7 @@ public void SaveAsPdf(string fileName) public void SaveAsPdf(string fileName, params ExcelWorksheet[] worksheets) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, worksheets[0].PrinterSettings); - PdfCatalog catalog = new PdfCatalog(settings, worksheets); + EPPlusToPdfWriter catalog = new EPPlusToPdfWriter(settings, worksheets); catalog.Save(fileName); } @@ -774,7 +774,7 @@ public void SaveAsPdf(string fileName, params ExcelWorksheet[] worksheets) public void SaveAsPdf(string fileName, params ExcelRangeBase[] ranges) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, ranges[0].Worksheet.PrinterSettings); - PdfCatalog catalog = new PdfCatalog(settings, ranges); + EPPlusToPdfWriter catalog = new EPPlusToPdfWriter(settings, ranges); catalog.Save(fileName); } @@ -790,7 +790,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(fileName); }, cancellationToken); } @@ -817,7 +817,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken, return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, worksheets); + var pdfCatalog = new EPPlusToPdfWriter(settings, worksheets); pdfCatalog.Save(fileName); }, cancellationToken); } @@ -844,7 +844,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken, return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, ranges); + var pdfCatalog = new EPPlusToPdfWriter(settings, ranges); pdfCatalog.Save(fileName); }, cancellationToken); } @@ -856,7 +856,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken, public void SaveAsPdf(Stream stream) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, Worksheets[View.ActiveTab].PrinterSettings); - PdfCatalog catalog = new PdfCatalog(settings, this); + EPPlusToPdfWriter catalog = new EPPlusToPdfWriter(settings, this); catalog.Save(stream); } @@ -868,7 +868,7 @@ public void SaveAsPdf(Stream stream) public void SaveAsPdf(Stream stream, params ExcelWorksheet[] worksheets) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, worksheets[0].PrinterSettings); - PdfCatalog catalog = new PdfCatalog(settings, worksheets); + EPPlusToPdfWriter catalog = new EPPlusToPdfWriter(settings, worksheets); catalog.Save(stream); } @@ -880,7 +880,7 @@ public void SaveAsPdf(Stream stream, params ExcelWorksheet[] worksheets) public void SaveAsPdf(Stream stream, params ExcelRangeBase[] ranges) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this, ranges[0].Worksheet.PrinterSettings); - PdfCatalog catalog = new PdfCatalog(settings, ranges); + EPPlusToPdfWriter catalog = new EPPlusToPdfWriter(settings, ranges); catalog.Save(stream); } @@ -896,7 +896,7 @@ public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken = return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(stream); }, cancellationToken); } @@ -923,7 +923,7 @@ public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken, p return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, worksheets); + var pdfCatalog = new EPPlusToPdfWriter(settings, worksheets); pdfCatalog.Save(stream); }, cancellationToken); } @@ -950,7 +950,7 @@ public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken, p return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, ranges); + var pdfCatalog = new EPPlusToPdfWriter(settings, ranges); pdfCatalog.Save(stream); }, cancellationToken); } diff --git a/src/EPPlus/ExcelWorksheet.cs b/src/EPPlus/ExcelWorksheet.cs index cc060ec75..997917740 100644 --- a/src/EPPlus/ExcelWorksheet.cs +++ b/src/EPPlus/ExcelWorksheet.cs @@ -3745,7 +3745,7 @@ internal bool IsDisposed public void SaveAsPdf(string fileName) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Workbook, PrinterSettings); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(fileName); } @@ -3761,7 +3761,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(fileName); }, cancellationToken); } @@ -3773,7 +3773,7 @@ public Task SaveAsPdfAsync(string fileName, CancellationToken cancellationToken public void SaveAsPdf(Stream stream) { var settings = GetPdfSettings.GetPdfSettingsFromPrinterSettings(this.Workbook, PrinterSettings); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(stream); } @@ -3789,7 +3789,7 @@ public Task SaveAsPdfAsync(Stream stream, CancellationToken cancellationToken = return Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); - var pdfCatalog = new PdfCatalog(settings, this); + var pdfCatalog = new EPPlusToPdfWriter(settings, this); pdfCatalog.Save(stream); }, cancellationToken); } diff --git a/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs index d3f716e1a..9d2d9d3c5 100644 --- a/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs +++ b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs @@ -15,6 +15,7 @@ Date Author Change using EPPlus.Export.Pdf.Layout; using EPPlus.Export.Pdf.Resources; using EPPlus.Export.Pdf.Settings; +using EPPlus.Export.Pdf.Settings.PdfPageSizes; using EPPlus.Fonts.OpenType.Integration; using EPPlus.Fonts.OpenType.Integration.DataHolders; using EPPlus.Graphics; @@ -926,6 +927,10 @@ internal static List GetPages(PdfPageSettings[] sheetSettings, PdfWorkshe var pdfSheet = pdfSheets[si]; var pageSettings = sheetSettings[si]; + if (pdfSheet.Ranges.Count > 0) + { + ResolveFitScale(pageSettings, pdfSheet, pdfSheet.Ranges[0]); + } for (int ri = 0; ri < pdfSheet.Ranges.Count; ri++) { var range = pdfSheet.Ranges[ri]; @@ -1481,8 +1486,8 @@ private static double RangeRowHeight(PdfRange range, int row) internal static Pages GetNumberOfPages(PdfPageSettings pageSettings, PdfWorksheet pdfSheet, ref PdfRange range) { - var xPages = (int)Math.Max(1, Math.Ceiling(range.TotalWidth / pageSettings.ContentBounds.Width)); - var yPages = (int)Math.Max(1, Math.Ceiling(range.TotalHeight / pageSettings.ContentBounds.Height)); + var xPages = (int)Math.Max(1, Math.Ceiling(range.TotalWidth / pageSettings.EffectiveContentWidth)); + var yPages = (int)Math.Max(1, Math.Ceiling(range.TotalHeight / pageSettings.EffectiveContentHeight)); if (pageSettings.ShowHeadings) { @@ -1491,24 +1496,27 @@ internal static Pages GetNumberOfPages(PdfPageSettings pageSettings, PdfWorkshee { prev = xPages; range.AdditionalWidth = xPages * ((rowHeadingWith1CharWidth - pdfSheet.ZeroCharWidth) + (Math.Abs(pdfSheet.ToRow).ToString().Length * pdfSheet.ZeroCharWidth)); - xPages = (int)Math.Max(1, Math.Ceiling((range.TotalWidth + range.AdditionalWidth) / pageSettings.ContentBounds.Width)); + xPages = (int)Math.Max(1, Math.Ceiling((range.TotalWidth + range.AdditionalWidth) / pageSettings.EffectiveContentWidth)); } while (prev != xPages); do { prev = yPages; range.AdditionalHeight = yPages * pdfSheet.Worksheet.DefaultRowHeight; - yPages = (int)Math.Max(1, Math.Ceiling((range.TotalHeight + range.AdditionalHeight) / pageSettings.ContentBounds.Height)); + yPages = (int)Math.Max(1, Math.Ceiling((range.TotalHeight + range.AdditionalHeight) / pageSettings.EffectiveContentHeight)); } while (prev != yPages); } - for (int i = range.Range._fromCol; i <= range.Range._toCol; i++) - { - if (pdfSheet.Worksheet.Column(i).PageBreak) - xPages++; - } - for (int i = range.Range._fromRow; i <= range.Range._toRow; i++) + if (pageSettings.Scaling?.ScalingMode != ScalingMode.FitToPages) { - if (pdfSheet.Worksheet.Row(i).PageBreak) - yPages++; + for (int i = range.Range._fromCol; i <= range.Range._toCol; i++) + { + if (pdfSheet.Worksheet.Column(i).PageBreak) + xPages++; + } + for (int i = range.Range._fromRow; i <= range.Range._toRow; i++) + { + if (pdfSheet.Worksheet.Row(i).PageBreak) + yPages++; + } } ComputePrintTitleDimensions(pdfSheet, range, out range.PrintTitleHeight, out range.PrintTitleWidth); range.PrintTitleRowTo = pdfSheet.PrintTitleRowFrom >= 0 ? pdfSheet.PrintTitleRowTo : -1; @@ -1584,7 +1592,7 @@ private static List GetColumnSegments(PdfPageSettings pageSettings, int actualCol = range.Range._fromCol + col; bool reserveTitle = titleWidth > 0d && printTitleColTo >= 0 && (range.Map.FromColumn + segStartIdx) > printTitleColTo; double effectiveAdded = addedWidth + (reserveTitle ? titleWidth : 0d); - if (width + range.ColWidths[col] + effectiveAdded >= pageSettings.ContentBounds.Width) + if (width + range.ColWidths[col] + effectiveAdded >= pageSettings.EffectiveContentWidth) { if (col == segStartIdx) { @@ -1600,7 +1608,7 @@ private static List GetColumnSegments(PdfPageSettings pageSettings, continue; } width += range.ColWidths[col]; - if (worksheet.Column(actualCol).PageBreak) + if (pageSettings.Scaling?.ScalingMode != ScalingMode.FitToPages && worksheet.Column(actualCol).PageBreak) { segments.Add(new PageSegment(range.Map.FromColumn + segStartIdx, range.Map.FromColumn + col)); segStartIdx = col + 1; @@ -1622,7 +1630,7 @@ private static List GetRowSegments(PdfPageSettings pageSettings, Pd int actualRow = range.Range._fromRow + row; bool reserveTitle = titleHeight > 0d && printTitleRowTo >= 0 && (range.Map.FromRow + segStartIdx) > printTitleRowTo; double effectiveAdded = addedHeight + (reserveTitle ? titleHeight : 0d); - if (height + range.RowHeights[row].Height + effectiveAdded >= pageSettings.ContentBounds.Height) + if (height + range.RowHeights[row].Height + effectiveAdded >= pageSettings.EffectiveContentHeight) { segments.Add(new PageSegment(range.Map.FromRow + segStartIdx, range.Map.FromRow + row - 1)); segStartIdx = row; @@ -1631,7 +1639,7 @@ private static List GetRowSegments(PdfPageSettings pageSettings, Pd continue; } height += range.RowHeights[row].Height; - if (worksheet.Row(actualRow).PageBreak) + if (pageSettings.Scaling?.ScalingMode != ScalingMode.FitToPages && worksheet.Row(actualRow).PageBreak) { segments.Add(new PageSegment(range.Map.FromRow + segStartIdx, range.Map.FromRow + row)); segStartIdx = row + 1; @@ -2029,7 +2037,49 @@ internal static double GetOriginY(PdfPageSettings pageSettings, Page page) internal static double GetClampedCellWidth(PdfPageSettings pageSettings, double cellX, double cellWidth) { - return System.Math.Min(cellWidth, pageSettings.PageSize.WidthPu - cellX); + double s = pageSettings.ContentScale; + double pageRightNatural = pageSettings.ContentBounds.Left + + (pageSettings.PageSize.WidthPu - pageSettings.ContentBounds.Left) / s; + return System.Math.Min(cellWidth, pageRightNatural - cellX); + } + + private static void ResolveFitScale(PdfPageSettings pageSettings, PdfWorksheet pdfSheet, PdfRange range) + { + var scaling = pageSettings.Scaling; + if (scaling == null || scaling.ScalingMode != ScalingMode.FitToPages) return; + + int N = scaling.PagesWide; // 0 = automatic + int M = scaling.PagesTall; + var worksheet = range.Range.Worksheet; + + // Same per-page reservations the real pagination uses (both are per-page constants — no circularity). + double addedWidth = pageSettings.ShowHeadings + ? (rowHeadingWith1CharWidth - pdfSheet.ZeroCharWidth) + (System.Math.Abs(pdfSheet.ToRow).ToString().Length * pdfSheet.ZeroCharWidth) + : 0d; + double addedHeight = pageSettings.ShowHeadings ? pdfSheet.Worksheet.DefaultRowHeight : 0d; + + ComputePrintTitleDimensions(pdfSheet, range, out double titleHeight, out double titleWidth); + int titleColTo = pdfSheet.PrintTitleColFrom >= 0 ? pdfSheet.PrintTitleColTo : -1; + int titleRowTo = pdfSheet.PrintTitleRowFrom >= 0 ? pdfSheet.PrintTitleRowTo : -1; + + bool Fits(double s) + { + pageSettings.SetResolvedFitScale(s); + bool okW = N <= 0 || GetColumnSegments(pageSettings, range, worksheet, addedWidth, titleWidth, titleColTo).Count <= N; + bool okH = M <= 0 || GetRowSegments(pageSettings, range, worksheet, addedHeight, titleHeight, titleRowTo).Count <= M; + return okW && okH; + } + + if (Fits(1.0d)) { pageSettings.SetResolvedFitScale(1.0d); return; } // fits at 100% → don't shrink + + // Largest scale in [0.1, 1.0] whose real pagination fits N×M (monotonic: fewer pages as scale shrinks). + double lo = 0.1d, hi = 1.0d; + for (int i = 0; i < 50; i++) + { + double mid = (lo + hi) * 0.5d; + if (Fits(mid)) lo = mid; else hi = mid; + } + pageSettings.SetResolvedFitScale(lo); } } } diff --git a/src/EPPlus/Export/PdfExport/PdfCatalog.cs b/src/EPPlus/Export/PdfExport/PdfCatalog.cs index e731ec487..3056b22c2 100644 --- a/src/EPPlus/Export/PdfExport/PdfCatalog.cs +++ b/src/EPPlus/Export/PdfExport/PdfCatalog.cs @@ -36,7 +36,7 @@ namespace OfficeOpenXml.Export.PdfExport /// The constructors only store the input - they do not perform any work. Call /// or to actually build the PDF and write it to disk/stream. /// - internal class PdfCatalog + internal class EPPlusToPdfWriter { internal PdfDictionaries _dictionaries = new PdfDictionaries(); private bool _addTextForHeadings = true; @@ -47,26 +47,26 @@ internal class PdfCatalog private readonly PdfPageSettings _pageSettings; private readonly Action> _build; - public PdfCatalog() { } + public EPPlusToPdfWriter() { } // // CONSTRUCTORS FOR MULTIPLE WORKSHEETS AS INPUT // - public PdfCatalog(PdfPageSettings pageSettings, ExcelWorkbook workbook) + public EPPlusToPdfWriter(PdfPageSettings pageSettings, ExcelWorkbook workbook) { _pageSettings = pageSettings; var worksheets = workbook.Worksheets.ToArray(); _build = writePdf => HandleWorksheetCollection(pageSettings, worksheets, writePdf); } - public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) + public EPPlusToPdfWriter(PdfPageSettings pageSettings, ExcelWorksheet[] worksheets) { _pageSettings = pageSettings; _build = writePdf => HandleWorksheetCollection(pageSettings, worksheets, writePdf); } - public PdfCatalog(PdfPageSettings pageSettings, List worksheets) + public EPPlusToPdfWriter(PdfPageSettings pageSettings, List worksheets) : this(pageSettings, worksheets.ToArray()) { } @@ -116,7 +116,7 @@ private void HandleWorksheetCollection(PdfPageSettings pageSettings, ExcelWorksh // CONSTRUCTORS FOR SINGLE WORKSHEET AS INPUT // - public PdfCatalog(PdfPageSettings pageSettings, ExcelWorksheet worksheet) + public EPPlusToPdfWriter(PdfPageSettings pageSettings, ExcelWorksheet worksheet) { _pageSettings = pageSettings; _build = writePdf => BuildPdf(pageSettings, worksheet, writePdf); @@ -160,7 +160,7 @@ private void BuildPdf(PdfPageSettings pageSettings, ExcelWorksheet worksheet, Ac // CONSTRUCTORS FOR RANGE AS INPUT // - public PdfCatalog(PdfPageSettings pageSettings, ExcelRangeBase range) + public EPPlusToPdfWriter(PdfPageSettings pageSettings, ExcelRangeBase range) { _pageSettings = pageSettings; _build = writePdf => BuildPdfFromRange(pageSettings, range, writePdf); @@ -190,13 +190,13 @@ private void BuildPdfFromRange(PdfPageSettings pageSettings, ExcelRangeBase rang } } - public PdfCatalog(PdfPageSettings pageSettings, ExcelRangeBase[] ranges) + public EPPlusToPdfWriter(PdfPageSettings pageSettings, ExcelRangeBase[] ranges) { _pageSettings = pageSettings; _build = writePdf => HandleRangeCollection(pageSettings, ranges, writePdf); } - public PdfCatalog(PdfPageSettings pageSettings, List ranges) + public EPPlusToPdfWriter(PdfPageSettings pageSettings, List ranges) : this(pageSettings, ranges.ToArray()) { } @@ -487,7 +487,6 @@ private void GetPrintTitles(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) if (worksheet.Names.ContainsKey("_xlnm.Print_Titles")) { var printTitlesName = worksheet.Names["_xlnm.Print_Titles"]; - if (printTitlesName.Addresses == null) { pdfSheet.PrintTitleRowFrom = printTitlesName._fromRow; diff --git a/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs b/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs index 5aff5a026..1e38fa97b 100644 --- a/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs +++ b/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs @@ -44,14 +44,13 @@ private static void ApplyPrinterSettings(PdfPageSettings settings, ExcelPrinterS 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.Scaling = eps.FitToPage ? new PdfScaling(eps.FitToWidth, eps.FitToHeight) : new PdfScaling(eps.Scale / 100d); 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; diff --git a/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs b/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs index 1d345ccd8..130d29f9d 100644 --- a/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs @@ -34,8 +34,8 @@ public PdfHeaderFooterCollection(PdfPageSettings pageSettings, PdfDictionaries d bool differentOddEven = pdfSheet.Worksheet.HeaderFooter.differentOddEven; HasFirstPage = differentFirst; HasOddEvenPages = differentOddEven; - bool AlignWithMargins = pdfSheet.Worksheet.HeaderFooter.AlignWithMargins; - bool ScaleWithDocument = pdfSheet.Worksheet.HeaderFooter.ScaleWithDocument; + AlignWithMargins = pdfSheet.Worksheet.HeaderFooter.AlignWithMargins; + ScaleWithDocument = pdfSheet.Worksheet.HeaderFooter.ScaleWithDocument; PdfHeaderFooter entry = null; if (differentFirst) { @@ -157,6 +157,21 @@ public PdfHeaderFooterCollection(PdfPageSettings pageSettings, PdfDictionaries d entry.Content.ContentAligmnet = PdfTextMap.GetAlignmentData(entry); PdfHeaderFooterEntries.Add(entry); } + + double hfScale = pageSettings.ContentScale; + if (ScaleWithDocument && hfScale != 1d) + { + foreach (var e in PdfHeaderFooterEntries) + { + if (e.Content?.TextFragments != null) + { + foreach (var tf in e.Content.TextFragments) + tf.Font.Size = (float)(tf.Font.Size * hfScale); + } + e.ImageWidth *= hfScale; + e.ImageHeight *= hfScale; + } + } } public PdfHeaderFooter Get(HeaderFooterType type, HeaderFooterSection section, HeaderFooterAlignment alignment) diff --git a/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs b/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs index 139b985fa..fedb501b0 100644 --- a/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs @@ -830,7 +830,7 @@ internal static int AddColumnsForNonWrappedText(PdfPageSettings pageSettings, Ex { if (ws.Dimension == null) return 0; //If dimension is null, there are no cells to check, so return 0. int columnsToAdd = 0; - var catalog = new PdfCatalog(); + var catalog = new EPPlusToPdfWriter(); var lastColumn = ws.Dimension.End.Column; ExcelRangeBase lastColumnRange = ws.Cells[1, lastColumn, ws.Dimension.End.Row, lastColumn]; var cc = catalog.GetCellCollectionFromRange(pageSettings, lastColumnRange);