BalancedColumns.cs
// 完毕:
using System;
using System.IO;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
namespace DsPdfWeb.Demos.Basics
{
// 创建具有平衡列的多列文本布局。
// 此示例的核心是 TextLayout.SplitAndBalance() 方法
// 它允许在多列之间拆分文本,
// 并平衡这些柱子,使它们的高度相似,
// 从而使您能够制作类似杂志和报纸的文本布局。
public class BalancedColumns
{
public int CreatePDF(Stream stream)
{
var doc = new GcPdfDocument();
var font = StandardFonts.Times;
var fontSize = 12;
// 周围 1/2" 边距(72 dpi 是 GcDocs.Pdf 使用的默认分辨率):
var margin = 72 / 2;
var pageWidth = doc.PageSize.Width;
var pageHeight = doc.PageSize.Height;
var cW = pageWidth - margin * 2;
// 章节标题的文本格式:
var tlCaption = new TextLayout(72);
tlCaption.DefaultFormat.Font = font;
tlCaption.DefaultFormat.FontSize = fontSize + 4;
tlCaption.DefaultFormat.Underline = true;
tlCaption.MaxWidth = pageWidth;
tlCaption.MaxHeight = pageHeight;
tlCaption.MarginLeft = tlCaption.MarginTop = tlCaption.MarginRight = tlCaption.MarginBottom = margin;
tlCaption.TextAlignment = TextAlignment.Center;
// 章节标题的高度(为简单起见,使用常量):
const float captionH = 24;
// 主文档正文的文本布局(默认 GcDocs.Pdf 分辨率为 72dpi):
var tl = new TextLayout(72);
tl.DefaultFormat.Font = font;
tl.DefaultFormat.FontSize = fontSize;
tl.FirstLineIndent = 72 / 2;
tl.MaxWidth = pageWidth;
tl.MaxHeight = pageHeight;
tl.MarginLeft = tl.MarginRight = tl.MarginBottom = margin;
tl.MarginTop = margin + captionH;
tl.ColumnWidth = cW * 0.3f;
tl.TextAlignment = TextAlignment.Justified;
// 控制附加列的 PageSplitArea 数组(第一列由
// “主”TextLayout,对于每个附加的 TextLayout,必须提供一个 PageSplitArea -
// 它将创建并返回一个 TextLayout,然后可用于呈现该列):
var psas = new PageSplitArea[]
{
new PageSplitArea(tl) { MarginLeft = tl.MarginLeft + (cW * 0.35f) },
new PageSplitArea(tl) { ColumnWidth = -cW * 0.3f }
};
// 用于控制页面之间拆分文本的拆分选项:
var tso = new TextSplitOptions(tl)
{
RestMarginTop = margin,
MinLinesInFirstParagraph = 2,
MinLinesInLastParagraph = 2
};
// 生成多个“章节”,为每个章节提供大纲条目:
const int NChapters = 20;
doc.Pages.Add();
for (int i = 0; i < NChapters; ++i)
{
// 打印所有列的章节标题:
string chapter = $"Chapter {i + 1}";
tlCaption.Clear();
tlCaption.Append(chapter);
tlCaption.PerformLayout(true);
doc.Pages.Last.Graphics.DrawTextLayout(tlCaption, PointF.Empty);
// 为章节添加大纲节点:
doc.Outlines.Add(new OutlineNode(chapter, new DestinationFitV(doc.Pages.Last, null)));
//
// 清除上一章的文本并添加新的章节:
tl.FirstLineIsStartOfParagraph = true;
tl.LastLineIsEndOfParagraph = true;
tl.Clear();
tl.Append(Common.Util.LoremIpsum(5, 7, 9, 15, 25));
tl.PerformLayout(true);
// 用于保存最后一章结尾底部坐标的变量:
float contentBottom = 0f;
// 打印章节:
var tls = new TextLayoutSplitter(tl);
while (true)
{
var tlCol0 = tls.SplitAndBalance(psas, tso);
var g = doc.Pages.Last.Graphics;
g.DrawTextLayout(tlCol0, PointF.Empty);
g.DrawTextLayout(psas[0].TextLayout, PointF.Empty);
g.DrawTextLayout(psas[1].TextLayout, PointF.Empty);
if (tls.SplitResult != SplitResult.Split)
{
// 章节结束,找出下一章的页面剩余高度:
contentBottom = tl.ContentY + tl.ContentHeight;
contentBottom = Math.Max(contentBottom, psas[0].TextLayout.ContentRectangle.Bottom);
contentBottom = Math.Max(contentBottom, psas[1].TextLayout.ContentRectangle.Bottom);
// 打印完成章节:
break;
}
// 在新页面上继续打印章节:
psas[0].MarginTop = psas[1].MarginTop = margin;
doc.Pages.Add();
}
// 下一章 - 查明当前页面是否有足够的空间来开始新的章节:
if (contentBottom + captionH < pageHeight * 0.8f)
{
// 在当前页面开始新章节:
contentBottom += pageHeight * 0.05f;
tlCaption.MarginTop = contentBottom;
tl.MarginTop = psas[0].MarginTop = psas[1].MarginTop = contentBottom + captionH;
}
else if (i < NChapters - 1)
{
// 在新的一页上开始新的篇章:
tlCaption.MarginTop = margin;
tl.MarginTop = psas[0].MarginTop = psas[1].MarginTop = margin + captionH;
doc.Pages.Add();
}
}
// 完毕:
doc.Save(stream);
return doc.Pages.Count;
}
}
}