1. 表格的对齐

2. 跨页表格的处理
This commit is contained in:
csh 2024-09-06 11:23:30 +08:00
parent 61b86d34e7
commit 440788412b
5 changed files with 142 additions and 72 deletions

View File

@ -8,6 +8,8 @@ public
function GetPdf(): PdfFile; function GetPdf(): PdfFile;
function GetCurrentSectWare(): TSSectWare; function GetCurrentSectWare(): TSSectWare;
function GetCurrentTextPoint(): Point; function GetCurrentTextPoint(): Point;
function GetCurrentHdrPoint(): Point;
function GetCurrentFtrPoint(): Point;
function GetCachePath(image_path: string): string; function GetCachePath(image_path: string): string;
function GetNextPage(page: TSPage): TSPage; function GetNextPage(page: TSPage): TSPage;
function GetCurrentXmlFile(): string; function GetCurrentXmlFile(): string;
@ -132,6 +134,16 @@ begin
return text_point_; return text_point_;
end; end;
function TSDocxToPdf.GetCurrentHdrPoint(): Point;
begin
return hdr_point_;
end;
function TSDocxToPdf.GetCurrentFtrPoint(): Point;
begin
return ftr_point_;
end;
function TSDocxToPdf.GetCurrentSectWare(): TSSectWare; function TSDocxToPdf.GetCurrentSectWare(): TSSectWare;
begin begin
return sect_ware_; return sect_ware_;

View File

