From 51dc8596be6e7600efab3a49d26692e184f77a89 Mon Sep 17 00:00:00 2001 From: csh Date: Thu, 4 Jul 2024 11:20:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9range=E8=BF=9B=E8=A1=8C=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TSDocxToPdf.tsf | 18 +- range/Advanced/TSPdfCellRange.tsf | 147 ++++++++++ range/Advanced/TSPdfLineRange.tsf | 59 ++++ range/{ => Advanced}/TSPdfParagraphRange.tsf | 155 +++++------ range/Advanced/TSPdfTableRange.tsf | 187 +++++++++++++ range/TSPdfAbstractRange.tsf | 10 - range/TSPdfImageRange.tsf | 21 -- range/TSPdfRectRange.tsf | 16 -- range/TSPdfTableRange.tsf | 273 ------------------- range/basic/TSPdfBasicRange.tsf | 27 ++ range/basic/TSPdfImageRange.tsf | 28 ++ range/basic/TSPdfRectangleRange.tsf | 22 ++ range/{ => basic}/TSPdfTextRange.tsf | 21 +- 13 files changed, 562 insertions(+), 422 deletions(-) create mode 100644 range/Advanced/TSPdfCellRange.tsf create mode 100644 range/Advanced/TSPdfLineRange.tsf rename range/{ => Advanced}/TSPdfParagraphRange.tsf (72%) create mode 100644 range/Advanced/TSPdfTableRange.tsf delete mode 100644 range/TSPdfAbstractRange.tsf delete mode 100644 range/TSPdfImageRange.tsf delete mode 100644 range/TSPdfRectRange.tsf delete mode 100644 range/TSPdfTableRange.tsf create mode 100644 range/basic/TSPdfBasicRange.tsf create mode 100644 range/basic/TSPdfImageRange.tsf create mode 100644 range/basic/TSPdfRectangleRange.tsf rename range/{ => basic}/TSPdfTextRange.tsf (57%) diff --git a/TSDocxToPdf.tsf b/TSDocxToPdf.tsf index 70d3355..3050faa 100644 --- a/TSDocxToPdf.tsf +++ b/TSDocxToPdf.tsf @@ -242,25 +242,23 @@ 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, current_page_, docx_components_, sect_ware, paragraph); - range.X := point_.X; - range.Y := point_.Y; - range.W := w; - range.H := 0; + range.StartX := point_.X; + range.StartY := point_.Y; + range.Width := w; range.Calc(); range.Do(); - point_.Y := range.Y; + point_.Y := range.EndY; end; function TSDocxToPdf.TransformTable(sect_ware: TSSectWare; table: Tbl); begin w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left; range := new TSPdfTableRange(self, current_page_, docx_components_, sect_ware, table); - range.X := point_.X; - range.Y := point_.Y; - range.W := w; - range.H := 0; + range.StartX := point_.X; + range.StartY := point_.Y; + range.Width := w; range.Calc(); range.Do(); - point_.Y := range.Y; + point_.Y := range.EndY; end; diff --git a/range/Advanced/TSPdfCellRange.tsf b/range/Advanced/TSPdfCellRange.tsf new file mode 100644 index 0000000..4c64ff0 --- /dev/null +++ b/range/Advanced/TSPdfCellRange.tsf @@ -0,0 +1,147 @@ +type TSPdfCellRange = class(TSPdfBasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; sect_ware: TSSectWare; tc: Tc; tbl_pr: TblPr); + function Calc(); + function AlignHeight(surplus: real); + function GetLastPage(); + function Do();override; + +private + docx_to_pdf_: TSDocxToPdf; + page_: PdfPage; + docx_components_: Components; + sect_ware_: TSSectWare; + tc_: Tc; + tbl_pr_: TblPr; + region_array_: array of Region; // 单元格可能跨页,所以可能存在多个 +end; + +type Region = class + function Create(); + begin + RectangleRange := new TSPdfRectangleRange(); + RangeArr := array(); + end + + RectangleRange: TSPdfRectangleRange; + RangeArr: array of TSPdfAbstractRange; +end; + +function TSPdfCellRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; sect_ware: TSSectWare; tc: Tc; tbl_pr: TblPr); +begin + docx_to_pdf_ := docx_to_pdf; + page_ := pg; + docx_components_ := components; + sect_ware_ := sect_ware; + tc_ := tc; + tbl_pr_ := tbl_pr; + region_array_ := array(); + self.Page := page_; +end; + +function TSPdfCellRange.Calc(); +begin + region := new Region(); + region.RectangleRange.EndX := self.StartX; + region.RectangleRange.EndY := self.StartY; + region.RectangleRange.Width := self.Width; + region.RectangleRange.FixedHeight := self.FixedHeight; + region.RectangleRange.Page := page_; + region_array_[length(region_array_)] := region; + + self.EndX := self.StartX; + self.EndY := self.StartY; + cell_x := self.EndX + tbl_pr_.TblCellMar.Left.W; + cell_y := self.EndY - tbl_pr_.TblCellMar.Top.W; + cell_w := self.Width - tbl_pr_.TblCellMar.Right.W - tbl_pr_.TblCellMar.Left.W; + cell_h := self.FixedHeight; + elements := tc_.Elements(); + for _,element in elements do + begin + range := nil; + if element.LocalName = "p" then + begin + 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_, page_, docx_components_, sect_ware_, element); + end + if ifObj(range) then + begin + range.StartX := cell_x; + range.StartY := cell_y; + range.Width := cell_w; + range.FixedHeight := cell_h; + range.Calc(); + region.RangeArr[length(region.RangeArr)] := range; + self.DynamicHeight += range.DynamicHeight; + cell_y -= range.DynamicHeight; + end + end + self.EndY := cell_y; + self.DynamicHeight += tbl_pr_.TblCellMar.Top.W + tbl_pr_.TblCellMar.Bottom.W; +end; + +function TSPdfCellRange.Do();override; +begin + for _,region in region_array_ do + begin + region.RectangleRange.Do(); + for _,range in region.RangeArr do + range.Do(); + end +end; + +function TSPdfCellRange.AlignHeight(surplus: real); +begin + region := region_array_[0]; + if surplus < 1e-6 then + begin + if region.RectangleRange.FixedHeight then region.RectangleRange.DynamicHeight := region.RectangleRange.FixedHeight; + self.EndY := self.StartY - region.RectangleRange.DynamicHeight; + return; + end + region.RectangleRange.DynamicHeight := self.StartY - sect_ware_.SectPr.PgMar.Bottom; + arr := region.RangeArr; + region.RangeArr := array(); + span := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top - sect_ware_.SectPr.PgMar.Bottom; + hash := array(region.RectangleRange.Page: region); + while surplus > span do + begin + page_ := docx_to_pdf_.GetNextPage(page_); + region := new Region(); + region.RectangleRange.EndX := self.StartX; + region.RectangleRange.EndY := self.StartY; + region.RectangleRange.Width := self.Width; + region.RectangleRange.DynamicHeight := span; + region.Page := page_; + region_array_[length(region_array_)] := region; + surplus -= span; + hash[region.RectangleRange.Page] := region; + end + if surplus > 1e-6 then + begin + page_ := docx_to_pdf_.GetNextPage(page_); + region := new Region(); + region.RectangleRange.EndX := self.StartX; + region.RectangleRange.EndY := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top; + region.RectangleRange.Width := self.Width; + region.RectangleRange.DynamicHeight := surplus; + region.RectangleRange.Page := page_; + region_array_[length(region_array_)] := region; + hash[region.RectangleRange.Page] := region; + self.EndY := region.RectangleRange.EndY - surplus; + end + for _,range in arr do + begin + region := hash[range.Page]; + region.RangeArr[length(region.RangeArr)] := range; + end +end; + +function TSPdfCellRange.GetLastPage(); +begin + return page_; +end; diff --git a/range/Advanced/TSPdfLineRange.tsf b/range/Advanced/TSPdfLineRange.tsf new file mode 100644 index 0000000..638747e --- /dev/null +++ b/range/Advanced/TSPdfLineRange.tsf @@ -0,0 +1,59 @@ +type TSPdfLineRange = class(TSPdfBasicRange) +public + function Create(pg: PdfPage); + function Do();override; + function AddRange(range: TSPdfBasicRange); + function SetAllRangeProp(pg: PdfPage; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); + function Align(jc: string); + +private + range_array_: array of TSPdfBasicRange; +end; + +function TSPdfLineRange.Create(pg: PdfPage); +begin + self.Page := pg; + range_array_ := array(); +end; + +function TSPdfLineRange.AddRange(range: TSPdfBasicRange); +begin + range_array_[length(range_array_)] := range; +end; + +function TSPdfLineRange.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function TSPdfLineRange.SetAllRangeProp(pg: PdfPage; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); +begin + for _,range in range_array_ do + begin + if not ifnil(pg) then range.Page := pg; + if not ifnil(sx) then range.StartX := sx; + if not ifnil(sy) then range.StartY := sy; + if not ifnil(ex) then range.EndX := ex; + if not ifnil(ey) then range.EndY := ey; + if not ifnil(w) then range.Width := w; + if not ifnil(fh) then range.FixedHeight := fh; + if not ifnil(dh) then range.DynamicHeight := dh; + end +end; + +function TSPdfLineRange.Align(jc: string); +begin + offset := 0; + first := range_array_[0]; + last := range_array_[length(range_array_)-1]; + case jc of + "center": + offset := (self.Width - last.EndX + first.EndX - last.Width) / 2; + "right": + offset := self.Width - last.EndX + first.EndX - last.Width; + end; + if offset <= 0 then return; + for _,range in range_array_ do + range.EndX += offset; +end; diff --git a/range/TSPdfParagraphRange.tsf b/range/Advanced/TSPdfParagraphRange.tsf similarity index 72% rename from range/TSPdfParagraphRange.tsf rename to range/Advanced/TSPdfParagraphRange.tsf index af6afcb..f00b2cb 100644 --- a/range/TSPdfParagraphRange.tsf +++ b/range/Advanced/TSPdfParagraphRange.tsf @@ -1,6 +1,6 @@ -type TSPdfParagraphRange = class(TSPdfAbstractRange) +type TSPdfParagraphRange = class(TSPdfBasicRange) public - function Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P); + function Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P); function Calc(); function Do();override; function SetExtraStyleId(style_id: string); @@ -21,6 +21,7 @@ private function RToDrawingRange(r: R; ppr: PPr); function SetLinesAlignment(ppr: PPr); function ResetCoordinates(ppr); + function NewLineRange(): TSPdfLineRange; private docx_to_pdf_: TSDocxToPdf; @@ -28,23 +29,22 @@ private sect_ware_: TSSectWare; paragraph_: P; extra_style_id_: string; - range_array_: array of TSPdfAbstractRange; page_: PdfPage; - point_: TSPoint; - lines_range_array_: tableArray; + range_array_: array of TSPdfBasicRange; + line_range_array_: array of TSPdfLineRange; end; -function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P); +function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P); begin docx_to_pdf_ := docx_to_pdf; - page_ := page; + page_ := pg; docx_components_ := Components; sect_ware_ := sect_ware; paragraph_ := paragraph; extra_style_id_ := ""; range_array_ := array(); - point_ := new TSPoint(); // 动态记录段落的坐标位置 - lines_range_array_ := array(); + line_range_array_ := array(); + self.Page := page_; end; function TSPdfParagraphRange.Calc(): tableArray; @@ -53,16 +53,17 @@ begin self.SetLvlText(); ppr := new PPrUnitDecorator(paragraph_.PPr); self.ResetCoordinates(ppr); - point_.X := self.X; - point_.Y := self.Y; - self.CheckAndAddPage(point_.Y, ppr.Spacing.Before); - point_.Y -= ppr.Spacing.Before; + self.EndX := self.StartX; + self.EndY := self.StartY; + self.CheckAndAddPage(self.EndY, ppr.Spacing.Before); + self.EndY -= ppr.Spacing.Before; + self.DynamicHeight += ppr.Spacing.Before; rs := paragraph_.Rs(); if length(rs) = 0 then begin line_space := self.GetParagraphLineSpace(ppr.RPr.Sz.Val, ppr.Spacing.Line); - if not self.H then self.H := ppr.Spacing.After + line_space; - point_.Y -= self.H; + self.DynamicHeight += ppr.Spacing.After + line_space; + self.EndY -= self.DynamicHeight; end else begin for _, r in rs do @@ -79,9 +80,8 @@ end; function TSPdfParagraphRange.Do(); begin - for _,line_range in lines_range_array_ do - for _,range in line_range do - range.Do(); + for _,line_range in line_range_array_ do + line_range.Do(); end; function TSPdfParagraphRange.SetExtraStyleId(style_id: string); @@ -89,94 +89,80 @@ begin extra_style_id_ := style_id; end; +function TSPdfParagraphRange.NewLineRange(): TSPdfLineRange; +begin + line_range := new TSPdfLineRange(page_); + line_range.StartX := self.EndX; + line_range.StartY := self.EndY; + line_range.Width := self.Width; + return line_range; +end; + function TSPdfParagraphRange.RangesToLines(ppr: PPr); begin - lines_range_array_ := array(); + line_range := self.NewLineRange(); i := 0; max_size := 0; max_y := 0; - line_range := array(); - total_height := 0; while i <= length(range_array_)-1 do begin range := range_array_[i]; - if i = 0 then point_.X += ppr.Ind.FirstLine; + if i = 0 then self.EndX += ppr.Ind.FirstLine; if range is class(TSPdfTextRange) and range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; - if range.H > max_y then max_y := range.H; + if range.DynamicHeight > max_y then max_y := range.DynamicHeight; 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 += diff; - if_newline := point_.X + range.W - self.X > self.W + 1e-6; - if if_newline and range.W < self.W then + diff := self.EndY - sect_ware_.SectPr.PgMar.Bottom; + if self.CheckAndAddPage(self.EndY, max(line_space, range.DynamicHeight)) then + self.DynamicHeight += diff; + if_newline := self.EndX + range.Width - self.StartX > self.Width + 1e-6; + if if_newline and range.Width < self.Width then begin offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; - for _,item in line_range do - begin - item.Page := page_; - item.Y := point_.Y - offset; - end - lines_range_array_[length(lines_range_array_)] := line_range; - line_range := array(); max_value := max(line_space, max_y); + line_range.Page := page_; + line_range.EndY := self.EndY - max_value; + line_range.DynamicHeight := max_value; + line_range.SetAllRangeProp(pg: page_, ey: self.EndY - offset); + line_range_array_[length(line_range_array_)] := line_range; + + line_range := self.NewLineRange(); max_size := 0; max_y := 0; - total_height += max_value; - point_.Y -= max_value; - point_.X := self.X; + self.DynamicHeight += max_value; + self.EndY -= max_value; + self.EndX := self.StartX; // 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; + self.EndX -= 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; + range.EndX := self.EndX - range.StartX; + self.EndX += range.Width; + line_range.AddRange(range); i++; if i = length(range_array_) then begin offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; - for _,item in line_range do - begin - item.Page := page_; - item.Y := point_.Y - offset; - end - lines_range_array_[length(lines_range_array_)] := line_range; max_value := max(line_space, max_y) + ppr.Spacing.After; - total_height += max_value; - point_.Y -= max_value; + line_range.Page := page_; + line_range.EndY := self.EndY - max_value; + line_range.DynamicHeight := max_value; + line_range.SetAllRangeProp(pg: page_, ey: self.EndY - offset); + line_range_array_[length(line_range_array_)] := line_range; + self.DynamicHeight += max_value; + self.EndY -= max_value; end end self.SetLinesAlignment(ppr); - if not self.H then self.H := total_height; - self.Y := point_.Y; end; 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]; - offset := 0; - case ppr.Jc.Val of - "center": - begin - first := line[0]; - last := line[length(line)-1]; - offset := (self.W - last.X + first.X - last.W) / 2; - end - "right": - begin - first := line[0]; - last := line[length(line)-1]; - 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; + if length(line_range_array_) = 0 then return; + idx := length(line_range_array_)-1; + line_range := line_range_array_[idx]; + line_range.Align(ppr.Jc.Val); end; function TSPdfParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; @@ -186,7 +172,7 @@ 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; + self.EndY := point.Y; return true; end return false; @@ -229,10 +215,7 @@ begin text_range.RPr := rpr; text_range.Text := word; text_range.Font := font_obj; - text_range.W := word_width; - text_range.H := 0; - text_range.X := 0; - text_range.Y := 0; + text_range.Width := word_width; range_array_[length(range_array_)] := text_range; end end; @@ -257,10 +240,10 @@ begin end; image_range := new TSPdfImageRange(); image_range.Image := image; - image_range.X := xfrm.Off.X; - image_range.Y := xfrm.Off.Y; - image_range.W := xfrm.Ext.CX; - image_range.H := xfrm.Ext.CY; + image_range.StartX := xfrm.Off.X; + image_range.StartY := xfrm.Off.Y; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; fileDelete("", image_path); range_array_[length(range_array_)] := image_range; end; @@ -360,7 +343,7 @@ 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; + self.StartX += 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; end; diff --git a/range/Advanced/TSPdfTableRange.tsf b/range/Advanced/TSPdfTableRange.tsf new file mode 100644 index 0000000..eca617b --- /dev/null +++ b/range/Advanced/TSPdfTableRange.tsf @@ -0,0 +1,187 @@ +type TSPdfTableRange = class(TSPdfBasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: 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); + function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); + function SetTcPr(var tc_pr: TcPr); + function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); + +private + docx_to_pdf_: TSDocxToPdf; + docx_components_: Components; + sect_ware_: TSSectWare; + table_: Tbl; + range_array_: tableArray; + page_: PdfPage; + point_: TSPoint; +end; + +function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; sect_ware: TSSectWare; table: Tbl); +begin + docx_to_pdf_ := docx_to_pdf; + page_ := pg; + docx_components_ := Components; + sect_ware_ := sect_ware; + table_ := table; + range_array_ := array(); + self.Page := page_; +end; + +function TSPdfTableRange.Calc(); +begin + self.SetTblPr(table_.TblPr); + tbl_pr := 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, grid_cols); + self.EndX := self.StartX; + self.EndY := self.StartY; + // 如果是根据内容自适应,应该计算并调整grid_cols的值 + trs := table_.Trs(); + for i,tr in trs do + 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(); + self.EndY := 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; + tc_x := self.EndX; + tc_y := self.EndY; + tc_h := height; + max_height := 0; + cell_range_array := array(); + tcs := tr.Tcs(); + for i,tc in tcs do + begin + cell_range := new TSPdfCellRange(docx_to_pdf_, page_, docx_components_, sect_ware_, tc, tbl_pr); + cell_range.StartX := tc_x; + cell_range.StartY := tc_y; + cell_range.Width := grid_cols[i].W; + cell_range.FixedHeight := tc_h; + cell_range.Calc(); + tc_x += grid_cols[i].W; + if cell_range.DynamicHeight > max_height then max_height := cell_range.DynamicHeight; + cell_range_array[length(cell_range_array)] := cell_range; + end + if tc_h > max_height then max_height := tc_h; + surplus := max_height - (self.EndY - sect_ware_.SectPr.PgMar.Bottom); + for _,range in cell_range_array do + begin + range.AlignHeight(surplus); + self.EndY := range.EndY; // 理论上每个range.EndY都是一个值 + page_ := range.GetLastPage(); + end + return cell_range_array; +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 := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter"); + style := styles.StyleId(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, table_.TblPr.TblStyle.Val); + new_tr_pr.Copy(tr_pr); + tr_pr.Copy(new_tr_pr); +end; + +function TSPdfTableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); +begin + styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter"); + style := styles.StyleId(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, table_.TblPr.TblStyle.Val); + new_tc_pr.Copy(tc_pr); + tc_pr.Copy(new_tc_pr); +end; + +function TSPdfTableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); +begin + styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter"); + style := styles.StyleId(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; diff --git a/range/TSPdfAbstractRange.tsf b/range/TSPdfAbstractRange.tsf deleted file mode 100644 index 164e365..0000000 --- a/range/TSPdfAbstractRange.tsf +++ /dev/null @@ -1,10 +0,0 @@ -type TSPdfAbstractRange = class -public - function Do();virtual; -public - X: real; - Y: real; // range的起始坐标(x,y) - W: real; // range的宽度 - H: real; // range的高度 - -end; diff --git a/range/TSPdfImageRange.tsf b/range/TSPdfImageRange.tsf deleted file mode 100644 index 4661acc..0000000 --- a/range/TSPdfImageRange.tsf +++ /dev/null @@ -1,21 +0,0 @@ -type TSPdfImageRange = class(TSPdfAbstractRange) -public - function Do();override; -public - Page: PdfPage; - Image: PdfImage; -end; - -function TSPdfImageRange.Do(); -begin - // println("image = {}, x = {}, y = {}, w = {}, h = {}", image, x, y, w, h); - self.Page.DrawImage(self.Image, self.X, self.Y, self.W, self.H); - -if sysparams["_PDF_IMAGE_DEBUG_"] then -begin - self.Page.SetLineWidth(0.1); - self.Page.SetRGBStroke(0.8, 0.8, 0); - self.Page.Rectangle(X, Y, W, H); - self.Page.Stroke(); -end -end; diff --git a/range/TSPdfRectRange.tsf b/range/TSPdfRectRange.tsf deleted file mode 100644 index 8455b83..0000000 --- a/range/TSPdfRectRange.tsf +++ /dev/null @@ -1,16 +0,0 @@ -type TSPdfRectRange = class(TSPdfAbstractRange) -public - function Do();override; -public - Page: PdfPage; -end; - -function TSPdfRectRange.Do();override; -begin - // 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 deleted file mode 100644 index d18fc23..0000000 --- a/range/TSPdfTableRange.tsf +++ /dev/null @@ -1,273 +0,0 @@ -type TSPdfTableRange = class(TSPdfAbstractRange) -public - 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); - function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); - function SetTcPr(var tc_pr: TcPr); - function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); - -private - docx_to_pdf_: TSDocxToPdf; - docx_components_: Components; - sect_ware_: TSSectWare; - table_: Tbl; - range_array_: tableArray; - page_: PdfPage; - point_: TSPoint; -end; - -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; - range_array_ := array(); - point_ := new TSPoint(); // 动态记录段落的坐标位置 -end; - -function TSPdfTableRange.Calc(); -begin - self.SetTblPr(table_.TblPr); - tbl_pr := 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, grid_cols); - point_.X := self.X; - point_.Y := self.Y; - // 如果是根据内容自适应,应该计算并调整grid_cols的值 - trs := table_.Trs(); - for i,tr in trs do - 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 i,tc in tcs do - begin - tc_w := grid_cols[i].W; - elements := tc.Elements(); - 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_; - 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_, 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_, page_, docx_components_, sect_ware_, element); - end - if ifObj(range) then - begin - 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 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; - 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; - -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.W; - case tbl_pr.jc.Val of - "center": - begin - offset := diff/2; - self.X -= offset; - end - "right": - begin - self.X -= diff; - end - end; - self.W := 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 := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter"); - style := styles.StyleId(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, table_.TblPr.TblStyle.Val); - new_tr_pr.Copy(tr_pr); - tr_pr.Copy(new_tr_pr); -end; - -function TSPdfTableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); -begin - styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter"); - style := styles.StyleId(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, table_.TblPr.TblStyle.Val); - new_tc_pr.Copy(tc_pr); - tc_pr.Copy(new_tc_pr); -end; - -function TSPdfTableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); -begin - styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter"); - style := styles.StyleId(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; diff --git a/range/basic/TSPdfBasicRange.tsf b/range/basic/TSPdfBasicRange.tsf new file mode 100644 index 0000000..f9b379a --- /dev/null +++ b/range/basic/TSPdfBasicRange.tsf @@ -0,0 +1,27 @@ +type TSPdfBasicRange = class +public + function Create(); + function Do();virtual; + +public + StartX: real; + StartY: real; // range的起始坐标(x,y) + EndX: real; + EndY: real; // range的结束坐标(x,y) + Width: real; + FixedHeight: real; + DynamicHeight: real; + Page: PdfPage; +end; + +function TSPdfBasicRange.Create(); +begin + self.StartX := 0; + self.StartY := 0; + self.EndX := 0; + self.EndY := 0; + self.Width := 0; + self.FixedHeight := 0; + self.DynamicHeight := 0; + self.Page := nil; +end; diff --git a/range/basic/TSPdfImageRange.tsf b/range/basic/TSPdfImageRange.tsf new file mode 100644 index 0000000..52ded8f --- /dev/null +++ b/range/basic/TSPdfImageRange.tsf @@ -0,0 +1,28 @@ +type TSPdfImageRange = class(TSPdfBasicRange) +public + function Create(); + function Do();override; + +public + Image: PdfImage; +end; + +function TSPdfImageRange.Create(); +begin + class(TSPdfBasicRange).Create(); + self.Image := nil; +end; + +function TSPdfImageRange.Do(); +begin + // println("image = {}, x = {}, y = {}, w = {}, h = {}", self.image, self.endx, self.endy, self.width, self.DynamicHeight); + self.Page.DrawImage(self.Image, self.EndX, self.EndY, self.Width, self.DynamicHeight); + +if sysparams["_PDF_IMAGE_DEBUG_"] then +begin + self.Page.SetLineWidth(0.1); + self.Page.SetRGBStroke(0.8, 0.8, 0); + self.Page.Rectangle(self.EndX, self.EndY, self.Width, self.DynamicHeight); + self.Page.Stroke(); +end +end; diff --git a/range/basic/TSPdfRectangleRange.tsf b/range/basic/TSPdfRectangleRange.tsf new file mode 100644 index 0000000..85a8633 --- /dev/null +++ b/range/basic/TSPdfRectangleRange.tsf @@ -0,0 +1,22 @@ +type TSPdfRectangleRange = class(TSPdfBasicRange) +public + function Create(); + function Do();override; + +end; + +function TSPdfRectangleRange.Create(); +begin + class(TSPdfBasicRange).Create(); +end; + +function TSPdfRectangleRange.Do();override; +begin + // self.Page.SetRGBStroke(1.0, 0.0, 0.0); + // println("page = {}, endx = {}, endy = {}, DynamicHeight = {}, Width = {}", self.Page, self.EndX, self.EndY, self.DynamicHeight, self.Width); + self.Page.SetGrayStroke(0.5); + self.Page.SetLineWidth(0.5); + self.Page.Rectangle(self.EndX, self.EndY - self.DynamicHeight, self.Width, self.DynamicHeight); + self.Page.Stroke(); + self.Page.SetGrayStroke(0); +end; diff --git a/range/TSPdfTextRange.tsf b/range/basic/TSPdfTextRange.tsf similarity index 57% rename from range/TSPdfTextRange.tsf rename to range/basic/TSPdfTextRange.tsf index f46dfc8..5738fd1 100644 --- a/range/TSPdfTextRange.tsf +++ b/range/basic/TSPdfTextRange.tsf @@ -1,23 +1,32 @@ -type TSPdfTextRange = class(TSPdfAbstractRange) +type TSPdfTextRange = class(TSPdfBasicRange) uses TSColorToolKit; public + function Create(); function Do();override; + public RPr: RPr; Text: string; Font: PdfFont; - Page: PdfPage; +end; + +function TSPdfTextRange.Create(); +begin + class(TSPdfBasicRange).Create(); + self.RPr := nil; + self.Text := ""; + self.Font := nil; end; function TSPdfTextRange.Do(); begin - // println("text = {}, x = {}, y = {}, w = {}, sz = {}", ansiToUtf8(text), x, y, w); + // println("text = {}, endx = {}, endy = {}, width = {}, page = {}", ansiToUtf8(text), endx, endy, width, page); [r, g, b] := array(0, 0, 0); if self.RPr.Color.Val then [r, g, b] := TSColorToolKit.HexToRGB(self.RPr.Color.Val); self.Page.SetRGBFill(r / 255, g / 255, b / 255); self.Page.SetFontAndSize(self.Font, self.RPr.Sz.Val); self.Page.BeginText(); - self.Page.TextOut(self.X, self.Y, self.Text); + self.Page.TextOut(self.EndX, self.EndY, self.Text); self.Page.EndText(); self.Page.SetRGBFill(0, 0, 0); @@ -26,8 +35,8 @@ 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(600, self.Y); + self.Page.MoveTo(0, self.EndY); + self.Page.LineTo(600, self.EndY); self.Page.Stroke(); end end;