From 20cfa5120adf6e9aa1baa3ade104dede8a353e95 Mon Sep 17 00:00:00 2001 From: csh Date: Tue, 25 Jun 2024 14:19:57 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=AC=AC=E4=B8=80=E7=89=88?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TSDocxToPdf.tsf | 29 ++++--- range/TSPdfImageRange.tsf | 17 ++-- range/TSPdfParagraphRange.tsf | 49 +++++++----- range/TSPdfRectRange.tsf | 5 +- range/TSPdfTableRange.tsf | 147 ++++++++++++++++++++++++++++------ range/TSPdfTextRange.tsf | 13 +-- 6 files changed, 190 insertions(+), 70 deletions(-) diff --git a/TSDocxToPdf.tsf b/TSDocxToPdf.tsf index f5752bd..8f78fd2 100644 --- a/TSDocxToPdf.tsf +++ b/TSDocxToPdf.tsf @@ -9,6 +9,7 @@ public function GetCurrentPoint(): Point; function GetTempPath(image_path: string): string; function GetPdf(): PdfFile; + function GetNextPage(page: PdfPage): PdfPage; function AddPage(sect_ware: TSSectWare): PdfPage; property Font read ReadFont; @@ -34,8 +35,9 @@ private sect_ware_array_: array of TSSectWare; // 页面布局组件数组 font_ware_: TSFontWare; // 字体部件 current_page_: PdfPage; - page_array_: array of PdfPage; point_: TSPoint; // 定位坐标点 + page_array_: array of PdfPage; + page_index_: tableArray; end; function TSDocxToPdf.Create(alias: string; file: string); @@ -47,8 +49,9 @@ begin self.InitSectWare(); font_ware_ := new TSFontWare(pdf_); current_page_ := nil; - page_array_ := array(); point_ := new TSPoint(); + page_array_ := array(); + page_index_ := array(); end; function TSDocxToPdf.Destroy(); @@ -162,7 +165,7 @@ begin sect_ware_array_[length(sect_ware_array_)] := ware; end end - println("sect_ware_array_ = {}", sect_ware_array_); + // println("sect_ware_array_ = {}", sect_ware_array_); end; function TSDocxToPdf.AddPage(sect_ware: TSSectWare): PdfPage; @@ -171,16 +174,23 @@ begin current_page_.SetWidth(sect_ware.SectPr.PgSz.W); current_page_.SetHeight(sect_ware.SectPr.PgSz.H); self.ResetCoordinates(sect_ware); - page_array_[length(page_array_)] := current_page_; -{$DEFINE WordToPdfTEST} -{$IFDEF WordToPdfTEST} + len := length(page_array_); + page_array_[len] := current_page_; + page_index_[current_page_] := len; + +if sysparams["_PDF_PAGE_GRID_DEBUG_"] then self.PrintGrid(current_page_, sect_ware); -{$ENDIF} return current_page_; end; +function TSDocxToPdf.GetNextPage(page: PdfPage); +begin + pos := page_index_[page]; + return page_array_[pos + 1]; +end; + function TSDocxToPdf.ResetCoordinates(sect_ware: TSSectWare); begin point_.X := sect_ware.SectPr.PgMar.Left; @@ -229,7 +239,7 @@ end; function TSDocxToPdf.TransformParagraph(sect_ware: TSSectWare; paragraph: P); begin w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left; - range := new TSPdfParagraphRange(self, docx_components_, sect_ware, paragraph); + range := new TSPdfParagraphRange(self, current_page_, docx_components_, sect_ware, paragraph); range.X := point_.X; range.Y := point_.Y; range.W := w; @@ -241,9 +251,8 @@ end; function TSDocxToPdf.TransformTable(sect_ware: TSSectWare; table: Tbl); begin - return; w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left; - range := new TSPdfTableRange(self, docx_components_, sect_ware, table); + range := new TSPdfTableRange(self, current_page_, docx_components_, sect_ware, table); range.X := point_.X; range.Y := point_.Y; range.W := w; diff --git a/range/TSPdfImageRange.tsf b/range/TSPdfImageRange.tsf index 3104964..4661acc 100644 --- a/range/TSPdfImageRange.tsf +++ b/range/TSPdfImageRange.tsf @@ -8,19 +8,14 @@ end; function TSPdfImageRange.Do(); begin - println("image = {}, x = {}, y = {}, w = {}, h = {}", image, x, y, w, h); + // println("image = {}, x = {}, y = {}, w = {}, h = {}", image, x, y, w, h); self.Page.DrawImage(self.Image, self.X, self.Y, self.W, self.H); -{$DEFINE WordToPdfTEST} -{$IFDEF WordToPdfTEST} - // Page.SetLineWidth(0.5); - // Page.SetGrayStroke(0.5); - // Page.MoveTo(0, self.Y); - // Page.LineTo(90, self.Y); - // Page.Stroke(); +if sysparams["_PDF_IMAGE_DEBUG_"] then +begin self.Page.SetLineWidth(0.1); - self.Page.SetGrayStroke(0.5); - self.Page.Rectangle(0, Y, 900, H); + self.Page.SetRGBStroke(0.8, 0.8, 0); + self.Page.Rectangle(X, Y, W, H); self.Page.Stroke(); -{$ENDIF} +end end; diff --git a/range/TSPdfParagraphRange.tsf b/range/TSPdfParagraphRange.tsf index 729a4c1..7249d39 100644 --- a/range/TSPdfParagraphRange.tsf +++ b/range/TSPdfParagraphRange.tsf @@ -1,6 +1,6 @@ type TSPdfParagraphRange = class(TSPdfAbstractRange) public - function Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P); + function Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P); function Calc(); function Do();override; function SetExtraStyleId(style_id: string); @@ -19,7 +19,8 @@ private function RToTextRange(r: R; ppr: PPr); function SplitTextToTextRange(text: string; rpr: RPr); function RToDrawingRange(r: R; ppr: PPr); - function SetLinesAlignment(lines_range_array: tableArray; ppr: PPr); + function SetLinesAlignment(ppr: PPr); + function ResetCoordinates(ppr); private docx_to_pdf_: TSDocxToPdf; @@ -33,14 +34,14 @@ private lines_range_array_: tableArray; end; -function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P); +function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P); begin docx_to_pdf_ := docx_to_pdf; + page_ := page; docx_components_ := Components; sect_ware_ := sect_ware; paragraph_ := paragraph; extra_style_id_ := ""; - page_ := docx_to_pdf_.GetCurrentPage(); range_array_ := array(); point_ := new TSPoint(); // 动态记录段落的坐标位置 lines_range_array_ := array(); @@ -51,9 +52,7 @@ begin self.SetPPr(paragraph_.PPr); self.SetLvlText(); ppr := new PPrUnitDecorator(paragraph_.PPr); - // 根据段落的间距确定新的坐标 - self.X += ppr.Ind.Left; - self.W := self.W - ppr.Ind.Left - ppr.Ind.Right; + self.ResetCoordinates(ppr); point_.X := self.X; point_.Y := self.Y; self.CheckAndAddPage(point_.Y, ppr.Spacing.Before); @@ -106,9 +105,9 @@ begin max_size := range.RPr.Sz.Val; if range.H > max_y then max_y := range.H; line_space := self.GetParagraphLineSpace(max_size, ppr.Spacing.Line); + diff := point_.Y - sect_ware_.SectPr.PgMar.Bottom; if self.CheckAndAddPage(point_.Y, max(line_space, range.H)) then - total_height += point_.Y - sect_ware_.SectPr.PgMar.Bottom; - range.X := point_.X - range.X; + total_height += diff; if_newline := point_.X + range.W - self.X > self.W + 1e-6; if if_newline and range.W < self.W then begin @@ -126,8 +125,12 @@ begin total_height += max_value; point_.Y -= max_value; point_.X := self.X; + // w:hanging + sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); + point_.X -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging; continue; end + range.X := point_.X - range.X; point_.X += range.W; line_range[length(line_range)] := range; i++; @@ -140,21 +143,21 @@ begin item.Y := point_.Y - offset; end lines_range_array_[length(lines_range_array_)] := line_range; - max_value := max(line_space, max_y); + max_value := max(line_space, max_y) + ppr.Spacing.After; total_height += max_value; point_.Y -= max_value; end end - // self.SetLinesAlignment(lines_range_array, ppr); + self.SetLinesAlignment(ppr); if not self.H then self.H := total_height; self.Y := point_.Y; end; -function TSPdfParagraphRange.SetLinesAlignment(lines_range_array: tableArray; ppr: PPr); +function TSPdfParagraphRange.SetLinesAlignment(ppr: PPr); begin - if length(lines_range_array) = 0 then return; - idx := length(lines_range_array)-1; - line := lines_range_array[idx]; + if length(lines_range_array_) = 0 then return; + idx := length(lines_range_array_)-1; + line := lines_range_array_[idx]; offset := 0; case ppr.Jc.Val of "center": @@ -170,6 +173,7 @@ begin offset := self.W - last.X + first.X - last.W; end end; + if offset < 0 then return; if offset then for i:=0 to length(line)-1 do line[i].X += offset; @@ -179,10 +183,10 @@ function TSPdfParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; begin if y - offset < sect_ware_.SectPr.PgMar.Bottom then begin - page_ := docx_to_pdf_.AddPage(sect_ware_); + page_ := docx_to_pdf_.GetNextPage(page_); + if ifnil(page_) then page_ := docx_to_pdf_.AddPage(sect_ware_); point := docx_to_pdf_.GetCurrentPoint(); point_.Y := point.Y; - page_array_ := array(page_); return true; end return false; @@ -217,7 +221,7 @@ begin word := utf8ToAnsi(word); pos += num; font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; - font_obj := docx_to_pdf_.Font.GetFont(font_name, 0, 0); + font_obj := docx_to_pdf_.Font.GetFont(font_name, rpr.B, rpr.I); if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); page_.SetFontAndSize(font_obj, rpr.Sz.Val); word_width := page_.TextWidth(word); @@ -351,3 +355,12 @@ begin rpr := new RPrUnitDecorator(lvl.RPr); self.SplitTextToTextRange(lvl_text, rpr); end; + +function TSPdfParagraphRange.ResetCoordinates(ppr); +begin + // 根据段落的间距确定新的坐标 + sz := ppr.RPr.SzCs.Val ? ppr.RPr.SzCs.Val : ppr.RPr.Sz.Val ? ppr.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); + self.X += ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left; + self.W -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left; + self.W -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right; +end; diff --git a/range/TSPdfRectRange.tsf b/range/TSPdfRectRange.tsf index ce7c8ac..8455b83 100644 --- a/range/TSPdfRectRange.tsf +++ b/range/TSPdfRectRange.tsf @@ -7,7 +7,10 @@ end; function TSPdfRectRange.Do();override; begin - self.Page.SetRGBStroke(1.0, 0.0, 0.0); + // self.Page.SetRGBStroke(1.0, 0.0, 0.0); + self.Page.SetGrayStroke(0.5); + self.Page.SetLineWidth(0.5); self.Page.Rectangle(self.X, self.Y - self.H, self.W, self.H); self.Page.Stroke(); + self.Page.SetGrayStroke(0); end; diff --git a/range/TSPdfTableRange.tsf b/range/TSPdfTableRange.tsf index fb3e5ee..6ac9dfc 100644 --- a/range/TSPdfTableRange.tsf +++ b/range/TSPdfTableRange.tsf @@ -1,11 +1,13 @@ type TSPdfTableRange = class(TSPdfAbstractRange) public - function Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P); - function Calc(): tableArray; + function Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P); + function Calc(); + function Do();override; private function ProcessTrData(grid_cols: array of GridCol; tr: Tr; tbl_pr: TblPr): array of TSPdfAbstractRange; function ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol); + function CheckAndAddPage(y: real; offset: real): boolean; function SetTblPr(tbl_pr: TblPr); function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); function SetTrPr(var tr_pr: TrPr); @@ -18,23 +20,23 @@ private docx_components_: Components; sect_ware_: TSSectWare; table_: Tbl; - range_array_: array of TSPdfAbstractRange; + range_array_: tableArray; page_: PdfPage; point_: TSPoint; end; -function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; table: Tbl); +function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; table: Tbl); begin docx_to_pdf_ := docx_to_pdf; + page_ := page; docx_components_ := Components; sect_ware_ := sect_ware; table_ := table; - page_ := docx_to_pdf_.GetCurrentPage(); range_array_ := array(); point_ := new TSPoint(); // 动态记录段落的坐标位置 end; -function TSPdfTableRange.Calc(): tableArray; +function TSPdfTableRange.Calc(); begin self.SetTblPr(table_.TblPr); tbl_pr := new TblPrUnitDecorator(table_.TblPr); @@ -46,51 +48,149 @@ begin point_.Y := self.Y; // 如果是根据内容自适应,应该计算并调整grid_cols的值 trs := table_.Trs(); - matrix := array(); for i,tr in trs do - matrix[i] := self.ProcessTrData(grid_cols, tr, tbl_pr); - return matrix; + range_array_[i] := self.ProcessTrData(grid_cols, tr, tbl_pr); +end; + +function TSPdfTableRange.Do(); +begin + for _,row in range_array_ do + for _,range in row do + range.Do(); +end; + +function TSPdfTableRange.CheckAndAddPage(y: real; offset: real): boolean; +begin + if y - offset < sect_ware_.SectPr.PgMar.Bottom then + begin + page_ := docx_to_pdf_.GetNextPage(page_); + if ifnil(page_) then page_ := docx_to_pdf_.AddPage(sect_ware_); + point := docx_to_pdf_.GetCurrentPoint(); + point_.Y := point.Y; + return true; + end + return false; end; function TSPdfTableRange.ProcessTrData(grid_cols: array of GridCol; tr: Tr; tbl_pr: TblPr): array of TSPdfAbstractRange; begin self.SetTrPr(tr.TrPr); tr_pr := new TrPrUnitDecorator(tr.TrPr); + height := tr_pr.TrHeight.Val; tcs := tr.Tcs(); + tc_x := point_.X; + tc_y := point_.Y; + tc_h := height; + max_height := tc_h; rows_range_array := array(); - for _,tc in tcs do + for i,tc in tcs do begin + tc_w := grid_cols[i].W; elements := tc.Elements(); rect_range := new TSPdfRectRange(); - rect_range.X := point_.X; - rect_range.Y := point_.Y; - rect_range.W := grid_col.W; - rect_range.H := 100; + rect_range.X := tc_x; + rect_range.Y := tc_y; + rect_range.W := tc_w; + rect_range.H := tc_h; + rect_range.Page := page_; rows_range_array[length(rows_range_array)] := rect_range; + + cell_x := tc_x + tbl_pr.TblCellMar.Left.W; + cell_y := tc_y - tbl_pr.TblCellMar.Top.W; + cell_w := tc_w - tbl_pr.TblCellMar.Right.W - tbl_pr.TblCellMar.Left.W; + cell_total_h := 0; for _,element in elements do begin range := nil; if element.LocalName = "p" then begin - range := new TSPdfParagraphRange(docx_to_pdf_, docx_components_, sect_ware_, element); + if element.w14paraId="5CEC646C" then + println("???????????"); + range := new TSPdfParagraphRange(docx_to_pdf_, page_, docx_components_, sect_ware_, element); range.SetExtraStyleId(tbl_pr.TblStyle.Val); end else if element.LocalName = "tbl" then begin - range := new TSPdfTableRange(docx_to_pdf_, docx_components_, sect_ware_, element); + range := new TSPdfTableRange(docx_to_pdf_, page_, docx_components_, sect_ware_, element); end if ifObj(range) then begin - range.X := point_.X - tbl_pr.TblCellMar.Left.W; - range.Y := point_.Y - tbl_pr.TblCellMar.Top.W; - range.W := grid_col.W - tbl_pr.TblCellMar.Right.W; - range.H := nil; - ret := range.Calc(); - point_.Y := range.Y; - point_.X += grid_col.W; + range.X := cell_x; + range.Y := cell_y; + range.W := cell_w; + range.H := tc_h; + range.Calc(); rows_range_array[length(rows_range_array)] := range; + cell_total_h += range.H; + cell_y -= range.H; end end + tc_x += tc_w; + if cell_total_h > max_height then max_height := cell_total_h; + end + // 判定是否跨页 + total_height := max_height + tbl_pr.TblCellMar.Top.W + tbl_pr.TblCellMar.Bottom.W; + surplus := total_height - (point_.Y - sect_ware_.SectPr.PgMar.Bottom); + if not tc_h and not self.H and surplus > 0 then + begin + for _,range in rows_range_array do + range.H := point_.Y - sect_ware_.SectPr.PgMar.Bottom; + span := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top - sect_ware_.SectPr.PgMar.Bottom; + quotient := surplus div span; + remainder := surplus % span; + println("page_ = {}, quotient = {}, remainder = {}", page_, quotient, remainder); + page := page_; + tc_y := point_.Y; + i := 0; + while i < quotient do + begin + tc_x := point_.X; + tc_y := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top; + tc_h := tc_y - sect_ware_.SectPr.PgMar.Bottom; + page := docx_to_pdf_.GetNextPage(page); + for j:=0 to length(tcs)-1 do + begin + tc_w := grid_cols[i].W; + rect_range := new TSPdfRectRange(); + rect_range.X := tc_x; + rect_range.Y := tc_y; + rect_range.W := tc_w; + rect_range.H := tc_h; + rect_range.Page := page; + tc_x += tc_w; + rows_range_array[length(rows_range_array)] := rect_range; + end + i++; + end + if remainder then + begin + tc_x := point_.X; + tc_y := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top; + tc_h := remainder; + page := docx_to_pdf_.GetNextPage(page); + for j:=0 to length(tcs)-1 do + begin + tc_w := grid_cols[i].W; + rect_range := new TSPdfRectRange(); + rect_range.X := tc_x; + rect_range.Y := tc_y; + rect_range.W := tc_w; + rect_range.H := tc_h; + rect_range.Page := page; + tc_x += tc_w; + rows_range_array[length(rows_range_array)] := rect_range; + end + end + point_.Y := tc_y - remainder; + self.Y := point_.Y; + page_ := page; + end + else begin + tc_h := tc_h ? tc_h : max_height; + for _,range in rows_range_array do + range.H := tc_h; + point_.Y -= tc_h; + self.Y := point_.Y; end return rows_range_array; end; @@ -118,7 +218,6 @@ end; function TSPdfTableRange.SetTblPr(var tbl_pr: TblPr); begin new_tbl_pr := new TblPr(); - tbl_pr.TblStyle.XmlNode.print; self.SetTblPrByStyleId(new_tbl_pr, tbl_pr.TblStyle.Val); new_tbl_pr.Copy(tbl_pr); tbl_pr.Copy(new_tbl_pr); diff --git a/range/TSPdfTextRange.tsf b/range/TSPdfTextRange.tsf index 4c4d79c..f46dfc8 100644 --- a/range/TSPdfTextRange.tsf +++ b/range/TSPdfTextRange.tsf @@ -21,13 +21,14 @@ begin self.Page.EndText(); self.Page.SetRGBFill(0, 0, 0); -{$DEFINE WordToPdfTEST} -{$IFDEF WordToPdfTEST} - self.Page.SetLineWidth(0.5); - self.Page.SetGrayStroke(0.5); + +if sysparams["_PDF_TEXT_DEBUG_"] then +begin + self.Page.SetLineWidth(0.1); + self.Page.SetRGBStroke(1.0, 0.5, 0.0); self.Page.MoveTo(0, self.Y); - self.Page.LineTo(90, self.Y); + self.Page.LineTo(600, self.Y); self.Page.Stroke(); -{$ENDIF} +end end;