Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/EPPlus.Export.Pdf.Tests/PdfTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Date Author Change
using EPPlus.Export.Pdf.Settings.PdfPageSizes;
using OfficeOpenXml;
using OfficeOpenXml.Export.PdfExport;
using OfficeOpenXml.Export.PdfExport.Data;
using OfficeOpenXml.Export.PdfExport.Layout;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
using OfficeOpenXml.Export.PdfExport.Settings;
using OfficeOpenXml.Style;
using System.Diagnostics;
Expand Down Expand Up @@ -761,5 +764,39 @@ public void EachWorksheetUsesItsOwnPaperSize()
}
}

[TestMethod]

public void GetOriginX_CenteringOff_ReturnsContentBoundsLeft()
{
var s = new PdfPageSettings(null);
var p = new Page()
{
FromRow = 1, ToRow = 10, FromColumn = 1, ToColumn = 5,
UsedWidth = 100,
UsedHeight = 100,
RowHeights = new double[10]
};

Assert.AreEqual(s.ContentBounds.Left, PdfLayout.GetOriginX(s, p), 0.0001);
}

[TestMethod]
public void GetOrigin_FlagsAreIndependent()
{
var s = new PdfPageSettings(null);
s.CenterOnPageHorizontally = true;
var p = new Page()
{
FromRow = 1,
ToRow = 10,
FromColumn = 1,
ToColumn = 5,
UsedWidth = s.ContentBounds.Width - 100d,
UsedHeight = s.ContentBounds.Height - 200d,
RowHeights = new double[10]
};
Assert.AreEqual(s.ContentBounds.Left + 50d, PdfLayout.GetOriginX(s, p), 0.0001);
Assert.AreEqual(s.ContentBounds.Top, PdfLayout.GetOriginY(s, p), 0.0001);
}
}
}
2 changes: 2 additions & 0 deletions src/EPPlus/Export/PdfExport/Data/PageData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ internal struct Page
public double[] RowHeights;
public double HeadingWidth;
public double HeadingHeight;
public double UsedWidth;
public double UsedHeight;
}

