From 9f84a7259594d775b0536ce05757c0409503675a Mon Sep 17 00:00:00 2001 From: csh Date: Mon, 24 Mar 2025 17:17:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=87=8D=E6=9E=84=20fix?= =?UTF-8?q?=EF=BC=9A=E8=A1=A8=E6=A0=BC=E8=BE=B9=E6=A1=86=E9=94=99=E8=AF=AF?= =?UTF-8?q?=20=E6=B3=A8=E6=84=8F=EF=BC=9A=E6=9A=82=E6=97=B6=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E8=84=9A=E6=B3=A8=E5=92=8C=E5=85=AC=E5=BC=8F=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TSDocxToPdf.tsf | 268 +-- internal/DTPAdvancedRanges.tsf | 3592 +++++++++++++++---------------- internal/DTPModules.tsf | 155 +- internal/DTPPrimitiveRanges.tsf | 107 +- internal/DTPUtils.tsf | 33 +- 5 files changed, 2015 insertions(+), 2140 deletions(-) diff --git a/TSDocxToPdf.tsf b/TSDocxToPdf.tsf index 657bc64..83cc4fb 100644 --- a/TSDocxToPdf.tsf +++ b/TSDocxToPdf.tsf @@ -8,10 +8,9 @@ public function GetCachePath(image_path: string): string; function GetCurrentXmlFile(): string; - function GetCurrentNoteModule(): NoteModule; function AddPage(flag: boolean): Page; - function ProcessNumpages(); + function ProcessRealtimeRange(); // docx页码扩展 function UpdateDocxPageNumPages(); @@ -19,10 +18,13 @@ public function SaveDocxFile(alias: string; file: string);overload; property PdfFile read pdf_; + property DocxComponents read docx_components_module_; property Font read font_module_; property PageManager read page_manager_module_; property Toc read toc_module_; property Note read note_module_; + property CurrentSect read current_sect_module_; + property CurrentPage read current_page_; private function InitDocxComponents(alias: string; file: string); @@ -31,16 +33,17 @@ private function InitSectModule(); function AllocateElementsToSectModule(); function ClassifyCols(var point: Point; cols: Cols); + function RangesSpacing(range: BasicRange); function SetHdr(type: string); function SetFtr(type: string); - function TransformP(paragraph: P; x: real; y: real; w: real; lb: real): ParagraphRange; - function TransformTbl(table: Tbl; x: real; y: real; w: real; lb: real): TableRange; - function TransformSdt(sdt: Sdt; x: real; y: real; w: real; lb: real): array of ParagraphRange; + function TransformP(p: P); + function TransformTbl(tbl: Tbl); + function TransformSdt(sdt: Sdt); private pdf_: PdfFile; - docx_components_module_: DocxComponentsModule; // TSDocxComponentsModule + docx_components_module_: DocxComponentsModule; // DocxComponentsModule cache_path_: string; // 临时目录,用来存放临时文件 font_module_: FontModule; // 字体模块 sect_module_array_: array of SectModule; // 页面布局模块数组 @@ -53,11 +56,13 @@ private toc_module_: TocModule; // 目录模块 note_module_: NoteModule; // 脚注/尾注 - range_page_number_array_: tableArray; - xml_file_: string; even_and_odd_flag_: boolean; + realtime_range_array_: array of BasicRange; // 最后才能计算出来的range,比如包含总页码的 + + last_range_: BasicRange; // 上一个range + // 回写docx docx_page_arr_: tableArray; update_docx_pages_: boolean; @@ -77,13 +82,14 @@ begin page_manager_module_ := new DTPModules.PageManagerModule(pdf_); toc_module_ := new DTPModules.TocModule(); - range_page_number_array_ := array(); xml_file_ := "document.xml"; settings := docx_components_module_.Settings; settings.XmlChildEvenAndOddHeaders.Deserialize(); even_and_odd_flag_ := settings.EvenAndOddHeaders ? true : false; - note_module_ := new ; + note_module_ := new DTPModules.NoteModule(self); + + realtime_range_array_ := array(); // 回写docx docx_page_arr_ := array(); @@ -109,7 +115,6 @@ begin current_sect_module_ := sect_module; current_sect_pr_adapter_ := new SectPrAdapter(current_sect_module_.SectPr.GetObject()); {self.}AddPage(true); - xml_file_ := "document.xml"; end // 分栏 @@ -120,28 +125,18 @@ begin columns := {self.}ClassifyCols(current_page_.TextPoint, cols); end else begin - w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left; - lb := max(current_page_.SectPr.PgMar.Bottom, current_page_.FtrPoint.Y); for _,element in elements do begin - x := current_page_.TextPoint.X; - y := current_page_.TextPoint.Y; - // if _ = 266 then break; - // if _ = 20 then - // println("_ = {}, xml_file_ = {}, error = {}", _, xml_file_, pdf_.GetError()); - range := nil; - if element.LocalName = "p" then range := {self.}TransformP(element, x, y, w, lb); - else if element.LocalName = "tbl" then range := {self.}TransformTbl(element, x, y, w, lb); - else if element.LocalName = "sdt" then {self.}TransformSdt(element, x, y, w, lb); - if ifObj(range) then - begin - current_page_.TextPoint.Y := range.EndY; - range.Do(); - end + // if _ = 100 then break; + // if _ = 17 then + // println("_ = {}, paraid = {}, xml_file_ = {}, error = {}", _, element.ParaId, xml_file_, pdf_.GetError()); + if element.LocalName = "p" then {self.}TransformP(element); + else if element.LocalName = "tbl" then {self.}TransformTbl(element); + else if element.LocalName = "sdt" then {self.}TransformSdt(element); end end end - {self.}ProcessNumpages(); + {self.}ProcessRealtimeRange(); end; function TSDocxToPdf.GetCachePath(image_path: string): string; @@ -197,12 +192,13 @@ begin sect.PgSz.Orient := sect.PgSz.Orient ? "portrait" : "landscape"; sect.Type.Val := sect.Type.Val ?: "nextPage"; module.SectPr := sect; + module.BaseSize := round(sect.DocGrid.LinePitch * 0.75); end for i:=0 to length(elements)-1 do begin element := elements[i]; module.AddElement(element); - if element.LocalName = "p" and ifObj(element.PPr.SectPr) then + if element.LocalName = "p" and element.PPr.SectPr then begin ##fp(module, element.PPr.SectPr); sect_module_array_[length(sect_module_array_)] := module; @@ -224,22 +220,8 @@ begin page := page_manager_module_.NewPage(); page.SectPr := current_sect_module_.SectPr; page.Number := flag ? ifnil(current_sect_module_.SectPr.PgNumType.Start) ? 1 : current_sect_module_.SectPr.PgNumType.Start : page_manager_module_[page_manager_module_.Count() - 2].Number + 1; - page.BaseSize := round(page.SectPr.DocGrid.LinePitch * 0.75); - - // 正文、页眉页脚坐标 - // 页眉:从上往下,不需要调整 - page.HdrPoint.X := page.SectPr.PgMar.Left; - page.HdrPoint.Y := page.SectPr.PgSz.H - page.SectPr.PgMar.Header; - // 页脚:从下往上,需要调整 - page.FtrPoint.X := page.SectPr.PgMar.Left; - page.FtrPoint.Y := page.SectPr.PgSz.H; - // 正文:运行完页眉页脚后需要再次计算 - page.TextPoint.X := page.SectPr.PgMar.Left; - page.TextPoint.Y := page.SectPr.PgSz.H - max(page.SectPr.PgMar.Top, page.SectPr.PgMar.Header); current_page_ := page; - // println("TextPoint.X = {}, TextPoint.Y = {}", current_page_.TextPoint.X, current_page_.TextPoint.Y); - // println("len = {}, Number = {}", page_manager_module_.Count(), current_page_.Number); // 页眉页脚 if current_sect_module_.SectPr.TitlePg and current_page_.Index = 0 then @@ -251,11 +233,17 @@ begin else type_name := "default"; - bk_file := xml_file_; {self.}SetHdr(type_name); {self.}SetFtr(type_name); - xml_file_ := bk_file; + // 设置完页眉页脚计算正文坐标 + page.TextPoint.X := page.SectPr.PgMar.Left; + page.TextPoint.Y := page.SectPr.PgSz.H - max(page.SectPr.PgMar.Top, page.SectPr.PgMar.Header); + page.TextPoint.Y := min(page.TextPoint.Y, page.HdrPoint.Y); + page.UpperBound := page.TextPoint.Y; + page.LowerBound := max(page.SectPr.PgMar.Bottom, page.FtrPoint.Y); + + // println("len = {}, Number = {}", page_manager_module_.Count(), current_page_.Number); // println("W = {}, H = {}", current_page_.SectPr.PgSz.W, current_page_.SectPr.PgSz.H); // println("Top = {}, Bottom = {}", current_page_.SectPr.PgMar.Top, current_page_.SectPr.PgMar.Bottom); // println("Left = {}, Right = {}", current_page_.SectPr.PgMar.Left, current_page_.SectPr.PgMar.Right); @@ -264,121 +252,146 @@ begin // println("HdrPoint.X = {}, HdrPoint.Y = {}", current_page_.HdrPoint.X, current_page_.HdrPoint.Y); // println("FtrPoint.X = {}, FtrPoint.Y = {}", current_page_.FtrPoint.X, current_page_.FtrPoint.Y); + xml_file_ := "document.xml"; return current_page_; end; function TSDocxToPdf.SetFtr(type: string); begin + // 页脚:从下往上,需要调整 + current_page_.FtrPoint.X := current_page_.SectPr.PgMar.Left; + current_page_.FtrPoint.Y := current_page_.SectPr.PgMar.Footer; + footer_reference := current_sect_pr_adapter_.GetFooterReferenceByType(type); - ftr_range := array(); - if ifObj(footer_reference) then - begin - rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); - rel := rels_adapter.GetRelationshipById(footer_reference.Id); - w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left; - lb := 0; - obj := docx_components_module_.GetFtr(rel.Target); - xml_file_ := rel.Target; - elements := obj.Elements(); - for _,element in elements do - begin - x := current_page_.FtrPoint.X; - y := current_page_.FtrPoint.Y; - range := nil; - if element.LocalName = "p" then range := {self.}TransformP(element, x, y, w, lb); - if ifObj(range) then - begin - current_page_.FtrPoint.Y := range.EndY; - ftr_range[length(ftr_range)] := range; - end - end - end - last_range := ftr_range[length(ftr_range)-1]; - y_offset := last_range.EndY - current_page_.SectPr.PgMar.Bottom; - height := 0; - for _,range in ftr_range do - begin - range.Offset(0, y_offset); - range.Do(); - height += range.DynamicHeight; - end - current_page_.FtrPoint.Y := current_page_.SectPr.PgMar.Bottom + height; + if not ifObj(footer_reference) then return; + rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); + rel := rels_adapter.GetRelationshipById(footer_reference.Id); + ftr := docx_components_module_.GetFtr(rel.Target); + xml_file_ := rel.Target; + + w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left; + ftr_range := new FtrRange(self, ftr); + ftr_range.Width := w; + ftr_range.Parent := self; + ftr_range.StartX := current_page_.SectPr.PgMar.Left; + ftr_range.StartY := current_page_.SectPr.PgSz.H; + ftr_range.StartPage := current_page_; + ftr_range.LowerBound := 0; + if ftr_range.Calc() then + ftr_range.Do(); + else + realtime_range_array_[length(realtime_range_array_)] := ftr_range; + + current_page_.FtrPoint.Y := ftr_range.EndY; end; function TSDocxToPdf.SetHdr(type: string); begin + // 正文、页眉页脚坐标 + // 页眉:从上往下,不需要调整 + current_page_.HdrPoint.X := current_page_.SectPr.PgMar.Left; + current_page_.HdrPoint.Y := current_page_.SectPr.PgSz.H - current_page_.SectPr.PgMar.Header; + header_reference := current_sect_pr_adapter_.GetHeaderReferenceByType(type); - if ifObj(header_reference) then + if not ifObj(header_reference) then return; + rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); + rel := rels_adapter.GetRelationshipById(header_reference.Id); + hdr := docx_components_module_.GetHdr(rel.Target); + xml_file_ := rel.Target; + + w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left; + hdr_range := new HdrRange(self, hdr); + hdr_range.Width := w; + hdr_range.Parent := self; + hdr_range.StartX := current_page_.SectPr.PgMar.Left; + hdr_range.StartY := current_page_.SectPr.PgSz.H - current_page_.SectPr.PgMar.Header; + hdr_range.StartPage := current_page_; + hdr_range.LowerBound := 0; + if hdr_range.Calc() then + hdr_range.Do(); + else + realtime_range_array_[length(realtime_range_array_)] := hdr_range; + + current_page_.HdrPoint.Y := hdr_range.EndY; +end; + +function TSDocxToPdf.RangesSpacing(range: BasicRange); +begin + if last_range_ then begin - rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); - rel := rels_adapter.GetRelationshipById(header_reference.Id); - w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left; - lb := 0; - obj := docx_components_module_.GetHdr(rel.Target); - xml_file_ := rel.Target; - elements := obj.Elements(); - for _,element in elements do + if last_range_ is class(PRange) and not ifnil(last_range_.PPrUnitDecorator.OutlineLvl.Val) and (range is class(TblRange) or ifnil(range.PPrUnitDecorator.OutlineLvl.Val)) then begin - x := current_page_.HdrPoint.X; - y := current_page_.HdrPoint.Y; - range := nil; - if element.LocalName = "p" then range := {self.}TransformP(element, x, y, w, lb); - if ifObj(range) then + if last_range_.PPrUnitDecorator.Spacing.AfterAutospacing then begin - current_page_.HdrPoint.Y := range.EndY; - range.Do(); - current_page_.TextPoint.Y := min(current_page_.TextPoint.Y, range.EndY); + line_range := last_range_.PLineRanges(); + line_range := line_range[length(line_range)-1]; + y := line_range.EndY - line_range.TextMaxSize; + if y >= 0 then current_page_.TextPoint.Y := y; + end + end + if range is class(PRange) and not ifnil(range.PPrUnitDecorator.OutlineLvl.Val) and (last_range_ is class(TblRange) or ifnil(last_range_.PPrUnitDecorator.OutlineLvl.Val)) then + begin + if range.PPrUnitDecorator.Spacing.BeforeAutospacing then + begin + line_range := range.PLineRanges(); + line_range := line_range[length(line_range)-1]; + y := last_range_.EndY - line_range.TextMaxSize; + if y >= 0 then current_page_.TextPoint.Y := y; end end end + last_range_ := range; end; -function TSDocxToPdf.TransformP(paragraph: P; x: real; y: real; w: real; lb: real): ParagraphRange; +function TSDocxToPdf.TransformP(p: P); begin - range := new ParagraphRange(self, current_page_, docx_components_module_, paragraph); - range.StartX := x; - range.StartY := y; + w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left; + range := new PRange(self, p); range.Width := w; - range.LowerBound := lb; range.Parent := self; - r := range.Calc(); - if r then return range; - else range_page_number_array_[length(range_page_number_array_)] := range; - return nil; + fg := range.Calc(); + {self.}RangesSpacing(range); + range.StartX := current_page_.TextPoint.X; + range.StartY := current_page_.TextPoint.Y; + range.StartPage := current_page_; + range.LowerBound := current_page_.LowerBound; + range.Run(); + if fg then + range.Do(); + else + realtime_range_array_[length(realtime_range_array_)] := range; + current_page_.TextPoint.Y := range.EndY; end; -function TSDocxToPdf.TransformTbl(table: Tbl; x: real; y: real; w: real; lb: real): TableRange; +function TSDocxToPdf.TransformTbl(tbl: Tbl); begin - range := new TableRange(self, current_page_, docx_components_module_, table); - range.StartX := x; - range.StartY := y; + w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left; + range := new TblRange(self, tbl); range.Width := w; - range.LowerBound := lb; range.Parent := self; - range.Calc(); - return range; + fg := range.Calc(); + {self.}RangesSpacing(range); + range.StartX := current_page_.TextPoint.X; + range.StartY := current_page_.TextPoint.Y; + range.StartPage := current_page_; + range.LowerBound := current_page_.LowerBound; + range.Run(); + range.Do(); + current_page_.TextPoint.Y := range.EndY; end; -function TSDocxToPdf.TransformSdt(sdt: Sdt; x: real; y: real; w: real; lb: real): array of ParagraphRange; +function TSDocxToPdf.TransformSdt(sdt: Sdt); begin ps := sdt.SdtContent.Ps(); - arr := array(); for _,p in ps do - begin - range := {self.}TransformP(p, x, y, w, lb); - if ifObj(range) then arr[length(arr)] := range; - end - return arr; + range := {self.}TransformP(p); end; -function TSDocxToPdf.ProcessNumpages(); +function TSDocxToPdf.ProcessRealtimeRange(); begin - nums := page_manager_module_[page_manager_module_.Count() - 1].Number; - for _,range in range_page_number_array_ do + for _,range in realtime_range_array_ do begin - range.SetNumPages(nums); - range.RangesToLines(); - range.Offset(0, current_page_.SectPr.PgSz.H - current_page_.SectPr.PgMar.Bottom); + range.ProcessRealtimeArray(); range.Do(); end end; @@ -398,14 +411,9 @@ begin return docx_components_module_.SaveAs(alias, file); end; -function TSDocxToPdf.GetCurrentNoteModule(): NoteModule; -begin - if ifnil(note_module_) then note_module_ := new NoteModule(current_sect_module_); - return note_module_; -end; - function TSDocxToPdf.ClassifyCols(var point: Point; cols: Cols); begin + return; bk_page := current_page_; columns := array(); x := point.X; diff --git a/internal/DTPAdvancedRanges.tsf b/internal/DTPAdvancedRanges.tsf index 0c11088..a2482f0 100644 --- a/internal/DTPAdvancedRanges.tsf +++ b/internal/DTPAdvancedRanges.tsf @@ -1,115 +1,197 @@ unit DTPAdvancedRanges; interface -uses DTPPrimitiveRanges, DTPUtils, DTPModules, SharedML, DocxML, DrawingMLUnitDecorator, DocxMLUnitDecorator; +uses DTPPrimitiveRanges, DTPUtils, DTPModules, SharedML, DocxML, DrawingMLUnitDecorator, DocxMLUnitDecorator, TSPdfEnumerations; -type RangeCollection = class(BasicRange) +type TocRange = class(BasicRange) +public + function Create(); + function CalculateRect(); + function LinkAnnot(dst: PdfDestination); + function AddPageNumber(pg: Page); + +public + TextRange: TextRange; + BaseLine: real; // 目录...基线 + [weakref]StartRange: BasicRange; + [weakref]EndRange: BasicRange; + +private + rect_: array of real; +end; + +type HdrRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr); + function Calc(): boolean; + function Do();override; + function ProcessRealtimeArray(); + +private + function Traverse(obj: OpenXmlElement); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + hdr_: Hdr; + range_array_: array of Range; +end; + +type FtrRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr); + function Calc(): boolean; + function Do();override; + function ProcessRealtimeArray(); + +private + function Traverse(obj: OpenXmlElement); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + ftr_: Ftr; + range_array_: array of Range; + y_offset_: real; +end; + +type PLineRange = class(BasicRange) public function Create(); function Do();override; - function Add(range: BasicRange); - -private - range_array_: array of BasicRange; -end; - -type ParagraphLineRange = class(BasicRange) -public - function Create(pg: Page); - function Do();override; + function CanFitInLine(range: BasicRange): boolean; function AddRange(range: BasicRange); - function SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); - function Align(jc: string); - function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); + function AdjustPosition(); + function Offset(x: real; y: real); + function Align(val: string); function AlignRightBound(right_bound: real); - function Offset(x_offset: real; y_offset; real); + function Arrange(); + function RangeArr(): array of BasicRange; +public + TextMaxSize: real; // 行的文字最大size + LineSpace: real; // 行间距 + Index: integer; private range_array_: array of BasicRange; end; -type ParagraphRange = class(BasicRange) +type PRange = class(BasicRange) public - function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); - function Calc(); + function Create(docx_to_pdf: TSDocxToPdf; p: P); + function Init(); function Do();override; - function SetTblStyleIdAndType(style_id: string; type: string); - function SetNumPages(num: integer); - function RangesToLines(); - function GetLastPage(): Page; - function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); - function GetParagraphLineRangeArr(): array of ParagraphLineRange; - function Empty(): boolean; + function Calc(): boolean; + function Run(); + function DeterminePosition(); + function ProcessRealtimeArray(); + function IsFirstLineOnNextPage(): boolean; function Offset(x: real; y: real); + function PLineRanges(): array of PLineRange; + + property PPrUnitDecorator read ppr_unit_decorator_; private + function RangesToLines(); + function BasicRangesToPLineRange(); + function UpdateTextRangeWidth(); + function CheckAndAddPage(y: real; offset: real): boolean; + function AlignRightBound(); + function HyperlinkToToc(); + function DoDrawingAnchor(); + function DoAlternateContentAnchor(); + function DoToc(); + function SetPPPr(var p: P); function SetPPrByStyleId(var ppr: PPr; style_id: string); function SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); function SetRPrByStyleId(var rpr: RPr; style_id: string); function SetRPrByTblStyleId(var rpr: RPr; style_id: string); function SetLvlText(); + function GetXYCordinates(): array of real; function GetImageFileType(data: binary): string; function GetImageData(id: string): PdfImage; function GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; - function BasicRangesToParagraphLineRange(): tableArray; - function UpdateTextRangeWidth(); - function CheckAndAddPage(y: real; offset: real): boolean; - function SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: string); - function RAlternateContent(r: R); + function SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; anchor: string); + + function RBr(r: R); + function RFootnoteReference(r: R); + function RT(r: R; anchor: string); function RDrawing(r: R); function RFldChar(r: R; stack: Stack); - function RFootnoteReference(r: R); - function RFootnoteRef(r: R); - function RObject(r: R); - function RT(r: R; link: string); - function FldSimple(fld_simple: FldSimple); + function RAlternateContent(r: R); + function FldSimple(fld_simple: fldSimple); function Hyperlink(hyperlink: Hyperlink); - - function SetLinesAlignment(); - function ResetCoordinates(); - function NewParagraphLineRange(): ParagraphLineRange; - function BookMarkLinkToc(); - function HyperlinkToToc(); - function HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator); - function GetXYCordinates(): array of real; - function AlignRightBound(); - function Init(); - function OMathPara(element: OMathPara); + function OMathPara(o_math_para: OMathPara); private [weakref]docx_to_pdf_: TSDocxToPdf; - [weakref]docx_components_module_: DocxComponentsModule; - [weakref]paragraph_: P; - [weakref]page_: Page; - body_range_array_: array of BasicRange; // 正文的range - bullet_range_array_: array of BasicRange; // 项目符号的range - line_range_array_: array of ParagraphLineRange; - - hyperlink_array_: tableArray; - bookmark_array_: tableArray; + p_: P; ppr_unit_decorator_: PPrUnitDecorator; - placeholder_array_: tableArray; - table_style_id_: string; - table_style_type_: string; - empty_: boolean; - right_bound_: real; - footnote_reference_hash_: hash; + body_range_array_: array of BasicRange; // 正文range + bullet_range_array_: array of BasicRange; // 项目符号的range + line_range_array_: array of PLineRange; // 行range + drawing_anchor_array_: array of Anchor; // 浮动对象节点,比如浮动型图片r.Drawing.Anchor + alternate_content_array_: array of AlternateContent; // 文本框 + right_bound_: real; // 右对齐边界 + br_type_: string; + bookmark_hash_: hash; + hyperlink_hash_: hash; + footnote_reference_hash_: hash; // 脚注 + + // 存放一些需要实时计算的值,比如页码 + realtime_page_array_: hash; + realtime_numpages_array_: hash; end; -type TableRange = class(BasicRange) +type TcRange = class(BasicRange) public - function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; table: Tbl); + function Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty); + function Do();override; + function DoBordersRangeFill(); + function Calc(); + function Run(); + function GetTblStyleId(): string; + function GetPrType(): string; + function ContentNextPage(): boolean; + function AlignHeight(height: real); + function SetVAlign(); + function SetTop(); + + property Tc Read tc_; + +public + Row: integer; + Col: integer; + OffsetX: real; + +private + function GetLowerBound(pg: Page): real; + function SetBorderRange(range: BordersRange); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + tc_: Tc; + trp_: TrProperty; + tc_pr_unit_decorator_: TcPrUnitDecorator; + content_next_page_: boolean; + range_array_: array of BasicRange; + region_array_: array of Region; + top_: boolean; +end; + + +type TblRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; tbl: Tbl); function Do();override; function Calc(); - function GetLastPage(): Page; - function Rows(): integer; - function Cols(): integer; - function RowLowerBound(row: integer): real; + function Run(); + + property TblPr read tbl_pr_unit_decorator_; + property Rows read rows_; + property Cols read cols_; private function CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); - function ComputeMatrixCells(); - function ResetCoordinates(tbl_pr: TblPrUnitDecorator; grid_cols: array of GridCol); + function ResetCoordinates(tbl_pr: TblPr; 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); @@ -120,1326 +202,318 @@ private private [weakref]docx_to_pdf_: TSDocxToPdf; - [weakref]last_page_: Page; - [weakref]docx_components_module_: DocxComponentsModule; - [weakref]table_: Tbl; + tbl_: Tbl; tbl_pr_unit_decorator_: TblPrUnitDecorator; - ts_trpr_array_: array of TSTrProperty; - cell_range_matrix_: array of CellRange; - row_lower_bound_: hash; + grid_cols_: array of GridColUnitDecorator; rows_: integer; cols_: integer; + tc_range_matrix_: array of TcRange; + tr_pr_array_: array of TrProperty; end; -type CellRange = class(BasicRange) +type OMathParaRange = class(BasicRange) public - function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); - function Calc(); - function Do();override; - function SetPage(pg: Page); - function GetLastPage(); - function AlignHeight(height: real; lb: real); - function SetVAlign(); - function IsReComputeByCantSplit(): boolean; - function IfRemoveEmptyRectangle(): boolean; - function SetTop(); - - property Tc read tc_; - -private - function GetCellPrType(): string; - function SetBorderRange(range: BordersRange); - -public - RemoveFlag: boolean; - Row: integer; - Col: integer; - VMerge: integer; - [weakref]TSTrPr: TSTrProperty; - -private - [weakref]docx_to_pdf_: TSDocxToPdf; - [weakref]last_page_: Page; - [weakref]docx_components_module_: DocxComponentsModule; - [weakref]tc_: Tc; - [weakref]tbl_pr_: TblPr; - tc_pr_unit_decorator_: TcPrUnitDecorator; - region_array_: array of Region; // 单元格可能跨页,所以可能存在多个 - top_: boolean; -end; - -type ColumnRange = class(BasicRange) -public - function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); - function AddElement(ele: Element); - function Elements(): array of Element; - function GetLastPage(): Page; - function Do();override; - -private - [weakref]docx_to_pdf_: TSDocxToPdf; - [weakref]docx_components_module_: DocxComponentsModule; - [weakref]page_: Page; - elements_: array of Elements; - paragraph_: P; - last_y_: real; -end; - -type MathRange = class(BasicRange) -public - function Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); - function Calc(); - function Do();override; - -private - [weakref]docx_to_pdf_: TSDocxToPdf; - [weakref]o_math_para_: OMathPara; - sub_math_range_: SubMathRange; -end; - -type SubMathRange = class(BasicRange) -public - function Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); + function Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara); function Do();override; + function Run(); function Calc(); private - function MathR(r: R; sz: real; x: real; y: real): RangeCollection; - function MathF(f: F; sz: real; x: real; y: real): RangeCollection; - function MathRad(rad: Rad; sz: real; x: real; y: real): RangeCollection; - function MathNary(nary: Nary; sz: real; x: real; y: real): RangeCollection; - function MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; + [weakref]docx_to_pdf_: TSDocxToPdf; + o_math_para_: OMathPara; + o_math_range_: OMathRange; +end; + +type OMathRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement); + function Do();override; + function Run(); + function Calc(); + function SetMathSize(); + + property Sz read sz_ write sz_; + +private + function MR(r: R; sz: real; x: real; y: real); private [weakref]docx_to_pdf_: TSDocxToPdf; - [weakref]ts_page_: Page; - [weakref]openxml_element_: OpenXmlElement; - range_collection_: RangeCollection; + element_: OMath; sz_: real; + range_array_: array of BasicRange; +end; + +type OMathFRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; f: F); + function Do();override; + function Calc(); + function Run(); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + f_: F; + range_array_: array of BasicRange; end; implementation -function MathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); +function TocRange.Create(); begin class(BasicRange).Create(); - docx_to_pdf_ := docx_to_pdf; - o_math_para_ := o_math_para; - sub_math_range_ := nil; - {self.}Page := pg; + {self.}TextRange := nil; + {self.}BaseLine := 0; end; -function MathRange.Calc(); +function TocRange.LinkAnnot(dst: PdfDestination); begin - sub_math_range_ := new SubMathRange(docx_to_pdf_, {self.}Page, o_math_para_.OMath, 11); - sub_math_range_.StartX := {self.}StartX; - sub_math_range_.StartY := {self.}StartY; - sub_math_range_.EndX := {self.}EndX; - sub_math_range_.EndY := {self.}EndY; - sub_math_range_.DynamicHeight := 100; - sub_math_range_.Calc(); - - {self.}EndX := sub_math_range_.EndX; - {self.}EndY := sub_math_range_.EndY; - {self.}Width := sub_math_range_.Width; - {self.}DynamicHeight := sub_math_range_.DynamicHeight; + annot := {self.}EndPage.PdfPage.CreateLinkAnnot(rect_, dst); + annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT); + annot.LinkAnnotSetBorderStyle(0, 0, 0); end; -function MathRange.Do();override; +function TocRange.AddPageNumber(pg: Page); begin - sub_math_range_.Do(); + number_str := tostring(pg.Number); + {self.}EndPage.PdfPage.SetFontAndSize({self.}TextRange.Font, {self.}TextRange.RPr.Sz.Val); + number_sz := {self.}EndPage.PdfPage.TextWidth(number_str); + x := rect_[2] - number_sz; + y := {self.}BaseLine; + {self.}TextRange.EndPage := {self.}EndPage; + {self.}TextRange.Text := number_str; + {self.}TextRange.EndX := x; + {self.}TextRange.EndY := y; + {self.}TextRange.Do(); + + // 目录...... + sx := {self.}EndX; + {self.}EndPage.PdfPage.SetRGBStroke(0, 0, 0); + {self.}EndPage.PdfPage.SetDash(array(0.5, 2), 2, 0); + {self.}EndPage.PdfPage.SetLineWidth(0.5); + {self.}EndPage.PdfPage.SetLineCap(TSPdfEnumerations.ROUND_END); + {self.}EndPage.PdfPage.MoveTo(sx, y); + {self.}EndPage.PdfPage.LineTo(x-0.5, y); + {self.}EndPage.PdfPage.Stroke(); end; -function SubMathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); +function TocRange.CalculateRect(); begin - class(BasicRange).Create(); - docx_to_pdf_ := docx_to_pdf; - ts_page_ := pg; - openxml_element_ := element; - {self.}Page := pg; - range_collection_ := new RangeCollection(); - sz_ := sz; -end; - -function SubMathRange.Do();override; -begin - range_collection_.Do(); -end; - -function SubMathRange.Calc(); -begin - elements := openxml_element_.Elements(); - min_y := {self.}StartY; - max_y := {self.}StartY; - {self.}EndX := {self.}StartX; - {self.}EndY := {self.}StartY; - for _,element in elements do + pline_range := {self.}Parent; + {self.}EndPage := pline_range.EndPage; + if {self.}StartRange then begin - range := nil; - if element.LocalName = "r" then - range := {self.}MathR(element, sz_, {self.}EndX, {self.}EndY); - else if element.LocalName = "f" then - range := {self.}MathF(element, sz_, {self.}EndX, {self.}EndY); - else if element.LocalName = "rad" then - range := {self.}MathRad(element, sz_, {self.}EndX, {self.}EndY); - else if element.LocalName = "nary" then - range := {self.}MathNary(element, sz_, {self.}EndX, {self.}EndY); - else if element.LocalName = "sSup" then - range := {self.}MathSSup(element, sz_, {self.}EndX, {self.}EndY); - - if not ifObj(range) then - begin - echo forma("Not support <%s>\n", element.ElementName); - continue; - end - if min_y > range.EndY then min_y := range.EndY; - if max_y < range.EndY + range.DynamicHeight then max_y := range.EndY + range.DynamicHeight; - - {self.}EndX := range.EndX; - {self.}EndY := range.EndY; - {self.}Width += range.Width; - range_collection_.Add(range); - end - range_collection_.DynamicHeight := max_y - min_y; - {self.}DynamicHeight := range_collection_.DynamicHeight; -end; - -function SubMathRange.MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; -begin - prange := new RangeCollection(); - prange.StartX := x; - prange.StartY := y; - prange.EndX := x; - prange.EndY := y; - - e_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.E, sz); - e_range.StartX := x; - e_range.StartY := y; - e_range.Calc(); - - sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.Sup, sz * 0.4); - sup_range.StartX := x + e_range.Width; - sup_range.StartY := y + sz * 0.57; - sup_range.Calc(); - - prange.Add(e_range); - prange.Add(sup_range); - prange.EndX := maxValue(array(e_range.EndX, sup_range.EndX)); - prange.EndY := e_range.EndY; - prange.Width := prange.EndX - prange.StartX; - prange.DynamicHeight := e_range.DynamicHeight + sup_range.DynamicHeight * 0.5; - - return prange; -end; - -function SubMathRange.MathR(r: R; sz: real; x: real; y: real): RangeCollection; -begin - // println("x = {}, y = {}", x, y); - prange := new RangeCollection(); - prange.StartX := x; - prange.StartY := y; - prange.EndX := x; - prange.EndY := y; - text := r.T.Text(); - pos := 1; - // println("text = {}", text); - while pos <= length(text) do - begin - num := Utf8CharLengthFromByte(text[pos]); - a_word := text[pos : pos+num-1]; - if num = 1 or DTPUtils.IsChineseChar(a_word) or DTPUtils.IsChinesePunctuation(a_word) then - begin - word := utf8ToAnsi(a_word); - font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", false, true); - end - else begin - word := class(SymbolMapper).SymbolChr(a_word); - if ifnil(word) then raise format("error symbol {{%s}}", a_word); - font_obj := docx_to_pdf_.Font.GetSymbolFont(); - end - rpr := new RPr(); - rpr.Sz.Val := sz; - ts_page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); - word_width := ts_page_.PdfPage.TextWidth(word); - text_range := new TextRange(); - text_range.RPr := rpr; - text_range.Text := word; - text_range.Font := font_obj; - text_range.StartX := prange.EndX; - text_range.StartY := prange.EndY; - text_range.Page := {self.}Page; - text_range.EndX := text_range.StartX; - text_range.EndY := text_range.StartY; - text_range.Width := word_width; - pos += num; - prange.Add(text_range); - prange.EndX += text_range.Width; - prange.Width += text_range.Width; - end - prange.DynamicHeight := sz; - return prange; -end; - -function SubMathRange.MathF(f: F; sz: real; x: real; y: real); -begin - prange := new ParagraphLineRange(); - prange.StartX := x; - prange.StartY := y; - prange.EndX := x; - prange.EndY := y; - - den_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Den, sz); - den_range.StartX := x; - den_range.StartY := y; - den_range.Calc(); - - num_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Num, sz); - num_range.StartX := x; - num_range.StartY := y + 1.418 * sz; - num_range.Calc(); - - max_len := max(den_range.Width, num_range.Width); - bar := max_len / 0.9; - line_range := new LineRange(); - line_range.StartX := x - (bar - max_len) / 2; - line_range.StartY := y + 0.928 * sz; - line_range.EndX := line_range.StartX; - line_range.EndY := line_range.StartY; - line_range.Width := bar; - line_range.Page := {self.}Page; - line_range.LineWidth := 0.04 * sz; - - prange.EndX := maxValue(array(den_range.EndX, num_range.EndX, line_range.EndX)); - prange.AddRange(den_range); - prange.AddRange(num_range); - prange.AddRange(line_range); - - return prange; - - // TODO: delete - // pg := {self.}Page.PdfPage; - // pg.SetFontAndSize(font, sz); - // len1 := pg.TextWidth(range1.Text); - // len2 := pg.TextWidth(range2.Text); - // max_len := len1 > len2 ? len1 : len2; - // bar := max_len / 0.9; - // pg.SetLineWidth(0.05*sz); - // pg.SetRGBStroke(0, 0, 0); - // x := {self.}StartX - (bar - max_len) / 2; - // y := {self.}StartY + 0.928 * sz; - // pg.MoveTo(x, y); - // pg.LineTo(x + bar, y); - // pg.Stroke(); - - // elements := f.Den.Elements(); - // {self.}TraverseElement(elements); - // elements := f.Num.Elements(); - // {self.}TraverseElement(elements); - - // for _,element in elements do - // begin - // if - // range1 := new TextRange(); - // range1.Text := "a"; - // range1.EndX := {self.}StartX; - // range1.EndY := {self.}StartY; - // rpr := new RPr(); - // rpr.Sz.Val := sz; - // range1.RPr := rpr; - // range1.Page := {self.}Page; - // range1.Font := font; - // range1.Do(); - // end - // for _,element in elements do - // begin - // range2 := new TextRange(); - // range2.Text := "b"; - // range2.EndX := {self.}StartX; - // range2.EndY := {self.}StartY + 1.418*sz; - // rpr := new RPr(); - // rpr.Sz.Val := sz; - // range2.RPr := rpr; - // range2.Page := {self.}Page; - // range2.Font := font; - // range2.Do(); - // // if element.LocalName = "r" then - // // begin - // // range1 := new TextRange(); - // // range1.Text := element.T.Text(); - // // end - // end -end; - -function SubMathRange.MathRad(rad: Rad; sz: real; x: real; y: real): ParagraphLineRange; -begin - prange := new ParagraphLineRange(); - prange.StartX := x; - prange.StartY := y; - prange.EndX := x; - prange.EndY := y; - - symbol := chr(0xD6); - symbol_font := docx_to_pdf_.Font.GetSymbolFont(); - pg := {self.}Page.PdfPage; - pg.SetFontAndSize(symbol_font, sz); - symbol_range := new TextRange(); - symbol_range.Text := symbol; - symbol_range.EndX := x; - symbol_range.EndY := y; - symbol_range.Font := symbol_font; - symbol_range.Width := pg.TextWidth(symbol); - symbol_range.RPr := new RPr(); - symbol_range.RPr.Sz.Val := sz; - symbol_range.Page := {self.}Page; - - deg_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.Deg, sz * 0.5); - deg_range.StartX := x; - deg_range.StartY := y + sz * 0.57; - deg_range.Calc(); - - e_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.E, sz); - e_range.StartX := x + symbol_range.Width; - e_range.StartY := y; - e_range.Calc(); - - line_range := new LineRange(); - line_range.StartX := x + symbol_range.Width * 0.9; - line_range.StartY := y + sz * 0.9; - line_range.EndX := line_range.StartX; - line_range.EndY := line_range.StartY; - line_range.Width := e_range.Width + symbol_range.Width / 3; - line_range.Page := {self.}Page; - line_range.LineWidth := 0.04 * sz; - - prange.EndX := maxValue(array(symbol_range.EndX, e_range.EndX, deg_range.EndX, line_range.EndX)); - prange.AddRange(symbol_range); - prange.AddRange(deg_range); - prange.AddRange(e_range); - prange.AddRange(line_range); - - return prange; - - // TODO: delete - // range := new TextRange(); - // range.Text := chr_hash_['α']; - // range.EndX := {self.}StartX; - // range.EndY := {self.}StartY + sz * 0.57; - // range.Font := symbol_font; - // range.RPr := new RPr(); - // range.RPr.Sz.Val := sz / 2; - // range.Page := {self.}Page; - // range.Do(); - - // range := new TextRange(); - // range.Text := "abcd"; - // range.EndX := {self.}StartX + symbol_w; - // range.EndY := {self.}StartY; - // range.Font := font; - // range.RPr := new RPr(); - // range.RPr.Sz.Val := sz; - // range.Page := {self.}Page; - // range.Do(); - - // pg.SetFontAndSize(font, sz); - // pg.SetLineWidth(0.04*sz); - // pg.SetRGBStroke(0, 0, 0); - // x := {self.}StartX + symbol_w * 0.9; - // y := {self.}StartY + sz * 0.9; - // pg.MoveTo(x, y); - // pg.LineTo(x + pg.TextWidth(range.Text)+symbol_w/3, y); - // pg.Stroke(); - -end; - -function SubMathRange.MathNary(nary: Nary; sz: real; x: real; y: real): ParagraphLineRange; -begin - prange := new ParagraphLineRange(); - prange.StartX := x; - prange.StartY := y; - prange.EndX := x; - prange.EndY := y; - - val := nary.NaryPr.Chr.Val ?: "Į"; - symbol := class(SymbolMapper).SymbolChr(val); - if ifnil(symbol) then raise format("error = %s", val); - symbol_font := docx_to_pdf_.Font.GetSymbolFont(); - pg := {self.}Page.PdfPage; - pg.SetFontAndSize(symbol_font, sz * 1.5); - symbol_range := new TextRange(); - symbol_range.Text := symbol; - symbol_range.EndX := x; - symbol_range.EndY := y; - symbol_range.Font := symbol_font; - symbol_range.RPr := new DocxML.RPr(); - symbol_range.RPr.Sz.Val := 1.5 * sz; - symbol_range.Page := {self.}Page; - symbol_range.Width := pg.TextWidth(symbol); - - if nary.NaryPr.LimLoc.Val = "subSup" then - begin - sup_start_x := x + symbol_range.Width * 1.2; - sup_start_y := y + sz * 1.5 * 0.73; - sub_start_x := x + symbol_range.Width * 0.7; - sub_start_y := y - sz * 1.5 * 0.2; - end - // else if nary.Nary.LimLoc.Val = "undOvr" then - else begin // undOvr - sup_start_x := x + symbol_range.Width * 0.5; - sup_start_y := y + sz * 1.5 * 0.8; - sub_start_x := x; - sub_start_y := y - sz * 1.5 * 0.5; - end - - sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sup, sz * 0.7); - sup_range.StartX := sup_start_x; - sup_range.StartY := sup_start_y; - sup_range.Calc(); - - sub_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sub, sz * 0.7); - sub_range.StartX := sub_start_x; - sub_range.StartY := sub_start_y; - sub_range.Calc(); - - if nary.NaryPr.LimLoc.Val = "subSup" then - begin - e_start_x := x + symbol_range.Width * 0.5 + max(sup_range.Width, sub_range.Width); - e_start_y := y + sz * 0.3; + rect_ := array({self.}StartRange.StartX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY); end else begin - e_start_x := x + symbol_range.Width; - e_start_y := y + sz * 0.3; + rect_ := array(pline_range.StartX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY); end - - e_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.E, sz); - e_range.StartX := e_start_x; - e_range.StartY := e_start_y; - e_range.Calc(); - - prange.EndX := maxValue(array(symbol_range.EndX, sup_range.EndX, sub_range.EndX, e_range.EndX)); - prange.AddRange(symbol_range); - prange.AddRange(sup_range); - prange.AddRange(sub_range); - prange.AddRange(e_range); - - return prange; - // TODO: delete - // val := nary.NaryPr.Chr.Val; - // symbol := class(SymbolMapper).SymbolChr(nary.NaryPr.Chr.Val); - // sz := 11; - // symbol_font := docx_to_pdf_.PdfFile().GetFont("Symbol", ""); - // symbol_range := new TextRange(); - // symbol_range.Text := symbol; - // symbol_range.EndX := {self.}StartX; - // symbol_range.EndY := {self.}StartY; - // symbol_range.Font := symbol_font; - // symbol_range.RPr := new RPr(); - // symbol_range.RPr.Sz.Val := 1.5 * sz; - // symbol_range.Page := {self.}Page; - // symbol_range.Do(); - - // pg := {self.}Page.PdfPage; - // pg.SetFontAndSize(symbol_font, sz * 1.5); - // symbol_w := pg.TextWidth(symbol); - // font := docx_to_pdf_.PdfFile().GetFont("SimSun,Italic", "GBK-EUC-H"); - - // range := new TextRange(); - // range.Text := chr_hash_["∞"]; - // range.EndX := {self.}StartX + symbol_w / 5; - // range.EndY := {self.}StartY + sz * 0.8 * 1.5; - // range.Font := symbol_font; - // range.RPr := new RPr(); - // range.RPr.Sz.Val := sz * 0.7; - // range.Page := {self.}Page; - // range.Do(); - - // range := new TextRange(); - // range.Text := "n=1"; - // pg.SetFontAndSize(font, sz*0.7); - // tw := pg.TextWidth(range.Text); - // range.EndX := {self.}StartX + (symbol_w - tw)/2; - // range.EndY := {self.}StartY - sz * 0.5 * 1.5; - // range.Font := font; - // range.RPr := new RPr(); - // range.RPr.Sz.Val := sz * 0.7; - // range.Page := {self.}Page; - // range.Do(); - - // range := new TextRange(); - // range.Text := chr_hash_["f"]; - // pg.SetFontAndSize(font, sz); - // tw := pg.TextWidth(range.Text); - // range.EndX := {self.}StartX + symbol_w; - // range.EndY := {self.}StartY + sz * 0.3; - // range.Font := symbol_font; - // range.RPr := new RPr(); - // range.RPr.Sz.Val := sz; - // range.Page := {self.}Page; - // range.Do(); - + offset := pline_range.LineSpace >= pline_range.DynamicHeight ? (pline_range.LineSpace - pline_range.TextMaxSize) / 2 + pline_range.TextMaxSize - pline_range.TextMaxSize / 5 : pline_range.DynamicHeight; + y := pline_range.StartY - offset; + {self.}BaseLine := y; + {self.}EndX := ifObj({self.}EndRange) ? {self.}EndRange.EndX + {self.}EndRange.Width + 1 : {self.}Parent.StartX; end; -// ColumnRange -function ColumnRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); +function HdrRange.Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr); begin + class(BasicRange).Create(); docx_to_pdf_ := docx_to_pdf; - page_ := pg; - docx_components_module_ := components; - elements_ := array(); - last_y_ := 0; + hdr_ := hdr; + range_array_ := array(); end; -function ColumnRange.AddElement(ele: Element); +function HdrRange.Calc(); begin - elements_[length(elements_)] := ele; -end; - -function ColumnRange.Elements(): array of Element; -begin - return elements_; -end; - -function ColumnRange.Do();override; -begin - x := {self.}StartX; - y := {self.}StartY; - for _,element in elements_ do - begin - range := nil; - if element.LocalName = "p" then - range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); - else if element.LocalName = "tbl" then - range := new TableRange(docx_to_pdf_, page_, docx_components_module_, element); - if ifnil(range) then continue; - range.StartX := x; - range.StartY := y; - range.Width := {self.}Width; - range.LowerBound := {self.}LowerBound; - range.Calc(); - range.Do(); - y := range.EndY; - page_ := range.GetLastPage(); - end - {self.}EndY := y; -end; - -function ColumnRange.GetLastPage(): Page; -begin - return page_; -end; - -// TableRange -function TableRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: Components; table: Tbl); -begin - docx_to_pdf_ := docx_to_pdf; - last_page_ := pg; - docx_components_module_ := Components; - table_ := table; - ts_trpr_array_ := array(); - cell_range_matrix_ := array(); - row_lower_bound_ := array(); - rows_ := 0; - cols_ := 0; - {self.}Page := last_page_; -end; - -function TableRange.Calc(); -begin - {self.}SetTblTblPr(table_); - tbl_pr_unit_decorator_ := new TblPrUnitDecorator(table_.TblPr); - tbl_grid_unit_decorator := new TblGridUnitDecorator(table_.TblGrid); - grid_cols := tbl_grid_unit_decorator.GridCols(); - {self.}ResetCoordinates(tbl_pr_unit_decorator_, grid_cols); - {self.}EndX := {self.}StartX; - {self.}EndY := {self.}StartY; - // 如果是根据内容自适应,应该计算并调整grid_cols的值 - 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 TableRange.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 not ifObj(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 TableRange.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 DTPUtils.TrProperty(); - 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 - begin - cell_range_matrix_[i][pos] := 0; - tc_x += grid_cols[pos++].W; - end - continue; - end - cell_range := new CellRange(docx_to_pdf_, last_page_, docx_components_module_, 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.Parent := self; - 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 - begin - cell_range_matrix_[i][pos] := 0; - cell_range.Width += grid_cols[pos++].W; - end - 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 TableRange.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 not ifObj(range) then - begin - j++; - continue; - end - range.StartY := tc_y; - range.SetPage(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_.PageManager[last_page_.Index + 1]; - [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, row_lower_bound_[i-1]); - 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, row_lower_bound_[i]); - range.SetVAlign(); - {self.}EndY := range.EndY; - last_page_ := range.GetLastPage(); - row_lower_bound_[i] := range.LowerBound; - end - i++; - end -end; - -function TableRange.RowLowerBound(row: integer): real; -begin - return row_lower_bound_[row]; -end; - -function TableRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); -begin - // tc_pr应该是经过外层copy的 - tbl_style_pr := docx_components_module_.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type); - if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr); -end; - -function TableRange.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 TableRange.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 TableRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); -begin - styles := docx_components_module_.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 TableRange.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 TableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); -begin - styles := docx_components_module_.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 TableRange.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 TableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); -begin - styles := docx_components_module_.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 TableRange.GetLastPage(): Page; -begin - return last_page_; -end; - -function TableRange.Rows(): integer; -begin - return rows_; -end; - -function TableRange.Cols(): integer; -begin - return cols_; -end; - -// CellRange -function CellRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: TSDocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); -begin - docx_to_pdf_ := docx_to_pdf; - last_page_ := pg; - docx_components_module_ := components; - tc_ := tc; - tbl_pr_ := tbl_pr; - region_array_ := array(); - top_ := false; - tc_pr_unit_decorator_ := new TcPrUnitDecorator(tc_.TcPr); - {self.}TSTrPr := trp; - {self.}Tc := tc; - {self.}VMerge := 1; - {self.}Page := last_page_; -end; - -function CellRange.Calc(); -begin - region_array_ := array(); - region := new DTPUtils.Region(); - region.BordersRange.EndX := {self.}StartX; - region.BordersRange.EndY := {self.}StartY; - region.BordersRange.Width := {self.}Width; - region.BordersRange.FixedHeight := {self.}FixedHeight; - region.BordersRange.Page := last_page_; - region.BordersRange.TcPr := tc_pr_unit_decorator_; - {self.}SetBorderRange(region.BordersRange); - region_array_[length(region_array_)] := region; - {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; + {self.}EndPage := {self.}StartPage; {self.}DynamicHeight := 0; - 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(); + return {self.}Traverse(hdr_); +end; + +function HdrRange.Traverse(obj: OpenXmlElement); +begin + flag := true; + elements := obj.Elements(); for _,element in elements do begin - range := nil; if element.LocalName = "p" then begin - range := new ParagraphRange(docx_to_pdf_, last_page_, docx_components_module_, element); - range.SetTblStyleIdAndType(tbl_pr_.TblStyle.Val, {self.}GetCellPrType()); - end - else if element.LocalName = "tbl" then - begin - range := new TableRange(docx_to_pdf_, last_page_, docx_components_module_, element); - continue; // TODO:表中表存在不可靠问题 - end - if ifObj(range) then - begin - range.StartX := cell_x; - range.StartY := cell_y; - range.Width := cell_w; - range.FixedHeight := cell_h; - range.LowerBound := {self.}LowerBound; + range := new PRange(docx_to_pdf_, element); + range.Width := {self.}Width; range.Parent := self; - range.Calc(); - region.RangeArr[length(region.RangeArr)] := range; + fg := range.Calc(); + if not fg then flag := fg; + range.StartX := {self.}EndX; + range.StartY := {self.}EndY; + range.StartPage := {self.}EndPage; + range.LowerBound := {self.}LowerBound; + range.Run(); + range_array_[length(range_array_)] := range; + {self.}EndY := range.EndY; {self.}DynamicHeight += range.DynamicHeight; - cell_y := range.EndY; - last_page_ := range.GetLastPage(); end - end - {self.}EndY := cell_y - tbl_pr_.TblCellMar.Bottom.W; - {self.}DynamicHeight += tbl_pr_.TblCellMar.Top.W + tbl_pr_.TblCellMar.Bottom.W; - - if {self.}EndY < {self.}LowerBound and not range.Empty() then - begin - last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; - if ifnil(last_page_) then last_page_ := docx_to_pdf_.AddPage(); - {self.}StartY := last_page_.TextPoint.Y; - {self.}Calc(); - end - if {self.}TSTrPr.TrPr.TrHeight.HRule <> "exact" and {self.}DynamicHeight > {self.}FixedHeight then - begin - region.BordersRange.FixedHeight := {self.}DynamicHeight; - {self.}FixedHeight := {self.}DynamicHeight; - end - if not {self.}Tc.TcPr.VMerge and {self.}DynamicHeight > {self.}TSTrPr.Height then - {self.}TSTrPr.Height := {self.}DynamicHeight; -end; - -function CellRange.Do();override; -begin - for _,region in region_array_ do - begin - if _ = 0 and {self.}RemoveFlag then continue; - // println("Row = {}, Col = {}", {self.}Row, {self.}Col); - region.BordersRange.Do(); - for _,range in region.RangeArr do - range.Do(); - end -end; - -function CellRange.SetPage(pg: Page); -begin - last_page_ := pg; - {self.}Page := pg; -end; - -function CellRange.AlignHeight(height: real; lb: real); -begin - region := region_array_[0]; - y_lowerbound := {self.}StartY - {self.}LowerBound; - surplus := height - y_lowerbound; - if surplus < 1e-6 then - begin - region.BordersRange.DynamicHeight := height; - {self.}SetBorderRange(region.BordersRange); - {self.}EndY := {self.}StartY - region.BordersRange.DynamicHeight; - {self.}LowerBound := {self.}StartY - height; - return; - end - // if lb then y_lowerbound := {self.}StartY - lb; - region.BordersRange.DynamicHeight := y_lowerbound; - arr := region.RangeArr; - region.RangeArr := array(); - hash := array(region.BordersRange.Page.Index: region); - last_page_ := {self.}Page; - [x, y] := last_page_.OriginalTextCoordinates(); - span := y - last_page_.FtrPoint.Y; - while surplus > span do - begin - last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; - region := new DTPUtils.Region(); - region.BordersRange.EndX := {self.}StartX; - region.BordersRange.EndY := y; - region.BordersRange.Width := {self.}Width; - region.BordersRange.DynamicHeight := span; - region.BordersRange.Page := last_page_; - region.BordersRange.TcPr := tc_pr_unit_decorator_; - region.BordersRange.Top := true; - region.BordersRange.Bottom := true; - {self.}SetBorderRange(region.BordersRange); - region_array_[length(region_array_)] := region; - surplus -= span; - hash[region.BordersRange.Page.Index] := region; - end - if surplus > 1e-6 then - begin - last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; - region := new DTPUtils.Region(); - region.BordersRange.EndX := {self.}StartX; - region.BordersRange.EndY := y; - region.BordersRange.Width := {self.}Width; - region.BordersRange.DynamicHeight := surplus; - region.BordersRange.Page := last_page_; - region.BordersRange.TcPr := tc_pr_unit_decorator_; - region.BordersRange.Top := true; - {self.}SetBorderRange(region.BordersRange); - region_array_[length(region_array_)] := region; - hash[region.BordersRange.Page.Index] := region; - {self.}EndY := region.BordersRange.EndY - surplus; - end - for _,range in arr do - begin - if range is class(ParagraphRange) then + else if element.LocalName = "sdt" then begin - line_arr := range.GetParagraphLineRangeArr(); - for _,r in line_arr do - begin - region := hash[r.Page.Index]; - region.RangeArr[length(region.RangeArr)] := r; - end + {self.}Traverse(element.SdtContent); end end + return flag; +end; + +function HdrRange.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function HdrRange.ProcessRealtimeArray(); +begin + for _,range in range_array_ do + range.ProcessRealtimeArray(); +end; + +function FtrRange.Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr); +begin + docx_to_pdf_ := docx_to_pdf; + ftr_ := ftr; + range_array_ := array(); + y_offset_ := 0; +end; + +function FtrRange.Calc(); +begin + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}EndPage := {self.}StartPage; + {self.}DynamicHeight := 0; + flag := {self.}Traverse(ftr_); + for _,range in range_array_ do + begin + range.StartX := {self.}EndX; + range.StartY := {self.}EndY; + range.StartPage := {self.}EndPage; + range.LowerBound := {self.}LowerBound; + range.Run(); + {self.}EndY := range.EndY; + {self.}DynamicHeight += range.DynamicHeight; + end + y_offset_ := {self.}EndY - {self.}EndPage.FtrPoint.Y; + for _,range in range_array_ do + range.Offset(0, -y_offset_); + {self.}EndY := {self.}EndPage.FtrPoint.Y + {self.}DynamicHeight; + return flag; +end; + +function FtrRange.Traverse(obj: OpenXmlElement); +begin + flag := true; + elements := obj.Elements(); + for _,element in elements do + begin + // println("LocalName = {}", element.LocalName); + if element.LocalName = "p" then + begin + range := new PRange(docx_to_pdf_, element); + range.Width := {self.}Width; + range.Parent := self; + fg := range.Calc(); + if not fg then flag := fg; + range_array_[length(range_array_)] := range; + end + else if element.LocalName = "sdt" then + begin + flag := {self.}Traverse(element.SdtContent); + end + end + return flag; +end; + +function FtrRange.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function FtrRange.ProcessRealtimeArray(); +begin + for _,range in range_array_ do + begin + range.ProcessRealtimeArray(); + range.Offset(0, -y_offset_); + end end; -function CellRange.GetLastPage(); +function PLineRange.Create(); begin - return last_page_; + class(BasicRange).Create(); + {self.}TextMaxSize := 0; + {self.}LineSpace := 0; + range_array_ := array(); +end + +function PLineRange.Do();override; +begin + for _,range in range_array_ do + range.Do(); end; -function CellRange.SetVAlign(); +function PLineRange.CanFitInLine(range: BasicRange): boolean; begin - val := tc_.TcPr.VAlign.Val; - region := region_array_[0]; - arr := region.RangeArr; - if length(arr) = 0 then return; - last_y := arr[length(arr)-1].EndY; - offset := last_y - (region.BordersRange.EndY - region.BordersRange.DynamicHeight) - tbl_pr_.TblCellMar.Bottom.W; - case val of - "center": - begin - offset /= 2; - for _,range in arr do - range.AdjustRangeOffset(region.BordersRange.Page, nil, -offset); - end + if range.Width > {self.}Width then return false; // 单一宽度比行宽还宽 + if {self.}EndX + range.Width < {self.}Width + 1e-6 then return false; // 未超过行宽 + if range is class(TextRange) and range.Type = 4 and not {self.}Parent.Parent is class(TcRange) then return false; // 中文标点不换行 + return true; +end; + +function PLineRange.AddRange(range: BasicRange); +begin + range_array_[length(range_array_)] := range; +end; + +function PLineRange.Offset(x: real; y: real); +begin + {self.}EndX += x; + {self.}EndY += y; + {self.}BaseSize += y; + for _,range in range_array_ do + begin + range.EndX += x; + range.EndY += y; end; end; -function CellRange.IsReComputeByCantSplit(): boolean; -begin - if {self.}Tc.TcPr.VMerge then return false; - return {self.}TSTrPr.TrPr.CantSplit and last_page_ <> {self.}Page; -end; - -function CellRange.IfRemoveEmptyRectangle(): boolean; -begin - return; - if length(region_array_) < 2 then return false; - return length(region_array_[0].RangeArr) ? false : true; -end; - -function CellRange.GetCellPrType(): string; -begin - if {self.}Row = 0 then return "firstRow"; - else if ({self.}Row + 1) % 2 = 0 then return "band1Horz"; - else return "band2Horz"; -end; - -function CellRange.SetBorderRange(range: BordersRange); -begin - if top_ then range.Top := true; - if ifObj(tbl_pr_.TblBorders) then - begin - if {self.}Row = 0 then - begin - if tbl_pr_.TblBorders.Top then - begin - if not tc_pr_unit_decorator_.TcBorders.Top then - tc_pr_unit_decorator_.TcBorders.Top.Copy(tbl_pr_.TblBorders.Top); - range.Top := true; - end - if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then - begin - if not tc_pr_unit_decorator_.TcBorders.Bottom then - tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); - range.Bottom := true; - end - if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then - begin - if not tc_pr_unit_decorator_.TcBorders.Right then - tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); - range.Right := true; - end - if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then - begin - if not tc_pr_unit_decorator_.TcBorders.Bottom then - tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); - range.Bottom := true; - end - end - else if {self.}Row = {self.}Parent.Rows()-1 then - begin - if tbl_pr_.TblBorders.Bottom then - begin - if not tc_pr_unit_decorator_.TcBorders.Bottom then - tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); - range.Bottom := true; - end - if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then - begin - if not tc_pr_unit_decorator_.TcBorders.Right then - tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); - range.Right := true; - end - end - else begin - if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then - begin - if not tc_pr_unit_decorator_.TcBorders.Bottom then - tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); - range.Bottom := true; - end - if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then - begin - if not tc_pr_unit_decorator_.TcBorders.Bottom then - tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); - range.Bottom := true; - end - if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then - begin - if not tc_pr_unit_decorator_.TcBorders.Right then - tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); - range.Right := true; - end - end - - if {self.}Col = 0 then - begin - if tbl_pr_.TblBorders.Left then - begin - if not tc_pr_unit_decorator_.TcBorders.Left then - tc_pr_unit_decorator_.TcBorders.Left.Copy(tbl_pr_.TblBorders.Left); - range.Left := true; - end - end - if {self.}Col = {self.}Parent.Cols()-1 then - begin - if tbl_pr_.TblBorders.Right then - begin - if not tc_pr_unit_decorator_.TcBorders.Right then - tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.Right); - range.Right := true; - end - end - end - else begin - range.Left := {self.}Col = 0; - range.Top := {self.}Row = 0; - range.Right := true; - range.Bottom := true; - end -end; - -function CellRange.SetTop(); -begin - top_ := true; -end; - -// RangeCollection; -function RangeCollection.Create(); -begin - class(BasicRange).Create(); - range_array_ := array(); -end; - -function RangeCollection.Do();override; -begin - for _,range in range_array_ do - range.Do(); -end; - -function RangeCollection.Add(range: BasicRange); -begin - range_array_[length(range_array_)] := range; -end; - -// ParagraphLineRange -function ParagraphLineRange.Create(pg: Page); -begin - class(BasicRange).Create(); - {self.}Page := pg; - range_array_ := array(); -end; - -function ParagraphLineRange.AddRange(range: BasicRange); -begin - range_array_[length(range_array_)] := range; -end; - -function ParagraphLineRange.Do();override; -begin - for _,range in range_array_ do - range.Do(); -end; - -function ParagraphLineRange.SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); +function PLineRange.AdjustPosition(); begin + {self.}EndX += {self.}StartX; + {self.}EndY := {self.}StartY - {self.}DynamicHeight; + {self.}EndPage := {self.}StartPage; + y_offset := {self.}LineSpace >= {self.}DynamicHeight ? ({self.}LineSpace - {self.}TextMaxSize) / 2 + {self.}TextMaxSize - {self.}TextMaxSize / 5 : {self.}DynamicHeight; + y := {self.}StartY - y_offset; 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; + range.EndPage := {self.}EndPage; + range.EndX += {self.}StartX; + range.EndY := y; end end; -function ParagraphLineRange.Align(jc: string); +function PLineRange.Align(val: string); begin offset := 0; - first := range_array_[0]; last := range_array_[length(range_array_)-1]; - case jc of + case val of "center": - offset := ({self.}Width + StartX - last.EndX - last.Width) / 2; + offset := ({self.}Width + {self.}StartX - {self.}EndX) / 2; "right": - offset := {self.}Width - last.EndX + first.EndX - last.Width; + offset := {self.}Width + {self.}StartX - {self.}EndX; end; if offset <= 0 then return; for _,range in range_array_ do range.EndX += offset; end; -function ParagraphLineRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); -begin - if pg <> {self.}Page then return; - 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; - -function ParagraphLineRange.AlignRightBound(right_bound: real); +function PLineRange.AlignRightBound(right_bound: real); begin last := range_array_[length(range_array_)-1]; diff := right_bound - (last.EndX + last.Width); @@ -1451,94 +525,101 @@ begin end end; -function ParagraphLineRange.Offset(x_offset: real; y_offset; real); +function PLineRange.RangeArr(): array of BasicRange; begin - for _,range in range_array_ do - begin - range.EndX += x_offset; - range.EndY -= y_offset; - end + return range_array_; end; - -// ParagraphRange -function ParagraphRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); +function PRange.Create(docx_to_pdf: TSDocxToPdf; p: P); begin + class(BasicRange).Create(); docx_to_pdf_ := docx_to_pdf; - page_ := pg; - docx_components_module_ := components; - paragraph_ := paragraph; - table_style_id_ := ""; - table_style_type_ := ""; + p_ := p; +end; + +function PRange.Init(); +begin + br_type_ := ""; body_range_array_ := array(); bullet_range_array_ := array(); line_range_array_ := array(); - hyperlink_array_ := array(); - bookmark_array_ := array(); - empty_ := false; - {self.}Page := page_; + drawing_anchor_array_ := array(); + alternate_content_array_ := array(); + bookmark_hash_ := array(); + hyperlink_hash_ := array(); footnote_reference_hash_ := array(); -end; + realtime_page_array_ := array(); + realtime_numpages_array_ := array(); + // 根据段落的间距确定新的坐标 + ppr := ppr_unit_decorator_; + sz := ppr.RPr.SzCs.Val ? : ppr.RPr.Sz.Val; + {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 ParagraphRange.Init(); +function PRange.Do();override; begin - body_range_array_ := array(); - right_bound_ := {self.}StartX + {self.}Width; - {self.}ResetCoordinates(); - {self.}EndX := {self.}StartX; - {self.}EndY := {self.}StartY; - {self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before); - {self.}EndY -= ppr_unit_decorator_.Spacing.Before; - {self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before; + for _,line_range in line_range_array_ do + line_range.Do(); - // TODO:项目符号应该单独写入 - {self.}SetLvlText(); + // 段落边框 + if length(line_range_array_) > 0 and ppr_unit_decorator_.PBdr.Bottom.Val = "single" then + begin + {self.}EndPage.PdfPage.SetLineWidth(0.5); + {self.}EndPage.PdfPage.SetGrayStroke(0.25); + {self.}EndPage.PdfPage.MoveTo({self.}StartX, {self.}EndY); + {self.}EndPage.PdfPage.LineTo({self.}StartX + {self.}Width, {self.}EndY); + {self.}EndPage.PdfPage.Stroke(); + end + + // 处理bookmark + for anchor,arr in bookmark_hash_ do + if arr[0] then docx_to_pdf_.Toc.LinkToToc(anchor, arr[0]); end; -function ParagraphRange.Calc(): tableArray; +function PRange.Calc(); begin // ppr.rpr是无效的,应该以ppr.pStyle为准 - {self.}SetPPPr(paragraph_); - ppr_unit_decorator_ := new DocxMLUnitDecorator.PPrUnitDecorator(paragraph_.PPr); - {self.}Init(); + {self.}SetPPPr(p_); + ppr_unit_decorator_ := new DocxMLUnitDecorator.PPrUnitDecorator(p_.PPr); if not ppr_unit_decorator_.RPr.Sz.Val then ppr_unit_decorator_.RPr.Sz.Val := docx_to_pdf_.Font.GetDefaultSz(); - if paragraph_.PPr.PageBreakBefore then - {self.}CheckAndAddPage({self.}LowerBound, 1); + {self.}Init(); + {self.}SetLvlText(); - elements := paragraph_.Elements(); - empty_flag := true; - bookmark_id := ''; - bookmark_name := ''; - bookmark_flag := false; + bookmark_name := ""; + elements := p_.Elements(); fld_stack := new DTPUtils.Stack(); - for _,element in elements do + for _, element in elements do begin - // println("LocalName = {}", element.LocalName); - if element.LocalName = "r" then + if element.LocalName = "pPr" then continue; + else if element.LocalName = "bookmarkStart" then + begin + bookmark_name := element.Name; + bookmark_hash_[bookmark_name] := array(); + end + else if element.LocalName = "bookmarkEnd" then + begin + bookmark_name := ""; + end + else if element.LocalName = "r" then begin - empty_flag := false; {self.}SetRRPr(element, ppr_unit_decorator_); - if element.FldChar.FldCharType = "begin" then begin fld_struct := new DTPUtils.FldStruct(); fld_stack.Push(fld_struct); + continue; end if not fld_stack.Empty() then begin {self.}RFldChar(element, fld_stack); continue; end - - if element.Br.Type = "page" then - {self.}EndY := {self.}LowerBound; + if element.T then {self.}RT(element, bookmark_name); + else if element.Br then {self.}RBr(element); else if element.Drawing then {self.}RDrawing(element); else if element.AlternateContent then {self.}RAlternateContent(element); else if element.FootnoteReference then {self.}RFootnoteReference(element); - else if element.Object then {self.}RObject(element); - else if element.FootnoteRef then {self.}RFootnoteRef(element); - else if element.Anchor then {self.}Hyperlink(element); // - else if element.T then {self.}RT(element, bookmark_name); end else if element.LocalName = "fldSimple" then begin @@ -1546,20 +627,8 @@ begin end else if element.LocalName = "hyperlink" then begin - empty_flag := false; {self.}Hyperlink(element); end - else if element.LocalName = "bookmarkStart" then - begin - bookmark_id := element.Id; - bookmark_name := element.Name; - bookmark_array_[bookmark_name] := array(); - end - else if element.LocalName = "bookmarkEnd" then - begin - bookmark_id := ''; - bookmark_name := ''; - end else if element.LocalName = "oMathPara" then begin {self.}OMathPara(element); @@ -1572,120 +641,139 @@ begin {self.}OMathPara(o_math_para); end end - if empty_flag then - begin - line_space := {self.}GetParagraphLineSpace(ppr_unit_decorator_.RPr.Sz.Val, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule); - {self.}DynamicHeight += line_space; - {self.}EndY -= {self.}DynamicHeight; - empty_ := true; - end - if placeholder_array_ then return false; {self.}RangesToLines(); - if hyperlink_array_ then {self.}HyperlinkToToc(); - if bookmark_array_ then {self.}BookMarkLinkToc(); - return true; + + // 需要实时计算总页码的情况是需要最后处理的 + return length(realtime_numpages_array_) ? false : true; end; -function ParagraphRange.SetNumPages(num: integer); +function PRange.RBr(r: R); begin - text := tostring(num); - last_index := length(body_range_array_); - {self.}SplitTextToTextRange(body_range_array_, text, placeholder_array_[1], link); - arr := array(); - len := length(body_range_array_); - for i:=last_index to len-1 do - arr[length(arr)] := body_range_array_[i]; - diff := len - last_index; - for i:=len-1 downto placeholder_array_[0] do - body_range_array_[i] := body_range_array_[i-diff]; - k := 0; - for i:=placeholder_array_[0] to placeholder_array_[0]+diff-1 do - body_range_array_[i] := arr[k++]; + br_type_ := r.Br.Type; end; -function ParagraphRange.BookMarkLinkToc(); +function PRange.RFootnoteReference(r: R); begin - for name,arr in bookmark_array_ do - if arr[0] then docx_to_pdf_.Toc.LinkToToc(name, arr[0].Page, arr[0].EndX, arr[0].EndY + arr[0].RPr.Sz.Val); + return; + docx_to_pdf_.Note.AddFootnoteId(r.FootnoteReference.Id); + rpr := new RPrUnitDecorator(r.RPr); + if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); + font_name := rpr.RFonts.Ascii ?: rpr.RFonts.EastAsia; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + text := new TextRange(); + text.RPr := rpr; + text.Font := font_obj; + text.Text := docx_to_pdf_.Note.GetFootnoteOrderNumber(); + text.Width := docx_to_pdf_.PageManager[0].PdfPage.TextWidth(text.Text); + body_range_array_[length(body_range_array_)] := text; + footnote_reference_hash_[text] := id; end; -function ParagraphRange.HyperlinkToToc(); +function PRange.RDrawing(r: R); begin - ppr := ppr_unit_decorator_; - max_size := 0; - for anchor,arr in hyperlink_array_ do // 整理hyperlink发送到docx_to_pdf_ + if r.Drawing.Anchor then begin - pg := arr[0].Page; - left := {self.}StartX; - right := {self.}StartX + {self.}Width; - top := {self.}StartY; - bottom := {self.}StartY; - x := arr[0].EndX; - y := arr[0].EndY; - if top - {self.}GetParagraphLineSpace(arr[0].RPr.Sz.Val, ppr.Spacing.Line, ppr.Spacing.LineRule) then - begin - top := pg.TextPoint.Y; - bottom := top; - end - for _,range in arr do - begin - if x + range.Width - {self.}StartX > {self.}Width + 1e-6 then // 换行 - begin - line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); - bottom -= line_space; - max_size := 0; - if range.Page <> pg then - begin - rect := array(left, bottom, right, top); - toc := new DTPModules.Toc(ppr, rect, pg, x, y); - docx_to_pdf_.Toc.AddToc(anchor, toc); - pg := range.Page; - bottom := {self.}StartY; - end - end - if range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; - x := range.EndX + range.Width; - y := range.EndY; - end - font_name := ppr.RPr.RFonts.EastAsia ? ppr.RPr.RFonts.EastAsia : ppr.RPr.RFonts.Ascii; - font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, ppr.RPr.B, ppr.RPr.I); - line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); - pg.PdfPage.SetFontAndSize(font_obj, max_size); - bottom -= line_space; - num_width := pg.PdfPage.TextWidth("." + tostring(pg.Number)); - if x + num_width - {self.}StartX > {self.}Width + 1e-6 then // 换行 - begin - offset := (line_space - max_size) / 2 + max_size - max_size / 5; - diff := {self.}EndY - {self.}LowerBound; - if {self.}CheckAndAddPage({self.}EndY, line_space) then - begin - {self.}DynamicHeight += diff; - pg := page_; - rect := array(left, bottom, right, top); - toc := new TSToc(ppr, rect, pg, x, y); - docx_to_pdf_.Toc.AddToc(anchor, toc); - bottom := {self.}StartY; - end - else begin - bottom -= line_space; - x := {self.}StartX; - y := {self.}EndY - offset; - {self.}EndY -= line_space; - {self.}DynamicHeight += line_space; - end - end - rect := array(left, bottom, right, top); - toc := new DTPModules.Toc(ppr, rect, pg, x, y, font_obj); - docx_to_pdf_.Toc.AddToc(anchor, toc); + anchor := r.Drawing.Anchor; + drawing_anchor_array_[length(drawing_anchor_array_)] := anchor; + end + else if r.Drawing._Inline then + begin + id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; + [image_type, image] := {self.}GetImageData(id); + if not image then return; + xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm); + image_range := new ImageRange(); + image_range.Image := image; + image_range.Type := image_type; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; + body_range_array_[length(body_range_array_)] := image_range; end end; -function ParagraphRange.FldSimple(fld_simple: FldSimple); +function PRange.RFldChar(r: R; stack: Stack); +begin + fld_struct := stack.Pop(); + if r.FldChar.FldCharType = "separate" then + begin + fld_struct.Status := 1; + stack.Push(fld_struct); + return; + end + // else if r.FldChar.FldCharType = "end" then + // fld_struct.Status = 2; + if fld_struct.Status = 2 then return; + + if r.InstrText.Text then + begin + fields := str2array(r.InstrText.Text, " "); + for _,field in fields do + begin + fld := trim(field); + if fld = "NUMPAGES" then + fld_struct.Type.NumPages := true; + else if fld = "PAGE" then + fld_struct.Type.Page := true; + else if fld = "QUOTE" then + fld_struct.Type.Quote := true; + else if fld = "PAGEREF" then + fld_struct.Type.PageRef := true; + else if fld = "Arabic" then + fld_struct.Arabic := true; + else if fld = "MERGEFORMAT" then + fld_struct.MergeFormat := true; + end + end + if fld_struct.Status = 1 then + begin + if fld_struct.Type.Page then + begin + rpr := new RPrUnitDecorator(r.RPr); + if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + text := new TextRange(); + text.RPr := rpr; + // text.Type := 1; + text.Font := font_obj; + text.DynamicHeight := rpr.Sz.Val; + text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度 + realtime_page_array_[length(realtime_page_array_)] := text; + body_range_array_[length(body_range_array_)] := text; + end + else if fld_struct.Type.NumPages then + begin + rpr := new RPrUnitDecorator(r.RPr); + if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + text := new TextRange(); + text.RPr := rpr; + // text.Type := 1; + text.Font := font_obj; + text.DynamicHeight := rpr.Sz.Val; + text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度 + realtime_numpages_array_[length(realtime_numpages_array_)] := text; + body_range_array_[length(body_range_array_)] := text; + end + fld_struct.Status := 2; + end + if fld_struct.Status <> 2 then stack.Push(fld_struct); + +end; + +function PRange.RAlternateContent(r: R); +begin + anchor := r.AlternateContent.Choice.Drawing.Anchor; + alternate_content_array_[length(alternate_content_array_)] := anchor; +end; + +function PRange.FldSimple(fld_simple: fldSimple); begin if fld_simple.Instr then begin fields := str2array(fld_simple.Instr, " "); - fld_struct := new DTPUtils.FldStruct2(); + fld_struct := new DTPUtils.FldStruct(); for _,field in fields do begin fld := trim(field); @@ -1699,33 +787,41 @@ begin end r := fld_simple.Rs(0); {self.}SetRRPr(r, ppr_unit_decorator_); - rpr := new RPrUnitDecorator(r.RPr); if fld_struct.Type.NumPages then begin if fld_struct.Arabic then begin - placeholder_array_ := array(length(body_range_array_), rpr); + rpr := new RPrUnitDecorator(r.RPr); + if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + text := new TextRange(); + text.RPr := rpr; + // text.Type := 1; + text.Font := font_obj; + text.DynamicHeight := rpr.Sz.Val; + text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度 + realtime_numpages_array_[length(realtime_numpages_array_)] := text; + body_range_array_[length(body_range_array_)] := text; end end end; -function ParagraphRange.Hyperlink(hyperlink: Hyperlink); +function PRange.Hyperlink(hyperlink: Hyperlink); begin i := length(body_range_array_); rs := hyperlink.Rs(); - separate := false; - stack := new DTPUtils.Stack(); + fld_stack := new DTPUtils.Stack(); for _,r in rs do begin if r.FldChar.FldCharType = "begin" then begin - fld_struct := new FldStruct2(); - stack.Push(fld_struct); + fld_struct := new DTPUtils.FldStruct(); + fld_stack.Push(fld_struct); end - // if r.InstrText.Text else if r.FldChar.FldCharType = "end" then begin - stack.Pop(); + fld_stack.Pop(); end else if r.FldChar.FldCharType = "separate" then begin @@ -1734,12 +830,23 @@ begin else if separate then begin docx_to_pdf_.Toc.AddDocxPage(hyperlink.Anchor, r); + + rpr := new RPrUnitDecorator(r.RPr); + if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + text := new TextRange(); + text.RPr := rpr; + text.Font := font_obj; + text.DynamicHeight := rpr.Sz.Val; + text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度 end - else if stack.Empty() then + if not fld_stack.Empty() then continue; + if r.T then begin {self.}SetRRPr(r, ppr_unit_decorator_); r.RPr.Color.Val := nil; - {self.}RT(r, hyperlink.Anchor); + {self.}RT(r); end end arr := array(); @@ -1748,32 +855,166 @@ begin arr[length(arr)] := body_range_array_[i]; i++; end - hyperlink_array_[hyperlink.Anchor] := arr; + hyperlink_hash_[hyperlink.Anchor] := array(text, arr); end; -function ParagraphRange.Do();override; +function PRange.OMathPara(o_math_para: OMathPara); begin - for _,line_range in line_range_array_ do - line_range.Do(); + return; + math_range := new OMathParaRange(docx_to_pdf_, o_math_para); + math_range.Width := {self.}Width; + math_range.Parent := self; + math_range.Calc(); + body_range_array_[length(body_range_array_)] := math_range; end; -function ParagraphRange.SetTblStyleIdAndType(style_id: string; type: string); +function PRange.HyperlinkToToc(); begin - table_style_id_ := style_id; - table_style_type_ := type; + ppr_ := ppr_unit_decorator_; + for anchor, arr in hyperlink_hash_ do + begin + text := arr[0]; + r_arr := arr[1]; + range0 := r_arr[0]; + range1 := r_arr[length(r_arr)-1]; + if range0.Parent.Index = range1.Parent.Index then // 同一行 + begin + if range1.Parent.EndX + text.Width < {self.}Width then // 页码不需要换行 + begin + toc := new TocRange(); + toc.Parent := range0.Parent; + toc.TextRange := text; + toc.StartRange := range0; + toc.EndRange := range1; + docx_to_pdf_.Toc.AddToc(anchor, toc); + end + else begin // 需要新增一行 + pline_range := new PLineRange(); + pline_range.Parent := self; + pline_range.Width := {self.}Width; + pline_range.EndX := 0; + pline_range.DynamicHeight := range1.Parent.DynamicHeight; + pline_range.LineSpace := range1.Parent.LineRule; + index := range1.Parent.Index + 1; + for i:=length(line_range_array_) downto index do + begin + line_range := line_range_array_[i]; + line_range.Index++; + line_range_array_[i+1] := line_range; + end + line_range_array_[index] := pline_range; + toc := new TocRange(); + toc.Parent := pline_range; + toc.TextRange := text; + docx_to_pdf_.Toc.AddToc(anchor, toc); + end + end + else begin + for i:=range0.Parent.Index to range1.Parent.Index do + begin + if i = range1.Parent.Index then + begin + if range1.Parent.EndX + text.Width < {self.}Width then // 页码不需要换行 + begin + toc := new TocRange(); + toc.Parent := range1.Parent; + toc.TextRange := text; + toc.EndRange := range1; + docx_to_pdf_.Toc.AddToc(anchor, toc); + end + else begin // 需要新增一行 + pline_range := new PLineRange(); + pline_range.Parent := self; + pline_range.Width := {self.}Width; + pline_range.EndX := 0; + pline_range.DynamicHeight := range1.Parent.DynamicHeight; + pline_range.LineSpace := range1.Parent.LineRule; + index := range1.Parent.Index + 1; + for i:=length(line_range_array_) downto index do + begin + line_range := line_range_array_[i]; + line_range.Index++; + line_range_array_[i+1] := line_range; + end + line_range_array_[index] := pline_range; + toc := new TocRange(); + toc.Parent := pline_range; + toc.TextRange := text; + docx_to_pdf_.Toc.AddToc(anchor, toc); + end + end + else begin + toc := new TocRange(); + toc.Parent := line_range_array_[i]; + toc.TextRange := text; + docx_to_pdf_.Toc.AddToc(anchor, toc); + end + end + end + end end; -function ParagraphRange.NewParagraphLineRange(): ParagraphLineRange; +function PRange.PLineRanges(): array of PLineRange; begin - line_range := new ParagraphLineRange(page_); - line_range.StartX := {self.}StartX; - line_range.StartY := {self.}EndY; - line_range.Width := {self.}Width; - return line_range; + return line_range_array_; end; -function ParagraphRange.UpdateTextRangeWidth(); +function PRange.RangesToLines(); begin + line_range_array_ := array(); + {self.}UpdateTextRangeWidth(); + {self.}BasicRangesToPLineRange(); + {self.}HyperlinkToToc(); +end; + +function PRange.BasicRangesToPLineRange(); +begin + pline_range := new PLineRange(); + pline_range.Parent := self; + pline_range.Width := {self.}Width; + pline_range.EndX := 0; + i := 0; + anchor := nil; + while i < length(body_range_array_) do + begin + range := body_range_array_[i]; + if i = 0 then + pline_range.EndX += ppr_unit_decorator_.Ind.FirstLine; + if_newline := pline_range.CanFitInLine(range); + if if_newline then + begin + pline_range.LineSpace := {self.}GetParagraphLineSpace(pline_range.TextMaxSize, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule); + pline_range.DynamicHeight := max(pline_range.LineSpace, pline_range.DynamicHeight); + pline_range.Index := length(line_range_array_); + line_range_array_[length(line_range_array_)] := pline_range; + + pline_range := new PLineRange(); + pline_range.Parent := self; + pline_range.Width := {self.}Width; + pline_range.EndX := 0; + end + if range is class(TextRange) and range.RPr.Sz.Val > pline_range.TextMaxSize then + pline_range.TextMaxSize := range.RPr.Sz.Val; + if range.DynamicHeight > pline_range.DynamicHeight then pline_range.DynamicHeight := range.DynamicHeight; + range.EndX := pline_range.EndX + range.StartX; // range.StartX是偏移值 + range.Parent := pline_range; + pline_range.AddRange(range); + pline_range.EndX += range.Width; + i++; + if i = length(body_range_array_) then + begin + pline_range.LineSpace := {self.}GetParagraphLineSpace(pline_range.TextMaxSize, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule); + pline_range.DynamicHeight := max(pline_range.LineSpace, pline_range.DynamicHeight); + pline_range.Index := length(line_range_array_); + line_range_array_[length(line_range_array_)] := pline_range; + end + end + // println("line_range_array_ = {}", line_range_array_); +end; + +function PRange.UpdateTextRangeWidth(); +begin + if length(realtime_page_array_) > 0 or length(realtime_numpages_array_) > 0 then return; head_range := body_range_array_[0]; i := 1; while i < length(body_range_array_) do @@ -1803,98 +1044,183 @@ begin end end; -function ParagraphRange.RangesToLines();overload; +function PRange.Run(); begin - {self.}UpdateTextRangeWidth(); - {self.}BasicRangesToParagraphLineRange(); + // 检查是否需要实时计算页码 + if length(realtime_page_array_) > 0 then + begin + pg := {self.}StartPage; + for _,range in realtime_page_array_ do + begin + pg.PdfPage.SetFontAndSize(range.Font, range.RPr.Sz.Val); + range.Text := tostring(pg.Number); + range.Width := pg.PdfPage.TextWidth(range.Text); + range.Type := 1; + end + realtime_page_array_ := array(); + {self.}RangesToLines(); + end + {self.}DeterminePosition(); +end; + +function PRange.DeterminePosition(); +begin + x := {self.}StartX; + y := {self.}StartY; + right_bound_ := x + {self.}Width; + {self.}StartX := x; + {self.}StartY := y; + ppr := ppr_unit_decorator_; + sz := ppr.RPr.SzCs.Val ? ppr.RPr.SzCs.Val : ppr.RPr.Sz.Val ? ppr.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); + {self.}StartX += ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left; + + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}EndPage := {self.}StartPage; + + // 检查是否有分页,分一栏 + if br_type_ = "page" then + {self.}EndY := {self.}LowerBound; + else if br_type_ = "column" and (ifnil(docx_to_pdf_.CurrentSect.SectPr.Cols.Num) or docx_to_pdf_.CurrentSect.SectPr.Cols.Num <= 1) then + {self.}EndY := {self.}LowerBound; + + {self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before); + {self.}EndY -= ppr_unit_decorator_.Spacing.Before; + {self.}DynamicHeight := ppr_unit_decorator_.Spacing.Before; + + // 检查是否有段前分页 + if ppr_unit_decorator_.PageBreakBefore then + {self.}CheckAndAddPage({self.}LowerBound, 1); + + for _,line_range in line_range_array_ do + begin + {self.}CheckAndAddPage({self.}EndY, line_range.DynamicHeight); + line_range.StartX := {self.}EndX; + line_range.StartY := {self.}EndY; + line_range.StartPage := {self.}EndPage; + line_range.AdjustPosition(); + line_range.Align(ppr_unit_decorator_.Jc.Val); + {self.}DynamicHeight += line_range.DynamicHeight; + {self.}EndY := line_range.EndY; + end + if not {self.}Parent is class(TcRange) then + {self.}AlignRightBound(); + + if length(line_range_array_) = 0 then // 空段落 + begin + line_space := {self.}GetParagraphLineSpace(ppr_unit_decorator_.RPr.Sz.Val, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule); + {self.}DynamicHeight += line_space; + {self.}EndY -= {self.}DynamicHeight; + end + + {self.}DoDrawingAnchor(); + {self.}DoAlternateContentAnchor(); + {self.}DoToc(); + {self.}DynamicHeight += ppr_unit_decorator_.Spacing.After; {self.}EndY -= ppr_unit_decorator_.Spacing.After; - if not {self.}Empty() and ppr_unit_decorator_.PBdr.Bottom.Val = "single" then +end; + +function PRange.DoToc(); +begin + for anchor,_ in hyperlink_hash_ do + docx_to_pdf_.Toc.CalculateRect(anchor); +end; + +function PRange.DoDrawingAnchor(); +begin + for _,anchor in drawing_anchor_array_ do begin - sect_pr := page_.SectPr; - page_.PdfPage.SetLineWidth(0.05); - page_.PdfPage.SetGrayStroke(0.25); - page_.PdfPage.MoveTo(sect_pr.PgMar.Left, {self.}EndY); - page_.PdfPage.LineTo(sect_pr.PgSz.W - sect_pr.PgMar.Right, {self.}EndY); - page_.PdfPage.Stroke(); + id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; + [image_type, image] := {self.}GetImageData(id); + if not image then return; + xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm); + position_h := new PositionHUnitDecorator(anchor.PositionH); + position_v := new PositionVUnitDecorator(anchor.PositionV); + [x, y] := {self.}GetXYCordinates(); + if position_h.RelativeFrom = "paragraph" then + x := {self.}StartY; + if position_v.RelativeFrom = "paragraph" then + y := {self.}StartY; + image_range := new ImageRange(); + image_range.Image := image; + image_range.Type := image_type; + image_range.EndX := x + position_h.PosOffset.Text; + image_range.EndY := y - position_v.PosOffset.Text - xfrm.Ext.CY; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; + image_range.EndPage := {self.}EndPage; + image_range.Do(); end end; -function ParagraphRange.BasicRangesToParagraphLineRange(); +function PRange.DoAlternateContentAnchor(); begin - ppr := ppr_unit_decorator_; - line_range := {self.}NewParagraphLineRange(); - i := 0; - max_size := 0; - max_y := 0; - while i <= length(body_range_array_)-1 do + for _,anchor in alternate_content_array_ do begin - range := body_range_array_[i]; - if i = 0 then {self.}EndX += ppr.Ind.FirstLine; - if range is class(TextRange) and range.RPr.Sz.Val > max_size then - max_size := range.RPr.Sz.Val; - if range.DynamicHeight > max_y then max_y := range.DynamicHeight; - line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); - diff := {self.}EndY - {self.}LowerBound; - 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 i = 0 then if_newline := 0; - if if_newline and (range is class(TextRange)) and (AnsiToUtf8(range.Text) in array(";", ":", "。", "“", "”", "!", "?", ",")) then - if_newline := 0; - if if_newline and range.Width < {self.}Width then + wsp := anchor.Graphic.GraphicData.Wsp; + [x, y] := {self.}GetXYCordinates(); + xfrm := new XfrmUnitDecorator(wsp.SpPr.Xfrm); + position_h := new PositionHUnitDecorator(anchor.PositionH); + position_v := new PositionVUnitDecorator(anchor.PositionV); + if position_h.RelativeFrom = "paragraph" then + x := {self.}StartY; + if position_v.RelativeFrom = "paragraph" then + y := {self.}StartY; + x += position_h.PosOffset.Text; + y -= position_v.PosOffset.Text; + w := xfrm.Ext.CX; + body_pr := new BodyPrUnitDecorator(wsp.BodyPr); + x += body_pr.LIns; + w -= (body_pr.LIns + body_pr.RIns); + ps := wsp.Txbx.TxbxContent.Ps(); + for _,p in ps do begin - offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; - 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.}NewParagraphLineRange(); - max_size := 0; - max_y := 0; - {self.}DynamicHeight += max_value; - {self.}EndY -= max_value; - {self.}EndX := {self.}StartX; - // w:hanging - if range is class(TextRange) then - sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); - else - sz := docx_to_pdf_.Font.GetDefaultSz(); - {self.}EndX -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging; - continue; - end - range.EndX := {self.}EndX - range.StartX; - {self.}EndX += range.Width; - line_range.AddRange(range); - i++; - if i = length(body_range_array_) then - begin - offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; - 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; - {self.}DynamicHeight += max_value; - {self.}EndY -= max_value; + range := new PRange(docx_to_pdf_, p); + range.Width := w; + range.Parent := self; + fg := range.Calc(); + if not fg then flag := fg; + range.StartPage := {self.}EndPage; + range.StartX := x; + range.StartY := y; + range.LowerBound := 0; + range.Run(); + range.Do(); + y := range.EndY; end end - {self.}SetLinesAlignment(); - if not {self.}Parent is class(CellRange) then - {self.}AlignRightBound(); end; -function ParagraphRange.SetLinesAlignment(); +function PRange.ProcessRealtimeArray(); begin + for _,range in realtime_numpages_array_ do + begin + range.Text := tostring(docx_to_pdf_.PageManager[docx_to_pdf_.PageManager.Count-1].Number); + first_page := docx_to_pdf_.PageManager[0]; + range.Width := first_page.PdfPage.TextWidth(range.Text); + range.Type := 1; + end + realtime_numpages_array_ := array(); + {self.}RangesToLines(); + {self.}DeterminePosition(); +end; + +function PRange.IsFirstLineOnNextPage(): boolean; +begin + lrange := line_range_array_[0]; + return ifnil(lrange) ? false : lrange.EndPage <> {self.}StartPage; +end; + +function PRange.Offset(x: real; y: real); +begin + {self.}EndX += x; + {self.}EndY += y; for _,line_range in line_range_array_ do - line_range.Align(ppr_unit_decorator_.Jc.Val); + line_range.Offset(x, y); end; -function ParagraphRange.AlignRightBound(); +function PRange.AlignRightBound(); begin len := length(line_range_array_); if len = 1 then return; @@ -1902,26 +1228,30 @@ begin line_range_array_[i].AlignRightBound(right_bound_); end; -function ParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; +function PRange.CheckAndAddPage(y: real; offset: real): boolean; begin - if y - offset < {self.}LowerBound then + lb := {self.}LowerBound; + if lb > 0 then + lb := lb > {self.}EndPage.LowerBound ? lb : {self.}EndPage.LowerBound; + if y - offset < lb then begin - page_ := docx_to_pdf_.PageManager[page_.Index + 1]; - if ifnil(page_) then page_ := docx_to_pdf_.AddPage(); - {self.}EndY := page_.TextPoint.Y; + {self.}DynamicHeight += y - lb; + {self.}EndPage := docx_to_pdf_.PageManager[{self.}EndPage.Index + 1]; + if ifnil({self.}EndPage) then {self.}EndPage := docx_to_pdf_.AddPage(); + {self.}EndY := {self.}EndPage.OriginalTextCoordinates()[1]; return true; end return false; end; -function ParagraphRange.RT(r: R; link: string); +function PRange.RT(r: R; anchor: string); begin - rpr := new RPrUnitDecorator(r.RPr); + rpr := new DocxMLUnitDecorator.RPrUnitDecorator(r.RPr); text := r.T.Text; - if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, link); + if text then {self.}SplitTextToTextRange(body_range_array_, text, rpr, anchor); end; -function ParagraphRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: string); +function PRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; anchor: string); begin pos := 1; if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); @@ -1939,22 +1269,26 @@ begin text_range.Type := 2; else if char >= 0x61 and char <= 0x7A then text_range.Type := 2; + else if char = 0x44 or char = 0x46 then + text_range.Type := 5; word := a_word; - font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + // font_name := rpr.RFonts.Ascii ?: rpr.RFonts.EastAsia; + // font_obj := docx_to_pdf_.Font.GetAsciiFont(font_name, rpr.B, rpr.I); end else if DTPUtils.IsChineseChar(a_word) then begin text_range.Type := 3; word := utf8ToAnsi(a_word); - font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end else if DTPUtils.IsChinesePunctuation(a_word) then begin text_range.Type := 4; word := utf8ToAnsi(a_word); - font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end else begin @@ -1966,257 +1300,135 @@ begin font_obj := docx_to_pdf_.Font.GetZapfDingbatsFont(); end else begin - font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end end - page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); - word_width := page_.PdfPage.TextWidth(word); + first_page := docx_to_pdf_.PageManager[0]; + pdf_page := first_page.PdfPage; + pdf_page.SetFontAndSize(font_obj, rpr.Sz.Val); text_range.RPr := rpr; text_range.Text := word; text_range.Font := font_obj; - text_range.Width := word_width; + text_range.Width := pdf_page.TextWidth(word); + text_range.DynamicHeight := rpr.Sz.Val; pos += num; range_arr[length(range_arr)] := text_range; - if ifarray(bookmark_array_[link]) then bookmark_array_[link] union= array(text_range); + + if ifarray(bookmark_hash_[anchor]) then bookmark_hash_[anchor] union= array(text_range); end end; -function ParagraphRange.RDrawing(r: R); +function PRange.SetPPPr(var p: P); begin - if r.Drawing._Inline then - begin - id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; - [image_type, image] := {self.}GetImageData(id); - if not image then return; - xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm); - image_range := new ImageRange(); - image_range.Image := image; - image_range.Type := image_type; - image_range.StartX := 0; - image_range.StartY := 0; - image_range.Width := xfrm.Ext.CX; - image_range.DynamicHeight := xfrm.Ext.CY; - body_range_array_[length(body_range_array_)] := image_range; - end - else if r.Drawing.Anchor then - begin - anchor := r.Drawing.Anchor; - id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; - [image_type, image] := {self.}GetImageData(id); - if not image then return; - [x, y] := {self.}GetXYCordinates(); - xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm); - position_h := new PositionHUnitDecorator(anchor.PositionH); - position_v := new PositionVUnitDecorator(anchor.PositionV); - if position_h.RelativeFrom = "paragraph" then - x := {self.}StartY; - if position_v.RelativeFrom = "paragraph" then - y := {self.}StartY; - image_range := new ImageRange(); - image_range.Image := image; - image_range.Type := image_type; - image_range.EndX := x + position_h.PosOffset.Text; - image_range.EndY := y - position_v.PosOffset.Text - xfrm.Ext.CY; - image_range.Width := xfrm.Ext.CX; - image_range.DynamicHeight := xfrm.Ext.CY; - image_range.Page := page_; - image_range.Do(); - end + new_ppr := new PPr(); + styles := docx_to_pdf_.DocxComponents.GetStyles(); + new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr); + new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr); + if {self.}Parent is class(TcRange) then + {self.}SetPPrByStyleId(new_ppr, {self.}Parent.GetTblStyleId()); + {self.}SetPPrByStyleId(new_ppr, p.PPr.PStyle.Val); + new_ppr.Copy(p.PPr); + p.PPr.Copy(new_ppr); end; -function ParagraphRange.RAlternateContent(r: R); +function PRange.SetPPrByStyleId(var ppr: PPr; style_id: string); begin - anchor := r.AlternateContent.Choice.Drawing.Anchor; - wsp := anchor.Graphic.GraphicData.Wsp; - [x, y] := {self.}GetXYCordinates(); - xfrm := new XfrmUnitDecorator(wsp.SpPr.Xfrm); - position_h := new PositionHUnitDecorator(anchor.PositionH); - position_v := new PositionVUnitDecorator(anchor.PositionV); - if position_h.RelativeFrom = "paragraph" then - x := {self.}StartY; - if position_v.RelativeFrom = "paragraph" then - y := {self.}StartY; - x += position_h.PosOffset.Text; - y -= position_v.PosOffset.Text; - w := xfrm.Ext.CX; - body_pr := new BodyPrUnitDecorator(wsp.BodyPr); - x += body_pr.LIns; - w -= (body_pr.LIns + body_pr.RIns); - ps := wsp.Txbx.TxbxContent.Ps(); - for _,p in ps do + styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then begin - range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, p); - range.StartX := x; - range.StartY := y; - range.Width := w; - range.Calc(); - range.Do(); - y := range.EndY; + based_on := style.BasedOn.Val; + {self.}SetPPrByStyleId(ppr, based_on); + ppr.Copy(style.PPr); + ppr.RPr.Copy(style.RPr); end end; -function ParagraphRange.RFootnoteReference(r: R); +function PRange.SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); begin - return; - id := R.FootnoteReference.Id; - footnotes_adapter := docx_components_module_.GetFootnotesAdapter(); - footnote := footnotes_adapter.GetFootnoteById(id); - sect_pr := page_.SectPr; - w := sect_pr.SectPr.PgSz.W - sect_pr.SectPr.PgMar.Right - sect_pr.SectPr.PgMar.Left; - lb := 0; - x := sect_pr.SectPr.PgMar.Left; - y := sect_pr.SectPr.PgSz.H; - - arr := array(); - elements := footnote.Elements(); - for _,element in elements do - begin - if element.LocalName = "p" then - begin - range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); - range.StartX := x; - range.StartY := y; - range.Width := w; - range.LowerBound := 0; - range.Calc(); - arr[length(arr)] := arr; - end - end - rpr := new RPrUnitDecorator(r.RPr); - note := docx_to_pdf_.Note; - text := docx_to_pdf_.GetCurrentNoteModule().GetIndex(); - i := length(body_range_array_); - if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); - footnote_reference_hash_[body_range_array_[i]] := arr; - - // range := new ParagraphRange(self, page_, docx_components_module_, ); + new_rpr := new RPr(); + styles := docx_to_pdf_.DocxComponents.GetStyles(); + new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr); + if {self.}Parent is class(TcRange) then + {self.}SetRPrByTblStyleId(new_rpr, {self.}Parent.GetTblStyleId()); + {self.}SetRPrByStyleId(new_rpr, ppr_unit_decorator.PStyle.Val); + {self.}SetRPrByStyleId(new_rpr, r.RPr.RStyle.Val); + new_rpr.Copy(r.RPr); + r.RPr.Copy(new_rpr); end; -function ParagraphRange.RFootnoteRef(r: R); +function PRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string); begin - return; - note_module := docx_to_pdf_.GetCurrentNoteModule(); - rpr := new RPrUnitDecorator(r.RPr); - text := note_module.GetFootnoteOrderNumber(); - if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); + styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetRPrByTblStyleId(rpr, based_on); + rpr.Copy(style.RPr); + end + if {self.}Parent is class(TcRange) then + begin + pr_type := {self.}Parent.GetPrType(); + tbl_style_pr := docx_to_pdf_.DocxComponents.GetTblStylePrByType(style_id, pr_type); + if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr); + end end; -function ParagraphRange.RObject(r: R); +function PRange.SetRPrByStyleId(var rpr: RPr; style_id: string); begin - id := r.Object.Shape.Imagedata.Id; - [image_type, image] := {self.}GetImageData(id); - if not image then return; - style := r.Object.Shape.Style; - style_arr := str2array(style, ";"); - for _,str in style_arr do + styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then begin - if startsStr("width:", str) then w := strtofloat(str[7:length(str)-2]); - else if startsStr("height:", str) then h := strtofloat(str[8:length(str)-2]); + based_on := style.BasedOn.Val; + {self.}SetRPrByStyleId(rpr, based_on); + rpr.Copy(style.RPr); end - image_range := new ImageRange(); - image_range.Image := image; - image_range.Type := image_type; - image_range.StartX := 0; - image_range.StartY := 0; - image_range.Width := w; - image_range.DynamicHeight := h; - body_range_array_[length(body_range_array_)] := image_range; end; -function ParagraphRange.RFldChar(r: R; stack: Stack); +function PRange.SetLvlText(); begin - fld_struct := stack.Pop(); - - if r.FldChar.FldCharType = "begin" then - fld_struct.EndFld := false; - else if r.FldChar.FldCharType = "end" then - fld_struct.EndFld := true; - else if r.FldChar.FldCharType = "separate" then - fld_struct.Separate := true; - - instr_text := ifString(r.InstrText.Text) ? trim(r.InstrText.Text) : ""; - if instr_text <> "" then - begin - if instr_text = "QUOTE" then - fld_struct.Quote := true; - else if instr_text = "\\* MERGEFORMAT" then - fld_struct.MergeFormat := true; - else if instr_text = "PAGE \\* Arabic \\* MERGEFORMAT" or instr_text = "PAGE \\* MERGEFORMAT" then - fld_struct.PageArabicMergeFormat := true; - else if instr_text = "NUMPAGES" then - fld_struct.NumPages := true; - else if instr_text = "\\* Arabic \\* MERGEFORMAT" then - fld_struct.ArabicMergeFormat := true; - else if instr_text = "NUMPAGES \\* Arabic \\* MERGEFORMAT" then - fld_struct.NumPages := fld_struct.ArabicMergeFormat := true; - end - if fld_struct.Quote then - begin - if not fld_struct.EndFld and not fld_struct.Separate then - begin - stack.Push(fld_struct); - return; - end - end - else if fld_struct.PageArabicMergeFormat then - begin - if fld_struct.Separate then - begin - r.T.Text := tostring(page_.Number); - {self.}RT(r, nil); - fld_struct.PageArabicMergeFormat := false; - end - end - else if fld_struct.ArabicMergeFormat then - begin - if fld_struct.Separate then - begin - rpr := new RPrUnitDecorator(r.RPr); - numpages_index := length(body_range_array_); - placeholder_array_ := array(numpages_index, rpr); - fld_struct.NumPages := false; - end - end - if not fld_struct.EndFld then - begin - stack.Push(fld_struct); - end - if ifObj(r.Drawing) then {self.}RDrawing(r); - else if ifObj(r.AlternateContent) then {self.}RAlternateContent(r); - else if ifObj(r.FootnoteReference) then {self.}RFootnoteReference(r); - else if ifObj(r.Object) then {self.}RObject(r); + numbering_module := docx_to_pdf_.DocxComponents.GetNumberingModule(); + if not ifObj(numbering_module) then return; + [lvl_text, lvl] := numbering_module.GetNumberLvl(p_.PPr); + if lvl_text = "" and ifnil(lvl) then return; + {self.}SetRRPr(lvl, ppr_unit_decorator_); + rpr := new RPrUnitDecorator(lvl.RPr); + // {self.}SplitTextToTextRange(bullet_range_array_, lvl_text, rpr); + {self.}SplitTextToTextRange(body_range_array_, lvl_text, rpr); end; -function ParagraphRange.GetXYCordinates(): array of real; +function PRange.GetXYCordinates(): array of real; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); if xml_file = "document.xml" then begin - [x, y] := page_.OriginalTextPoint(); + [x, y] := {self.}EndPage.OriginalTextCoordinates(); end else begin - x := page_.SectPr.PgMar.Left; + x := {self.}EndPage.SectPr.PgMar.Left; if ansiContainsStr(xml_file, "footer") then - y := page_.SectPr.PgMar.Bottom; + y := {self.}EndPage.SectPr.PgMar.Bottom; else if ansiContainsStr(xml_file, "header") then - y := page_.SectPr.PgSz.H - page_.SectPr.PgMar.Header; + y := {self.}EndPage.SectPr.PgSz.H - {self.}EndPage.SectPr.PgMar.Header; end return array(x, y); end; -function ParagraphRange.GetImageData(id: string): PdfImage; +function PRange.GetImageData(id: string): PdfImage; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); - if xml_file = "document.xml" then - rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); - else if ansiContainsStr(xml_file, "footer") then - rels_adapter := docx_components_module_.GetFtrRelsAdapter(xml_file); - else if ansiContainsStr(xml_file, "header") then - rels_adapter := docx_components_module_.GetHdrRelsAdapter(xml_file); + if {self.}Parent is class(HdrRange) then + rels_adapter := docx_to_pdf_.DocxComponents.GetHdrRelsAdapter(xml_file); + else if {self.}Parent is class(FtrRange) then + rels_adapter := docx_to_pdf_.DocxComponents.GetFtrRelsAdapter(xml_file); + else + rels_adapter := docx_to_pdf_.DocxComponents.GetDocumentRelsAdapter(); rel := rels_adapter.GetRelationshipById(id); image_path := "word/" + rel.Target; - image := docx_components_module_.Zip().Get(image_path); + image := docx_to_pdf_.DocxComponents.Zip().Get(image_path); data := image.Data(); image_path := docx_to_pdf_.GetCachePath(image_path); writeFile(rwBinary(), "", image_path, 0, length(data), data); @@ -2236,7 +1448,7 @@ begin return array(image_type, image); end; -function ParagraphRange.GetImageFileType(data: binary): string; +function PRange.GetImageFileType(data: binary): string; begin stream := new TMemoryStream(); size := length(data); @@ -2262,7 +1474,7 @@ begin return ''; end; -function ParagraphRange.GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; +function PRange.GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; begin if not line then line := 240; if line_rule = "exact" or line_rule = "atLeast" then @@ -2272,137 +1484,797 @@ begin end else begin lines := roundto(line / 240, -1); - multi := ceil(size / page_.BaseSize); + multi := ceil(size / docx_to_pdf_.CurrentSect.BaseSize); if (not ifnil(ppr_unit_decorator_.SnapToGrid) and not ppr_unit_decorator_.SnapToGrid) or ((ifnil(ppr_unit_decorator_.SnapToGrid) or ppr_unit_decorator_.SnapToGrid) and lines > multi) then multi *= lines; - return page_.SectPr.DocGrid.LinePitch * multi; + return docx_to_pdf_.CurrentSect.SectPr.DocGrid.LinePitch * multi; end end; -function ParagraphRange.SetPPPr(var p: P); +function TcRange.Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty); begin - new_ppr := new PPr(); - styles := docx_components_module_.GetStyles(); - new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr); - new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr); - {self.}SetPPrByStyleId(new_ppr, table_style_id_); - {self.}SetPPrByStyleId(new_ppr, p.PPr.PStyle.Val); - new_ppr.Copy(p.PPr); - p.PPr.Copy(new_ppr); + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + tc_ := tc; + trp_ := trp; + tc_pr_unit_decorator_ := new TcPrUnitDecorator(tc_.TcPr); + content_next_page_ := false; + top_ := false; end; -function ParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string); +function TcRange.Do(); begin - styles := docx_components_module_.GetStylesAdapter(); + for _,region in region_array_ do + begin + region.BordersRange.Do(); + for __,range in region.RangeArr do + range.Do(); + end +end; + +function TcRange.DoBordersRangeFill(); +begin + for _,region in region_array_ do + begin + region.BordersRange.DoFill(); + end +end; + +function TcRange.Calc(); +begin + range_array_ := array(); + cell_w := {self.}Width - {self.}Parent.TblPr.TblCellMar.Right.W - {self.}Parent.TblPr.TblCellMar.Left.W; + elements := tc_.Elements(); + for _,element in elements do + begin + if element.LocalName = "p" then + begin + range := new PRange(docx_to_pdf_, element); + range.Width := cell_w; + range.Parent := self; + range.Calc(); + range_array_[length(range_array_)] := range; + end + end +end; + +function TcRange.Run(); +begin + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}EndPage := {self.}StartPage; + {self.}DynamicHeight := 0; + content_next_page_ := false; + + cell_x := {self.}EndX + {self.}Parent.TblPr.TblCellMar.Left.W; + cell_y := {self.}EndY - {self.}Parent.TblPr.TblCellMar.Top.W; + cell_h := {self.}FixedHeight; + for _,range in range_array_ do + begin + range.StartX := cell_x; + range.StartY := cell_y; + range.LowerBound := {self.}LowerBound; + range.StartPage := {self.}EndPage; + range.Run(); + if _ = 0 and range.IsFirstLineOnNextPage() then + begin + content_next_page_ := true; + break; + end + cell_y := range.EndY; + {self.}EndPage := range.EndPage; + {self.}DynamicHeight += range.DynamicHeight; + end + {self.}EndY := cell_y - {self.}Parent.TblPr.TblCellMar.Bottom.W; + {self.}DynamicHeight += {self.}Parent.TblPr.TblCellMar.Bottom.W + {self.}Parent.TblPr.TblCellMar.Top.W; + + // 同步行高 + if not tc_.TcPr.VMerge and {self.}DynamicHeight > trp_.Height then + trp_.Height := {self.}DynamicHeight; +end; + +function TcRange.SetTop(); +begin + top_ := true; +end; + +function TcRange.ContentNextPage(): boolean; +begin + return content_next_page_; +end; + +function TcRange.AlignHeight(height: real); +begin + region_array_ := array(); + region := new DTPUtils.Region(); + region.BordersRange.Width := {self.}Width; + region.BordersRange.FixedHeight := {self.}FixedHeight; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + + pg := {self.}StartPage; + y := {self.}StartY; + page_remaining_height := y - {self.}GetLowerBound(pg); + surplus := height - page_remaining_height; + if surplus < 1e-6 then // 一页就够 + begin + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := {self.}StartY; + region.BordersRange.EndPage := pg; + region.BordersRange.DynamicHeight := height; + region.RangeArr union= range_array_; + {self.}EndY := {self.}StartY - height; + end + else begin + page_hash := array(); + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := {self.}StartY; + region.BordersRange.EndPage := pg; + region.BordersRange.DynamicHeight := page_remaining_height; + page_hash[pg.Index] := region; + // surplus -= page_remaining_height; + pg := docx_to_pdf_.PageManager[{self.}pg.Index + 1]; + y := pg.OriginalTextCoordinates()[1]; + page_remaining_height := y - {self.}GetLowerBound(pg); + while surplus > page_remaining_height do + begin + region := new DTPUtils.Region(); + region.BordersRange.Width := {self.}Width; + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := y; + region.BordersRange.EndPage := pg; + region.BordersRange.DynamicHeight := page_remaining_height; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + region.BordersRange.Top := true; + region.BordersRange.Bottom := true; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + page_hash[pg.Index] := region; + surplus -= page_remaining_height; + pg := docx_to_pdf_.PageManager[{self.}pg.Index + 1]; + y := pg.OriginalTextCoordinates()[1]; + page_remaining_height := y - {self.}GetLowerBound(pg); + end + if surplus > 1e-6 then + begin + region := new DTPUtils.Region(); + region.BordersRange.Width := {self.}Width; + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := y; + region.BordersRange.EndPage := pg; + region.BordersRange.DynamicHeight := surplus; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + region.BordersRange.Top := true; + page_hash[pg.Index] := region; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + {self.}EndY := y - surplus; + end + + // 对应page分散到对应region + ranges := array(); + for _,range in range_array_ do + ranges union= range.PLineRanges(); + for _,range in ranges do + begin + region := page_hash[range.EndPage.Index]; + region.RangeArr[length(region.RangeArr)] := range; + end + end +end; + +function TcRange.GetLowerBound(pg: Page): real; +begin + return {self.}LowerBound = 0 ? pg.LowerBound : max({self.}LowerBound, pg.LowerBound); +end; + +function TcRange.SetVAlign(); +begin + val := tc_.TcPr.VAlign.Val; + region := region_array_[0]; + arr := region.RangeArr; + if length(arr) = 0 then return; + last_y := arr[length(arr)-1].EndY; + offset := last_y - (region.BordersRange.EndY - region.BordersRange.DynamicHeight) - {self.}Parent.TblPr.TblCellMar.Bottom.W; + case val of + "center": + begin + offset /= 2; + for _,range in arr do + range.Offset(0, -offset); + end + end; +end; + +function TcRange.SetBorderRange(range: BordersRange); +begin + tbl_pr := {self.}Parent.TblPr; + if ifObj(tbl_pr.TblBorders) then + begin + if {self.}Row = 0 then + begin + if tbl_pr.TblBorders.Top then + begin + if not tc_pr_unit_decorator_.TcBorders.Top then + tc_pr_unit_decorator_.TcBorders.Top.Copy(tbl_pr.TblBorders.Top); + range.Top := true; + end + if tbl_pr.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.InsideH); + range.Bottom := true; + end + if tbl_pr.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.InsideV); + range.Right := true; + end + if tbl_pr.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.Bottom); + range.Bottom := true; + end + end + else if {self.}Row = {self.}Parent.Rows-1 then + begin + if tbl_pr.TblBorders.Bottom then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.Bottom); + range.Bottom := true; + end + if tbl_pr.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.InsideV); + range.Right := true; + end + end + else begin + if tbl_pr.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.Bottom); + range.Bottom := true; + end + if tbl_pr.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.InsideH); + range.Bottom := true; + end + if tbl_pr.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.InsideV); + range.Right := true; + end + end + + if {self.}Col = 0 then + begin + if tbl_pr.TblBorders.Left then + begin + if not tc_pr_unit_decorator_.TcBorders.Left then + tc_pr_unit_decorator_.TcBorders.Left.Copy(tbl_pr.TblBorders.Left); + range.Left := true; + end + end + if {self.}Col = {self.}Parent.Cols()-1 then + begin + if tbl_pr.TblBorders.Right then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.Right); + range.Right := true; + end + end + end + else begin + range.Left := {self.}Col = 0; + range.Top := {self.}Row = 0; + range.Right := true; + range.Bottom := true; + end + if top_ then range.Top := true; +end; + +function TcRange.GetTblStyleId(): string; +begin + return {self.}Parent.TblPr.TblStyle.Val; +end; + +function TcRange.GetPrType(): string; +begin + if {self.}Row = 0 then return "firstRow"; + else if ({self.}Row + 1) % 2 = 0 then return "band1Horz"; + else return "band2Horz"; +end; + +function TblRange.Create(docx_to_pdf: TSDocxToPdf; tbl: Tbl); +begin + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + tbl_ := tbl; +end; + +function TblRange.Do(); +begin + for _,r in tc_range_matrix_ do + for __,range in r do + if ifObj(range) then + range.DoBordersRangeFill(); + for _,r in tc_range_matrix_ do + for __,range in r do + if ifObj(range) then + range.Do(); +end; + +function TblRange.Calc(); +begin + {self.}SetTblTblPr(tbl_); + tbl_pr_unit_decorator_ := new TblPrUnitDecorator(tbl_.TblPr); + tbl_grid_unit_decorator := new TblGridUnitDecorator(tbl_.TblGrid); + grid_cols_ := tbl_grid_unit_decorator.GridCols(); + // 如果是根据内容自适应,应该计算并调整grid_cols的值 + trs := tbl_.Trs(); + rows_ := length(trs); + cols_ := length(grid_cols_); + tr_pr_array_ := array(); + tc_range_matrix_ := nils(rows_, cols_); + // 先构建一个矩阵 + {self.}CreateTableMatrix(grid_cols_, trs); +end; + +function TblRange.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 := 0; + trp := new DTPUtils.TrProperty(); + trp.TrPr := tr_pr; + tr_pr_array_[i] := trp; + tcs := tr.Tcs(); + 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 + begin + tc_range_matrix_[i][pos] := 0; + tc_x += grid_cols[pos++].W; + end + continue; + end + tc_range := new TcRange(docx_to_pdf_, tc, trp); + tc_range.Width := grid_cols[pos].W; + tc_range.FixedHeight := tr_pr.TrHeight.Val; + tc_range.Parent := self; + tc_range.OffsetX := tc_x; + tc_range.Row := i; + tc_range.Col := pos; + tc_range_matrix_[i][pos] := tc_range; + pos++; + // 水平合并的单元格,占位需要和垂直的区分 + for k:=grid_span.Val-1 downto 1 do + begin + tc_range_matrix_[i][pos] := 0; // 水平合并占位0 + tc_range.Width += grid_cols[pos++].W; + end + tc_x += tc_range.Width; + end + end + // for i,arr in tc_range_matrix_ do + // println("i = {}, arr = {}", i, arr); + // println("\n"); +end; + +function TblRange.Run(); +begin + {self.}ResetCoordinates(tbl_pr_unit_decorator_, grid_cols_); + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}EndPage := {self.}StartPage; + i := 0; + merge_arr := array(); + vmerge_height := array(); + vmerge_info := array(); + while i < rows_ do + begin + // println("i = {}", i); + // if i = 11 then return; + // if i = 10 then + // println(">>>>>>>>>>>>>>>>"); + j := 0; + tc_y := {self.}EndY; + top := recompute_flag; + recompute_flag := false; + while j < cols_ do + begin + range := tc_range_matrix_[i][j]; + if not ifObj(range) then + begin + j++; + continue; + end + range.StartX := {self.}EndX + range.OffsetX; + range.StartY := tc_y; + range.StartPage := {self.}EndPage; + range.LowerBound := {self.}LowerBound; + if top then range.SetTop(); + range.Calc(); + range.Run(); + if range.ContentNextPage() then // 单元格新页开始,调整上一页的下边界,并重新计算 + begin + top := true; + recompute_flag := true; + {self.}EndPage.LowerBound := tc_y; + {self.}EndPage := docx_to_pdf_.PageManager[{self.}EndPage.Index + 1]; + [x, y] := {self.}EndPage.OriginalTextCoordinates(); + {self.}EndY := y; + break; + end + if range.Tc.TcPr.VMerge then + begin + b_merge_index := i; + e_merge_index := i + 1; + while ifnil(tc_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; + if ifnil(vmerge_height[e_merge_index]) or range.DynamicHeight > vmerge_height[e_merge_index] then + vmerge_height[e_merge_index] := range.DynamicHeight; + vmerge_info[e_merge_index] := b_merge_index; + end + j++; + end + if recompute_flag then continue; + top := false; + i_height := 0; + for k,v in merge_arr[i] do + begin + i_height := tr_pr_array_[i].Height; + r := tc_range_matrix_[v][k]; + total_height := 0; + for index:=v to i-1 do + total_height += tr_pr_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 tr_pr_array_[i].Height := i_height; + for _,range in tc_range_matrix_[i] do + begin + if not ifObj(range) or range.Tc.TcPr.VMerge then continue; + range.AlignHeight(tr_pr_array_[i].Height); + range.SetVAlign(); + {self.}EndY := range.EndY; + if {self.}EndPage.Index < range.EndPage.Index then + {self.}EndPage := range.EndPage; + end + i++; + end +end; + +function TblRange.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 TblRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); +begin + // tc_pr应该是经过外层copy的 + tbl_style_pr := docx_to_pdf_.DocxComponents.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type); + if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr); +end; + +function TblRange.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 TblRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); +begin + styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; - {self.}SetPPrByStyleId(ppr, based_on); - ppr.Copy(style.PPr); - ppr.RPr.Copy(style.RPr); + {self.}SetTblPrByStyleId(tbl_pr, based_on); + tbl_pr.Copy(style.TblPr); end end; -function ParagraphRange.SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); +function TblRange.SetTrTrPr(var tr: Tr); begin - new_rpr := new RPr(); - styles := docx_components_module_.GetStyles(); - new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr); - {self.}SetRPrByTblStyleId(new_rpr, table_style_id_); - {self.}SetRPrByStyleId(new_rpr, ppr_unit_decorator.PStyle.Val); - {self.}SetRPrByStyleId(new_rpr, r.RPr.RStyle.Val); - new_rpr.Copy(r.RPr); - r.RPr.Copy(new_rpr); + 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 ParagraphRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string); +function TblRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); begin - styles := docx_components_module_.GetStylesAdapter(); + styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; - {self.}SetRPrByTblStyleId(rpr, based_on); - rpr.Copy(style.RPr); - end - if table_style_type_ then - begin - tbl_style_pr := docx_components_module_.GetTblStylePrByType(table_style_id_, table_style_type_); - if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr); + {self.}SetTrPrByStyleId(tr_pr, based_on); + tr_pr.Copy(style.TrPr); end end; -function ParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string); +function TblRange.SetTcTcPr(var tc: Tc); begin - styles := docx_components_module_.GetStylesAdapter(); + 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 TblRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); +begin + styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; - {self.}SetRPrByStyleId(rpr, based_on); - rpr.Copy(style.RPr); + {self.}SetTcPrByStyleId(tc_pr, based_on); + tc_pr.Copy(style.TcPr); end end; -function ParagraphRange.SetLvlText(); +function OMathParaRange.Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara); begin - numbering_module := docx_components_module_.GetNumberingModule(); - if not ifObj(numbering_module) then return; - [lvl_text, lvl] := numbering_module.GetNumberLvl(paragraph_.PPr); - if lvl_text = "" and ifnil(lvl) then return; - {self.}SetRRPr(lvl, ppr_unit_decorator_); - rpr := new RPrUnitDecorator(lvl.RPr); - // {self.}SplitTextToTextRange(bullet_range_array_, lvl_text, rpr); - {self.}SplitTextToTextRange(body_range_array_, lvl_text, rpr); + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + o_math_para_ := o_math_para; end; -function ParagraphRange.ResetCoordinates(); +function OMathParaRange.Do();override; begin - // 根据段落的间距确定新的坐标 - ppr := ppr_unit_decorator_; - sz := ppr.RPr.SzCs.Val ? ppr.RPr.SzCs.Val : ppr.RPr.Sz.Val ? ppr.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); - {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; -function ParagraphRange.GetLastPage(): Page; +function OMathParaRange.Run();override; begin - return page_; end; -function ParagraphRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); +function OMathParaRange.Calc(); begin - for _,line_range in line_range_array_ do - line_range.AdjustRangeOffset(pg, x_offset, y_offset); + o_math_ := new OMathRange(docx_to_pdf_, o_math_para_.OMath); + o_math_.Width := {self.}Width; + o_math_.Parent := self; + o_math_.StartX := 0; + o_math_.StartY := 0; + o_math_.SetMathSize(); + o_math_.Calc(); end; -function ParagraphRange.GetParagraphLineRangeArr(): array of ParagraphLineRange; +function OMathRange.Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement); begin - return line_range_array_; + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + element_ := element; + sz_ := 0; end; -function ParagraphRange.Empty(): boolean; +function OMathRange.Do();override; begin - return empty_; end; -function ParagraphRange.Offset(x: real; y: real); +function OMathRange.Calc(); begin - for _,line_range in line_range_array_ do - line_range.Offset(x, y); + range_array_ := array(); + elements := element_.Elements(); + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + for _,element in elements do + begin + range := nil; + if element.LocalName = "r" then + range := {self.}MR(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "f" then + range := {self.}MF(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "rad" then + range := {self.}MRad(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "nary" then + range := {self.}MNary(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "sSup" then + range := {self.}MSSup(element, sz_, {self.}EndX, {self.}EndY); + + if not ifObj(range) then + begin + echo format("Math do not support <%s>\n", element.ElementName); + continue; + end + {self.}EndX := range.EndX; + {self.}EndY := range.EndY; + range_array_[length(range_array_)] := range; + end end; -function ParagraphRange.OMathPara(element: OMathPara); +function OMathRange.SetMathSize(); begin - math_range := new MathRange(docx_to_pdf_, page_, element); - math_range.StartX := {self.}StartX; - math_range.StartY := {self.}StartY - 15.6; - math_range.Calc(); - // math_range.Do(); - body_range_array_[length(body_range_array_)] := math_range; + elements := element_.Elements(); + element := elements[0]; + rpr := nil; + if element.LocalName = "r" then + rpr := element.RPr; + else if element.LocalName = "f" then + rpr := element.FPr.CtrlPr.RPr; + else if element.LocalName = "nary" then + rpr := element.NaryPr.CtrlPr.RPr; + else if element.LocalName = "rad" then + rpr := element.RadPr.CtrlPr.RPr; + else if element.LocalName = "sSup" then + rpr := element.SSupPr.CtrlPr.RPr; + + styles := docx_to_pdf_.DocxComponents.GetStyles(); + default_rpr := styles.DocDefaults.RPrDefault.RPr(); + if rpr then default_rpr.Copy(rpr); + sz_ := default_rpr.Sz.Val; end; +function OMathRange.MR(r: R; sz: real; x: real; y: real): PLineRange; +begin + if not r.T then return; + line_range := new PLineRange(); + line_range.Parent := self; + line_range.EndX := x; + line_range.EndY := y - sz; + line_range.Width := 0; + line_range.TextMaxSize := sz; + line_range.DynamicHeight := sz; + text := r.T.Text; + pos := 1; + while pos <= length(text) do + begin + text_range := new TextRange(); + num := DTPUtils.Utf8CharLengthFromByte(text[pos]); + a_word := text[pos : pos+num-1]; + if num = 1 then + begin + char := ord(a_word); + if char >= 0x30 and char <= 0x39 then + text_range.Type := 1; + else if char >= 0x41 and char <= 0x5A then + text_range.Type := 2; + else if char >= 0x61 and char <= 0x7A then + text_range.Type := 2; + else if char = 0x44 or char = 0x46 then + text_range.Type := 5; + word := a_word; + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + else if DTPUtils.IsChineseChar(a_word) then + begin + text_range.Type := 3; + word := utf8ToAnsi(a_word); + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + else if DTPUtils.IsChinesePunctuation(a_word) then + begin + text_range.Type := 4; + word := utf8ToAnsi(a_word); + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + else begin + word := utf8ToAnsi(a_word); + if word = "?" then + begin + word := class(SymbolMapper).ZapfDingbatsChr(a_word); + if ifnil(word) then word := "u"; + font_obj := docx_to_pdf_.Font.GetZapfDingbatsFont(); + end + else begin + font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + end + first_page := docx_to_pdf_.PageManager[0]; + pdf_page := first_page.PdfPage; + pdf_page.SetFontAndSize(font_obj, rpr.Sz.Val); + rpr := new RPr(); + rpr.Sz.Val := sz; + text_range.RPr := rpr; + text_range.Text := word; + text_range.Font := font_obj; + text_range.Width := pdf_page.TextWidth(word); + text_range.Parent := line_range; + text_range.DynamicHeight := rpr.Sz.Val; + text_range.EndX := line_range.EndX; + text_range.EndY := line_range.EndY; + line_range.EndX += text_range.Width; + line_range.Width += text_range.Width; + pos += num; + line_range.AddRange(text_range); + end + return line_range; +end; + +function OMathFRange.Create(docx_to_pdf: TSDocxToPdf; f: F); +begin + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + f_ := f; + range_array_ := array(); +end; + +function OMathFRange.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function OMathFRange.Calc(); +begin + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + + den_range := new OMathRange(docx_to_pdf_, f.Den); + den_range.Sz := sz_; + den_range.StartX := {self.}EndX; + den_range.StartY := {self.}EndY; + den_range.Calc(); // 需要得到高宽 + + num_range := new OMathRange(docx_to_pdf_, f.Num); + num_range.Sz := sz_; + num_range.StartX := {self.}EndX; + num_range.StartY := {self.}EndY + 1.418 * sz; + num_range.Calc(); // 需要得到高宽 + + max_len := max(den_range.Width, num_range.Width); + bar := max_len / 0.9; + line_range := new LineRange(); + line_range.StartX := x - (bar - max_len) / 2; + line_range.StartY := y + 0.928 * sz; + line_range.EndX := line_range. + line_range.Width := bar; + line_range.LineWidth := 0.04 * sz; + + range_array_ union= array(den_range, num_range, line_range); +end; + + end. diff --git a/internal/DTPModules.tsf b/internal/DTPModules.tsf index 98f9071..f87b8fd 100644 --- a/internal/DTPModules.tsf +++ b/internal/DTPModules.tsf @@ -1,6 +1,6 @@ unit DTPModules; interface -uses TSPdfEnumerations, DocxMLAdapter, SharedMLAdapter; +uses DTPAdvancedRanges, DocxMLAdapter, SharedMLAdapter; type DocxComponentsModule = class(DocxComponents) public @@ -57,19 +57,21 @@ end; type NoteModule = class public - function Create(sect_module: SectModule); + function Create(docx_to_pdf: TSDocxToPdf); + function AddFootnoteId(id: string); function GetFootnoteOrderNumber(): string; function GetFootnoteIndex(): string; - function AddFootnote(); private function CalculateNumber(num_fmt: string; num: integer): string; function ChineseCountingThousand(n: integer): string; private - footnote_reference_hash_: hash; + [weakref]docx_to_pdf_: TSDocxToPdf; + footnote_hash_: hash; footnote_index_: integer; - [weakref]sect_module_: SectModule; + endnote_hash_: hash; + endnote_index_: integer; end; type NumberingModule = class @@ -89,35 +91,21 @@ end; type SectModule = class public function Create(); - function Destroy(); - function Do(); function AddElement(element: tslobj); public - Elements: array of tslobj; SectPr: SectPrUnitDecorator; -end; - -type Toc = class -public - function Create(ppr: PPrUnitDecorator; rect: array of real; page: Page; x: real; y: real; font: PdfFont); - function LinkAnnot(dst: PdfDestination); - function AddPageNumber(page: Page); - -private - [weakref]page_: Page; - ppr_: PPrUnitDecorator; - rect_: array of real; - font_: PdfFont; - x_; - y_; + Elements: array of tslobj; + BaseSize: real; end; type TocModule = class public function Create(); function UpdateDocxNumPages(); - function LinkToToc(anchor: string; pg: Page; left: real; top: real); + function CalculateRect(anchor: string); + + function LinkToToc(anchor: string; range: BasicRange); function AddToc(anchor: string; toc: Toc); function AddDocxPage(anchor: string; r: R); @@ -154,11 +142,13 @@ public Index: integer; Number: integer; SectPr: SectPrUnitDecorator; - BaseSize: real; TextPoint: Point; // 正文坐标 FtrPoint: Point; // 页脚坐标 HdrPoint: Point; // 页眉坐标 + UpperBound: real; // 上界 + LowerBound: real; // 下界 + private [weakref]pdf_file_: PdfFile; pdf_page_: PdfPage; @@ -371,9 +361,12 @@ begin if bold and italic then font_name := "Times-BoldItalic"; else if bold then - font_name += "Times-Bold"; + font_name := "Times-Bold"; else if italic then - font_name += "Times-Italic"; + font_name := "Times-Italic"; + end + else begin + font_name := "Courier"; end return pdf_.GetFont(font_name, ""); end; @@ -394,16 +387,65 @@ begin end; // NoteModule -function NoteModule.Create(sect_module: SectModule); +function NoteModule.Create(docx_to_pdf: TSDocxToPdf); begin - sect_module_ := sect_module; - footnote_reference_hash_ := array(); + docx_to_pdf_ := docx_to_pdf; + footnote_hash_ := array(); + endnote_hash_ := array(); footnote_index_ := 0; + endnote_index_ := 0; end; +function NoteModule.AddFootnoteId(id: string); +begin + footnotes_adapter := docx_to_pdf_.DocxComponents.GetFootnotesAdapter(); + footnote := footnotes_adapter.GetFootnoteById(id); + sect_pr := docx_to_pdf_.CurrentSect.SectPr; + w := sect_pr.SectPr.PgSz.W - sect_pr.SectPr.PgMar.Right - sect_pr.SectPr.PgMar.Left; + lb := 0; + arr := array(); + elements := footnote.Elements(); + for _,element in elements do + begin + if element.LocalName = "p" then + begin + range := new PRange(docx_to_pdf_, element); + range.Width := w; + range.LowerBound := lb; + range.Parent := self; + range.Calc(); + arr[length(arr)] := range; + end + end + footnote_hash_[id] := arr; +end; + +// function NoteModule.RunFootnote(id: string; x: real; y: real; pg: Page); +// begin +// sx := x; +// sy := y; +// spg := pg; +// height := 0; +// arr := array(); +// hash := footnote_hash_[id]; +// for id,range in hash do +// begin +// range.StartX := x; +// range.StartY := y; +// range.StartPage := spg; +// range.LowerBound := 0; +// range.Run(); +// sy := range.EndY; +// height += range.DynamicHeight; +// arr union= range.PLineRanges(); +// footnote_hash_[id] := arr; +// end +// return height; +// end; + function NoteModule.GetFootnoteOrderNumber(); begin - num_fmt := sect_module_.SectPr.FootnotePr.NumFmt.Val; + num_fmt := docx_to_pdf_.CurrentSect.SectPr.FootnotePr.NumFmt.Val; if ifnil(num_fmt) then num_fmt := "decimal"; return CalculateNumber(num_fmt, ++footnote_index_); end; @@ -640,16 +682,24 @@ begin update_docx_num_pages_ := true; end; -function TocModule.LinkToToc(anchor: string; pg: Page; left: real; top: real); +function TocModule.CalculateRect(anchor: string); +begin + arr := toc_hash_[anchor]; + for _,toc in arr do + toc.CalculateRect(); +end; + +function TocModule.LinkToToc(anchor: string; range: BasicRange); begin arr := toc_hash_[anchor]; if ifnil(arr) then begin - toc_unmatched_hash_[anchor] := array(pg, left, top); + toc_unmatched_hash_[anchor] := range; return; end + pg := range.EndPage; dst := pg.PdfPage.CreateDestination(); - dst.SetXYZ(left, top, 1); + dst.SetXYZ(range.EndX, range.EndY + range.RPr.Sz.Val, 1); for _,toc in arr do toc.LinkAnnot(dst); toc.AddPageNumber(pg); @@ -679,41 +729,4 @@ begin docx_page_hash_[anchor] := r; end; -// Toc -function Toc.Create(ppr: PPrUnitDecorator; rect: array of real; pg: Page; x: real; y: real; font: PdfFont); -begin - ppr_ := ppr; - rect_ := rect; - page_ := pg; - x_ := x; - y_ := y; - font_ := font; -end; - -function Toc.LinkAnnot(dst: PdfDestination); -begin - annot := page_.PdfPage.CreateLinkAnnot(rect_, dst); - annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT); - annot.LinkAnnotSetBorderStyle(0, 0, 0); -end; - -function Toc.AddPageNumber(pg: Page); -begin - number := tostring(pg.Number); - page_.PdfPage.SetFontAndSize(font_, ppr_.RPr.Sz.Val); - number_sz := page_.PdfPage.TextWidth(number); - x := rect_[2] - number_sz; - page_.PdfPage.BeginText(); - page_.PdfPage.TextOut(x, y_, number); - page_.PdfPage.EndText(); - - page_.PdfPage.SetRGBStroke(0, 0, 0); - page_.PdfPage.SetDash(array(0.5, 2), 2, 0); - page_.PdfPage.SetLineWidth(0.5); - page_.PdfPage.SetLineCap(TSPdfEnumerations.ROUND_END); - page_.PdfPage.MoveTo(x_+1, y_); - page_.PdfPage.LineTo(x-0.5, y_); - page_.PdfPage.Stroke(); -end; - end. diff --git a/internal/DTPPrimitiveRanges.tsf b/internal/DTPPrimitiveRanges.tsf index 95ff70e..94eff13 100644 --- a/internal/DTPPrimitiveRanges.tsf +++ b/internal/DTPPrimitiveRanges.tsf @@ -11,13 +11,14 @@ public RPr: RPr; Text: string; Font: PdfFont; - Type: integer; // 0:默认,1: 数字,2:英文,3:中文,4:中文标点 + Type: integer; // 0:默认,1: 数字,2:英文,3:中文,4:中文标点,5:,.英文逗号和点 end; type BordersRange = class(BasicRange) public function Create(); function Do();override; + function DoFill(); public TcPr: TcPr; Left: boolean; @@ -65,7 +66,8 @@ public DynamicHeight: real; LowerBound: real; [weakref]Parent: tslobj; - [weakref]Page: Page; + [weakref]StartPage: Page; // 起始page + [weakref]EndPage: Page; // 结束page end; implementation @@ -81,7 +83,7 @@ begin {self.}DynamicHeight := 0; {self.}LowerBound := 0; {self.}FixedHeight := 0; - {self.}Page := nil; + {self.}EndPage := nil; end; // ImageRange @@ -96,18 +98,18 @@ function ImageRange.Do();override; begin // println("image = {}, type = {}, x = {}, y = {}, w = {}, h = {}", {self.}image, {self.}Type, {self.}endx, {self.}endy, {self.}width, {self.}DynamicHeight); if {self.}Type = "emf" then - {self.}Page.PdfPage.DrawEmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + {self.}EndPage.PdfPage.DrawEmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); else if {self.}Type = "wmf" then - {self.}Page.PdfPage.DrawWmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + {self.}EndPage.PdfPage.DrawWmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); else - {self.}Page.PdfPage.DrawImage({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + {self.}EndPage.PdfPage.DrawImage({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); if sysparams["_PDF_IMAGE_DEBUG_"] then begin - {self.}Page.PdfPage.SetLineWidth(0.1); - {self.}Page.PdfPage.SetRGBStroke(0.8, 0.8, 0); - {self.}Page.PdfPage.Rectangle({self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); - {self.}Page.PdfPage.Stroke(); + {self.}EndPage.PdfPage.SetLineWidth(0.1); + {self.}EndPage.PdfPage.SetRGBStroke(0.8, 0.8, 0); + {self.}EndPage.PdfPage.Rectangle({self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + {self.}EndPage.PdfPage.Stroke(); end end; @@ -122,32 +124,37 @@ begin {self.}Bottom := false; end; -function BordersRange.Do();override; +function BordersRange.DoFill(); begin - // println("Left = {}, Top = {}, Right = {}, Bottom = {}, Tl2Br = {}, Tr2Bl = {}", Left, Top, Right, Bottom, Tl2Br, Tr2Bl); borders := {self.}TcPr.TcBorders; if {self.}TcPr.Shd.Fill and {self.}TcPr.Shd.Fill <> "auto" then begin [r, g, b] := DTPColorToolKit.HexToRGB({self.}TcPr.Shd.Fill); - {self.}Page.PdfPage.SetRGBFill(r/255, g/255, b/255); + {self.}EndPage.PdfPage.SetRGBFill(r/255, g/255, b/255); x := {self.}EndX; y := {self.}EndY - {self.}DynamicHeight; w := {self.}Width; h := {self.}DynamicHeight; - tmp := borders.Left.Sz ? borders.Left.Sz / 2 : 0.25; - x += tmp; - w -= tmp; - w -= borders.Right.Sz ? borders.Right.Sz / 2 : 0.25; - tmp := borders.Bottom.Sz ? borders.Bottom.Sz / 2 : 0.25; - y += tmp; - h -= tmp; - h -= borders.Top.Sz ? borders.Top.Sz / 2 : 0.25; + // tmp := borders.Left.Sz ? borders.Left.Sz / 2 : 0.25; + // x += tmp; + // w -= tmp; + // w -= borders.Right.Sz ? borders.Right.Sz / 2 : 0.25; + // tmp := borders.Bottom.Sz ? borders.Bottom.Sz / 2 : 0.25; + // y += tmp; + // h -= tmp; + // h -= borders.Top.Sz ? borders.Top.Sz / 2 : 0.25; - {self.}Page.PdfPage.Rectangle(x, y, w, h); - {self.}Page.PdfPage.Fill(); - {self.}Page.PdfPage.SetRGBFill(0, 0, 0); - {self.}Left := true; + {self.}EndPage.PdfPage.Rectangle(x, y, w, h); + {self.}EndPage.PdfPage.Fill(); + {self.}EndPage.PdfPage.SetRGBFill(0, 0, 0); + // {self.}Left := true; end +end; + +function BordersRange.Do();override; +begin + // println("Left = {}, Top = {}, Right = {}, Bottom = {}, Tl2Br = {}, Tr2Bl = {}", Left, Top, Right, Bottom, Tl2Br, Tr2Bl); + borders := {self.}TcPr.TcBorders; if {self.}Left then {self.}DrawLine(borders.Left, {self.}EndX, {self.}EndY, {self.}EndX, {self.}EndY - {self.}DynamicHeight); if {self.}Top then @@ -165,9 +172,9 @@ end; function BordersRange.SetDash(val: string); begin if val = "single" or ifnil(val) then - {self.}Page.PdfPage.SetDash(array(), 0, 0); - if val = "dashed" then - {self.}Page.PdfPage.SetDash(array(1), 1, 0); + {self.}EndPage.PdfPage.SetDash(array(), 0, 0); + else if val = "dashed" then + {self.}EndPage.PdfPage.SetDash(array(1), 1, 0); end; function BordersRange.DrawLine(border: Border; x1: real; y1: real; x2: real; y2: real); @@ -176,12 +183,12 @@ begin line_width := border.Sz ?: 0.5; {self.}SetDash(border.Val); if border.Color and border.Color <> "auto" then [r, g, b] := DTPColorToolKit.HexToRGB(border.Color); - {self.}Page.PdfPage.SetRGBStroke(r, g, b); - {self.}Page.PdfPage.SetLineWidth(line_width); - {self.}Page.PdfPage.MoveTo(x1, y1); - {self.}Page.PdfPage.LineTo(x2, y2); - {self.}Page.PdfPage.Stroke(); - {self.}Page.PdfPage.SetRGBStroke(0, 0, 0); + {self.}EndPage.PdfPage.SetRGBStroke(r/255, g/255, b/255); + {self.}EndPage.PdfPage.SetLineWidth(line_width); + {self.}EndPage.PdfPage.MoveTo(x1, y1); + {self.}EndPage.PdfPage.LineTo(x2, y2); + {self.}EndPage.PdfPage.Stroke(); + {self.}EndPage.PdfPage.SetRGBStroke(0, 0, 0); end; // TextRange @@ -207,21 +214,21 @@ begin y += sz / 3; sz := sz * 2 / 3; end - {self.}Page.PdfPage.SetRGBFill(r / 255, g / 255, b / 255); - {self.}Page.PdfPage.SetFontAndSize({self.}Font, sz); - {self.}Page.PdfPage.BeginText(); - {self.}Page.PdfPage.TextOut({self.}EndX, y, {self.}Text); - {self.}Page.PdfPage.EndText(); - {self.}Page.PdfPage.SetRGBFill(0, 0, 0); + {self.}EndPage.PdfPage.SetRGBFill(r / 255, g / 255, b / 255); + {self.}EndPage.PdfPage.SetFontAndSize({self.}Font, sz); + {self.}EndPage.PdfPage.BeginText(); + {self.}EndPage.PdfPage.TextOut({self.}EndX, y, {self.}Text); + {self.}EndPage.PdfPage.EndText(); + {self.}EndPage.PdfPage.SetRGBFill(0, 0, 0); if sysparams["_PDF_TEXT_DEBUG_"] then begin - {self.}Page.PdfPage.SetLineWidth(0.1); - {self.}Page.PdfPage.SetRGBStroke(1.0, 0.5, 0.0); - {self.}Page.PdfPage.MoveTo(0, {self.}EndY); - {self.}Page.PdfPage.LineTo(600, {self.}EndY); - {self.}Page.PdfPage.Stroke(); + {self.}EndPage.PdfPage.SetLineWidth(0.1); + {self.}EndPage.PdfPage.SetRGBStroke(1.0, 0.5, 0.0); + {self.}EndPage.PdfPage.MoveTo(0, {self.}EndY); + {self.}EndPage.PdfPage.LineTo(600, {self.}EndY); + {self.}EndPage.PdfPage.Stroke(); end end; @@ -235,11 +242,11 @@ end; function LineRange.Do();override; begin // println("endx = {}, endy = {}, width = {}", EndX, EndY, Width); - {self.}Page.PdfPage.SetLineWidth({self.}LineWidth); - {self.}Page.PdfPage.SetRGBStroke(0, 0, 0); - {self.}Page.PdfPage.MoveTo({self.}EndX, {self.}EndY); - {self.}Page.PdfPage.LineTo({self.}EndX + {self.}Width, {self.}EndY); - {self.}Page.PdfPage.Stroke(); + {self.}EndPage.PdfPage.SetLineWidth({self.}LineWidth); + {self.}EndPage.PdfPage.SetRGBStroke(0, 0, 0); + {self.}EndPage.PdfPage.MoveTo({self.}EndX, {self.}EndY); + {self.}EndPage.PdfPage.LineTo({self.}EndX + {self.}Width, {self.}EndY); + {self.}EndPage.PdfPage.Stroke(); end; end. diff --git a/internal/DTPUtils.tsf b/internal/DTPUtils.tsf index 868ed33..b902a84 100644 --- a/internal/DTPUtils.tsf +++ b/internal/DTPUtils.tsf @@ -27,20 +27,6 @@ private index_: integer; end; -type FldStruct = class -public - function Create(); -public - FldLock: boolean; - MergeFormat: boolean; - Quote: boolean; - Separate: boolean; - PageArabicMergeFormat: boolean; - NumPages: boolean; - ArabicMergeFormat: boolean; - EndFld: boolean; -end; - type FldType = class public function Create(); @@ -52,7 +38,7 @@ public PageRef: boolean; end; -type FldStruct2 = class +type FldStruct = class public function Create(); @@ -60,6 +46,7 @@ public Type: FldType; Arabic: boolean; MergeFormat: boolean; + Status: integer; // 0: begin 1: separate 2: end end; type TrProperty = class @@ -155,19 +142,6 @@ begin return index_ = 0; end; -// FldStruct -function FldStruct.Create(); -begin - FldLock := false; - MergeFormat := false; - Quote := false; - Separate := false; - PageArabicMergeFormat := false; - NumPages := false; - ArabicMergeFormat := false; - EndFld := false; -end; - // FldType function FldType.Create(); begin @@ -178,11 +152,12 @@ begin end; // FldStruct -function FldStruct2.Create(); +function FldStruct.Create(); begin {self.}Type := new FldType(); {self.}Arabic := false; {self.}MergeFormat := false; + {self.}Status := 0; end; // TrProperty