一、思路
在AI的大背景,应用层算法已经不是问题,那么程序员的差距主要在认知思维模式和创新上面。目前AI的局限主要却决于沟通的效率,这是双方的问题,AI可能理解能力不足,或者提问者表达能力不足。
这里我以PDFsharp实现Grid布局模式分享一下基于GPT实现的过程。因为PDFsharp只提供了XGraphics。类似.NET自带的Drawing图像库。
即这个思路通用适用于支持Drawing操作相关的库。
开源地址:https://github.com/soul-soft/Soul.PDFsharp.Extensions
- Grid布局:基于行列进行布局。
- 内外边距:行和单元格存在内外边距,这里的内外边距控制当前元素绘制的起点实现。
- 行宽:优先扣除掉行左右外边距,如果宽度不够那么压缩最后一个单元格。这样实现了行居中的效果,通过控制内外边距Margin。
- 单元格的宽度:如果是一个文本单元格,用户未指定宽度,那么使用XGraphics计算出来文本的宽度,作为单元格的宽度。如果行内只有一个单元格并且没有指定宽度,那么等于行宽。
- 单元格的高度:如果当前是单行文本,那么使用XGraphics计算出来文本的高度,如果单元格支持换行。我们这时候需要先计算完所有单元格的宽度,然后基于单元格的宽度(扣除掉内边距,因为宽度计算方式由思路4决定),就可以计算出来行数了,显然内边距会影响行数。
- 单元格的高度:行数 * 字体高度 +(行数-1)* 行间距 + 上下内边距。(高度自适应)
- 行高:等于行内单元格最高的高度,实现高度自适应。如果用户指定了行高,并且大于行内单元格最高的高度,那么行高使用用户指定的行高
二、抽象数据结构
//网格
public class XGrid
{
private readonly List<XGridRow> _rows = new List<XGridRow>();
public void DrawRow(Action<XGridRow> configure)
{
var row = new XGridRow();
configure(row);
_rows.Add(row);
}
internal IReadOnlyList<XGridRow> Rows => _rows;
}
//行
public class XGridRow
{
private readonly List<XGridCell> _cells = new List<XGridCell>();
public XGridBox Margin { get; set; } = new XGridBox(0);
public double Height { get; set; }
public double Width { get; set; }
public XGridBorder Border { get; } = new XGridBorder();
public void DrawTextCell(Action<XGridTextCell> configure)
{
var cell = new XGridTextCell();
configure(cell);
_cells.Add(cell);
}
public void DrawImageCell(Action<XGridImageCell> configure)
{
var cell = new XGridImageCell();
configure(cell);
_cells.Add(cell);
}
internal IReadOnlyList<XGridCell> Cells => _cells;
}
//单元格
public abstract class XGridCell
{
/// <summary>
/// 高度
/// </summary>
public double Height { get; set; }
/// <summary>
/// 宽度
/// </summary>
public double Width { get; set; }
/// <summary>
/// 控制内边距
/// </summary>
public XGridBox Margin { get; set; } = new XGridBox(0);
/// <summary>
/// 控制外边距
/// </summary>
public XGridBox Padding { get; set; } = new XGridBox(0);
/// <summary>
/// 水平对齐方式
/// </summary>
public XGridAlignment HorizontalAlignment { get; set; } = XGridAlignment.Left;
/// <summary>
/// 垂直对齐方式
/// </summary>
public XGridAlignment VerticalAlignment { get; set; } = XGridAlignment.Center;
internal XGridRow Row { get; }
/// <summary>
/// 控制边框
/// </summary>
public XGridBorder Border { get; } = new XGridBorder();
}
//文本单元格
public class XGridTextCell : XGridCell
{
/// <summary>
/// 控制换行
/// </summary>
public bool Warp { get; set; } = true;
/// <summary>
/// 文本
/// </summary>
public string Text { get; set; }
/// <summary>
/// 多行文本的行间距
/// </summary>
public double LineSpacing { get; set; } = 0;
}
//图像单元格
public class XGridImageCell : XGridCell
{
/// <summary>
/// 要在此单元格中渲染的图片。
/// </summary>
public XImage Image { get; set; }
public double ImageWidth { get; set; }
public double ImageHeight { get; set; }
}
//边框,对齐,内外边距就略过了。
三、定义保留的API和使用方式
document.DrawPage((page, gfx) =>
{
var footerFont = new XFont("STSONG.TTF", 18, XFontStyleEx.Bold);
//绘制网格,指定y轴偏移
gfx.DrawGrid(100, footerFont, XBrushes.Black, grid =>
{
//绘制行
grid.DrawRow(row =>
{
//设置内外边距
row.Margin.SetHorizontal(100, 100);
row.DrawTextCell(cell =>
{
cell.Text = "你好";
cell.Border.Visible = true;
cell.Width = 100;
cell.VerticalAlignment = XGridAlignment.Top;
cell.HorizontalAlignment = XGridAlignment.Right;
});
row.DrawTextCell(cell =>
{
cell.Text = "工程造价咨询报告书工程造价咨询报告书工程造价咨询报告书工程造价咨询报告书工程造价咨询报告书工程造价咨询报告书";
cell.Border.Visible = true;
cell.Width = 200;
cell.Padding = 0;//设置内边距,这里用到了隐式转换语法,Padding 实际是一个class
cell.HorizontalAlignment = XGridAlignment.Left;
});
row.DrawImageCell(cell =>
{
cell.Image = XImage.FromFile("./images/hjd.jpg");
cell.Border.Visible = true;
cell.Width = 200;
cell.ImageWidth = 40;
cell.ImageHeight = 40;
cell.HorizontalAlignment = XGridAlignment.Center;
cell.VerticalAlignment = XGridAlignment.Center;
});
});
});
});
四、通过GPT实现
我们将实现思路和定义好的数据结构给他,告诉他需要实现的函数签名即:void DrawGrid(this XGraphics graphics, double y, XFont font, XBrush brush, Action
我们一步步引导完成。省事省力。
五最终效果