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

View File

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

View File

@ -5,6 +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);
private private
range_array_: array of TSPdfBasicRange; range_array_: array of TSPdfBasicRange;
@ -57,3 +58,12 @@ begin
for _,range in range_array_ do for _,range in range_array_ do
range.EndX += offset; range.EndX += offset;
end; 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 SetExtraStyleId(style_id: string);
function SetNumPages(num: integer); function SetNumPages(num: integer);
function RangesToLines(); function RangesToLines();
function FirstValidTSPage(): TSPage;
function IsSamePage(): boolean;
function GetLastPage(): TSPage;
function AdjustRangeOffset(x_offset: real; y_offset: real);
private private
function SetPPr(var ppr: PPr); function SetPPr(var ppr: PPr);
@ -70,6 +74,7 @@ begin
{self.}EndX := {self.}StartX; {self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY; {self.}EndY := {self.}StartY;
{self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before); {self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before);
{self.}TSPage := page_;
{self.}EndY -= ppr_unit_decorator_.Spacing.Before; {self.}EndY -= ppr_unit_decorator_.Spacing.Before;
{self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before; {self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before;
@ -366,9 +371,7 @@ end;
function TSPdfParagraphRange.SetLinesAlignment(); function TSPdfParagraphRange.SetLinesAlignment();
begin begin
if length(line_range_array_) = 0 then return; for _,line_range in line_range_array_ do
idx := length(line_range_array_)-1;
line_range := line_range_array_[idx];
line_range.Align(ppr_unit_decorator_.Jc.Val); line_range.Align(ppr_unit_decorator_.Jc.Val);
end; end;
@ -641,3 +644,26 @@ begin
{self.}Width -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left; {self.}Width -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
{self.}Width -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right; {self.}Width -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right;
end; 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 Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: Components; table: Tbl);
function Calc(); function Calc();
function Do();override; function Do();override;
function FirstValidTSPage(): TSPage;
function IsSamePage(): boolean;
function GetLastPage(): TSPage;
private private
function GetCellMatrix(grid_cols: array of GridColUnitDecorator); function GetCellMatrix(grid_cols: array of GridColUnitDecorator);
@ -57,24 +60,41 @@ end;
function TSPdfTableRange.GetCellMatrix(grid_cols: array of GridColUnitDecorator); function TSPdfTableRange.GetCellMatrix(grid_cols: array of GridColUnitDecorator);
begin begin
trs := table_.Trs(); trs := table_.Trs();
// 先构建一个矩阵
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);
height := tr_pr.TrHeight.Val;
tc_x := {self.}EndX; tc_x := {self.}EndX;
tc_y := {self.}EndY;
tc_h := height;
max_height := 0;
tcs := tr.Tcs(); tcs := tr.Tcs();
pos := 0; pos := 0;
for j,tc in tcs do for j,tc in tcs do
begin begin
{self.}SetTcPr(tc.TcPr);
if i = 0 then {self.}SetTblStylePr(tc.TcPr, "firstRow"); 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 := new TSPdfCellRange(docx_to_pdf_, page_, docx_components_ware_, tc, table_.TblPr);
cell_range.StartX := tc_x; cell_range.StartX := tc_x;
cell_range.StartY := tc_y;
cell_range.FixedHeight := tc_h;
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; range_array_[i][pos] := cell_range;
@ -82,39 +102,86 @@ begin
pos++; pos++;
for k:=grid_span.Val-1 downto 1 do for k:=grid_span.Val-1 downto 1 do
cell_range.Width += grid_cols[pos++].W; cell_range.Width += grid_cols[pos++].W;
cell_range.Calc();
tc_x += cell_range.Width; tc_x += cell_range.Width;
if cell_range.DynamicHeight > max_height then max_height := cell_range.DynamicHeight;
end end
if tc_h > max_height then max_height := tc_h; end
surplus := max_height - ({self.}EndY - {self.}LowerBound);
arr := range_array_[i]; // for i,arr in range_array_ do
for _,range in arr 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 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); range.AlignHeight(max_height, surplus);
{self.}EndY := range.EndY; // 理论上每个range.EndY都是一个值 range.SetVAlign(tc.TcPr.VAlign.Val);
{self.}EndY := range.EndY;
page_ := range.GetLastPage(); page_ := range.GetLastPage();
end end
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; end;
function TSPdfTableRange.SetTblStylePr(var tc_pr: TcPr; type: string); function TSPdfTableRange.SetTblStylePr(var tc_pr: TcPr; type: string);
@ -203,3 +270,19 @@ begin
tc_pr.Copy(style.TcPr); tc_pr.Copy(style.TcPr);
end end
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; function GetHdrRelsAdapter(target: string): RelationShipsAdapter;
private private
styles_deserialize_flag_; styles_deserialize_flag_: boolean;
styles_adapter_; styles_adapter_: StylesAdapter;
document_rels_adapter_; document_rels_adapter_: RelationShipsAdapter;
numbering_ware_; numbering_ware_: TSNumberingWare;
tbl_style_pr_hash_; tbl_style_pr_hash_: array of TblStylePr;
ftr_hash_; ftr_hash_: array of Ftr;
hdr_hash_; hdr_hash_: array of Hdr;
hdr_rel_hash_; hdr_rel_hash_: array of RelationShipsAdapter;
ftr_rel_hash_; ftr_rel_hash_: array of RelationShipsAdapter;
end; end;
function TSDocxComponentsWare.Create(); function TSDocxComponentsWare.Create();
@ -110,7 +110,7 @@ end;
function TSDocxComponentsWare.GetFtrRelsAdapter(target: string): RelationShipsAdapter; function TSDocxComponentsWare.GetFtrRelsAdapter(target: string): RelationShipsAdapter;
begin begin
if ftr_rel_hash_[target] then return ftr_rel_hash_[target]; 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 := {self.}FooterRels(strtoint(index));
obj.Deserialize(); obj.Deserialize();
rels_adapter := new RelationShipsAdapter(obj); rels_adapter := new RelationShipsAdapter(obj);