diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfBorderRenderer.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfBorderRenderer.cs index cab8e0dfc..7031399f4 100644 --- a/src/EPPlus.Export.Pdf/DocumentObjects/PdfBorderRenderer.cs +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfBorderRenderer.cs @@ -51,7 +51,6 @@ public PdfBorderRenderer(PdfCellBorderLayout cell) public void RenderBorder(PdfContentStream contentStream) { - contentStream.AddCommand($"% Border Start: {Name}"); contentStream.AddCommand("q"); if (Top != null) RenderBorder(contentStream, Top); if (Bottom != null) RenderBorder(contentStream, Bottom); @@ -60,12 +59,10 @@ public void RenderBorder(PdfContentStream contentStream) if (DiagonalUp != null) RenderBorder(contentStream, DiagonalUp); if (DiagonalDown != null) RenderBorder(contentStream, DiagonalDown); contentStream.AddCommand("Q"); - contentStream.AddCommand($"% Border End: {Name}"); } private void RenderBorder(PdfContentStream contentStream, PdfCellBorderData border) { - contentStream.AddCommand($"% Border Type Start: {border.LineType.ToString()}"); double x1 = X, y1 = Y, x2 = X, y2 = Y; switch (border.LineType) { @@ -132,7 +129,6 @@ private void RenderBorder(PdfContentStream contentStream, PdfCellBorderData bord contentStream.AddCommand($"{x1.ToPdfStringF4()} {y1.ToPdfStringF4()} m"); contentStream.AddCommand($"{x2.ToPdfStringF4()} {y2.ToPdfStringF4()} l"); contentStream.AddCommand("S"); - contentStream.AddCommand($"% Border Type End: {border.LineType.ToString()}"); return; } switch (border.BorderStyle) @@ -182,7 +178,6 @@ private void RenderBorder(PdfContentStream contentStream, PdfCellBorderData bord contentStream.AddCommand($"{x1.ToPdfStringF4()} {y1.ToPdfStringF4()} m"); contentStream.AddCommand($"{x2.ToPdfStringF4()} {y2.ToPdfStringF4()} l"); contentStream.AddCommand("S"); - contentStream.AddCommand($"% Border Type End: {border.LineType.ToString()}"); } private void DrawBasicBorder(PdfContentStream contentStream, PdfCellBorderData border, double width, string dash) diff --git a/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs b/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs index 9b12b8912..1c8d972c9 100644 --- a/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs +++ b/src/EPPlus.Export.Pdf/DocumentObjects/PdfContentStream.cs @@ -60,18 +60,15 @@ public void AddCellLayout(PdfCellLayout cell, string label) if (cell.Size.X <= 0d || cell.Size.Y <= 0d) return; if (cell.CellFillData.GradientFillData != null && cell.CellFillData.PatternStyle != ExcelFillStyle.Solid) { - commands.Add($"% Pattern Start: {cell.Name}"); commands.Add("q"); commands.Add("/Pattern cs"); commands.Add($"/{label} scn"); commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re"); commands.Add("f"); commands.Add("Q"); - commands.Add($"% Pattern End: {cell.Name}"); } else if (cell.CellFillData.BackgroundColor != Color.Empty && cell.CellFillData.PatternStyle == ExcelFillStyle.Solid) { - commands.Add($"% Solid Fill Start: {cell.Name}"); commands.Add("q"); commands.Add($"{GridLine.HalfWidth.ToPdfString()} w"); commands.Add(cell.CellFillData.BackgroundColor.ToFillCommand()); @@ -79,11 +76,9 @@ public void AddCellLayout(PdfCellLayout cell, string label) commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re"); commands.Add("B"); commands.Add("Q"); - commands.Add($"% Solid Fill End: {cell.Name}"); } else if (cell.CellFillData.PatternStyle != ExcelFillStyle.None) { - commands.Add($"% Pattern Start: {cell.Name}"); if (cell.CellFillData.BackgroundColor != Color.Empty) { commands.Add("q"); @@ -94,14 +89,12 @@ public void AddCellLayout(PdfCellLayout cell, string label) commands.Add("B"); commands.Add("Q"); } - commands.Add("q"); commands.Add("/Pattern cs"); commands.Add($"/{label} scn"); commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re"); commands.Add("f"); commands.Add("Q"); - commands.Add($"% Pattern End: {cell.Name}"); } } @@ -372,12 +365,10 @@ private static ushort GetUnitsPerEm(ushort[] fontUnitsPerEm, byte fontId, ushort public void AddCellContentLayout(PdfCellContentLayout cell, PdfDictionaries dictionaries, PdfPageSettings pageSettings) { - commands.Add($"% Content Start: {cell.Name}"); commands.Add("q"); if (cell.Clip) AddClipping(cell); AddText(cell, cell.LocalPosition, cell.CellAlignmentData.TextRotation, dictionaries, pageSettings); commands.Add("Q"); - commands.Add($"% Content End: {cell.Name}"); } private void AddClipping(PdfCellContentLayout cell) @@ -389,8 +380,6 @@ public void AddInnerGridLines(Transform pageLayout) { if (pageLayout is not PdfPageLayout pl) return; if (pl.isCommentsPage) return; - - commands.Add($"% Gridlines Start"); commands.Add("q"); commands.Add($"{GridLine.Width.ToPdfString()} w"); commands.Add(Color.Black.ToFillCommand()); @@ -413,24 +402,20 @@ public void AddInnerGridLines(Transform pageLayout) } commands.Add("f"); commands.Add("Q"); - commands.Add($"% Gridlines End"); } public void AddImage(string label, double x, double y, double width, double height) { - commands.Add($"% Image Start: {label}"); commands.Add("q"); commands.Add($"{width.ToPdfString()} 0 0 {height.ToPdfString()} {x.ToPdfString()} {y.ToPdfString()} cm"); commands.Add($"/{label} Do"); commands.Add("Q"); - commands.Add($"% Image End: {label}"); } public void AddPrintTitleGridLines(Transform pageLayout) { if (pageLayout is not PdfPageLayout pl) return; if (pl.isCommentsPage) return; - commands.Add($"% Print Title Gridlines Start"); commands.Add("q"); commands.Add($"{GridLine.Width.ToPdfString()} w"); commands.Add(Color.Black.ToFillCommand()); @@ -453,7 +438,6 @@ public void AddPrintTitleGridLines(Transform pageLayout) } commands.Add("f"); commands.Add("Q"); - commands.Add($"% Print Title Gridlines End"); } public void AddOuterGridBorder(Transform pageLayout) @@ -461,7 +445,6 @@ public void AddOuterGridBorder(Transform pageLayout) if (pageLayout is not PdfPageLayout pl) return; if (pl.isCommentsPage) return; - commands.Add($"% Gridlines Border Start"); commands.Add("q"); commands.Add("1.0 w"); commands.Add("2 J"); @@ -474,14 +457,12 @@ public void AddOuterGridBorder(Transform pageLayout) } commands.Add("S"); commands.Add("Q"); - commands.Add($"% Gridlines Border End"); } public void AddMarginClipping(PdfPageLayout pageLayout, PdfPageSettings pageSettings) { if (pageLayout is not PdfPageLayout pl) return; if (pageLayout.isCommentsPage) return; - commands.Add($"% Margin Clip Start"); if (pl.BorderLines.Count == 0) return; double top = double.MinValue; double bottom = double.MaxValue; diff --git a/src/EPPlus.Export.Pdf/ExcelPdf.cs b/src/EPPlus.Export.Pdf/ExcelPdf.cs index 6da361832..4616a1b06 100644 --- a/src/EPPlus.Export.Pdf/ExcelPdf.cs +++ b/src/EPPlus.Export.Pdf/ExcelPdf.cs @@ -31,7 +31,7 @@ namespace EPPlus.Export.Pdf /// internal class ExcelPdf { - private PdfDocumentSettings _documentSettings; + private PdfDocumentSettings _documentSettings; private PdfDictionaries _dictionaries; internal List _document = new List(); private string _debugString; @@ -184,13 +184,13 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) var cells = pageLayout.ChildObjects.Where(t => (t is PdfCellLayout || t is PdfCellContentLayout || t is PdfCellBorderLayout) && !(t is PdfCellLayout cc && (cc.IsHeading || cc.IsPrintTitle)) && - !(t is PdfCellContentLayout ccl && (ccl.IsHeaderFooter || ccl.IsHeading || ccl.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 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)); var contentStream = new PdfContentStream(_document.Count + 1); - contentStream.AddCommand($"% {pageLayout.Name} start"); //Start page content clipping rectangle. contentStream.AddCommand("q"); contentStream.AddContentScale(contentScale, scaleAnchorX, scaleAnchorY); @@ -201,17 +201,14 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) } foreach (PdfCellLayout fill in cells.OfType()) { - contentStream.AddCommand($"% CELL FILL : {fill.Name}"); contentStream.AddCellLayout(fill, GetPatternLabel(fill)); } foreach (PdfCellContentLayout content in cells.OfType()) { - contentStream.AddCommand($"% CELL TEXT : {content.Name}"); contentStream.AddCellContentLayout(content, _dictionaries, pageSettings); } foreach (PdfCellBorderLayout border in cells.OfType()) { - contentStream.AddCommand($"% CELL BORDER : {border.Name}"); contentStream.AddBorderLayout(border); } foreach (PdfImageLayout image in pageLayout.ChildObjects.OfType()) @@ -223,13 +220,11 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) } //Close the clipping rectangle. 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}"); switch (heading) { case PdfCellLayout layout: @@ -268,7 +263,6 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) contentStream.AddContentScale(contentScale, scaleAnchorX, scaleAnchorY); foreach (var titleCell in printTitleLayouts) { - contentStream.AddCommand($"% PRINT TITLE : {titleCell.Name}"); switch (titleCell) { case PdfCellLayout layout: @@ -280,9 +274,12 @@ private void AddContent(PdfPageLayout pageLayout, PdfPage page) } } contentStream.AddCommand("Q"); + foreach (var content in AdditionalContent) + { + contentStream.AddCellContentLayout(content, _dictionaries, pageSettings); + } _document.Add(contentStream); page.contentObjectNumbers.Add(contentStream.objectNumber); - contentStream.AddCommand($"% {pageLayout.Name} end"); } //Add Info @@ -337,7 +334,7 @@ internal void CreatePdf(PdfDocumentSettings documentSettings, PdfDictionaries di //Create Page and Content for (int i = 0; i < layout.ChildObjects.Count; i++) { - var pageLayout = (PdfPageLayout)layout.ChildObjects[i]; + var pageLayout = (PdfPageLayout)layout.ChildObjects[i]; var page = AddPage(2, new List(), pageLayout.Settings); AddContent(pageLayout, page); pages.pageObjectNumbers.Add(page.objectNumber); diff --git a/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs b/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs index 3dc9eeae4..1005c3b5d 100644 --- a/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs +++ b/src/EPPlus.Export.Pdf/Layout/PdfCellContentLayout.cs @@ -29,6 +29,7 @@ internal class PdfCellContentLayout : Transform public bool Clip; public Rect Clipping; public bool IsHeaderFooter; + public bool IsAddedContent; public bool IsHeading; public bool IsPrintTitle; public TextLayoutEngine textLayoutEngine; @@ -40,7 +41,7 @@ internal class PdfCellContentLayout : Transform public List ShapedTexts { get; set; } - public PdfCellContentLayout(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfCellBase cell, MergedCellDrawInfo mergedCellInfo, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null) + public PdfCellContentLayout(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfCellBase cell, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null) : base(x, y-height, width, height, scaleX, scaleY, rotation, parent) { Z = 2; @@ -100,8 +101,21 @@ private double CalculateHorizontalAlignment(string text, double textLength, doub double newX = x; switch (CellAlignmentData.HorizontalAlignment) { + case ExcelHorizontalAlignment.Left: + newX = x + padding; + break; + case ExcelHorizontalAlignment.Center: + case ExcelHorizontalAlignment.CenterContinuous: + newX = x + (width - textLength) / 2d; + break; + case ExcelHorizontalAlignment.Right: + newX = x + (width - textLength) - padding; + break; + case ExcelHorizontalAlignment.Distributed: + case ExcelHorizontalAlignment.Justify: case ExcelHorizontalAlignment.Fill: case ExcelHorizontalAlignment.General: + default: if (double.TryParse(text, out double value)) { newX = x + (width - textLength) - padding; @@ -111,18 +125,6 @@ private double CalculateHorizontalAlignment(string text, double textLength, doub newX = x + padding; } break; - case ExcelHorizontalAlignment.Left: - case ExcelHorizontalAlignment.Justify: - case ExcelHorizontalAlignment.Distributed: - newX = x + padding; - break; - case ExcelHorizontalAlignment.Center: - case ExcelHorizontalAlignment.CenterContinuous: - newX = x + (width - textLength) / 2d; - break; - case ExcelHorizontalAlignment.Right: - newX = x + (width - textLength) - padding; - break; } return newX; } diff --git a/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooter.cs b/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooter.cs index 6831d092b..74923b715 100644 --- a/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooter.cs +++ b/src/EPPlus.Export.Pdf/Layout/PdfHeaderFooter.cs @@ -32,7 +32,7 @@ internal enum HeaderFooterAlignment internal enum HeaderFooterSection { Header = 0, - Footer = 1 + Footer = 1, } internal class PdfHeaderFooter diff --git a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs index 24e1bad2d..fe96ac403 100644 --- a/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs +++ b/src/EPPlus.Export.Pdf/Settings/PdfPageSettings.cs @@ -12,7 +12,6 @@ Date Author Change *************************************************************************************************/ using EPPlus.Export.Pdf.Settings.PdfPageSizes; using EPPlus.Fonts.OpenType; -using OfficeOpenXml; using OfficeOpenXml.Interfaces.Fonts; using System.Collections.Generic; @@ -241,6 +240,8 @@ internal double ContentScale internal PdfContentBounds ContentBounds = new PdfContentBounds(PdfMargins.Normal, PdfPageSize.A4); internal string defaultFontName = ""; + internal string AdditionalContent; + //DEBUG internal bool Debug = false; internal bool PrintAsText = false; @@ -270,6 +271,7 @@ internal PdfPageSettings CloneForSheet() c.GposFeatures = GposFeatures; c.Debug = Debug; c.PrintAsText = PrintAsText; + c.AdditionalContent = AdditionalContent; return c; } } diff --git a/src/EPPlus/Export/PdfExport/Data/PageData.cs b/src/EPPlus/Export/PdfExport/Data/PageData.cs index 444d21966..c8c48b1bd 100644 --- a/src/EPPlus/Export/PdfExport/Data/PageData.cs +++ b/src/EPPlus/Export/PdfExport/Data/PageData.cs @@ -31,6 +31,7 @@ internal struct Page public double PrintTitleHeight; public PdfCellCollection Map; public PdfHeaderFooterCollection HeaderFooters; + public PdfAdditionalContent AddedContent; public Dictionary MergedCells; public List Images; public List PrintTitleCells; diff --git a/src/EPPlus/Export/PdfExport/Data/PdfWorksheet.cs b/src/EPPlus/Export/PdfExport/Data/PdfWorksheet.cs index 9a7c00919..7b3e74167 100644 --- a/src/EPPlus/Export/PdfExport/Data/PdfWorksheet.cs +++ b/src/EPPlus/Export/PdfExport/Data/PdfWorksheet.cs @@ -25,6 +25,7 @@ internal class PdfWorksheet public List Ranges = null; public PdfRange CommentsAndNotes; public PdfHeaderFooterCollection HeaderFooters = null; + public PdfAdditionalContent AdditionalContent = null; public double ZeroCharWidth; public int ToRow; public int PrintTitleRowFrom = -1; diff --git a/src/EPPlus/Export/PdfExport/PdfCatalog.cs b/src/EPPlus/Export/PdfExport/EPPlusToPdfWriter.cs similarity index 95% rename from src/EPPlus/Export/PdfExport/PdfCatalog.cs rename to src/EPPlus/Export/PdfExport/EPPlusToPdfWriter.cs index 3056b22c2..c54d316b7 100644 --- a/src/EPPlus/Export/PdfExport/PdfCatalog.cs +++ b/src/EPPlus/Export/PdfExport/EPPlusToPdfWriter.cs @@ -40,6 +40,13 @@ internal class EPPlusToPdfWriter { internal PdfDictionaries _dictionaries = new PdfDictionaries(); private bool _addTextForHeadings = true; + private static bool IsFullEdition + { + get + { + return (int) ExcelPackage.License.LicenseType == (int) EPPlusLicenseType.Commercial; + } + } // Captures which "build" method to run (worksheet collection, single worksheet or range // collection) together with the data it needs, but NOT the destination (file/stream). @@ -75,7 +82,7 @@ private void HandleWorksheetCollection(PdfPageSettings pageSettings, ExcelWorksh { // Match the single-worksheet path: resolve the default font before building. pageSettings.defaultFontName = worksheets[0].Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; - + pageSettings.AdditionalContent = AddAdditionalContent(); PdfWorksheet[] pdfSheets = null; try { @@ -122,9 +129,17 @@ public EPPlusToPdfWriter(PdfPageSettings pageSettings, ExcelWorksheet worksheet) _build = writePdf => BuildPdf(pageSettings, worksheet, writePdf); } + private static string AddAdditionalContent() + { + if (IsFullEdition) + return "FullEdition"; + return "null"; + } + private void BuildPdf(PdfPageSettings pageSettings, ExcelWorksheet worksheet, Action writePdf) { pageSettings.defaultFontName = worksheet.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; + pageSettings.AdditionalContent = AddAdditionalContent(); PdfWorksheet pdfSheet = null; try { @@ -169,7 +184,7 @@ public EPPlusToPdfWriter(PdfPageSettings pageSettings, ExcelRangeBase range) private void BuildPdfFromRange(PdfPageSettings pageSettings, ExcelRangeBase range, Action writePdf) { pageSettings.defaultFontName = range.Worksheet.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; - + pageSettings.AdditionalContent = AddAdditionalContent(); PdfWorksheet pdfSheet = null; try { @@ -204,7 +219,7 @@ public EPPlusToPdfWriter(PdfPageSettings pageSettings, List rang private void HandleRangeCollection(PdfPageSettings pageSettings, ExcelRangeBase[] ranges, Action writePdf) { pageSettings.defaultFontName = ranges[0].Worksheet.Workbook.ThemeManager.GetOrCreateTheme().FontScheme.MinorFont[0].Typeface; - + pageSettings.AdditionalContent = AddAdditionalContent(); PdfWorksheet[] pdfSheets = null; try { @@ -314,6 +329,9 @@ internal void BuildSubsets(PdfPageSettings pageSettings) internal void ShapeTextInPdfWorksheet(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) { IterateCells(pdfSheet, cell => PdfTextShaper.ShapeText(pageSettings, _dictionaries, cell)); + + if (pdfSheet.AdditionalContent != null) + PdfTextShaper.ShapeText(pageSettings, _dictionaries, pdfSheet.AdditionalContent.content); } private void IterateCells(PdfWorksheet pdfSheet, System.Action action) @@ -363,6 +381,7 @@ internal PdfWorksheet GetPdfWorksheet(PdfPageSettings pageSettings, ExcelWorkshe GetMaps(pageSettings, pdfSheet, pdfSheet.Ranges); GetPrintTitles(pageSettings, pdfSheet); GetHeaderFooter(pageSettings, pdfSheet); + GetAdditionalContent(pageSettings, pdfSheet); GetCommentsAndNotes(pageSettings, pdfSheet); ReadDrawings(pdfSheet); return pdfSheet; @@ -379,6 +398,7 @@ private PdfWorksheet GetPdfWorksheet(PdfPageSettings pageSettings, ExcelRangeBas pdfSheet.Ranges[0] = GetMaps(pageSettings, pdfSheet, pdfSheet.Ranges[0]); GetPrintTitles(pageSettings, pdfSheet); GetHeaderFooter(pageSettings, pdfSheet); + GetAdditionalContent(pageSettings, pdfSheet); GetCommentsAndNotes(pageSettings, pdfSheet); ReadDrawings(pdfSheet); return pdfSheet; @@ -427,6 +447,7 @@ private PdfWorksheet GetPdfWorksheet(PdfPageSettings pageSettings, ExcelWorkshee GetMaps(pageSettings, pdfSheet, pdfSheet.Ranges); GetPrintTitles(pageSettings, pdfSheet); GetHeaderFooter(pageSettings, pdfSheet); + GetAdditionalContent(pageSettings, pdfSheet); GetCommentsAndNotes(pageSettings, pdfSheet); ReadDrawings(pdfSheet); return pdfSheet; @@ -555,6 +576,11 @@ private static void MarkPrintTitleCells(PdfWorksheet pdfSheet, PdfRange range) } } + private void GetAdditionalContent(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) + { + pdfSheet.AdditionalContent = string.IsNullOrEmpty(pageSettings.AdditionalContent) ? null : new PdfAdditionalContent(pageSettings, _dictionaries, pdfSheet.Worksheet); + } + private void GetHeaderFooter(PdfPageSettings pageSettings, PdfWorksheet pdfSheet) { pdfSheet.HeaderFooters = new PdfHeaderFooterCollection(pageSettings, _dictionaries, pdfSheet, pdfSheet.Worksheet.HeaderFooter); diff --git a/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs index 9d2d9d3c5..90e6b728a 100644 --- a/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs +++ b/src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs @@ -154,7 +154,7 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio var sourceMap = (map.TextLines != null && map.TextLines.Count > 0) ? map : (map.Main != null && map.Main.TextLines != null && map.Main.TextLines.Count > 0) ? map.Main : null; if (sourceMap != null) { - var text = new PdfCellContentLayout(pageSettings, dictionaries, sourceMap, info, info.X, info.Y, info.Width, info.Height); + var text = new PdfCellContentLayout(pageSettings, dictionaries, sourceMap, info.X, info.Y, info.Width, info.Height); text.Name = map.Name; text.GidsAndCharMap(dictionaries); text.SetupClipping(info.X, info.Y, info.Width, info.Height); @@ -200,7 +200,7 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio //Text if (map.TextLines != null && map.TextLines.Count > 0) { - var text = new PdfCellContentLayout(pageSettings, dictionaries, map, info, x, y, effectiveWidth, rowHeight); + 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)) @@ -397,6 +397,25 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio } } } + if (page.AddedContent != null && page.AddedContent.content?.TextLines != null && page.AddedContent.content.TextLines.Count > 0) + { + var content = page.AddedContent.content; + int last = content.TextLines.Count - 1; + var descent = content.TextLines[last].LargestDescent; + var ascent = content.TextLines[last].LargestAscent; + var sx = 10d; + var sy = descent + 2d; + var width = pageSettings.PageSize.WidthPu - pageSettings.Margins.LeftPu - pageSettings.Margins.RightPu; + var cellcont = new PdfCellContentLayout(pageSettings, dictionaries, content, sx, sy, width, 0); + cellcont.IsAddedContent = true; + cellcont.GidsAndCharMap(dictionaries); + pageLayout.AddChild(cellcont); + sy = pageSettings.PageSize.HeightPu - (descent + ascent + 4d); + cellcont = new PdfCellContentLayout(pageSettings, dictionaries, content, sx, sy, width, 0); + cellcont.IsAddedContent = true; + cellcont.GidsAndCharMap(dictionaries); + pageLayout.AddChild(cellcont); + } PdfGridlinesLayout.AddGridLines(pageSettings, pages[j], pageLayout, borderOnly: !pageSettings.ShowGridLines || pdfPages[i].IsCommentsPage); pageLayout.ChildObjects.Sort((a, b) => { @@ -623,7 +642,7 @@ private static void AddHeadingCell(PdfPageSettings pageSettings, PdfDictionaries if (cell.TextLines != null && cell.TextLines.Count > 0) { var info = new MergedCellDrawInfo { X = x, Y = y, Width = width, Height = height }; - var text = new PdfCellContentLayout(pageSettings, dictionaries, cell, info, x, y, width, height); + var text = new PdfCellContentLayout(pageSettings, dictionaries, cell, x, y, width, height); text.Name = namePrefix + "_Text"; text.IsHeading = true; text.GidsAndCharMap(dictionaries); @@ -727,7 +746,7 @@ private static void AddSpillCells(PdfPageSettings pageSettings, PdfDictionaries if (map.TextLines == null || map.TextLines.Count == 0) continue; if (s.ClipWidth <= 0d || s.ClipHeight <= 0d) continue; - var text = new PdfCellContentLayout(pageSettings, dictionaries, map, new MergedCellDrawInfo(), s.X, s.Y, s.Width, s.Height); + var text = new PdfCellContentLayout(pageSettings, dictionaries, map, s.X, s.Y, s.Width, s.Height); text.Name = "Spill_" + map.Name; text.IsPrintTitle = s.IsPrintTitle; text.GidsAndCharMap(dictionaries); @@ -753,7 +772,7 @@ private static void AddPrintTitleCells(PdfPageSettings pageSettings, PdfDictiona if (map.TextLines != null && map.TextLines.Count > 0) { var info = new MergedCellDrawInfo { X = t.X, Y = t.Y, Width = t.Width, Height = t.Height }; - var text = new PdfCellContentLayout(pageSettings, dictionaries, map, info, t.X, t.Y, t.Width, t.Height); + var text = new PdfCellContentLayout(pageSettings, dictionaries, map, t.X, t.Y, t.Width, t.Height); text.Name = map.Name; text.IsPrintTitle = true; text.GidsAndCharMap(dictionaries); @@ -938,6 +957,7 @@ internal static List GetPages(PdfPageSettings[] sheetSettings, PdfWorkshe pages = AssignRangeToPages(pageSettings, range, pages); pages = MapPage(range, pages); pages = GetHeaderFooter(range, pages, pdfSheet); + pages = GetAdditionalContent(pages, pdfSheet); pages = PrecomputeMergedCells(pageSettings, range, pages); pages = PrecomputeSpillCells(pageSettings, range, pages); pages = PrecomputePrintTitleCells(pageSettings, pdfSheet, range, pages); @@ -957,6 +977,7 @@ internal static List GetPages(PdfPageSettings[] sheetSettings, PdfWorkshe pages = AssignRangeToPages(pageSettings, pdfSheet.CommentsAndNotes, pages); pages = MapPage(pdfSheet.CommentsAndNotes, pages); pages = GetHeaderFooter(pdfSheet.CommentsAndNotes, pages, pdfSheet); + pages = GetAdditionalContent(pages, pdfSheet); pageSettings.ShowHeadings = savedShowHeadings; pages.IsCommentsPage = true; pages.Settings = pageSettings; @@ -1701,6 +1722,17 @@ private static Pages GetHeaderFooter(PdfRange range, Pages pdfPages, PdfWorkshee return pdfPages; } + private static Pages GetAdditionalContent(Pages pdfPages, PdfWorksheet pdfSheet) + { + for (int i = 0; i < pdfPages.Page.Length; i++) + { + var page = pdfPages.Page[i]; + page.AddedContent = pdfSheet.AdditionalContent; + pdfPages.Page[i] = page; + } + return pdfPages; + } + private static void SubstitutePageNumbers(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfHeaderFooter hf, int pageNumber, int totalPages) { if (hf == null) return; diff --git a/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs b/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs index 1e38fa97b..cb93622c7 100644 --- a/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs +++ b/src/EPPlus/Export/PdfExport/Settings/GetPdfSettings.cs @@ -21,6 +21,7 @@ internal static class GetPdfSettings { internal static PdfPageSettings GetPdfSettingsFromPrinterSettings(ExcelWorkbook workbook, ExcelPrinterSettings eps) { + bool stampNonCommercial = ExcelPackage.License.LicenseType == EPPlusLicenseType.NonCommercialOrganization; var settings = new PdfPageSettings(workbook.RenderContext.FontEngine); ApplyPrinterSettings(settings, eps); return settings; diff --git a/src/EPPlus/Export/PdfExport/TextMapping/PdfAdditionalContent.cs b/src/EPPlus/Export/PdfExport/TextMapping/PdfAdditionalContent.cs new file mode 100644 index 000000000..083a6ae4a --- /dev/null +++ b/src/EPPlus/Export/PdfExport/TextMapping/PdfAdditionalContent.cs @@ -0,0 +1,93 @@ +/************************************************************************************************* + 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.Layout; +using EPPlus.Export.Pdf.Resources; +using EPPlus.Export.Pdf.Settings; +using EPPlus.Fonts.OpenType.Integration; +using EPPlus.Fonts.OpenType.Integration.DataHolders; +using OfficeOpenXml.Interfaces.Fonts; +using System.Collections.Generic; +using System.Drawing; + +namespace OfficeOpenXml.Export.PdfExport.TextMapping +{ + internal class PdfAdditionalContent + { + internal static readonly Color TextColor = Color.Gray; + internal const float FontSize = 7f; + internal PdfCellBase content; + + public PdfAdditionalContent(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelWorksheet ws) + { + if (string.IsNullOrEmpty(pageSettings.AdditionalContent)) + { + return; + } + else + { + var ns = ws.Workbook.Styles.GetNormalStyle(); + var fragment = new TextFragment + { + Font = new RichTextFormatSimple + { + Family = ns.Style.Font.Name, + Size = FontSize, + SubFamily = FontSubFamily.Regular, + }, + Text = ComposeAdditionalContent(), + }; + fragment.RichTextOptions.UnderlineType = 12; + fragment.RichTextOptions.StrikeType = 1; + fragment.RichTextOptions.FontColor = TextColor; + content = new PdfCellBase + { + TextFragments = new List { fragment }, + ContentAligmnet = new PdfCellAlignmentData + { + HorizontalAlignment = EPPlus.Export.Pdf.Enums.ExcelHorizontalAlignment.Left, + VerticalAlignment = EPPlus.Export.Pdf.Enums.ExcelVerticalAlignment.Bottom, + }, + }; + dictionaries.AddFont(pageSettings, fragment.Font.Family, fragment.Font.SubFamily, fragment.Text); + } + } + + private static string ComposeAdditionalContent() + { + byte[] d = + { + 0xF3, 0xAE, 0x8C, 0x77, 0x03, 0x12, 0x25, 0xC6, 0xBF, 0xC9, 0xBC, 0x8F, + 0x3B, 0x5F, 0x21, 0x08, 0xF8, 0xC4, 0xA1, 0x91, 0x77, 0x12, 0x24, 0x03, + 0xE6, 0xC0, 0xAA, 0xCC, 0x4E, 0x7A, 0x19, 0x04, 0xF2, 0xD5, 0xE5, 0x91, + 0x6D, 0x46, 0x24, 0x12, 0x5F, 0xFF, 0x9D, 0xB2, 0x94, 0x74, 0x14, 0x3B, + 0x18, 0xFB, 0xD8, 0xB1, 0x81, 0x71, 0x58, 0x31, 0x03, 0xAE, 0xC1, 0xA5, + 0x88, 0x6F, 0x47, 0x3B, 0x02, 0xA6, 0xC3, 0xAB, 0x91, 0x22, 0x51, 0x25, + 0x2D, 0x0D, 0xF2, 0xD2, 0xBA, 0x96, 0x39, 0x57, 0x25, 0x56, 0xFB, 0xDB, + 0xBD, 0xDF, 0x72, 0x5F, 0x22, 0x03, 0xE8, 0xDE, 0xA8, 0x83, 0x68, 0x44, + 0x67, 0x13, 0xF6, 0xC1, 0xED, 0xC2, 0x55, 0x4F, 0x1F, 0x2C, 0x18, 0xF1, + 0xD4, 0xAC, 0x9C, 0x38, 0x43, 0x3E, 0x1C, 0xE7, 0x93, 0xBC, 0x9E, 0x64, + 0x46, 0x2D, 0x08, 0xA0, 0x8B, 0xBC, 0x80, 0x7B, 0x4E, 0x32, 0x45, 0xEC, + 0xD7, 0xB6, 0x91, 0x73, 0x25, 0x11, 0x72, 0x0B, 0xEC, 0xCD, 0xF7, 0x9D, + 0x67, 0x46, 0x39, 0x01, 0xE0, 0xC1, 0xBE, 0x96, 0x7B, 0x59, 0x2C, 0x1E, + 0xEE, 0x84, 0xAA, 0x87, 0x6A, 0x09, 0x65, 0x10, 0xEC, 0x82, 0xB1, 0x95, + 0x8D, 0x7D, 0x5C, 0x2F, 0x1E, 0xBA, 0xD8, 0xF8, 0x9B, 0x7F, 0x56, 0x31, + 0x1D, 0xE1, 0xD4, 0xFE, + }; + const int a = 0xA7, m = 31; + var buf = new char[d.Length]; + for (int i = 0; i < d.Length; i++) + buf[i] = (char)(d[i] ^ ((a + i * m) & 0xFF)); + return new string(buf); + } + } +}