type TSPdfTableRange = class(TSPdfBasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: Components; table: Tbl); function Do();override; function Calc(); function GetLastPage(): TSPage; function Rows(): integer; function Cols(): integer; 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: TblPrUnitDecorator; grid_cols: array of GridCol); function SetTblTblPr(var table: Tbl); function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); function SetTrTrPr(var tr_pr: TrPr); function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); function SetTcTcPr(var tc: Tc); function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); function OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]last_page_: TSPage; [weakref]docx_components_ware_: Components; [weakref]table_: Tbl; tbl_pr_unit_decorator_: TblPrUnitDecorator; ts_trpr_array_: array of TSTrProperty; cell_range_matrix_: array of TSPdfCellRange; rows_: integer; cols_: integer; end; function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; table: Tbl); begin docx_to_pdf_ := docx_to_pdf; last_page_ := pg; docx_components_ware_ := Components; table_ := table; ts_trpr_array_ := array(); cell_range_matrix_ := array(); rows_ := 0; cols_ := 0; {self.}TSPage := last_page_; end; function TSPdfTableRange.Calc(); begin {self.}SetTblTblPr(table_); 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_matrix_ do begin flag := nil; for __,range in row do begin if ifnil(flag) and ifObj(range) then flag := range.IfRemoveEmptyRectangle(); if ifnil(range) then continue; if 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(); rows_ := length(trs); cols_ := length(grid_cols); cell_range_matrix_ := nils(rows_, cols_); // 先构建一个矩阵 {self.}CreateTableMatrix(grid_cols, trs); // 遍历矩阵后进行计算合并 {self.}ComputeMatrixCells(); end; function TSPdfTableRange.CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); begin for i,tr in trs do begin {self.}SetTrTrPr(tr); tr_pr := new TrPrUnitDecorator(tr.TrPr); tc_x := {self.}EndX; tcs := tr.Tcs(); trp := new TSTrProperty(); trp.TrPr := tr_pr; ts_trpr_array_[i] := trp; pos := 0; for j,tc in tcs do begin {self.}SetTcTcPr(tc); if i = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "firstRow"); else if i = length(trs)-1 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "lastRow") else if (i + 1) % 2 = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band1Horz"); else {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band2Horz"); grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan); if tc.TcPr.VMerge and tc.TcPr.VMerge <> "restart" then begin tc_x += grid_cols[pos++].W; for k:=grid_span.Val-1 downto 1 do tc_x += grid_cols[pos++].W; continue; end cell_range := new TSPdfCellRange(self, docx_to_pdf_, last_page_, docx_components_ware_, tc, tbl_pr_unit_decorator_, trp); cell_range.StartX := tc_x; cell_range.Width := grid_cols[pos].W; cell_range.LowerBound := {self.}LowerBound; cell_range.FixedHeight := tr_pr.TrHeight.Val; cell_range.Row := i; cell_range.Col := pos; cell_range_matrix_[i][pos] := cell_range; 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 i,arr in cell_range_matrix_ do // println("i = {}, arr = {}", i, arr); // println("\n"); return; end; function TSPdfTableRange.ComputeMatrixCells(); begin i := 0; merge_arr := array(); vmerge_height := array(); while i < rows_ do begin j := 0; tc_y := {self.}EndY; recompute_flag := false; while j < cols_ do begin range := cell_range_matrix_[i][j]; if ifnil(range) then begin j++; continue; end range.StartY := tc_y; range.SetTSPage(last_page_); range.Calc(); if range.IsReComputeByCantSplit() then begin // 调整上一行的下边界 arr := cell_range_matrix_[i-1]; for _,r in arr do begin if ifnil(r) then begin pos := i-2; while pos > 0 do begin rr := cell_range_matrix_[pos][_]; pos--; if ifnil(rr) then continue; rr.LowerBound := tc_y; break; end end if not ifnil(r) then r.LowerBound := tc_y; end last_page_ := docx_to_pdf_.GetNextPage(last_page_); [x, y] := docx_to_pdf_.CalculateTextCoordinates(); {self.}EndY := y; j := 0; recompute_flag := true; arr := cell_range_matrix_[i]; for _,r in arr do if not ifnil(r) then r.SetTop(); break; end if range.Tc.TcPr.VMerge then begin b_merge_index := i; e_merge_index := i + 1; while ifnil(cell_range_matrix_[e_merge_index+1][j]) and e_merge_index < rows_-1 do e_merge_index++; merge_arr[e_merge_index][j] := b_merge_index; range.VMerge := e_merge_index; if ifnil(vmerge_height[e_merge_index]) or range.DynamicHeight > vmerge_height[e_merge_index] then vmerge_height[e_merge_index] := range.DynamicHeight; end j++; end if recompute_flag then continue; i_height := 0; for k,v in merge_arr[i] do begin i_height := ts_trpr_array_[i].Height; r := cell_range_matrix_[v][k]; total_height := 0; for index:=v to i-1 do total_height += ts_trpr_array_[index].Height; h := vmerge_height[i]; if h > total_height + i_height then i_height := h - total_height; else h := total_height + i_height; r.AlignHeight(h); r.SetVAlign(); end if i_height then ts_trpr_array_[i].Height := i_height; for _,range in cell_range_matrix_[i] do begin if not ifObj(range) or range.Tc.TcPr.VMerge then continue; range.AlignHeight(ts_trpr_array_[i].Height); range.SetVAlign(); {self.}EndY := range.EndY; last_page_ := range.GetLastPage(); end i++; end end; function TSPdfTableRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); begin // tc_pr应该是经过外层copy的 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.SetTblTblPr(var tbl: Tbl); begin new_tbl_pr := new TblPr(); {self.}SetTblPrByStyleId(new_tbl_pr, tbl.TblPr.TblStyle.Val); new_tbl_pr.Copy(tbl.TblPr); tbl.TblPr.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.SetTrTrPr(var tr: Tr); begin new_tr_pr := new TrPr(); {self.}SetTrPrByStyleId(new_tr_pr, tbl_pr_unit_decorator_.TblStyle.Val); new_tr_pr.Copy(tr.TrPr); tr.TrPr.Copy(new_tr_pr); 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.SetTcTcPr(var tc: Tc); begin new_tc_pr := new TcPr(); {self.}SetTcPrByStyleId(new_tc_pr, tbl_pr_unit_decorator_.TblStyle.Val); new_tc_pr.Copy(tc.TcPr); tc.TcPr.Copy(new_tc_pr); 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.GetLastPage(): TSPage; begin return last_page_; end; function TSPdfTableRange.Rows(): integer; begin return rows_; end; function TSPdfTableRange.Cols(): integer; begin return cols_; end;