1. 优化单元格合并

2. 支持单元格垂直居中
This commit is contained in:
csh 2024-09-03 16:49:25 +08:00
parent ca18537538
commit a0ea61af14
6 changed files with 213 additions and 65 deletions

View File

@ -116,9 +116,9 @@ begin
elements := sect_ware.Elements();
for _,element in elements do
begin
// if _ = 109 then break;
// if _ = 109 then
println("_ = {}", _);
// if _ = 3 then break;
// if _ <> 4 then continue;
// println("_ = {}, xml_file_ = {}", _, xml_file_);
if element.LocalName = "p" then {self.}TransformP(text_point_, element, w, lb);
else if element.LocalName = "tbl" then {self.}TransformTbl(text_point_, element, w, lb);
else if element.LocalName = "sdt" then {self.}TransformSdt(sect_ware, element);
@ -242,8 +242,11 @@ begin
type_name := "even"
else
type_name := "default";
bk_file := xml_file_;
{self.}SetHdr(type_name);
{self.}SetFtr(type_name);
xml_file_ := bk_file;
// 正文坐标
[x, y] := {self.}CalculateTextCoordinates();

View File

@ -2,11 +2,13 @@ type TSPdfCellRange = class(TSPdfBasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; tc: Tc; tbl_pr: TblPr);
function Calc();
function AlignHeight(height: real; surplus: real);
function GetLastPage();
function Do();override;
function SetVMergeEdge(range: TSPdfCellRange);
function GetRegionArr(): array of Region;
function SetTSPage(page: TSPage);
function GetLastPage();
function AlignHeight(height: real; surplus: real);
function IsSamePage(): boolean;
function FirstValidTSPage(): TSPage;
function SetVAlign(val: string);
public
VMerge;
@ -40,7 +42,7 @@ begin
tbl_pr_ := tbl_pr;
region_array_ := array();
{self.}TSPage := page_;
{self.}VMerge := tc_.TcPr.XmlChildVMerge.Val ? tc_.TcPr.XmlChildVMerge.Val : tc_.TcPr.VMerge;
{self.}VMerge := 0;
end;
function TSPdfCellRange.Calc();
@ -83,7 +85,8 @@ begin
range.Calc();
region.RangeArr[length(region.RangeArr)] := range;
{self.}DynamicHeight += range.DynamicHeight;
cell_y -= range.DynamicHeight;
cell_y := range.EndY;
page_ := range.GetLastPage();
end
end
{self.}EndY := cell_y;
@ -94,12 +97,19 @@ function TSPdfCellRange.Do();override;
begin
for _,region in region_array_ do
begin
// if length(region.RangeArr) = 0 then continue;
region.RectangleRange.Do();
for _,range in region.RangeArr do
range.Do();
end
end;
function TSPdfCellRange.SetTSPage(page: TSPage);
begin
page_ := page;
{self.}TSPage := page;
end;
function TSPdfCellRange.AlignHeight(height: real; surplus: real);
begin
region := region_array_[0];
@ -116,6 +126,7 @@ begin
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);
page_ := {self.}TSPage;
while surplus > span do
begin
page_ := docx_to_pdf_.GetNextPage(page_);
@ -146,7 +157,8 @@ begin
end
for _,range in arr do
begin
region := hash[range.TSPage.Index];
region := hash[range.FirstValidTSPage().Index];
// region := hash[range.TSPage.Index];
region.RangeArr[length(region.RangeArr)] := range;
end
end;
@ -156,15 +168,29 @@ begin
return page_;
end;
function TSPdfCellRange.GetRegionArr(): array of Region;
function TSPdfCellRange.SetVAlign(val: string);
begin
return region_array_;
region := region_array_[0];
arr := region.RangeArr;
if length(arr) = 0 then return;
last_y := arr[length(arr)-1].EndY;
offset := last_y - (region.RectangleRange.EndY - region.RectangleRange.DynamicHeight) - tbl_pr_.TblCellMar.Bottom.W;
case val of
"center":
begin
offset /= 2;
for _,range in arr do
range.AdjustRangeOffset(nil, -offset);
end
end;
end;
function TSPdfCellRange.SetVMergeEdge(range: TSPdfCellRange);
function TSPdfCellRange.IsSamePage(): boolean;
begin
rect := region_array_[length(region_array_)-1].RectangleRange;
range_rect := range.GetRegionArr();
range_rect := range_rect[0].RectangleRange;
rect.DynamicHeight += range_rect.DynamicHeight;
return page_ = {self.}TSPage;
end;
function TSPdfCellRange.FirstValidTSPage(): TSPage;
begin
return region_array_[0].RangeArr[0].TSPage;
end;

View File

