diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs index ac4da4f1c..756dea4b4 100644 --- a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs +++ b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs @@ -1307,12 +1307,23 @@ public void MultiSheet_PerSheetScaling_IsIsolated() $"combined ({combined}) should equal plain ({plainAlone}) + scaled ({scaledAlone}) - " + "per-sheet scaling must stay isolated"); } - public void TableDxfStyleTest() + + [TestMethod] + public void TableDxfStyleTest1() { using var p = OpenTemplatePackage("TableDxfStylePdf1.xlsx"); var ws = p.Workbook.Worksheets[0]; string path = _pdfPath + "TableDxfStylePdf1.pdf"; ws.SaveAsPdf(path); } + + [TestMethod] + public void TableDxfStyleTest2() + { + using var p = OpenTemplatePackage("TableDxfStylePdf2.xlsx"); + var ws = p.Workbook.Worksheets[0]; + string path = _pdfPath + "TableDxfStylePdf2.pdf"; + ws.SaveAsPdf(path); + } } } diff --git a/src/EPPlus.Export.Pdf/ExcelPdf.cs b/src/EPPlus.Export.Pdf/ExcelPdf.cs index 3ec3f38ac..ebdfd3e8f 100644 --- a/src/EPPlus.Export.Pdf/ExcelPdf.cs +++ b/src/EPPlus.Export.Pdf/ExcelPdf.cs @@ -186,7 +186,7 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) !(t is PdfCellLayout cc && (cc.IsHeading || cc.IsPrintTitle)) && !(t is PdfCellContentLayout ccl && (ccl.IsHeaderFooter || ccl.IsHeading || ccl.IsPrintTitle || ccl.IsAddedContent)) && !(t is PdfCellBorderLayout cbl && cbl.IsPrintTitle)).ToList(); - var headerFooterLayouts = pageLayout.ChildObjects.OfType().Where(t => t.IsHeaderFooter); + //var headerFooterLayouts = pageLayout.ChildObjects.OfType().Where(t => t.IsHeaderFooter); var AdditionalContent = pageLayout.ChildObjects.OfType().Where(t => t.IsAddedContent && !(pageSettings.AdditionalContent != "null")); var headingLayouts = pageLayout.ChildObjects.Where(t => (t is PdfCellLayout cl && cl.IsHeading) || (t is PdfCellContentLayout ccl && ccl.IsHeading)); var printTitleLayouts = pageLayout.ChildObjects.Where(t => (t is PdfCellLayout pl && pl.IsPrintTitle) || (t is PdfCellContentLayout pcl && pcl.IsPrintTitle) || (t is PdfCellBorderLayout pbl && pbl.IsPrintTitle)); @@ -246,17 +246,32 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) contentStream.AddCommand("Q"); } //Add header and footer. - foreach (var hf in headerFooterLayouts) + foreach (var part in pageLayout.HeaderFooterParts) { - contentStream.AddCellContentLayout(hf, _dictionaries, pageSettings); - } - //Add images - foreach (PdfImageLayout image in pageLayout.ChildObjects.OfType()) - { - if (!image.IsHeaderFooter) continue; - var imageResource = _dictionaries.AddImage(image.ImageBytes); - contentStream.AddImage(imageResource.Label, image.LocalPosition.X, image.LocalPosition.Y, image.Size.X, image.Size.Y); - if (PdfImageXObject.ProducesSoftMask(image.ImageBytes)) page.HasTransparency = true; + bool scaleHf = pageLayout.ScaleHeaderFooterWithDocument; + if (scaleHf) + { + contentStream.AddCommand("q"); + contentStream.AddContentScale(contentScale, part.ScalePivot.X, part.ScalePivot.Y); + } + + foreach (var item in part.Items) + { + switch (item) + { + case PdfCellContentLayout text: + contentStream.AddCellContentLayout(text, _dictionaries, pageSettings); + break; + case PdfImageLayout image: + var imageResource = _dictionaries.AddImage(image.ImageBytes); + contentStream.AddImage(imageResource.Label, image.LocalPosition.X, image.LocalPosition.Y, image.Size.X, image.Size.Y); + if (PdfImageXObject.ProducesSoftMask(image.ImageBytes)) page.HasTransparency = true; + break; + } + } + + if (scaleHf) + contentStream.AddCommand("Q"); } //Add print titles contentStream.AddCommand("q"); diff --git a/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs index 1005c3b5d..10c716033 100644 --- a/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs +++ b/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs @@ -36,6 +36,8 @@ internal class PdfCellContentLayout : Transform public TextLineCollection TextLines; public double LeftTextSpillLength = 0d; public double RightTextSpillLength = 0d; + public double ScaleAnchorX; + public double ScaleAnchorY; private double bottomMargin = 3.5d; //Guessed number private double rightMargin = 1.4d; //I guessed this one too.. @@ -203,14 +205,16 @@ private Vector2 CalculateRotatedAlignment(double textLength, double textHeight, return new Vector2(bx - minX, by - minY); } - internal void SetupClipping(double cellX, double cellY, double cellWidth, double cellHeight) + internal void SetupClipping(double cellX, double cellY, double cellWidth, double cellHeight, bool spillLeft = false, bool spillRight = false) { + double li = spillLeft ? 0d : rightMargin; + double ri = spillRight ? 0d : rightMargin; Clip = true; Clipping = new Rect() { - X = cellX + rightMargin, + X = cellX + li, Y = cellY - cellHeight, - Width = cellWidth - rightMargin * 2, + Width = cellWidth - li - ri, Height = cellHeight }; } diff --git a/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooterPart.cs b/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooterPart.cs new file mode 100644 index 000000000..19d3da079 --- /dev/null +++ b/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooterPart.cs @@ -0,0 +1,24 @@ +/************************************************************************************************* + 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.Graphics; +using EPPlus.Graphics.Geometry; +using System.Collections.Generic; + +namespace EPPlus.Export.Pdf.Layout +{ + internal sealed class PdfHeaderFooterPart + { + public Vector2 ScalePivot; + public readonly List Items = new List(); + } +} diff --git a/src/EPPlus.Export.Pdf/Layout/PdfPageLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfPageLayout.cs index 814ac2c49..b9f07f9ce 100644 --- a/src/EPPlus.Export.Pdf/Layout/PdfPageLayout.cs +++ b/src/EPPlus.Export.Pdf/Layout/PdfPageLayout.cs @@ -28,6 +28,8 @@ internal class PdfPageLayout : Transform public double PrintTitleWidth; public double PrintTitleHeight; public bool isCommentsPage = false; + public bool ScaleHeaderFooterWithDocument; + internal List HeaderFooterParts = new List(); internal PdfPageSettings Settings; public PdfPageLayout(double x, double y, double width, double height) : base(x, y, width, height) diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs index 6f182a9b1..128297a05 100644 --- a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs @@ -203,6 +203,8 @@ public PdfScaling Scaling private double _resolvedFitScale = 1d; internal void SetResolvedFitScale(double s) { _resolvedFitScale = s; } + internal bool ScaleHeaderWithDocument { get; set; } + internal double ContentScale { get diff --git a/src/EPPlus/ExcelHeaderFooter.cs b/src/EPPlus/ExcelHeaderFooter.cs index 894ecd352..0288b137d 100644 --- a/src/EPPlus/ExcelHeaderFooter.cs +++ b/src/EPPlus/ExcelHeaderFooter.cs @@ -381,7 +381,7 @@ public bool AlignWithMargins { get { - return GetXmlNodeBool(alignWithMarginsPath); + return GetXmlNodeBool(alignWithMarginsPath, true); } set { diff --git a/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs index 90e6b728a..3258f1687 100644 --- a/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs +++ b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs @@ -19,12 +19,14 @@ Date Author Change using EPPlus.Fonts.OpenType.Integration; using EPPlus.Fonts.OpenType.Integration.DataHolders; using EPPlus.Graphics; +using EPPlus.Graphics.Geometry; using EPPlus.Graphics.Units; using OfficeOpenXml.Drawing; using OfficeOpenXml.Export.PdfExport.Data; using OfficeOpenXml.Export.PdfExport.TextShaping; using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; using OfficeOpenXml.Interfaces.Fonts; using OfficeOpenXml.Style; using OfficeOpenXml.Style.Dxf; @@ -203,8 +205,8 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio var text = new PdfCellContentLayout(pageSettings, dictionaries, map, x, y, effectiveWidth, rowHeight); text.Name = map.Name; text.GidsAndCharMap(dictionaries); - if (NeedsClipping(map, pages[j], row, col)) - text.SetupClipping(x, y, effectiveWidth, rowHeight); + var (clipX, clipW, spillLeft, spillRight) = GetOverflowClip(map, pages[j], row, col, x, effectiveWidth); + text.SetupClipping(clipX, y, clipW, rowHeight, spillLeft, spillRight); pageLayout.AddChild(text); } } @@ -244,82 +246,86 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio } if (page.HeaderFooters != null) { + pageLayout.ScaleHeaderFooterWithDocument = page.HeaderFooters.ScaleWithDocument; var hfType = page.HeaderFooters.GetPageType(physicalPageIndex); var leftH = page.HeaderFooters.Get(hfType, HeaderFooterSection.Header, HeaderFooterAlignment.Left); + bool alignHf = page.HeaderFooters.AlignWithMargins; + var (hfBoxLeft, hfBoxWidth) = HeaderFooterBox(pageSettings, alignHf); if (leftH != null && !leftH.HasImage && ShapeHeaderFooterText(pageSettings, dictionaries, leftH, displayedPageNumber, totalPages)) { var ascent = leftH.Content.TextLines[0].LargestAscent; - var hfx = pageSettings.Margins.LeftPu; + var hfx = hfBoxLeft; var hfy = pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu - ascent; var text = new PdfCellContentLayout(pageSettings, dictionaries, leftH, hfx, hfy, 0, 0); + text.ScaleAnchorX = hfx; // left edge + text.ScaleAnchorY = hfy + ascent; text.Name = "LeftHeader"; - text.IsHeaderFooter = true; - text.GidsAndCharMap(dictionaries); - pageLayout.AddChild(text); + AddHeaderFooterTextPart(pageLayout, dictionaries, text, HeaderFooterSection.Header, HeaderFooterAlignment.Left, pageSettings, alignHf); } var centerH = page.HeaderFooters.Get(hfType, HeaderFooterSection.Header, HeaderFooterAlignment.Center); if (centerH != null && !centerH.HasImage && ShapeHeaderFooterText(pageSettings, dictionaries, centerH, displayedPageNumber, totalPages)) { var ascent = centerH.Content.TextLines[0].LargestAscent; - var hfx = pageSettings.Margins.LeftPu; + var hfx = hfBoxLeft; var hfy = pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu - ascent; - var hfWidth = pageSettings.PageSize.WidthPu - pageSettings.Margins.LeftPu - pageSettings.Margins.RightPu; + var hfWidth = hfBoxWidth; var text = new PdfCellContentLayout(pageSettings, dictionaries, centerH, hfx, hfy, hfWidth, 0); + text.ScaleAnchorX = hfx + hfWidth / 2d; + text.ScaleAnchorY = hfy + ascent; text.Name = "CenterHeader"; - text.IsHeaderFooter = true; - text.GidsAndCharMap(dictionaries); - pageLayout.AddChild(text); + AddHeaderFooterTextPart(pageLayout, dictionaries, text, HeaderFooterSection.Header, HeaderFooterAlignment.Center, pageSettings, alignHf); } var rightH = page.HeaderFooters.Get(hfType, HeaderFooterSection.Header, HeaderFooterAlignment.Right); if (rightH != null && !rightH.HasImage && ShapeHeaderFooterText(pageSettings, dictionaries, rightH, displayedPageNumber, totalPages)) { var ascent = rightH.Content.TextLines[0].LargestAscent; - var hfx = pageSettings.PageSize.WidthPu - pageSettings.Margins.RightPu; + var hfx = hfBoxLeft + hfBoxWidth; var hfy = pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu - ascent; var text = new PdfCellContentLayout(pageSettings, dictionaries, rightH, hfx, hfy, 0, 0); + text.ScaleAnchorX = hfx; + text.ScaleAnchorY = hfy + ascent; text.Name = "RightHeader"; - text.IsHeaderFooter = true; - text.GidsAndCharMap(dictionaries); - pageLayout.AddChild(text); + AddHeaderFooterTextPart(pageLayout, dictionaries, text, HeaderFooterSection.Header, HeaderFooterAlignment.Right, pageSettings, alignHf); } var leftF = page.HeaderFooters.Get(hfType, HeaderFooterSection.Footer, HeaderFooterAlignment.Left); if (leftF != null && !leftF.HasImage && ShapeHeaderFooterText(pageSettings, dictionaries, leftF, displayedPageNumber, totalPages)) { int last = leftF.Content.TextLines.Count - 1; var descent = leftF.Content.TextLines[last].LargestDescent; - var hfx = pageSettings.Margins.LeftPu; + var hfx = hfBoxLeft; var hfy = pageSettings.Margins.FooterPu + descent; var text = new PdfCellContentLayout(pageSettings, dictionaries, leftF, hfx, hfy, 0, 0); + text.ScaleAnchorX = hfx; + text.ScaleAnchorY = hfy - descent; text.Name = "LeftFooter"; - text.IsHeaderFooter = true; - text.GidsAndCharMap(dictionaries); - pageLayout.AddChild(text); + AddHeaderFooterTextPart(pageLayout, dictionaries, text, HeaderFooterSection.Footer, HeaderFooterAlignment.Left, pageSettings, alignHf); } var centerF = page.HeaderFooters.Get(hfType, HeaderFooterSection.Footer, HeaderFooterAlignment.Center); if (centerF != null && !centerF.HasImage && ShapeHeaderFooterText(pageSettings, dictionaries, centerF, displayedPageNumber, totalPages)) { int last = centerF.Content.TextLines.Count - 1; var descent = centerF.Content.TextLines[last].LargestDescent; - var hfx = pageSettings.PageSize.WidthPu / 2d; + var hfx = hfBoxLeft; var hfy = pageSettings.Margins.FooterPu + descent; - var text = new PdfCellContentLayout(pageSettings, dictionaries, centerF, hfx, hfy, 0, 0); + var hfWidth = hfBoxWidth; + var text = new PdfCellContentLayout(pageSettings, dictionaries, centerF, hfx, hfy, hfWidth, 0); + text.ScaleAnchorX = hfx + hfWidth / 2d; + text.ScaleAnchorY = hfy - descent; text.Name = "CenterFooter"; - text.IsHeaderFooter = true; - text.GidsAndCharMap(dictionaries); - pageLayout.AddChild(text); + AddHeaderFooterTextPart(pageLayout, dictionaries, text, HeaderFooterSection.Footer, HeaderFooterAlignment.Center, pageSettings, alignHf); } var rightF = page.HeaderFooters.Get(hfType, HeaderFooterSection.Footer, HeaderFooterAlignment.Right); if (rightF != null && !rightF.HasImage && ShapeHeaderFooterText(pageSettings, dictionaries, rightF, displayedPageNumber, totalPages)) { int last = rightF.Content.TextLines.Count - 1; var descent = rightF.Content.TextLines[last].LargestDescent; - var hfx = pageSettings.PageSize.WidthPu - pageSettings.Margins.RightPu; + var hfx = hfBoxLeft + hfBoxWidth; var hfy = pageSettings.Margins.FooterPu + descent; var text = new PdfCellContentLayout(pageSettings, dictionaries, rightF, hfx, hfy, 0, 0); + text.ScaleAnchorX = hfx; + text.ScaleAnchorY = hfy - descent; text.Name = "RightFooter"; - text.IsHeaderFooter = true; - text.GidsAndCharMap(dictionaries); - pageLayout.AddChild(text); + AddHeaderFooterTextPart(pageLayout, dictionaries, text, HeaderFooterSection.Footer, HeaderFooterAlignment.Right, pageSettings, alignHf); } double hfContentLeft = pageSettings.Margins.LeftPu; double hfContentWidth = pageSettings.PageSize.WidthPu - pageSettings.Margins.LeftPu - pageSettings.Margins.RightPu; @@ -372,17 +378,17 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio ? pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu - ascent : pageSettings.Margins.FooterPu + descent; double textY = System.Math.Min(naturalBaseline, imgBottom + descent); - + var part = new PdfHeaderFooterPart { ScalePivot = HeaderFooterPivot(hfSection, hfAlign, pageSettings, alignHf) }; double cursor = runStart; if (beforeRun != null) { - pageLayout.AddChild(PlaceHeaderFooterRun(pageSettings, dictionaries, beforeRun, cursor, textY)); + part.Items.Add(PlaceHeaderFooterRun(pageSettings, dictionaries, beforeRun, cursor, textY)); } cursor += beforeWidth; if (canEmbed) { - pageLayout.AddChild(new PdfImageLayout(cursor, imgTop, imgW, imgH) + part.Items.Add(new PdfImageLayout(cursor, imgTop, imgW, imgH) { ImageBytes = hf.ImageBytes, IsHeaderFooter = true, @@ -392,8 +398,10 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio cursor += imgW; if (afterRun != null) { - pageLayout.AddChild(PlaceHeaderFooterRun(pageSettings, dictionaries, afterRun, cursor, textY)); + part.Items.Add(PlaceHeaderFooterRun(pageSettings, dictionaries, afterRun, cursor, textY)); } + if (part.Items.Count > 0) + pageLayout.HeaderFooterParts.Add(part); } } } @@ -614,6 +622,60 @@ private static bool NeedsClipping(PdfCell map, Page page, int row, int col) } return false; } + private static (double clipX, double clipW, bool spillLeft, bool spillRight) GetOverflowClip(PdfCell map, Page page, int row, int col, double x, double effectiveWidth) + { + double clipX = x, clipW = effectiveWidth; + var a = map.ContentAligmnet; + if (a == null) + return (clipX, clipW, false, false); + var L = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Left; + var G = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.General; + var R = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Right; + var C = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Center; + var F = (EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment)ExcelHorizontalAlignment.Fill; + var h = a.HorizontalAlignment; + if (h == F || a.WrapText || map.TotalTextLength <= map.ColumnWidth) + return (clipX, clipW, false, false); + double ScanRight() + { + double w = 0d; + for (int c = col + 1; c <= page.ToColumn; c++) + { + var n = page.Map[row, c]; + if (!string.IsNullOrEmpty(n.Text)) break; + w += n.ColumnWidth; + } + return w; + } + double ScanLeft() + { + double w = 0d; + for (int c = col - 1; c >= page.FromColumn; c--) + { + var n = page.Map[row, c]; + if (!string.IsNullOrEmpty(n.Text)) break; + w += n.ColumnWidth; + } + return w; + } + if (h == L || h == G) + { + clipW = effectiveWidth + ScanRight(); + return (clipX, clipW, false, true); + } + if (h == R) + { + double extra = ScanLeft(); + return (x - extra, effectiveWidth + extra, true, false); + } + if (h == C) + { + double left = ScanLeft(), right = ScanRight(); + return (x - left, effectiveWidth + left + right, true, true); + } + return (clipX, clipW, false, false); + } + private static bool HasBorder(PdfCellStyle cellStyle) { @@ -1746,6 +1808,34 @@ private static bool ShapeHeaderFooterText(PdfPageSettings pageSettings, PdfDicti return hf.Content != null && hf.Content.TextLines != null && hf.Content.TextLines.Count > 0; } + private static Vector2 HeaderFooterPivot(HeaderFooterSection section, HeaderFooterAlignment align, PdfPageSettings ps, bool alignWithMargins) + { + var (left, width) = HeaderFooterBox(ps, alignWithMargins); + double x = align == HeaderFooterAlignment.Left ? left + : align == HeaderFooterAlignment.Right ? left + width + : left + width / 2d; + double y = section == HeaderFooterSection.Header + ? ps.PageSize.HeightPu - ps.Margins.HeaderPu + : ps.Margins.FooterPu; + return new Vector2(x, y); + } + private static (double Left, double Width) HeaderFooterBox(PdfPageSettings ps, bool alignWithMargins) + { + if (alignWithMargins) + return (ps.Margins.LeftPu, ps.PageSize.WidthPu - ps.Margins.LeftPu - ps.Margins.RightPu); + + double d = UnitConversion.MmToPoints(19.05); + return (d, ps.PageSize.WidthPu - 2d * d); + } + private static void AddHeaderFooterTextPart(PdfPageLayout pageLayout, PdfDictionaries dictionaries, PdfCellContentLayout text, HeaderFooterSection section, HeaderFooterAlignment align, PdfPageSettings ps, bool alignWithMargins) + { + text.IsHeaderFooter = true; + text.GidsAndCharMap(dictionaries); + var part = new PdfHeaderFooterPart { ScalePivot = HeaderFooterPivot(section, align, ps, alignWithMargins) }; + part.Items.Add(text); + pageLayout.HeaderFooterParts.Add(part); + } + private static void ApplyPageNumbers(PdfHeaderFooter hf, int pageNumber, int totalPages) { if (hf == null) return; diff --git a/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs b/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs index 130d29f9d..c7204d51f 100644 --- a/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfHeaderFooterCollection.cs @@ -157,21 +157,6 @@ 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 fedb501b0..9fa2b13a1 100644 --- a/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfTextMap.cs @@ -190,40 +190,31 @@ private static void HandleMergedCell(PdfPageSettings pageSettings, PdfDictionari tempMap.Merged = true; } - private static IEnumerable GetApplicableTableElements( - ExcelTable table, ExcelTableNamedStyle ts, int tableRow, int tableCol, ExcelRangeBase cell) + private static IEnumerable GetApplicableTableElements(ExcelTable table, ExcelTableNamedStyle ts, int tableRow, int tableCol, ExcelRangeBase cell) { var range = table.Range; bool firstCol = table.ShowFirstColumn && tableCol == 0; bool lastCol = table.ShowLastColumn && cell._fromCol == range._toCol; bool header = table.ShowHeader && tableRow == 0; bool total = table.ShowTotal && cell._fromRow == range._toRow; + yield return ts.WholeTable; // 1 + // column-spanning: header + data + total + if (table.ShowColumnStripes) + yield return (tableCol & 1) == 0 ? ts.FirstColumnStripe // 2 + : ts.SecondColumnStripe; // 3 + // row stripes: data rows only + if (!header && !total && table.ShowRowStripes) + yield return (tableRow & 1) != 0 ? ts.FirstRowStripe // 4 + : ts.SecondRowStripe; // 5 - yield return ts.WholeTable; // 1 (base) - - if (header) - { - yield return ts.HeaderRow; // 9 - if (firstCol) yield return ts.FirstHeaderCell; // 10 - if (lastCol) yield return ts.LastHeaderCell; // 11 - } - else if (total) - { - yield return ts.TotalRow; // 8 - if (firstCol) yield return ts.FirstTotalCell; // 12 - if (lastCol) yield return ts.LastTotalCell; // 13 - } - else // data rows (no stripes on header/total) - { - if (table.ShowColumnStripes) - yield return (tableCol & 1) == 0 ? ts.FirstColumnStripe // 2 - : ts.SecondColumnStripe; // 3 - if (table.ShowRowStripes) - yield return (tableRow & 1) != 0 ? ts.FirstRowStripe // 4 - : ts.SecondRowStripe; // 5 - if (lastCol) yield return ts.LastColumn; // 6 - if (firstCol) yield return ts.FirstColumn; // 7 - } + if (lastCol) yield return ts.LastColumn; // 6 + if (firstCol) yield return ts.FirstColumn; // 7 + if (total) yield return ts.TotalRow; // 8 + if (header) yield return ts.HeaderRow; // 9 + if (header && firstCol) yield return ts.FirstHeaderCell; // 10 + if (header && lastCol) yield return ts.LastHeaderCell; // 11 + if (total && firstCol) yield return ts.FirstTotalCell; // 12 + if (total && lastCol) yield return ts.LastTotalCell; // 13 } // Overlay only the font properties `src` actually specifies onto `dst`. All members are on the base type. diff --git a/src/EPPlus/Export/PdfExport/TextShaping/PdfTextShaper.cs b/src/EPPlus/Export/PdfExport/TextShaping/PdfTextShaper.cs index 4344c29a0..d86753b15 100644 --- a/src/EPPlus/Export/PdfExport/TextShaping/PdfTextShaper.cs +++ b/src/EPPlus/Export/PdfExport/TextShaping/PdfTextShaper.cs @@ -83,6 +83,19 @@ public static void ShapeText(PdfPageSettings pageSettings, PdfDictionaries dicti cell.TextFragments[i] = tf; cell.ShapedTexts[i] = st; } + if (cell.ContentAligmnet?.ShrinkToFit == true && cell.ContentAligmnet?.WrapText != true && cell.ContentAligmnet?.IsVertical != true) + { + double hInset = 1.4d; + double cw = (cell.Merged && cell.Main == null) ? cell.Width : cell.ColumnWidth; + double avail = cw - 2d * hInset; + if (avail > 0 && totalTextLength > avail) + { + float shrink = (float)(avail / totalTextLength); + foreach (var tf in cell.TextFragments) + tf.Font.Size *= shrink; + totalTextLength *= shrink; + } + } if (cell.TextLayoutEngine != null) { double wrapWidth = (cell.Merged && cell.Main == null) ? cell.Width : cell.ColumnWidth;