type TSPdfTableRange = class(TSPdfBasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: Components; table: Tbl); function Do();override; function Calc(); function FirstValidTSPage(): TSPage; function IsSamePage(): boolean; function GetLastPage(): TSPage; private 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 SetTblPr(tbl_pr: TblPr); function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); function SetTrPr(var tr_pr: TrPr); function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); function SetTcPr(var tc_pr: TcPr); function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); function SetTblStylePr(var tc_pr: TcPr; type: string); private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]docx_components_ware_: Components; [weakref]table_: Tbl; [weakref]page_: TSPage; tbl_pr_unit_decorator_: TblPrUnitDecorator; cell_range_array_: tableArray; end; function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; table: Tbl); begin docx_to_pdf_ := docx_to_pdf; page_ := pg; docx_components_ware_ := Components; table_ := table; cell_range_array_ := array(); {self.}TSPage := page_; end; function TSPdfTableRange.Calc(); begin {self.}SetTblPr(table_.TblPr); tbl_pr_unit_decorator_ := new TblPrUnitDecorator(table_.TblPr); grid_cols := table_.TblGrid.GridCols(); for i:=0 to length(grid_cols)-1 do grid_cols[i] := new GridColUnitDecorator(grid_cols[i]); {self.}ResetCoordinates(tbl_pr_unit_decorator_, grid_cols); {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; // 如果是根据内容自适应,应该计算并调整grid_cols的值 {self.}GetCellMatrix(grid_cols); end; function TSPdfTableRange.Do();override; begin for _,row in cell_range_array_ do begin flag := nil; for _,range in row do begin if ifnil(flag) and ifObj(range) then flag := range.IfRemoveEmptyRectangle(); if not ifObj(range) or flag <> range.IfRemoveEmptyRectangle() then begin flag := false; break; end end for _,range in row do begin if ifObj(range) then begin range.RemoveFlag := flag; range.Do(); end end end end; function TSPdfTableRange.GetCellMatrix(grid_cols: array of GridColUnitDecorator); begin 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(); for i,tr in trs do begin {self.}SetTrPr(tr.TrPr); tr_pr := new TrPrUnitDecorator(tr.TrPr); tc_h := tr_pr.TrHeight.Val; tc_x := {self.}EndX; 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 cell_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]++; cell_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 cell_range_array_[vmerge_arr[pos][0]][pos].VMerge := vmerge_arr[pos][1]; vmerge_arr[pos] := nil; end cell_range := new TSPdfCellRange(self, docx_to_pdf_, page_, docx_components_ware_, tc, tbl_pr_unit_decorator_, tr.TrPr); cell_range.StartX := tc_x; cell_range.Width := grid_cols[pos].W; cell_range.LowerBound := {self.}LowerBound; cell_range.FixedHeight := tc_h; cell_range_array_[i][pos] := cell_range; grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan); pos++; for k:=grid_span.Val-1 downto 1 do cell_range.Width += grid_cols[pos++].W; tc_x += cell_range.Width; end end for pos,arr in vmerge_arr do if ifarray(arr) then cell_range_array_[arr[0]][pos].VMerge := arr[1]; // for i,arr in cell_range_array_ do // begin // println("i = {}, len = {}, arr = {}", i, length(arr), arr); // end return; end; function TSPdfTableRange.ComputeMatrixCells(); begin i := 0; vmerge_arr := array(); row_height := array(); while i < length(cell_range_array_) do begin tc_y := {self.}EndY; max_height := 0; recompute_flag := false; vmerge_flag_arr := array(); for j,range in cell_range_array_[i] do begin if range = 0 then begin vmerge_arr[j][1]--; if vmerge_arr[j][1] = 0 then vmerge_flag_arr[length(vmerge_flag_arr)] := j; continue; end range.StartY := tc_y; range.SetTSPage(page_); range.Calc(); if range.IsReComputeByCantSplit() then 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; 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 range.FixedHeight > max_height then max_height := tc_h; end if recompute_flag then continue; row_height[i] := max_height; for _,col_index in vmerge_flag_arr do begin total_height := max_height; row_index := vmerge_arr[col_index][0]; r := cell_range_array_[row_index][col_index]; // 统计总高度 while row_index <= i-1 do total_height += row_height[row_index++]; r_height := total_height; if r.DynamicHeight > r_height then r_height := r.DynamicHeight; r.AlignHeight(r_height); r.SetVAlign(); max_height := r_height - total_height + max_height; end for j,range in cell_range_array_[i] do begin if not ifObj(range) or range.VMerge then continue; range.AlignHeight(max_height); range.SetVAlign(); {self.}EndY := range.EndY; page_ := range.GetLastPage(); end i++; end end; function TSPdfTableRange.SetTblStylePr(var tc_pr: TcPr; type: string); begin {self.}SetTcPr(tc_pr); tbl_style_pr := docx_components_ware_.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type); if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr); end; function TSPdfTableRange.ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol); begin total_width := 0; for _,grid_col in grid_cols do total_width += grid_col.W; diff := total_width - {self.}Width; case tbl_pr.Jc.Val of "center": begin offset := diff/2; {self.}StartX -= offset; end "right": begin {self.}StartX -= diff; end end; {self.}Width := total_width; end; function TSPdfTableRange.SetTblPr(var tbl_pr: TblPr); begin new_tbl_pr := new TblPr(); {self.}SetTblPrByStyleId(new_tbl_pr, tbl_pr.TblStyle.Val); new_tbl_pr.Copy(tbl_pr); tbl_pr.Copy(new_tbl_pr); end; function TSPdfTableRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetTblPrByStyleId(tbl_pr, based_on); tbl_pr.Copy(style.TblPr); end end; function TSPdfTableRange.SetTrPr(var tr_pr: TrPr); begin new_tr_pr := new TrPr(); {self.}SetTrPrByStyleId(new_tr_pr, tbl_pr_unit_decorator_.TblStyle.Val); if ifObj(tr_pr) then begin new_tr_pr.Copy(tr_pr); tr_pr.Copy(new_tr_pr); end end; function TSPdfTableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetTrPrByStyleId(tr_pr, based_on); tr_pr.Copy(style.TrPr); end end; function TSPdfTableRange.SetTcPr(var tc_pr: TcPr); begin new_tc_pr := new TcPr(); {self.}SetTcPrByStyleId(new_tc_pr, tbl_pr_unit_decorator_.TblStyle.Val); if ifObj(tc_pr) then begin new_tc_pr.Copy(tc_pr); tc_pr.Copy(new_tc_pr); end end; function TSPdfTableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetTcPrByStyleId(tc_pr, based_on); tc_pr.Copy(style.TcPr); end end; function TSPdfTableRange.FirstValidTSPage(): TSPage; begin range := cell_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;