@ -5,6 +5,7 @@ public
function AddRange(range: TSPdfBasicRange);
function SetAllRangeProp(pg: TSPage; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real);
function Align(jc: string);
function AdjustRangeOffset(x_offset: real; y_offset: real);
private
range_array_: array of TSPdfBasicRange;
@ -57,3 +58,12 @@ begin
for _,range in range_array_ do
range.EndX += offset;
end;
function TSPdfLineRange.AdjustRangeOffset(x_offset: real; y_offset: real);
begin
for _,range in range_array_ do
begin
if not ifnil(x_offset) then range.EndX += x_offset;
if not ifnil(y_offset) then range.EndY += y_offset;
end;
end;

View File

@ -6,6 +6,10 @@ public
function SetExtraStyleId(style_id: string);
function SetNumPages(num: integer);
function RangesToLines();
function FirstValidTSPage(): TSPage;
function IsSamePage(): boolean;
function GetLastPage(): TSPage;
function AdjustRangeOffset(x_offset: real; y_offset: real);
private
function SetPPr(var ppr: PPr);
@ -70,6 +74,7 @@ begin
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before);
{self.}TSPage := page_;
{self.}EndY -= ppr_unit_decorator_.Spacing.Before;
{self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before;
@ -366,9 +371,7 @@ end;
function TSPdfParagraphRange.SetLinesAlignment();
begin
if length(line_range_array_) = 0 then return;
idx := length(line_range_array_)-1;
line_range := line_range_array_[idx];
for _,line_range in line_range_array_ do
line_range.Align(ppr_unit_decorator_.Jc.Val);
end;
@ -641,3 +644,26 @@ begin
{self.}Width -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
{self.}Width -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right;
end;
function TSPdfParagraphRange.FirstValidTSPage(): TSPage;
begin
range := range_array_[0];
return ifObj(range) ? range.TSPage : page_;
end;
function TSPdfParagraphRange.IsSamePage(): boolean;
begin
pg := range_array_[0] ? range.TSPage : {self.}TSPage;
return page_ = pg;
end;
function TSPdfParagraphRange.GetLastPage(): TSPage;
begin
return page_;
end;
function TSPdfParagraphRange.AdjustRangeOffset(x_offset: real; y_offset: real);
begin
for _,line_range in line_range_array_ do
line_range.AdjustRangeOffset(x_offset, y_offset);
end;

View File

@ -3,6 +3,9 @@ public
function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: Components; table: Tbl);
function Calc();
function Do();override;
function FirstValidTSPage(): TSPage;
function IsSamePage(): boolean;
function GetLastPage(): TSPage;
private
function GetCellMatrix(grid_cols: array of GridColUnitDecorator);
@ -57,24 +60,41 @@ end;
function TSPdfTableRange.GetCellMatrix(grid_cols: array of GridColUnitDecorator);
begin
trs := table_.Trs();
// 先构建一个矩阵
vmerge_arr := array();
for i,tr in trs do
begin
{self.}SetTrPr(tr.TrPr);
tr_pr := new TrPrUnitDecorator(tr.TrPr);
height := tr_pr.TrHeight.Val;
tc_x := {self.}EndX;
tc_y := {self.}EndY;
tc_h := height;
max_height := 0;
tcs := tr.Tcs();
pos := 0;
for j,tc in tcs do
begin
{self.}SetTcPr(tc.TcPr);
if i = 0 then {self.}SetTblStylePr(tc.TcPr, "firstRow");
vmerge := tc.TcPr.XmlChildVMerge.Val ? tc.TcPr.XmlChildVMerge.Val : tc.TcPr.VMerge;
if vmerge = "restart" then
begin
if ifarray(vmerge_arr[pos]) then range_array_[vmerge_arr[pos][0]][pos].VMerge := vmerge_arr[pos][1];
vmerge_arr[pos] := array(i, 0);
end
else if vmerge then
begin
vmerge_arr[pos][1]++;
range_array_[i][pos] := 0;
tc_x += grid_cols[pos].W;
grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan);
pos++;
for k:=grid_span.Val-1 downto 1 do
tc_x += grid_cols[pos++].W;
continue;
end
else if ifarray(vmerge_arr[pos]) then
begin
range_array_[vmerge_arr[pos][0]][pos].VMerge := vmerge_arr[pos][1];
vmerge_arr[pos] := nil;
end
cell_range := new TSPdfCellRange(docx_to_pdf_, page_, docx_components_ware_, tc, table_.TblPr);
cell_range.StartX := tc_x;
cell_range.StartY := tc_y;
cell_range.FixedHeight := tc_h;
cell_range.Width := grid_cols[pos].W;
cell_range.LowerBound := {self.}LowerBound;
range_array_[i][pos] := cell_range;
@ -82,39 +102,86 @@ begin
pos++;
for k:=grid_span.Val-1 downto 1 do
cell_range.Width += grid_cols[pos++].W;
cell_range.Calc();
tc_x += cell_range.Width;
if cell_range.DynamicHeight > max_height then max_height := cell_range.DynamicHeight;
end
if tc_h > max_height then max_height := tc_h;
surplus := max_height - ({self.}EndY - {self.}LowerBound);
arr := range_array_[i];
for _,range in arr do
end
// for i,arr in range_array_ do
// begin
// println("i = {}, len = {}, arr = {}", i, length(arr), arr);
// end
// 遍历矩阵后进行计算合并
vmerge_arr := array();
row_height := array();
for i,arr in range_array_ do
begin
tr := trs[i];
{self.}SetTrPr(tr.TrPr);
tr_pr := new TrPrUnitDecorator(tr.TrPr);
tc_h := tr_pr.TrHeight.Val;
tc_y := {self.}EndY;
max_height := 0;
flag := nil;
first_page := nil;
for j,range in arr do
begin
if range = 0 then
begin
vmerge_arr[j][1]--;
if vmerge_arr[j][1] = 0 then flag := j;
continue;
end
if not ifObj(range) then continue;
range.StartY := tc_y;
range.FixedHeight := tc_h;
range.SetTSPage(page_);
range.Calc();
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 ifnil(first_page) then first_page := range.FirstValidTSPage();
if first_page <> range.FirstValidTSPage() then page_flag := true;
end
// TODO跨页断行
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;
if not ifnil(flag) then
begin
total_height := max_height;
ind := vmerge_arr[flag][0];
r := range_array_[ind][flag];
// 统计总高度
while ind <= i-1 do
begin
total_height += row_height[ind];
ind++;
end
r_height := total_height;
if r.DynamicHeight > r_height then r_height := r.DynamicHeight;
surplus := r_height - ({self.}EndY - {self.}LowerBound);
r.AlignHeight(r_height, surplus);
r.SetVAlign(tc.TcPr.VAlign.Val);
max_height := r_height - total_height + max_height;
end
surplus := max_height - ({self.}EndY - {self.}LowerBound);
for j,range in range_array_[i] do
begin
if not ifObj(range) or range.VMerge then continue;
range.AlignHeight(max_height, surplus);
{self.}EndY := range.EndY; // 理论上每个range.EndY都是一个值
range.SetVAlign(tc.TcPr.VAlign.Val);
{self.}EndY := range.EndY;
page_ := range.GetLastPage();
end
end
for i:=length(range_array_)-1 downto 0 do
begin
for j:=0 to length(range_array_[i])-1 do
begin
range := range_array_[i][j];
if ifnil(range) then continue;
if range.VMerge then
begin
if range.VMerge = "restart" then
begin
break;
end
else begin
range_array_[i-1][j].SetVMergeEdge(range);
range_array_[i][j] := nil;
end
end
end
end
end;
function TSPdfTableRange.SetTblStylePr(var tc_pr: TcPr; type: string);
@ -203,3 +270,19 @@ begin
tc_pr.Copy(style.TcPr);
end
end;
function TSPdfTableRange.FirstValidTSPage(): TSPage;
begin
range := range_array_[0][0];
return ifObj(range) ? range.TSPage : page_;
end;
function TSPdfTableRange.IsSamePage(): boolean;
begin
return page_ = {self.}TSPage;
end;
function TSPdfTableRange.GetLastPage(): TSPage;
begin
return page_;
end;