internal struct Pages
Expand Down
11 changes: 6 additions & 5 deletions src/EPPlus/Export/PdfExport/Layout/PdfGridlinesLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static void AddGridLines(PdfPageSettings pageSettings, Page page, PdfPage
// colX[ci] = X of left edge of column ci (0-based within page).
// colX[colCount] = X of right edge of last column.
var colX = new double[colCount + 1];
colX[0] = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth;
colX[0] = PdfLayout.GetOriginX(pageSettings, page) + page.HeadingWidth + page.PrintTitleWidth;
for (int ci = 0; ci < colCount; ci++)
{
var cell = page.Map[page.FromRow, page.FromColumn + ci];
Expand All @@ -61,9 +61,10 @@ public static void AddGridLines(PdfPageSettings pageSettings, Page page, PdfPage
// rowY[rowCount] = Y of bottom edge of last row.
// Y decreases downward (PDF coordinate system used throughout GetCatalog).
var rowY = new double[rowCount + 1];
rowY[0] = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight;
//rowY[0] = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight;
rowY[0] = PdfLayout.GetOriginY(pageSettings, page) - page.HeadingHeight - page.PrintTitleHeight;

for (int ri = 0; ri < rowCount; ri++)
for (int ri = 0; ri < rowCount; ri++)
{
rowY[ri + 1] = rowY[ri] - page.RowHeights[ri];
}
Expand All @@ -72,9 +73,9 @@ public static void AddGridLines(PdfPageSettings pageSettings, Page page, PdfPage
// Always computed so BorderLines is available for margin clipping regardless of
// whether ShowGridLines is on. When borderOnly is true we stop here.

double frameLeft = pageSettings.ContentBounds.Left; //colX[0];
double frameLeft = PdfLayout.GetOriginX(pageSettings, page);
double frameRight = colX[colCount];
double frameTop = pageSettings.ContentBounds.Top; //rowY[0];
double frameTop = PdfLayout.GetOriginY(pageSettings, page);
double frameBottom = rowY[rowCount];

pageLayout.BorderLines.Add(new GridLine(frameLeft, frameTop, frameRight, frameTop));
Expand Down
79 changes: 58 additions & 21 deletions src/EPPlus/Export/PdfExport/Layout/PdfLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ internal static Transform GetCatalog(int firstPageNumber, PdfDictionaries dictio
pageLayout.PrintTitleWidth = page.PrintTitleWidth;
pageLayout.PrintTitleHeight = page.PrintTitleHeight;
var drawnMergedCells = new HashSet<string>();
double contentStartX = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth;
double contentStartY = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight;
double contentStartX = GetOriginX(pageSettings, page) + page.HeadingWidth + page.PrintTitleWidth;
double contentStartY = GetOriginY(pageSettings, page) - page.HeadingHeight - page.PrintTitleHeight;
if (pageSettings.ShowHeadings && !pdfPages[i].IsCommentsPage)
{
AddHeadingCells(pageSettings, dictionaries, page, pageLayout, contentStartX, contentStartY, page.HeadingWidth, page.HeadingHeight, pdfPages[i].HeadingFontName, pdfPages[i].HeadingFontSize, pdfPages[i].HeadingFill);
Expand Down Expand Up @@ -463,7 +463,7 @@ private static void AddHeadingCells(PdfPageSettings pageSettings, PdfDictionarie
{
var headingStyle = new PdfCellStyle();
headingStyle.xfFill = fill;
var cornerFill = new PdfCellLayout(pageSettings.ContentBounds.Left, pageSettings.ContentBounds.Top, headingWidth, headingHeight);
var cornerFill = new PdfCellLayout(GetOriginX(pageSettings, page), GetOriginY(pageSettings, page), headingWidth, headingHeight);
SetFill(dictionaries, headingStyle, "", cornerFill);
cornerFill.Name = "Heading_Corner";
cornerFill.UpdateShadingPositionMatrix(pageSettings);
Expand All @@ -475,7 +475,7 @@ private static void AddHeadingCells(PdfPageSettings pageSettings, PdfDictionarie
if (colWidth == 0d) { x += colWidth; continue; }
string colLetter = ExcelCellBase.GetColumnLetter(col);
AddHeadingCell(pageSettings, dictionaries, pageLayout, headingStyle, colLetter,
x, pageSettings.ContentBounds.Top, colWidth, headingHeight, fontName, fontSize, "Heading_Col_" + colLetter);
x, GetOriginY(pageSettings, page), colWidth, headingHeight, fontName, fontSize, "Heading_Col_" + colLetter);
x += colWidth;
}
double y = contentStartY;
Expand All @@ -485,7 +485,7 @@ private static void AddHeadingCells(PdfPageSettings pageSettings, PdfDictionarie
if (rowHeight == 0d) { y -= rowHeight; continue; }
string rowNum = row.ToString();
AddHeadingCell(pageSettings, dictionaries, pageLayout, headingStyle, rowNum,
pageSettings.ContentBounds.Left, y, headingWidth, rowHeight, fontName, fontSize, "Heading_Row_" + rowNum);
GetOriginX(pageSettings, page), y, headingWidth, rowHeight, fontName, fontSize, "Heading_Row_" + rowNum);
y -= rowHeight;
}
}
Expand Down Expand Up @@ -726,7 +726,7 @@ private static Page PrecomputePageMergedCells(PdfPageSettings pageSettings, PdfR
}
// --- Y ---
// Replace the * 15d line with a sum of real row heights
double drawY = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight;
double drawY = GetOriginY(pageSettings, page) - page.HeadingHeight - page.PrintTitleHeight;
for (int r = page.FromRow; r < row; r++)
{
drawY -= range.RowHeights[r - range.Range._fromRow].Height;
Expand Down Expand Up @@ -775,7 +775,7 @@ private static double[] BuildColumnXPositions(PdfPageSettings pageSettings, Page
{
int colCount = page.ToColumn - page.FromColumn + 1;
var colX = new double[colCount];
double x = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth;
double x = GetOriginY(pageSettings, page) + page.HeadingWidth + page.PrintTitleWidth;
for (int col = page.FromColumn; col <= page.ToColumn; col++)
{
colX[col - page.FromColumn] = x;
Expand Down Expand Up @@ -827,15 +827,15 @@ private static Page PrecomputePagePrintTitleCells(PdfPageSettings pageSettings,

// Content-column X: same origin/widths the content loop uses (step-2 origin).
var contentColX = new Dictionary<int, double>();
double cx = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth;
double cx = PdfLayout.GetOriginX(pageSettings, page) + page.HeadingWidth + page.PrintTitleWidth;
for (int c = page.FromColumn; c <= page.ToColumn; c++)
{
contentColX[c] = cx;
cx += RangeColWidth(range, page.FromRow, c);
}
// Content-row Y.
var contentRowY = new Dictionary<int, double>();
double cy = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight;
double cy = GetOriginY(pageSettings, page) - page.HeadingHeight - page.PrintTitleHeight;
for (int r = page.FromRow; r <= page.ToRow; r++)
{
contentRowY[r] = cy;
Expand All @@ -845,7 +845,7 @@ private static Page PrecomputePagePrintTitleCells(PdfPageSettings pageSettings,
var titleColX = new Dictionary<int, double>();
if (leftBand)
{
double tx = pageSettings.ContentBounds.Left + page.HeadingWidth;
double tx = GetOriginX(pageSettings, page) + page.HeadingWidth;
for (int c = pdfSheet.PrintTitleColFrom; c <= pdfSheet.PrintTitleColTo; c++)
{
titleColX[c] = tx;
Expand All @@ -856,7 +856,7 @@ private static Page PrecomputePagePrintTitleCells(PdfPageSettings pageSettings,
var titleRowY = new Dictionary<int, double>();
if (topBand)
{
double ty = pageSettings.ContentBounds.Top - page.HeadingHeight;
double ty = GetOriginY(pageSettings, page) - page.HeadingHeight;
for (int r = pdfSheet.PrintTitleRowFrom; r <= pdfSheet.PrintTitleRowTo; r++)
{
titleRowY[r] = ty;
Expand Down Expand Up @@ -899,7 +899,7 @@ private static Page PrecomputePagePrintTitleCells(PdfPageSettings pageSettings,
{
IsRow = true,
Index = r,
X = pageSettings.ContentBounds.Left,
X = GetOriginX(pageSettings, page),
Y = titleRowY[r],
Width = page.HeadingWidth,
Height = h
Expand All @@ -916,7 +916,7 @@ private static Page PrecomputePagePrintTitleCells(PdfPageSettings pageSettings,
IsRow = false,
Index = c,
X = titleColX[c],
Y = pageSettings.ContentBounds.Top,
Y = GetOriginY(pageSettings, page),
Width = w,
Height = page.HeadingHeight
});
Expand All @@ -926,24 +926,24 @@ private static Page PrecomputePagePrintTitleCells(PdfPageSettings pageSettings,
// repeated title-row text continues onto the next horizontal page's band
if (topBand)
AddIncomingSpill(page, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo, page.FromColumn, page.ToColumn,
pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth,
pageSettings.ContentBounds.Top - page.HeadingHeight,
GetOriginX(pageSettings, page) + page.HeadingWidth + page.PrintTitleWidth,
GetOriginY(pageSettings, page) - page.HeadingHeight,
isPrintTitle: true);

// left band: a neighbour whose text spills INTO a title column travels with the repeated column
if (leftBand)
AddIncomingSpill(page, range, page.FromRow, page.ToRow,
pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo,
pageSettings.ContentBounds.Left + page.HeadingWidth, // band origin X (left edge of the title columns)
pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight, // content-rows origin Y
GetOriginX(pageSettings, page) + page.HeadingWidth, // band origin X (left edge of the title columns)
GetOriginY(pageSettings, page) - page.HeadingHeight - page.PrintTitleHeight, // content-rows origin Y
isPrintTitle: true);

// corner: same, for the title-rows × title-columns intersection
if (topBand && leftBand)
AddIncomingSpill(page, range, pdfSheet.PrintTitleRowFrom, pdfSheet.PrintTitleRowTo,
pdfSheet.PrintTitleColFrom, pdfSheet.PrintTitleColTo,
pageSettings.ContentBounds.Left + page.HeadingWidth, // band origin X
pageSettings.ContentBounds.Top - page.HeadingHeight, // title-rows origin Y
GetOriginX(pageSettings, page) + page.HeadingWidth, // band origin X
GetOriginY(pageSettings, page) - page.HeadingHeight, // title-rows origin Y
isPrintTitle: true);

return page;
Expand Down Expand Up @@ -1420,6 +1420,20 @@ internal static Pages MapPage(PdfRange range, Pages pdfPages)
page.Map[row, col] = range.Map[row, col];
}
}
double usedWidth = page.HeadingWidth + page.PrintTitleWidth;
for (int col = page.FromColumn; col <= page.ToColumn; col++)
{
usedWidth += page.Map[page.FromRow, col]?.ColumnWidth ?? 0d;
}
page.UsedWidth = usedWidth;

double usedHeight = page.HeadingHeight + page.PrintTitleHeight;
for (int ri = 0; ri < page.RowHeights.Length; ri++)
{
usedHeight += page.RowHeights[ri];
}
page.UsedHeight = usedHeight;

pdfPages.Page[i] = page;
}
pdfPages = pages;
Expand Down Expand Up @@ -1566,8 +1580,8 @@ internal static Pages PrecomputeSpillCells(PdfPageSettings pageSettings, PdfRang
{
var page = pdfPages.Page[i];
page.SpillCells = new List<SpillCellDraw>();
double originX = pageSettings.ContentBounds.Left + page.HeadingWidth + page.PrintTitleWidth;
double originY = pageSettings.ContentBounds.Top - page.HeadingHeight - page.PrintTitleHeight;
double originX = GetOriginX(pageSettings, page) + page.HeadingWidth + page.PrintTitleWidth;
double originY = GetOriginY(pageSettings, page) - page.HeadingHeight - page.PrintTitleHeight;
AddIncomingSpill(page, range, page.FromRow, page.ToRow, page.FromColumn, page.ToColumn, originX, originY, isPrintTitle: false);
pdfPages.Page[i] = page;
}
Expand Down Expand Up @@ -1623,5 +1637,28 @@ private static void EmitBandFrameV(List<GridLine> target, PdfRange range, double
}
if (rs != null) target.Add(new GridLine(x, rs.Value, x, re));
}

/// <summary>
/// The X coordinate where the page's printed block begins.
/// Currently the left content bound; will include the centering offset.
/// </summary>
internal static double GetOriginX(PdfPageSettings pageSettings, Page page)
{
if (!pageSettings.CenterOnPageHorizontally) return pageSettings.ContentBounds.Left;

var offset = (pageSettings.ContentBounds.Width - page.UsedWidth) / 2d;
return pageSettings.ContentBounds.Left + Math.Max(0d, offset);
}

/// <summary>
/// The Y coordinate where the page's printed block begins (top edge).
/// </summary>
internal static double GetOriginY(PdfPageSettings pageSettings, Page page)
{
if (!pageSettings.CenterOnPageVertically) return pageSettings.ContentBounds.Top;

var offset = (pageSettings.ContentBounds.Height - page.UsedHeight) / 2d;
return pageSettings.ContentBounds.Top - Math.Max(0d, offset);
}
}
}
Loading