@ -1,24 +1,27 @@
type TSPdfCellRange = class(TSPdfBasicRange) type TSPdfCellRange = class(TSPdfBasicRange)
public public
function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; tc: Tc; tbl_pr: TblPr); function Create(table_range: TSPdfTableRange; docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; tc: Tc; tbl_pr: TblPr; tr_pr: TrPr);
function Calc(); function Calc();
function Do();override; function Do();override;
function SetTSPage(page: TSPage); function SetTSPage(page: TSPage);
function GetLastPage(); function GetLastPage();
function AlignHeight(height: real; surplus: real); function AlignHeight(height: real);
function IsSamePage(): boolean; function IsSamePage(): boolean;
function FirstValidTSPage(): TSPage; function FirstValidTSPage(): TSPage;
function SetVAlign(val: string); function SetVAlign();
function IsReComputeByCantSplit(): boolean;
public public
VMerge; VMerge;
private private
[weakref]parent_: TSPdfTableRange;
[weakref]docx_to_pdf_: TSDocxToPdf; [weakref]docx_to_pdf_: TSDocxToPdf;
[weakref]page_: TSPage; [weakref]page_: TSPage;
[weakref]docx_components_ware_: TSDocxComponentsWare; [weakref]docx_components_ware_: TSDocxComponentsWare;
[weakref]tc_: Tc; [weakref]tc_: Tc;
[weakref]tbl_pr_: TblPr; [weakref]tbl_pr_: TblPr;
[weakref]tr_pr_: TrPr;
region_array_: array of Region; // 单元格可能跨页,所以可能存在多个 region_array_: array of Region; // 单元格可能跨页,所以可能存在多个
end; end;
@ -33,13 +36,15 @@ type Region = class
RangeArr: array of TSPdfAbstractRange; RangeArr: array of TSPdfAbstractRange;
end; end;
function TSPdfCellRange.Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; tc: Tc; tbl_pr: TblPr); function TSPdfCellRange.Create(table_range: TSPdfTableRange; docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; tc: Tc; tbl_pr: TblPr; tr_pr: TrPr);
begin begin
parent_ := table_range;
docx_to_pdf_ := docx_to_pdf; docx_to_pdf_ := docx_to_pdf;
page_ := pg; page_ := pg;
docx_components_ware_ := components; docx_components_ware_ := components;
tc_ := tc; tc_ := tc;
tbl_pr_ := tbl_pr; tbl_pr_ := tbl_pr;
tr_pr_ := tr_pr;
region_array_ := array(); region_array_ := array();
{self.}TSPage := page_; {self.}TSPage := page_;
{self.}VMerge := 0; {self.}VMerge := 0;
@ -47,6 +52,7 @@ end;
function TSPdfCellRange.Calc(); function TSPdfCellRange.Calc();
begin begin
region_array_ := array();
region := new Region(); region := new Region();
region.RectangleRange.EndX := {self.}StartX; region.RectangleRange.EndX := {self.}StartX;
region.RectangleRange.EndY := {self.}StartY; region.RectangleRange.EndY := {self.}StartY;
@ -58,6 +64,7 @@ begin
{self.}EndX := {self.}StartX; {self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY; {self.}EndY := {self.}StartY;
{self.}DynamicHeight := 0;
cell_x := {self.}EndX + tbl_pr_.TblCellMar.Left.W; cell_x := {self.}EndX + tbl_pr_.TblCellMar.Left.W;
cell_y := {self.}EndY - tbl_pr_.TblCellMar.Top.W; cell_y := {self.}EndY - tbl_pr_.TblCellMar.Top.W;
cell_w := {self.}Width - tbl_pr_.TblCellMar.Right.W - tbl_pr_.TblCellMar.Left.W; cell_w := {self.}Width - tbl_pr_.TblCellMar.Right.W - tbl_pr_.TblCellMar.Left.W;
@ -74,6 +81,7 @@ begin
else if element.LocalName = "tbl" then else if element.LocalName = "tbl" then
begin begin
range := new TSPdfTableRange(docx_to_pdf_, page_, docx_components_ware_, element); range := new TSPdfTableRange(docx_to_pdf_, page_, docx_components_ware_, element);
continue; // TODO表中表存在不可靠问题
end end
if ifObj(range) then if ifObj(range) then
begin begin
@ -110,23 +118,26 @@ begin
{self.}TSPage := page; {self.}TSPage := page;
end; end;
function TSPdfCellRange.AlignHeight(height: real; surplus: real); function TSPdfCellRange.AlignHeight(height: real);
begin begin
if {self.}FixedHeight > height then height := {self.}FixedHeight;
region := region_array_[0]; region := region_array_[0];
surplus := height - ({self.}StartY - {self.}LowerBound);
if surplus < 1e-6 then if surplus < 1e-6 then
begin begin
region.RectangleRange.DynamicHeight := height; region.RectangleRange.DynamicHeight := height;
if region.RectangleRange.FixedHeight then region.RectangleRange.DynamicHeight := region.RectangleRange.FixedHeight; if {self.}FixedHeight then region.RectangleRange.DynamicHeight := {self.}FixedHeight;
{self.}EndY := {self.}StartY - region.RectangleRange.DynamicHeight; {self.}EndY := {self.}StartY - region.RectangleRange.DynamicHeight;
return; return;
end end
region.RectangleRange.DynamicHeight := {self.}StartY - {self.}LowerBound; region.RectangleRange.DynamicHeight := {self.}StartY - {self.}LowerBound;
arr := region.RangeArr; arr := region.RangeArr;
region.RangeArr := array(); region.RangeArr := array();
sect_ware := docx_to_pdf_.GetCurrentSectWare();
span := sect_ware.SectPr.PgSz.H - sect_ware.SectPr.PgMar.Top - sect_ware.SectPr.PgMar.Bottom;
hash := array(region.RectangleRange.TSPage.Index: region); hash := array(region.RectangleRange.TSPage.Index: region);
page_ := {self.}TSPage; page_ := {self.}TSPage;
[x, y] := docx_to_pdf_.CalculateTextCoordinates();
ftr_point := docx_to_pdf_.GetCurrentFtrPoint();
span := y - ftr_point.Y;
while surplus > span do while surplus > span do
begin begin
page_ := docx_to_pdf_.GetNextPage(page_); page_ := docx_to_pdf_.GetNextPage(page_);
@ -146,7 +157,7 @@ begin
page_ := docx_to_pdf_.GetNextPage(page_); page_ := docx_to_pdf_.GetNextPage(page_);
region := new Region(); region := new Region();
region.RectangleRange.EndX := {self.}StartX; region.RectangleRange.EndX := {self.}StartX;
region.RectangleRange.EndY := sect_ware.SectPr.PgSz.H - sect_ware.SectPr.PgMar.Top; region.RectangleRange.EndY := y;
region.RectangleRange.Width := {self.}Width; region.RectangleRange.Width := {self.}Width;
region.RectangleRange.DynamicHeight := surplus; region.RectangleRange.DynamicHeight := surplus;
region.RectangleRange.TSPage := page_; region.RectangleRange.TSPage := page_;
@ -157,9 +168,15 @@ begin
end end
for _,range in arr do for _,range in arr do
begin begin
region := hash[range.FirstValidTSPage().Index]; if range is class(TSPdfParagraphRange) then
// region := hash[range.TSPage.Index]; begin
region.RangeArr[length(region.RangeArr)] := range; line_arr := range.GetLineRangeArr();
for _,r in line_arr do
begin
region := hash[r.TSPage.Index];
region.RangeArr[length(region.RangeArr)] := r;
end
end
end end
end; end;
@ -168,8 +185,9 @@ begin
return page_; return page_;
end; end;
function TSPdfCellRange.SetVAlign(val: string); function TSPdfCellRange.SetVAlign();
begin begin
val := tc_.TcPr.VAlign.Val;
region := region_array_[0]; region := region_array_[0];
arr := region.RangeArr; arr := region.RangeArr;
if length(arr) = 0 then return; if length(arr) = 0 then return;
@ -180,7 +198,7 @@ begin
begin begin
offset /= 2; offset /= 2;
for _,range in arr do for _,range in arr do
range.AdjustRangeOffset(nil, -offset); range.AdjustRangeOffset(region.RectangleRange.TSPage, nil, -offset);
end end
end; end;
end; end;
@ -194,3 +212,9 @@ function TSPdfCellRange.FirstValidTSPage(): TSPage;
begin begin
return region_array_[0].RangeArr[0].TSPage; return region_array_[0].RangeArr[0].TSPage;
end; end;
function TSPdfCellRange.IsReComputeByCantSplit(): boolean;
begin
if {self.}VMerge then return false;
return tr_pr_.CantSplit and page_ <> {self.}TSPage;
end;

View File

@ -5,7 +5,7 @@ public
function AddRange(range: TSPdfBasicRange); function AddRange(range: TSPdfBasicRange);
function SetAllRangeProp(pg: TSPage; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); function SetAllRangeProp(pg: TSPage; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real);
function Align(jc: string); function Align(jc: string);
function AdjustRangeOffset(x_offset: real; y_offset: real); function AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
private private
range_array_: array of TSPdfBasicRange; range_array_: array of TSPdfBasicRange;
@ -59,8 +59,9 @@ begin
range.EndX += offset; range.EndX += offset;
end; end;
function TSPdfLineRange.AdjustRangeOffset(x_offset: real; y_offset: real); function TSPdfLineRange.AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
begin begin
if page <> {self.}TSPage then return;
for _,range in range_array_ do for _,range in range_array_ do
begin begin
if not ifnil(x_offset) then range.EndX += x_offset; if not ifnil(x_offset) then range.EndX += x_offset;

View File

@ -9,7 +9,8 @@ public
function FirstValidTSPage(): TSPage; function FirstValidTSPage(): TSPage;
function IsSamePage(): boolean; function IsSamePage(): boolean;
function GetLastPage(): TSPage; function GetLastPage(): TSPage;
function AdjustRangeOffset(x_offset: real; y_offset: real); function AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
function GetLineRangeArr(): array of TSPdfLineRange;
private private
function SetPPr(var ppr: PPr); function SetPPr(var ppr: PPr);
@ -662,8 +663,13 @@ begin
return page_; return page_;
end; end;
function TSPdfParagraphRange.AdjustRangeOffset(x_offset: real; y_offset: real); function TSPdfParagraphRange.AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
begin begin
for _,line_range in line_range_array_ do for _,line_range in line_range_array_ do
line_range.AdjustRangeOffset(x_offset, y_offset); line_range.AdjustRangeOffset(page, x_offset, y_offset);
end;
function TSPdfParagraphRange.GetLineRangeArr(): array of TSPdfLineRange;
begin
return line_range_array_;
end; end;

View File

@ -1,14 +1,16 @@
type TSPdfTableRange = class(TSPdfBasicRange) type TSPdfTableRange = class(TSPdfBasicRange)
public public
function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: Components; table: Tbl); function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: Components; table: Tbl);
function Calc();
function Do();override; function Do();override;
function Calc();
function FirstValidTSPage(): TSPage; function FirstValidTSPage(): TSPage;
function IsSamePage(): boolean; function IsSamePage(): boolean;
function GetLastPage(): TSPage; function GetLastPage(): TSPage;
private private
function GetCellMatrix(grid_cols: array of GridColUnitDecorator); function GetCellMatrix(grid_cols: array of GridColUnitDecorator);
function CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr);
function ComputeMatrixCells();
function ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol); function ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol);
function SetTblPr(tbl_pr: TblPr); function SetTblPr(tbl_pr: TblPr);
function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string);
@ -23,7 +25,7 @@ private
[weakref]docx_components_ware_: Components; [weakref]docx_components_ware_: Components;
[weakref]table_: Tbl; [weakref]table_: Tbl;
[weakref]page_: TSPage; [weakref]page_: TSPage;
range_array_: tableArray; cell_range_array_: tableArray;
end; end;
function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; table: Tbl); function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; table: Tbl);
@ -32,7 +34,7 @@ begin
page_ := pg; page_ := pg;
docx_components_ware_ := Components; docx_components_ware_ := Components;
table_ := table; table_ := table;
range_array_ := array(); cell_range_array_ := array();
{self.}TSPage := page_; {self.}TSPage := page_;
end; end;
@ -50,9 +52,9 @@ begin
{self.}GetCellMatrix(grid_cols); {self.}GetCellMatrix(grid_cols);
end; end;
function TSPdfTableRange.Do(); function TSPdfTableRange.Do();override;
begin begin
for _,row in range_array_ do for _,row in cell_range_array_ do
for _,range in row do for _,range in row do
if ifObj(range) then range.Do(); if ifObj(range) then range.Do();
end; end;
@ -61,9 +63,19 @@ function TSPdfTableRange.GetCellMatrix(grid_cols: array of GridColUnitDecorator)
begin begin
trs := table_.Trs(); trs := table_.Trs();
// 先构建一个矩阵 // 先构建一个矩阵
{self.}CreateTableMatrix(grid_cols, trs);
// 遍历矩阵后进行计算合并
{self.}ComputeMatrixCells();
end;
function TSPdfTableRange.CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr);
begin
vmerge_arr := array(); vmerge_arr := array();
for i,tr in trs do for i,tr in trs do
begin begin
{self.}SetTrPr(tr.TrPr);
tr_pr := new TrPrUnitDecorator(tr.TrPr);
tc_h := tr_pr.TrHeight.Val;
tc_x := {self.}EndX; tc_x := {self.}EndX;
tcs := tr.Tcs(); tcs := tr.Tcs();
pos := 0; pos := 0;
@ -74,13 +86,13 @@ begin
vmerge := tc.TcPr.XmlChildVMerge.Val ? tc.TcPr.XmlChildVMerge.Val : tc.TcPr.VMerge; vmerge := tc.TcPr.XmlChildVMerge.Val ? tc.TcPr.XmlChildVMerge.Val : tc.TcPr.VMerge;
if vmerge = "restart" then if vmerge = "restart" then
begin begin
if ifarray(vmerge_arr[pos]) then range_array_[vmerge_arr[pos][0]][pos].VMerge := vmerge_arr[pos][1]; if ifarray(vmerge_arr[pos]) then cell_range_array_[vmerge_arr[pos][0]][pos].VMerge := vmerge_arr[pos][1];
vmerge_arr[pos] := array(i, 0); vmerge_arr[pos] := array(i, 0);
end end
else if vmerge then else if vmerge then
begin begin
vmerge_arr[pos][1]++; vmerge_arr[pos][1]++;
range_array_[i][pos] := 0; cell_range_array_[i][pos] := 0;
tc_x += grid_cols[pos].W; tc_x += grid_cols[pos].W;
grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan); grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan);
pos++; pos++;
@ -90,14 +102,15 @@ begin
end end
else if ifarray(vmerge_arr[pos]) then else if ifarray(vmerge_arr[pos]) then
begin begin
range_array_[vmerge_arr[pos][0]][pos].VMerge := vmerge_arr[pos][1]; cell_range_array_[vmerge_arr[pos][0]][pos].VMerge := vmerge_arr[pos][1];
vmerge_arr[pos] := nil; vmerge_arr[pos] := nil;
end end
cell_range := new TSPdfCellRange(docx_to_pdf_, page_, docx_components_ware_, tc, table_.TblPr); cell_range := new TSPdfCellRange(self, docx_to_pdf_, page_, docx_components_ware_, tc, table_.TblPr, tr.TrPr);
cell_range.StartX := tc_x; cell_range.StartX := tc_x;
cell_range.Width := grid_cols[pos].W; cell_range.Width := grid_cols[pos].W;
cell_range.LowerBound := {self.}LowerBound; cell_range.LowerBound := {self.}LowerBound;
range_array_[i][pos] := cell_range; cell_range.FixedHeight := tc_h;
cell_range_array_[i][pos] := cell_range;
grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan); grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan);
pos++; pos++;
for k:=grid_span.Val-1 downto 1 do for k:=grid_span.Val-1 downto 1 do
@ -106,82 +119,96 @@ begin
end end
end end
// for i,arr in range_array_ do // for i,arr in cell_range_array_ do
// begin // begin
// println("i = {}, len = {}, arr = {}", i, length(arr), arr); // println("i = {}, len = {}, arr = {}", i, length(arr), arr);
// end // end
return;
end;
// 遍历矩阵后进行计算合并 function TSPdfTableRange.ComputeMatrixCells();
begin
i := 0;
vmerge_arr := array(); vmerge_arr := array();
row_height := array(); row_height := array();
for i,arr in range_array_ do while i < length(cell_range_array_)-1 do
begin begin
tr := trs[i];
{self.}SetTrPr(tr.TrPr);
tr_pr := new TrPrUnitDecorator(tr.TrPr);
tc_h := tr_pr.TrHeight.Val;
tc_y := {self.}EndY; tc_y := {self.}EndY;
max_height := 0; max_height := 0;
flag := nil; recompute_flag := false;
first_page := nil; vmerge_flag_arr := array();
for j,range in arr do for j,range in cell_range_array_[i] do
begin begin
if range = 0 then if range = 0 then
begin begin
vmerge_arr[j][1]--; vmerge_arr[j][1]--;
if vmerge_arr[j][1] = 0 then flag := j; if vmerge_arr[j][1] = 0 then vmerge_flag_arr[length(vmerge_flag_arr)] := j;
continue; continue;
end end
if not ifObj(range) then continue;
range.StartY := tc_y; range.StartY := tc_y;
range.FixedHeight := tc_h;
range.SetTSPage(page_); range.SetTSPage(page_);
range.Calc(); range.Calc();
if range.VMerge then if range.IsReComputeByCantSplit() then
vmerge_arr[j] := array(i, range.VMerge); begin
// 调整上一行的下边界
arr := cell_range_array_[i - 1];
if ifarray then
begin
for k,range in arr do
begin
if range = 0 then
begin
pos := i - 2;
while pos > 0 do
begin
r := cell_range_array_[pos][k];
if r = 0 then continue;
r.LowerBound := tc_y;
break;
end
end
else begin
range.LowerBound := tc_y;
end
end
end
page_ := docx_to_pdf_.GetNextPage(page_);
[x, y] := docx_to_pdf_.CalculateTextCoordinates();
{self.}EndY := y;
println("y = {}", y);
recompute_flag := true;
break;
end
if range.VMerge then vmerge_arr[j] := array(i, range.VMerge);
if not range.VMerge and range.DynamicHeight > max_height then max_height := range.DynamicHeight; if not range.VMerge and range.DynamicHeight > max_height then max_height := range.DynamicHeight;
if ifnil(first_page) then first_page := range.FirstValidTSPage();
if first_page <> range.FirstValidTSPage() then page_flag := true;
end end
if recompute_flag then continue;
// TODO跨页断行 if range.FixedHeight > max_height then max_height := tc_h;
if tr_pr.CantSplit then
begin
end
else begin
end
if tc_h > max_height then max_height := tc_h;
row_height[i] := max_height; row_height[i] := max_height;
if not ifnil(flag) then for _,col_index in vmerge_flag_arr do
begin begin
total_height := max_height; total_height := max_height;
ind := vmerge_arr[flag][0]; row_index := vmerge_arr[col_index][0];
r := range_array_[ind][flag]; r := cell_range_array_[row_index][col_index];
// 统计总高度 // 统计总高度
while ind <= i-1 do while row_index <= i-1 do
begin total_height += row_height[row_index++];
total_height += row_height[ind];
ind++;
end
r_height := total_height; r_height := total_height;
if r.DynamicHeight > r_height then r_height := r.DynamicHeight; if r.DynamicHeight > r_height then r_height := r.DynamicHeight;
surplus := r_height - ({self.}EndY - {self.}LowerBound); r.AlignHeight(r_height);
r.AlignHeight(r_height, surplus); r.SetVAlign();
r.SetVAlign(tc.TcPr.VAlign.Val);
max_height := r_height - total_height + max_height; max_height := r_height - total_height + max_height;
end end
surplus := max_height - ({self.}EndY - {self.}LowerBound); for j,range in cell_range_array_[i] do
for j,range in range_array_[i] do
begin begin
if not ifObj(range) or range.VMerge then continue; if not ifObj(range) or range.VMerge then continue;
range.AlignHeight(max_height, surplus); range.AlignHeight(max_height);
range.SetVAlign(tc.TcPr.VAlign.Val); range.SetVAlign();
{self.}EndY := range.EndY; {self.}EndY := range.EndY;
page_ := range.GetLastPage(); page_ := range.GetLastPage();
end end
i++;
end end
end; end;
function TSPdfTableRange.SetTblStylePr(var tc_pr: TcPr; type: string); function TSPdfTableRange.SetTblStylePr(var tc_pr: TcPr; type: string);
@ -273,7 +300,7 @@ end;
function TSPdfTableRange.FirstValidTSPage(): TSPage; function TSPdfTableRange.FirstValidTSPage(): TSPage;
begin begin
range := range_array_[0][0]; range := cell_range_array_[0][0];
return ifObj(range) ? range.TSPage : page_; return ifObj(range) ? range.TSPage : page_;
end; end;