From a0ea61af147e043b831bd8fba477f2f8ea5dbbf1 Mon Sep 17 00:00:00 2001 From: csh Date: Tue, 3 Sep 2024 16:49:25 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BC=98=E5=8C=96=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=A0=BC=E5=90=88=E5=B9=B6=202.=20=E6=94=AF=E6=8C=81=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=A0=BC=E5=9E=82=E7=9B=B4=E5=B1=85=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TSDocxToPdf.tsf | 9 +- range/Advanced/TSPdfCellRange.tsf | 54 ++++++--- range/Advanced/TSPdfLineRange.tsf | 10 ++ range/Advanced/TSPdfParagraphRange.tsf | 34 +++++- range/Advanced/TSPdfTableRange.tsf | 151 +++++++++++++++++++------ ware/TSDocxComponentsWare.tsf | 20 ++-- 6 files changed, 213 insertions(+), 65 deletions(-) diff --git a/TSDocxToPdf.tsf b/TSDocxToPdf.tsf index 09ac3c1..c9723bc 100644 --- a/TSDocxToPdf.tsf +++ b/TSDocxToPdf.tsf @@ -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(); diff --git a/range/Advanced/TSPdfCellRange.tsf b/range/Advanced/TSPdfCellRange.tsf index 6865081..aa6e137 100644 --- a/range/Advanced/TSPdfCellRange.tsf +++ b/range/Advanced/TSPdfCellRange.tsf @@ -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; diff --git a/range/Advanced/TSPdfLineRange.tsf b/range/Advanced/TSPdfLineRange.tsf index 7c595f8..e5ff25f 100644 --- a/range/Advanced/TSPdfLineRange.tsf +++ b/range/Advanced/TSPdfLineRange.tsf @@ -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; diff --git a/range/Advanced/TSPdfParagraphRange.tsf b/range/Advanced/TSPdfParagraphRange.tsf index f2c8e82..6258bdf 100644 --- a/range/Advanced/TSPdfParagraphRange.tsf +++ b/range/Advanced/TSPdfParagraphRange.tsf @@ -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,10 +371,8 @@ 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]; - line_range.Align(ppr_unit_decorator_.Jc.Val); + for _,line_range in line_range_array_ do + line_range.Align(ppr_unit_decorator_.Jc.Val); end; function TSPdfParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; @@ -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; diff --git a/range/Advanced/TSPdfTableRange.tsf b/range/Advanced/TSPdfTableRange.tsf index de0daf6..50fb081 100644 --- a/range/Advanced/TSPdfTableRange.tsf +++ b/range/Advanced/TSPdfTableRange.tsf @@ -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; diff --git a/ware/TSDocxComponentsWare.tsf b/ware/TSDocxComponentsWare.tsf index abbf488..b5e6798 100644 --- a/ware/TSDocxComponentsWare.tsf +++ b/ware/TSDocxComponentsWare.tsf @@ -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);