View File

@ -12,15 +12,15 @@ public
function GetHdrRelsAdapter(target: string): RelationShipsAdapter;
private
styles_deserialize_flag_;
styles_adapter_;
document_rels_adapter_;
numbering_ware_;
tbl_style_pr_hash_;
ftr_hash_;
hdr_hash_;
hdr_rel_hash_;
ftr_rel_hash_;
styles_deserialize_flag_: boolean;
styles_adapter_: StylesAdapter;
document_rels_adapter_: RelationShipsAdapter;
numbering_ware_: TSNumberingWare;
tbl_style_pr_hash_: array of TblStylePr;
ftr_hash_: array of Ftr;
hdr_hash_: array of Hdr;
hdr_rel_hash_: array of RelationShipsAdapter;
ftr_rel_hash_: array of RelationShipsAdapter;
end;
function TSDocxComponentsWare.Create();
@ -110,7 +110,7 @@ end;
function TSDocxComponentsWare.GetFtrRelsAdapter(target: string): RelationShipsAdapter;
begin
if ftr_rel_hash_[target] then return ftr_rel_hash_[target];
index := replaceStr(replaceStr(target, "header", ""), ".xml", "");
index := replaceStr(replaceStr(target, "footer", ""), ".xml", "");
obj := {self.}FooterRels(strtoint(index));
obj.Deserialize();
rels_adapter := new RelationShipsAdapter(obj);