unit DTPAdvancedRanges; interface uses DTPPrimitiveRanges, DTPUtils, DocxML, TSPdfEnumerations; type AdvancedRange = class(BasicRange) public function Create(); function Do();virtual; function Calc(): boolean;virtual; function Offset(x: real; y: real; page: Page);virtual; public LowerBound: real; StartPage: Page; StartX: real; StartY: real; end; type TocRange = class(AdvancedRange) public function Create(); function CalculateRect(); function LinkAnnot(dst: PdfDestination); function AddPageNumber(pg: Page); public TextRange: TextRange; BaseLine: real; // 目录...基线 [weakref]StartRange: AdvancedRange; [weakref]EndRange: AdvancedRange; private rect_: array of real; end; type HdrRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr); function Do();override; function Calc(): boolean;override; function Offset(x: real; y: real; page: Page);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(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr); function Do();override; function Calc(): boolean;override; function Offset(x: real; y: real; page: Page);override; function ProcessRealtimeArray(); private function Traverse(obj: OpenXmlElement); private [weakref]docx_to_pdf_: TSDocxToPdf; ftr_: Ftr; range_array_: array of Range; end; type PLineRange = class(AdvancedRange) public function Create(); function Do();override; function Offset(x: real; y: real; page: Page);override; function CanFitInLine(range: BasicRange): boolean; function AddRange(range: BasicRange); function Align(val: string); function AlignRightBound(right_bound: real); function RangeArr(): array of BasicRange; public TextMaxSize: real; // 行的文字最大size LineSpace: real; // 行间距 Index: integer; private range_array_: array of BasicRange; end; type PRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; p: P); function Init(); function Do();override; function Calc(): boolean;override; function Offset(x: real; y: real; page: Page);override; function DeterminePosition(); function ProcessRealtimeArray(); function IsFirstLineOnNextPage(): boolean; function PLineRanges(): array of PLineRange; property P read p_; private function RangesToLines(); function BasicRangesToPLineRange(); function UpdateTextRangeWidth(); function NewPLineRange(): PLineRange; function AddPLineRange(pline_range: PLineRange); 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_: PPr); 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 SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPr; 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 RAlternateContent(r: R); function RObject(r: R); function FldSimple(fld_simple: fldSimple); function Hyperlink(hyperlink: Hyperlink); function OMathPara(o_math_para: OMathPara); function OMath(o_math: OMath); private [weakref]docx_to_pdf_: TSDocxToPdf; p_: P; ppr_: PPr; 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 TcRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty); function Do();override; function Calc(): boolean;override; function Offset(x: real; y: real; page: Page);override; function DoBordersRangeFill(); 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; SpacingBottom: real; private function GetLowerBound(pg: Page): real; function SetBorderRange(range: BordersRange); private [weakref]docx_to_pdf_: TSDocxToPdf; tc_: Tc; trp_: TrProperty; tc_pr_: TcPr; content_next_page_: boolean; range_array_: array of BasicRange; region_array_: array of Region; top_: boolean; end; type TblRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; tbl: Tbl); function Do();override; function Calc(): boolean;override; function Offset(x: real; y: real; page: Page);override; property TblPr read tbl_pr_; property Rows read rows_; property Cols read cols_; private function CreateTableMatrix(grid_cols: array of GridCol; trs: array of Tr); 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); function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); function SetTcTcPr(var tc: Tc; type: string); function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string; type: string); private [weakref]docx_to_pdf_: TSDocxToPdf; tbl_: Tbl; tbl_pr_: TblPr; grid_cols_: array of GridCol; rows_: integer; cols_: integer; tc_range_matrix_: array of TcRange; tr_pr_array_: array of TrProperty; end; type OMathParaRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);override; public BaseHeight: real; // 基准高度 private [weakref]docx_to_pdf_: TSDocxToPdf; o_math_para_: OMathPara; o_math_range_: OMathRange; end; type OMathRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);override; function SetMathSize(); public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 SingleLine: boolean; // 是否单行公式 private [weakref]docx_to_pdf_: TSDocxToPdf; element_: OMath; range_array_: array of BasicRange; end; type OMathRRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; r: R); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; r_: R; range_array_: array of BasicRange; end; type OMathFRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; f: F); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; f_: F; range_array_: array of BasicRange; end; type OMathNaryRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; nary: Nary); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; nary_: Nary; range_array_: array of BasicRange; end; type OMathRadRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; rad: Rad); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; rad_: rad; range_array_: array of BasicRange; end; type OMathSSupRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; s_sup: SSup); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; s_sup_: SSup; range_array_: array of BasicRange; end; type OMathSSubRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; s_sub: SSub); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; s_sub_: SSub; range_array_: array of BasicRange; end; type OMathDRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; d: D); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; d_: D; range_array_: array of BasicRange; end; type OMathFuncRange = class(AdvancedRange) public function Create(docx_to_pdf: TSDocxToPdf; func: Func); function Do();override; function Calc();override; function Offset(x: real; y: real; page: Page);override; function AdjustOffset(x: real; y: real);overload; public BaseHeight: real; // 基准高度 BaseSz: real; // 基准字体大小 private [weakref]docx_to_pdf_: TSDocxToPdf; func_: Func; range_array_: array of BasicRange; end; implementation function AdvancedRange.Create(); begin class(BasicRange).Create(); {self.}LowerBound := 0.0; {self.}StartPage := nil; {self.}StartX := 0.0; {self.}StartY := 0.0; range_array_ := array(); end; function AdvancedRange.Offset(x: real; y: real; page: Page); begin {self.}StartX := {self.}XOffset + x; {self.}StartY := {self.}YOffset + y; {self.}StartPage := page; {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; {self.}EndPage := {self.}StartPage; end; function TocRange.Create(); begin class(AdvancedRange).Create(); {self.}TextRange := nil; {self.}BaseLine := 0; end; function TocRange.LinkAnnot(dst: PdfDestination); begin annot := {self.}EndPage.PdfPage.CreateLinkAnnot(rect_, dst); annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT); annot.LinkAnnotSetBorderStyle(0, 0, 0); end; function TocRange.AddPageNumber(pg: Page); begin 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 TocRange.CalculateRect(); begin pline_range := {self.}Parent; {self.}EndPage := pline_range.EndPage; if {self.}StartRange then begin rect_ := array({self.}StartRange.EndX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY); end else begin rect_ := array(pline_range.StartX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY); end 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; function HdrRange.Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; hdr_ := hdr; range_array_ := array(); end; function HdrRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function HdrRange.Calc(): boolean;override; begin {self.}DynamicHeight := 0; return {self.}Traverse(hdr_); end; function HdrRange.Offset(x: real; y: real; page: Page);virtual; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do begin range.LowerBound := {self.}LowerBound; range.Offset({self.}EndX, {self,}EndY, {self.}EndPage); {self.}EndY := range.EndY; end end; function HdrRange.Traverse(obj: OpenXmlElement); begin flag := true; elements := obj.Elements(); for _,element in elements do begin 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; {self.}DynamicHeight += range.DynamicHeight; end else if element.LocalName = "sdt" then begin {self.}Traverse(element.SdtContent); end end return flag; end; function HdrRange.ProcessRealtimeArray(); begin for _,range in range_array_ do range.ProcessRealtimeArray(); end; function FtrRange.Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; ftr_ := ftr; range_array_ := array(); end; function FtrRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function FtrRange.Calc(); begin {self.}DynamicHeight := 0; return {self.}Traverse(ftr_); end; function FtrRange.Offset(x: real; y: real; page: Page);virtual; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do begin range.LowerBound := {self.}LowerBound; range.Offset({self.}StartX, {self.}EndY, {self.}EndPage); {self.}EndY := range.EndY; end end; function FtrRange.Traverse(obj: OpenXmlElement); begin flag := true; elements := obj.Elements(); for _,element in elements do begin 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; {self.}DynamicHeight += range.DynamicHeight; end else if element.LocalName = "sdt" then begin flag := {self.}Traverse(element.SdtContent); end end return flag; end; function FtrRange.ProcessRealtimeArray(); begin for _,range in range_array_ do begin range.ProcessRealtimeArray(); end end; function PLineRange.Create(); begin class(AdvancedRange).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 PLineRange.Offset(x: real; y: real; page: Page);override; begin {self.}StartX := x; {self.}StartY := y; {self.}StartPage := page; {self.}EndX := x + {self.}XOffset; {self.}EndY := y - {self.}DynamicHeight; // 没用上YOffset {self.}EndPage := page; offset := {self.}LineSpace >= {self.}DynamicHeight ? ({self.}LineSpace - {self.}TextMaxSize) / 2 + {self.}TextMaxSize - {self.}TextMaxSize / 5 : {self.}DynamicHeight; y_offset := {self.}StartY - offset; for _,range in range_array_ do begin if range is class(OMathRange) then // 公式不是y值,需要处理公式 range.Offset(x, y, page); // range.Offset(0, 841.9, page); else range.Offset(x, y_offset, page); end end; function PLineRange.CanFitInLine(range: BasicRange): boolean; begin if range.Width > {self.}Width then return false; // 单一宽度比行宽还宽 if {self.}XOffset + 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; // 中文标点不换行 if range is class(OMathParaRange) then return false; // 公式不换行 return true; end; function PLineRange.AddRange(range: BasicRange); begin range_array_[length(range_array_)] := range; end; function PLineRange.Align(val: string); begin offset := 0; last := range_array_[length(range_array_)-1]; case val of "center": offset := ({self.}Width + {self.}StartX - {self.}EndX) / 2; "right": offset := {self.}Width + {self.}StartX - {self.}EndX; end; if offset <= 0 then return; for _,range in range_array_ do range.EndX += offset; end; function PLineRange.AlignRightBound(right_bound: real); begin last := range_array_[length(range_array_)-1]; diff := right_bound - (last.EndX + last.Width); if diff > 1e-6 then begin avg := diff / (length(range_array_) - 1); for i:=1 to length(range_array_)-1 do range_array_[i].EndX += avg * i; end end; function PLineRange.RangeArr(): array of BasicRange; begin return range_array_; end; function PRange.Create(docx_to_pdf: TSDocxToPdf; p: P); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; p_ := p; end; function PRange.Init(); begin br_type_ := ""; body_range_array_ := array(); bullet_range_array_ := array(); line_range_array_ := array(); drawing_anchor_array_ := array(); alternate_content_array_ := array(); bookmark_hash_ := array(); hyperlink_hash_ := array(); footnote_reference_hash_ := array(); realtime_page_array_ := array(); realtime_numpages_array_ := array(); // 根据段落的间距确定新的坐标 ppr := ppr_; 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 PRange.Do();override; begin for _,line_range in line_range_array_ do line_range.Do(); // 段落边框 if length(line_range_array_) > 0 and ppr_.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]); // 检查是否有hyperlink要链接 for anchor,_ in hyperlink_hash_ do docx_to_pdf_.Toc.LinkToToc(anchor); end; function PRange.Calc(): boolean;override; begin // ppr.rpr是无效的,应该以ppr.pStyle为准 {self.}SetPPPr(p_); if not p_.PPr.RPr.Sz.Val then p_.PPr.RPr.Sz.Val := docx_to_pdf_.Font.GetDefaultSz(); ppr_ := p_.PPr; {self.}Init(); {self.}SetLvlText(); bookmark_name := ""; elements := p_.Elements(); fld_stack := new DTPUtils.Stack(); for _, element in elements do begin 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 {self.}SetRRPr(element, ppr_); 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.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.Anchor then {self.}Hyperlink(element); end else if element.LocalName = "fldSimple" then begin {self.}FldSimple(element); end else if element.LocalName = "hyperlink" then begin {self.}Hyperlink(element); end else if element.LocalName = "oMathPara" then begin // 公式单独成行 {self.}OMathPara(element); end else if element.LocalName = "oMath" then begin // 公式嵌入段落 {self.}OMath(element); end end {self.}RangesToLines(); // 需要实时计算总页码的情况是需要最后处理的 return length(realtime_numpages_array_) ? false : true; end; function PRange.Offset(x: real; y: real; page: Page);override; begin // println("PRange::x = {}, y = {}, page = {}", x, y, page); class(AdvancedRange).Offset(x, y, page); right_bound_ := {self.}StartX + {self.}Width; // 检查是否需要实时计算页码 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.RBr(r: R); begin br_type_ := r.Br.Type; end; function PRange.RFootnoteReference(r: R); begin return; docx_to_pdf_.Note.AddFootnoteId(r.FootnoteReference.Id); 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.IsApplied, rpr.I.IsApplied); 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 PRange.RDrawing(r: R); begin if r.Drawing.Anchor then begin 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 := 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; image_range.RPr := r.RPr; body_range_array_[length(body_range_array_)] := image_range; end end; function PRange.RObject(r: R); 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 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]); end image_range := new ImageRange(); image_range.Image := image; image_range.Type := image_type; image_range.Width := w; image_range.DynamicHeight := h; image_range.RPr := r.RPr; body_range_array_[length(body_range_array_)] := image_range; end; 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 rpr := r.RPr; if fld_struct.Type.Page then begin 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.IsApplied, rpr.I.IsApplied); 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 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.IsApplied, rpr.I.IsApplied); 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 else if fld_struct.Type.Quote then begin if r.Drawing then {self.}RDrawing(r); 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.FldStruct(); for _,field in fields do begin fld := trim(field); if fld = "NUMPAGES" then fld_struct.Type.NumPages := true; else if fld = "Arabic" then fld_struct.Arabic := true; else if fld = "MERGEFORMAT" then fld_struct.MergeFormat := true; end end r := fld_simple.Rs(0); {self.}SetRRPr(r, ppr_); if fld_struct.Type.NumPages then begin if fld_struct.Arabic then begin rpr := 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.IsApplied, rpr.I.IsApplied); 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 PRange.Hyperlink(hyperlink: Hyperlink); begin i := length(body_range_array_); rs := hyperlink.Rs(); fld_stack := new DTPUtils.Stack(); for _,r in rs do begin if r.FldChar.FldCharType = "begin" then begin fld_struct := new DTPUtils.FldStruct(); fld_stack.Push(fld_struct); end else if r.FldChar.FldCharType = "end" then begin fld_stack.Pop(); end else if r.FldChar.FldCharType = "separate" then begin separate := true; end else if separate then begin docx_to_pdf_.Toc.AddDocxPage(hyperlink.Anchor, r); rpr := 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.IsApplied, rpr.I.IsApplied); text := new TextRange(); text.RPr := rpr; text.Font := font_obj; text.DynamicHeight := rpr.Sz.Val; text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度 end if not fld_stack.Empty() then continue; if r.T then begin {self.}SetRRPr(r, ppr_); r.RPr.Color.Val := nil; {self.}RT(r); end end arr := array(); while i < length(body_range_array_) do begin arr[length(arr)] := body_range_array_[i]; i++; end hyperlink_hash_[hyperlink.Anchor] := array(text, arr); end; function PRange.OMathPara(o_math_para: OMathPara); begin math_para_range := new OMathParaRange(docx_to_pdf_, o_math_para); math_para_range.Width := 0; math_para_range.Parent := self; math_para_range.Calc(); body_range_array_[length(body_range_array_)] := math_para_range; end; function PRange.OMath(o_math: OMath); begin math_range := new OMathRange(docx_to_pdf_, o_math); math_range.Width := 0; math_range.Parent := self; math_range.XOffset := 0; math_range.YOffset := 0; math_range.SetMathSize(); math_range.Calc(); math_range.AdjustOffset(0, -math_range.DynamicHeight); body_range_array_[length(body_range_array_)] := math_range; end; function PRange.HyperlinkToToc(); begin 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 PRange.PLineRanges(): array of PLineRange; begin return line_range_array_; end; function PRange.RangesToLines(); begin {self.}UpdateTextRangeWidth(); {self.}BasicRangesToPLineRange(); {self.}HyperlinkToToc(); end; function PRange.BasicRangesToPLineRange(); begin line_range_array_ := array(); {self.}DynamicHeight := 0; {self.}DynamicHeight += ppr_.Spacing.Before; // 段落的x偏移是缩进 {self.}XOffset := ppr_.Ind.LeftChars ? ppr_.Ind.LeftChars * ppr_.RPr.Sz.Val : ppr_.Ind.Left; {self.}YOffset := 0; pline_range := {self.}NewPLineRange(); pline_range.XOffset := ppr_.Ind.FirstLine; // 首行有间距.用offsetx作为位置计算 i := 0; anchor := nil; while i < length(body_range_array_) do begin range := body_range_array_[i]; if_newline := pline_range.CanFitInLine(range); if if_newline then begin {self.}AddPLineRange(pline_range); {self.}DynamicHeight += pline_range.DynamicHeight; pline_range := {self.}NewPLineRange(); 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.AdjustOffset(pline_range.XOffset, 0); range.XOffset := pline_range.XOffset; range.Parent := pline_range; pline_range.AddRange(range); pline_range.XOffset += range.Width; i++; if i = length(body_range_array_) then begin {self.}AddPLineRange(pline_range); {self.}DynamicHeight += pline_range.DynamicHeight; end end if length(line_range_array_) = 0 then begin line_space := {self.}GetParagraphLineSpace(ppr_.RPr.Sz.Val, ppr_.Spacing.Line, ppr_.Spacing.LineRule); {self.}DynamicHeight += line_space; end {self.}DynamicHeight += ppr_.Spacing.After; // println("line_range_array_ = {}", line_range_array_); end; function PRange.NewPLineRange(): PLineRange; begin pline_range := new PLineRange(); pline_range.Parent := self; pline_range.Width := {self.}Width; return pline_range; end; function PRange.AddPLineRange(pline_range: PLineRange); begin pline_range.LineSpace := {self.}GetParagraphLineSpace(pline_range.TextMaxSize, ppr_.Spacing.Line, ppr_.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; function PRange.UpdateTextRangeWidth(); begin if length(realtime_page_array_) > 0 or length(realtime_numpages_array_) > 0 then return; i := 0; head_range := nil; tail_range := nil; while i < length(body_range_array_)-1 do begin if not (head_range is class(TextRange)) then begin i++; head_range := body_range_array_[i]; end tail_range := body_range_array_[i]; if not (tail_range is class(TextRange)) then begin head_range := body_range_array_[i+1]; i += 2; continue; end if not (tail_range is class(TextRange)) then begin head_range := tail_range; i++; continue; end if head_range then begin if head_range.Type in array(1, 2) and tail_range.Type = 3 then head_range.Width += head_range.Width / 2; else if head_range.Type = 3 and tail_range.Type in array(1, 2) then head_range.Width += tail_range.Width / 2; end head_range := tail_range; i++; end end; function PRange.DeterminePosition(); begin // 检查是否有分页,分一栏 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; // 段前距只有不换页情况才计算 if not {self.}CheckAndAddPage({self.}EndY, ppr_.Spacing.Before) then {self.}EndY -= ppr_.Spacing.Before; // 检查是否有段前分页 if ppr_.PageBreakBefore then {self.}CheckAndAddPage({self.}LowerBound, 1); for _,line_range in line_range_array_ do begin y := {self.}EndY; if {self.}CheckAndAddPage(y, line_range.DynamicHeight) then // 行不够时候调整上一页LowerBound docx_to_pdf_.PageManager[{self.}EndPage.Index - 1].LowerBound := y; line_range.Offset({self.}EndX, {self.}EndY, {self.}EndPage); line_range.Align(ppr_.Jc.Val); {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_.RPr.Sz.Val, ppr_.Spacing.Line, ppr_.Spacing.LineRule); {self.}EndY -= line_space; end {self.}DoDrawingAnchor(); {self.}DoAlternateContentAnchor(); {self.}DoToc(); {self.}EndY -= ppr_.Spacing.After; 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 id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; [image_type, image] := {self.}GetImageData(id); if not image then return; xfrm := anchor.Graphic.GraphicData.Pic.SpPr.Xfrm; position_h := anchor.PositionH; position_v := 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 PRange.DoAlternateContentAnchor(); begin for _,anchor in alternate_content_array_ do begin wsp := anchor.Graphic.GraphicData.Wsp; [x, y] := {self.}GetXYCordinates(); xfrm := wsp.SpPr.Xfrm; position_h := anchor.PositionH; position_v := 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 := wsp.BodyPr; x += body_pr.LIns; w -= (body_pr.LIns + body_pr.RIns); ps := wsp.Txbx.TxbxContent.Ps(); for _,p in ps do begin range := new PRange(docx_to_pdf_, p); range.Width := w; range.Parent := self; range.LowerBound := 0; fg := range.Calc(); if not fg then flag := fg; range.Offset(x, y, {self.}EndPage); range.Do(); y := range.EndY; end end end; 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.AlignRightBound(); begin len := length(line_range_array_); if len = 1 then return; for i:=0 to len-2 do line_range_array_[i].AlignRightBound(right_bound_); end; function PRange.CheckAndAddPage(y: real; offset: real): boolean; begin lb := {self.}LowerBound; if lb > 0 then lb := lb > {self.}EndPage.LowerBound ? lb : {self.}EndPage.LowerBound; if y - offset < lb then begin {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 PRange.RT(r: R; anchor: string); begin text := r.T.Text; if text then {self.}SplitTextToTextRange(body_range_array_, text, r.rpr, anchor); end; function PRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPr; 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(); 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.IsApplied, rpr.I.IsApplied); // font_name := rpr.RFonts.Ascii ?: rpr.RFonts.EastAsia; // font_obj := docx_to_pdf_.Font.GetAsciiFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied); 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.IsApplied, rpr.I.IsApplied); 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.IsApplied, rpr.I.IsApplied); 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.IsApplied, rpr.I.IsApplied); end end 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 := pdf_page.TextWidth(word); text_range.DynamicHeight := rpr.Sz.Val; pos += num; range_arr[length(range_arr)] := text_range; if ifarray(bookmark_hash_[anchor]) then bookmark_hash_[anchor] union= array(text_range); end end; function PRange.SetPPPr(var p: P); begin if not p.PPr then begin styles := docx_to_pdf_.DocxComponents.GetStyles(); p.PPr := styles.DocDefaults.PPrDefault.PPr; end else begin if p.PPr.PStyle.Val then {self.}SetPPrByStyleId(p.PPr, p.PPr.PStyle.Val); else if {self.}Parent is class(TcRange) then {self.}SetPPrByStyleId(p.PPr, {self.}Parent.GetTblStyleId()); end end; function PRange.SetPPrByStyleId(var ppr: PPr; style_id: string); begin styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin ppr.SetFallback(style.PPr); based_on := style.BasedOn.Val; {self.}SetPPrByStyleId(ifnil(style.PPr) ? ppr : style.PPr, based_on); end end; function PRange.SetRRPr(var r: R; ppr_: PPr); begin if ifnil(r.RPr) then begin styles := docx_to_pdf_.DocxComponents.GetStyles(); r.RPr := styles.DocDefaults.RPrDefault.RPr; end else begin if r.RPr.RStyle.Val then {self.}SetRPrByStyleId(r.RPr, r.RPr.RStyle.Val); else if ppr_.PStyle.Val then {self.}SetRPrByStyleId(r.RPr, ppr_.PStyle.Val); else if {self.}Parent is class(TcRange) then {self.}SetRPrByTblStyleId(r.RPr, {self.}Parent.GetTblStyleId()); end end; function PRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string); begin styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin pr_type := {self.}Parent.GetPrType(); tbl_style_pr := docx_to_pdf_.DocxComponents.GetTblStylePrByType(style_id, pr_type); rpr.SetFallback(tbl_style_pr.RPr); {self.}SetRPrByTblStyleId(ifnil(tbl_style_pr.RPr) ? rpr : tbl_style_pr.RPr, style.BasedOn.Val); end end; function PRange.SetRPrByStyleId(var rpr: RPr; style_id: string); begin styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin rpr.SetFallback(style.RPr); based_on := style.BasedOn.Val; {self.}SetRPrByStyleId(ifnil(style.RPr) ? rpr : style.RPr, based_on); end end; function PRange.SetLvlText(); begin 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_); // {self.}SplitTextToTextRange(bullet_range_array_, lvl_text, rpr); {self.}SplitTextToTextRange(body_range_array_, lvl_text, lvl.RPr); end; function PRange.GetXYCordinates(): array of real; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); if xml_file = "document.xml" then begin [x, y] := {self.}EndPage.OriginalTextCoordinates(); end else begin x := {self.}EndPage.SectPr.PgMar.Left; if ansiContainsStr(xml_file, "footer") then y := {self.}EndPage.SectPr.PgMar.Bottom; else if ansiContainsStr(xml_file, "header") then y := {self.}EndPage.SectPr.PgSz.H - {self.}EndPage.SectPr.PgMar.Header; end return array(x, y); end; function PRange.GetImageData(id: string): PdfImage; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); 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_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); image := nil; image_type := GetImageFileType(data); case image_type of "png": image := docx_to_pdf_.PdfFile().LoadPngImageFromFile("", image_path); "jpg": image := docx_to_pdf_.PdfFile().LoadJpegImageFromFile("", image_path); "emf": image := docx_to_pdf_.PdfFile().LoadEmfImageFromFile("", image_path); "wmf": image := docx_to_pdf_.PdfFile().LoadWmfImageFromFile("", image_path); end; fileDelete("", image_path); return array(image_type, image); end; function PRange.GetImageFileType(data: binary): string; begin stream := new TMemoryStream(); size := length(data); stream.Write(data[0:size-1], size); def := array( ('name': 'png', 'position': 0, 'value': array(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)), ('name': 'jpg', 'position': 0, 'value': array(0xFF, 0xD8)), ('name': 'emf', 'position': 40, 'value': array(0x20, 0x45, 0x4d, 0x46)), ('name': 'wmf', 'position': 0, 'value': array(0xd7, 0xcd, 0xc6, 0x9a)), ); for i:=0 to length(def)-1 do begin value := def[i]['value']; stream.Seek(def[i]['position']); for j:=0 to length(value)-1 do begin r := 0; stream.Read(r, 1); if r <> value[j] then break; if j = length(value)-1 then return def[i]['name']; end end return ''; end; 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 begin lines := line / 240; return size + lines; end else begin lines := roundto(line / 240, -1); multi := ceil(size / docx_to_pdf_.CurrentSect.BaseSize); if (not ifnil(ppr_.SnapToGrid) and not ppr_.SnapToGrid) or ((ifnil(ppr_.SnapToGrid) or ppr_.SnapToGrid) and lines > multi) then multi *= lines; return docx_to_pdf_.CurrentSect.SectPr.DocGrid.LinePitch * multi; end end; function TcRange.Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; tc_ := tc; trp_ := trp; tc_pr_ := tc_.TcPr; content_next_page_ := false; top_ := false; end; function TcRange.Do(); begin 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(): boolean;override; begin range_array_ := array(); {self.}DynamicHeight := 0; 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; {self.}DynamicHeight += range.DynamicHeight; end end {self.}DynamicHeight += {self.}Parent.TblPr.TblCellMar.Bottom.W + {self.}Parent.TblPr.TblCellMar.Top.W; // 同步行高 if not tc_.TcPr.VMerge.IsApplied and {self.}DynamicHeight > trp_.Height then trp_.Height := {self.}DynamicHeight; return true; end; function TcRange.Offset(x: real; y: real; page: Page);override; begin // println("TcRange::x = {}, y = {}, page = {}", x, y, page); class(AdvancedRange).Offset(x, y, page); 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.LowerBound := {self.}LowerBound; range.Offset(cell_x, cell_y, {self.}EndPage); if _ = 0 and range.IsFirstLineOnNextPage() then begin content_next_page_ := true; break; end cell_y := range.EndY; {self.}EndPage := range.EndPage; end {self.}EndY := cell_y - {self.}Parent.TblPr.TblCellMar.Bottom.W; 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_; {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]; if ifnil(pg) then // 受间距影响,实际上文字没有进入下一页 begin region.RangeArr union= range_array_; {self.}EndY := {self.}StartY - page_remaining_height; return; end 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_; 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_; 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(range.StartX, range.StartY - offset, range.StartPage); 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_.TcBorders.Top then tc_pr_.TcBorders.Top.SetFallback(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_.TcBorders.Bottom then tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Right then tc_pr_.TcBorders.Right.SetFallback(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_.TcBorders.Bottom then tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Bottom then tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Right then tc_pr_.TcBorders.Right.SetFallback(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_.TcBorders.Bottom then tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Bottom then tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Right then tc_pr_.TcBorders.Right.SetFallback(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_.TcBorders.Left then tc_pr_.TcBorders.Left.SetFallback(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_.TcBorders.Right then tc_pr_.TcBorders.Right.SetFallback(tbl_pr.TblBorders.Right); range.Right := true; end end end else begin range.Left := false; range.Top := false; range.Right := false; range.Bottom := false; end if top_ and ifObj(tbl_pr.TblBorders) 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(AdvancedRange).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_:= tbl_.TblPr; tbl_grid_:= tbl_.TblGrid; grid_cols_ := tbl_grid_.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 GridCol; trs: array of Tr); begin for i,tr in trs do begin {self.}SetTrTrPr(tr); tr_pr := 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 if i = 0 then {self.}SetTcTcPr(tc, "firstRow"); else if i = length(trs)-1 then {self.}SetTcTcPr(tc, "lastRow"); else if (i + 1) % 2 = 0 then {self.}SetTcTcPr(tc, "band1Horz"); else {self.}SetTcTcPr(tc, "band2Horz"); grid_span := tc.TcPr.GridSpan; if tc.TcPr.VMerge.IsApplied and tc.TcPr.VMerge.Val <> "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.XOffset := 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"); return true; end; function TblRange.Offset(x: real; y: real; page: Page);override; begin // println("TblRange::x = {}, y = {}, page = {}", x, y, page); {self.}StartX := x + {self.}XOffset; {self.}StartY := y + {self.}YOffset; // table的offset实际都为0 {self.}StartPage := page; {self.}ResetCoordinates(tbl_pr_, 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 j := 0; tc_y := {self.}EndY; top := recompute_flag; recompute_flag := false; while j < cols_ do begin // if i = 13 then // println(">>>>>>>>>>>>>>>"); range := tc_range_matrix_[i][j]; if not ifObj(range) then begin j++; continue; end if top then range.SetTop(); range.Calc(); range.LowerBound := {self.}LowerBound; range.Offset({self.}EndX, {self.}tc_y, {self.}EndPage); // println("i = {}, j = {}, height = {}, sy = {}, LowerBound = {}", i, j, range.DynamicHeight, range.StartY, range.LowerBound); 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.IsApplied 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.IsApplied 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.SetTblTblPr(var tbl: Tbl); begin if ifnil(tbl.TblPr) then tbl.TblPr := new TblPr(); {self.}SetTblPrByStyleId(tbl.TblPr, tbl.TblPr.TblStyle.Val); 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 tbl_pr.SetFallback(style.TblPr); based_on := style.BasedOn.Val; {self.}SetTblPrByStyleId(ifnil(style.TblPr) ? tbl_pr : style.TblPr, based_on); end end; function TblRange.SetTrTrPr(var tr: Tr); begin if ifnil(tr.TrPr) then tr.TrPr := new TrPr(); {self.}SetTrPrByStyleId(tr.TrPr, tbl_pr_.TblStyle.Val); end; function TblRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); begin styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin tr_pr.SetFallback(style.TrPr); based_on := style.BasedOn.Val; {self.}SetTrPrByStyleId(ifnil(style.TrPr) ? tr_pr : style.TrPr, based_on); end end; function TblRange.SetTcTcPr(var tc: Tc; type: string); begin if ifnil(tc.TcPr) then tc.TcPr := new TcPr(); {self.}SetTcPrByStyleId(tc.TcPr, tbl_pr_.TblStyle.Val, type); end; function TblRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string; type: string); begin if type then begin style := docx_to_pdf_.DocxComponents.GetTblStylePrByType(style_id, type); if ifObj(style) then tc_pr.SetFallback(style.TcPr); end else begin styles := docx_to_pdf_.DocxComponents.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin tc_pr.SetFallback(style.TcPr); based_on := style.BasedOn.Val; {self.}SetTcPrByStyleId(ifnil(style.TcPr) ? tc_pr : style.TcPr, based_on); end end end; function OMathParaRange.Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; o_math_para_ := o_math_para; end; function OMathParaRange.Do();override; begin o_math_range_.Do(); end; function OMathParaRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); o_math_range_.Offset({self.}EndX, {self.}EndY, {self.}EndPage); end; function OMathParaRange.Calc();override; begin o_math_range_ := new OMathRange(docx_to_pdf_, o_math_para_.OMath); o_math_range_.Width := {self.}Width; o_math_range_.Parent := self; o_math_range_.XOffset := 0; o_math_range_.YOffset := 0; o_math_range_.SingleLine := true; o_math_range_.SetMathSize(); o_math_range_.Calc(); o_math_range_.AdjustOffset(0, -o_math_range_.DynamicHeight); {self.}Width := o_math_range_.Width; {self.}DynamicHeight := o_math_range_.DynamicHeight; end; function OMathParaRange.AdjustOffset(x: real; y: real);override; begin class(BasicRange).AdjustOffset(x, y); o_math_range_.AdjustOffset(x, y); end; function OMathRange.Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; element_ := element; {self.}BaseHeight := 0; {self.}BaseSz := 0; {self.}SingleLine := false; end; function OMathRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathRange.AdjustOffset(x: real; y: real);overload; begin class(BasicRange).AdjustOffset(x, y); for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathRange.Calc();override; begin range_array_ := array(); x := {self.}XOffset; y := {self.}YOffset; elements := element_.Elements(); up_h := 0; for _,element in elements do begin range := nil; if element.LocalName = "r" then begin range := new OMathRRange(docx_to_pdf_, element); range.BaseSz := {self.}BaseSz; end else if element.LocalName = "f" then begin range := new OMathFRange(docx_to_pdf_, element); range.BaseSz := {self.}SingleLine ? {self.}BaseSz : 0.7 * {self.}BaseSz; end else if element.LocalName = "rad" then begin range := new OMathRadRange(docx_to_pdf_, element); range.BaseSz := {self.}BaseSz; end else if element.LocalName = "nary" then begin range := new OMathNaryRange(docx_to_pdf_, element); range.BaseSz := {self.}BaseSz; end else if element.LocalName = "sSup" then begin range := new OMathSSupRange(docx_to_pdf_, element); range.BaseSz := {self.}BaseSz; end else if element.LocalName = "sSub" then begin range := new OMathSSubRange(docx_to_pdf_, element); range.BaseSz := {self.}BaseSz; end else if element.LocalName = "d" then begin range := new OMathDRange(docx_to_pdf_, element); range.BaseSz := {self.}BaseSz; end else if element.LocalName = "func" then begin range := new OMathFuncRange(docx_to_pdf_, element); range.BaseSz := {self.}BaseSz; end if not ifObj(range) then begin echo format("Math do not support <%s>\n", element.ElementName); continue; end range.Parent := self; range.XOffset := x; range.YOffset := y; range.Calc(); x += range.Width; // 下一个元素偏移位置 {self.}Width += range.Width; if range.BaseHeight > {self.}BaseHeight then {self.}BaseHeight := range.BaseHeight; if range.DynamicHeight - range.BaseHeight > up_h then up_h := range.DynamicHeight - range.BaseHeight; // if range.DynamicHeight > {self.}DynamicHeight then // {self.}DynamicHeight := range.DynamicHeight; range_array_[length(range_array_)] := range; end {self.}DynamicHeight := {self.}BaseHeight + up_h; for _,range in range_array_ do range.AdjustOffset(0, {self.}BaseHeight - range.BaseHeight); end; function OMathRange.SetMathSize(); begin elements := element_.Elements(); element := elements[0]; rpr := nil; if element.LocalName = "r" then rpr := element.RPr("w"); else if element.LocalName = "f" then rpr := element.FPr.CtrlPr.RPr("w"); else if element.LocalName = "nary" then rpr := element.NaryPr.CtrlPr.RPr("w"); else if element.LocalName = "rad" then rpr := element.RadPr.CtrlPr.RPr("w"); else if element.LocalName = "sSup" then rpr := element.SSupPr.CtrlPr.RPr("w"); styles := docx_to_pdf_.DocxComponents.GetStyles(); default_rpr := styles.DocDefaults.RPrDefault.RPr; default_rpr.SetFallback(rpr); {self.}BaseSz := strtofloat(default_rpr.Sz.Val) / 2; end; function OMathFRange.Create(docx_to_pdf: TSDocxToPdf; f: F); begin class(AdvancedRange).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.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathFRange.Calc();override; begin x := {self.}XOffset; y := {self.}YOffset; // 分子分母单独计算高度,最后再合并 // 分母 den_range := new OMathRange(docx_to_pdf_, f_.Den); den_range.BaseSz := {self.}BaseSz; den_range.XOffset := x; den_range.YOffset := y; den_range.Calc(); // 需要得到高宽 // 分子 num_range := new OMathRange(docx_to_pdf_, f_.Num); num_range.BaseSz := {self.}BaseSz; num_range.XOffset := x; num_range.YOffset := y; num_range.Calc(); // 需要得到高宽 max_len := max(den_range.Width, num_range.Width); xo := (max_len - num_range.Width) / 2; num_range.AdjustOffset(xo, den_range.DynamicHeight + 0.3 * {self.}BaseSz); xo := (max_len - den_range.Width) / 2; den_Range.AdjustOffset(xo, 0); // 线 line_range := new LineRange(); line_range.XOffset := {self.}XOffset; line_range.YOffset := y + den_range.DynamicHeight; line_range.Width := max_len; line_range.LineWidth := 0.04 * {self.}BaseSz; {self.}DynamicHeight := num_range.DynamicHeight + den_range.DynamicHeight + 0.3 * {self.}BaseSz; {self.}Width := line_range.Width; range_array_ union= array(den_range, num_range, line_range); // 分式的基准在line处 {self.}BaseHeight := den_range.DynamicHeight; end; function OMathFRange.AdjustOffset(x: real; y: real);override; begin class(BasicRange).AdjustOffset(x, y); for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathRRange.Create(docx_to_pdf: TSDocxToPdf; r: R); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; r_ := r; range_array_ := array(); end; function OMathRRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathRRange.Offset(x: real; y: real; page: Page); begin class(AdvancedRange).Offset(x, y, page); {self.}DynamicHeight := {self.}BaseSz; for _,range in range_array_ do range.Offset(x, y, page); {self.}EndY := {self.}StartY - {self.}DynamicHeight; end; function OMathRRange.AdjustOffset(x: real; y: real);override; begin class(BasicRange).AdjustOffset(x, y); for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathRRange.Calc(); begin {self.}DynamicHeight := {self.}BaseSz; if not r_.T then return; x := {self.}XOffset; y := {self.}YOffset; text := r_.T.Text; pos := 1; case r_.RPr.Sty.Val of "p": begin b := false; i := false; end "b": begin b := true; i := false; end "i": begin b := false; i := true; end "bi": begin b := true; i := true; end else begin b := false; i := true; end end; 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_obj := docx_to_pdf_.Font.GetCNSFont("Times-Roman", b, i); end else if DTPUtils.IsChineseChar(a_word) then begin text_range.Type := 3; word := utf8ToAnsi(a_word); font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", b, i); end else if DTPUtils.IsChinesePunctuation(a_word) then begin text_range.Type := 4; word := utf8ToAnsi(a_word); font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", b, i); end else begin word := class(SymbolMapper).SymbolChr(a_word); if ifnil(word) then begin echo format("error symbol {{%s}}.\n", a_word); word := chr(0x20); end font_obj := docx_to_pdf_.Font.GetSymbolFont(); end rpr := new RPr(); rpr.Sz.Val := {self.}BaseSz; first_page := docx_to_pdf_.PageManager[0]; pdf_page := first_page.PdfPage; pdf_page.SetFontAndSize(font_obj, {self.}BaseSz); text_range.RPr := rpr; text_range.Text := word; text_range.Font := font_obj; text_range.Width := pdf_page.TextWidth(word); text_range.Parent := self; text_range.DynamicHeight := rpr.Sz.Val; text_range.XOffset := x; text_range.YOffset := y; x += text_range.Width; pos += num; range_array_[length(range_array_)] := text_range; {self.}Width += text_range.Width; end {self.}BaseHeight := {self.}BaseSz / 4; end; function OMathNaryRange.Create(docx_to_pdf: TSDocxToPdf; nary: Nary); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; nary_ := nary; range_array_ := array(); end; function OMathNaryRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathNaryRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathNaryRange.AdjustOffset(x: real; y: real);overload; begin for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathNaryRange.Calc();override; begin x := {self.}XOffset; y := {self.}YOffset; val := nary_.NaryPr.Chr.Val ?: "Į"; symbol := class(SymbolMapper).SymbolChr(val); if ifnil(symbol) then begin echo format("error = %s", val); return; end symbol_font := docx_to_pdf_.Font.GetSymbolFont(); first_page := docx_to_pdf_.PageManager[0]; pdf_page := first_page.PdfPage; size := {self.}BaseSz; pdf_page.SetFontAndSize(symbol_font, size); symbol_range := new TextRange(); symbol_range.Text := symbol; symbol_range.XOffset := x; symbol_range.YOffset := y; symbol_range.Width := pdf_page.TextWidth(symbol); symbol_range.Font := symbol_font; symbol_range.RPr := new DocxML.RPr(); symbol_range.RPr.Sz.Val := size; symbol_range.DynamicHeight := size; sub_range := new OMathRange(docx_to_pdf_, nary_.Sub); sub_range.BaseSz := {self.}BaseSz / 2; sub_range.XOffset := x; sub_range.YOffset := y; sub_range.Calc(); sup_range := new OMathRange(docx_to_pdf_, nary_.Sup); sup_range.BaseSz := {self.}BaseSz / 2; sup_range.XOffset := x; sup_range.YOffset := y; sup_range.Calc(); // 需要得到高宽 if nary_.NaryPr.LimLoc.Val = "subSup" then begin max_width := max(sub_range.Width, sup_range.Width) + symbol_range.Width; sub_range.AdjustOffset(symbol_range.Width, -sub_range.DynamicHeight/2); sup_range.AdjustOffset(symbol_range.Width, symbol_range.DynamicHeight - sup_range.DynamicHeight/2); {self.}Width := max_width; {self.}DynamicHeight := symbol_range.DynamicHeight + sub_range.DynamicHeight/2 + sup_range.DynamicHeight + {self.}BaseSz * 0.1; end // else if nary_.Nary.LimLoc.Val = "undOvr" then else begin // undOvr max_width := maxValue(array(sub_range.Width, sup_range.Width, symbol_range.Width)); sub_range.AdjustOffset((max_width - sub_range.Width)/2, 0); symbol_range.AdjustOffset((max_width - symbol_range.Width)/2, sub_range.DynamicHeight); sup_range.AdjustOffset((max_width - sup_range.Width)/2, symbol_range.DynamicHeight + sub_range.DynamicHeight); {self.}Width := max_width; {self.}DynamicHeight := sup_range.DynamicHeight + symbol_range.DynamicHeight + sub_range.DynamicHeight; end e_range := new OMathRange(docx_to_pdf_, nary_.E); e_range.BaseSz := {self.}BaseSz; e_range.XOffset := x + max_width; e_range.YOffset := y + sub_range.DynamicHeight; e_range.Calc(); range_array_ union= array(symbol_range, sub_range, sup_range, e_range); {self.}Width += e_range.Width; {self.}DynamicHeight := max({self.}DynamicHeight, e_range.DynamicHeight); {self.}BaseHeight := symbol_range.DynamicHeight / 4 + sub_range.DynamicHeight; end; function OMathRadRange.Create(docx_to_pdf: TSDocxToPdf; rad: Rad); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; rad_ := rad; range_array_ := array(); end; function OMathRadRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathRadRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathRadRange.AdjustOffset(x: real; y: real);overload; begin for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathRadRange.Calc();override; begin x := {self.}XOffset; y := {self.}YOffset; deg_range := new OMathRange(docx_to_pdf_, rad_.Deg); deg_range.BaseSz := {self.}BaseSz / 2; deg_range.XOffset := x; deg_range.YOffset := y; deg_range.Calc(); e_range := new OMathRange(docx_to_pdf_, rad_.E); e_range.BaseSz := {self.}BaseSz; e_range.XOffset := x; e_range.YOffset := y; e_range.Calc(); // 需要得到高宽 symbol := chr(0xD6); symbol_font := docx_to_pdf_.Font.GetSymbolFont(); first_page := docx_to_pdf_.PageManager[0]; pdf_page := first_page.PdfPage; size := e_range.DynamicHeight; pdf_page.SetFontAndSize(symbol_font, size); symbol_range := new TextRange(); symbol_range.Text := symbol; symbol_range.XOffset := x; symbol_range.YOffset := y; symbol_range.Width := pdf_page.TextWidth(symbol); symbol_range.Font := symbol_font; symbol_range.RPr := new DocxML.RPr(); symbol_range.RPr.Sz.Val := size; symbol_range.DynamicHeight := size; deg_range.AdjustOffset(0, -e_range.DynamicHeight / 2); symbol_range.AdjustOffset(deg_range.Width, 0); e_range.AdjustOffset(size*0.3 + deg_range.Width, 0); line_range := new LineRange(); line_range.XOffset := symbol_range.XOffset + symbol_range.Width * 0.9; line_range.YOffset := symbol_range.DynamicHeight * 0.9; line_range.Width := e_range.Width; line_range.LineWidth := 0.04 * size; range_array_ union= array(symbol_range, deg_range, e_range, line_range); {self.}Width := deg_range.Width + symbol_range.Width + e_range.Width + 0.3*size; {self.}DynamicHeight := symbol_range.DynamicHeight; {self.}BaseHeight := symbol_range.DynamicHeight / 2; end; function OMathSSupRange.Create(docx_to_pdf: TSDocxToPdf; s_sup: SSup); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; s_sup_ := s_sup; range_array_ := array(); end; function OMathSSupRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathSSupRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathSSupRange.AdjustOffset(x: real; y: real);overload; begin for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathSSupRange.Calc();override; begin x := {self.}XOffset; y := {self.}YOffset; e_range := new OMathRange(docx_to_pdf_, s_sup_.E); e_range.BaseSz := {self.}BaseSz; e_range.XOffset := x; e_range.YOffset := y; e_range.Calc(); // 需要得到高宽 sup_range := new OMathRange(docx_to_pdf_, s_sup_.Sup); sup_range.BaseSz := {self.}BaseSz * 0.4; sup_range.XOffset := x; sup_range.YOffset := y; sup_range.Calc(); sup_range.AdjustOffset(e_range.Width, e_range.DynamicHeight / 2); range_array_ union= array(e_range, sup_range); {self.}Width := e_range.Width + sup_range.Width; h := sup_range.DynamicHeight + e_range.DynamicHeight / 2; {self.}DynamicHeight := max(h, e_range.DynamicHeight); {self.}BaseHeight := e_range.BaseHeight; end; function OMathSSubRange.Create(docx_to_pdf: TSDocxToPdf; s_sub: SSub); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; s_sub_ := s_sub; range_array_ := array(); end; function OMathSSubRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathSSubRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathSSubRange.AdjustOffset(x: real; y: real);overload; begin for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathSSubRange.Calc();override; begin x := {self.}XOffset; y := {self.}YOffset; e_range := new OMathRange(docx_to_pdf_, s_sub_.E); e_range.BaseSz := {self.}BaseSz; e_range.XOffset := x; e_range.YOffset := y; e_range.Calc(); // 需要得到高宽 sub_range := new OMathRange(docx_to_pdf_, s_sub_.Sub); sub_range.BaseSz := {self.}BaseSz * 0.4; sub_range.XOffset := x; sub_range.YOffset := y; sub_range.Calc(); sub_range.AdjustOffset(e_range.Width, -(sub_range.DynamicHeight - {self.}BaseSz * 0.4)); range_array_ union= array(e_range, sub_range); {self.}Width += e_range.Width + sub_range.Width; h := e_range.DynamicHeight + sub_range.DynamicHeight - {self.}BaseSz * 0.4; {self.}DynamicHeight := max(h, e_range.DynamicHeight); {self.}BaseHeight := e_range.BaseHeight; end; function OMathDRange.Create(docx_to_pdf: TSDocxToPdf; d: D); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; d_ := d; range_array_ := array(); end; function OMathDRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathDRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathDRange.AdjustOffset(x: real; y: real);overload; begin for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathDRange.Calc();override; begin x := {self.}XOffset; y := {self.}YOffset; e_range := new OMathRange(docx_to_pdf_, d_.E); e_range.BaseSz := {self.}BaseSz; e_range.XOffset := x; e_range.YOffset := y; e_range.Calc(); beg_chr := class(SymbolMapper).SymbolChr(d_.DPr.BegChr.Val) ?: chr(0x28); // ( end_chr := class(SymbolMapper).SymbolChr(d_.DPr.EndChr.Val) ?: chr(0x29); // ) max_h := e_range.DynamicHeight; font_obj := docx_to_pdf_.Font.GetSymbolFont(); first_page := docx_to_pdf_.PageManager[0]; pdf_page := first_page.PdfPage; pdf_page.SetFontAndSize(font_obj, max_h); beg_range := new TextRange(); beg_range.Text := beg_chr; beg_range.RPr := new RPr(); beg_range.RPr.Sz.Val := max_h; beg_range.Font := font_obj; beg_range.Width := pdf_page.TextWidth(beg_chr); beg_range.Parent := self; beg_range.DynamicHeight := max_h; beg_range.XOffset := x; beg_range.YOffset := y; end_range := new TextRange(); end_range.Text := end_chr; end_range.RPr := new RPr(); end_range.RPr.Sz.Val := max_h; end_range.Font := font_obj; end_range.Width := pdf_page.TextWidth(end_chr); end_range.Parent := self; end_range.DynamicHeight := max_h; end_range.XOffset := x; end_range.YOffset := y; e_range.AdjustOffset(beg_range.Width, 0); end_range.AdjustOffset(e_range.Width + beg_range.Width, 0); range_array_ union= array(beg_range, e_range, end_range); {self.}Width := beg_range.Width + e_range.Width + end_range.Width; {self.}DynamicHeight := max_h; {self.}BaseHeight := {self.}DynamicHeight / 2; end; function OMathFuncRange.Create(docx_to_pdf: TSDocxToPdf; func: Func); begin class(AdvancedRange).Create(); docx_to_pdf_ := docx_to_pdf; func_ := func; range_array_ := array(); end; function OMathFuncRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function OMathFuncRange.Offset(x: real; y: real; page: Page);override; begin class(AdvancedRange).Offset(x, y, page); for _,range in range_array_ do range.Offset(x, y, page); end; function OMathFuncRange.AdjustOffset(x: real; y: real);overload; begin for _,range in range_array_ do range.AdjustOffset(x, y); end; function OMathFuncRange.Calc();override; begin x := {self.}XOffset; y := {self.}YOffset; f_name_range := new OMathRange(docx_to_pdf_, func_.FName); f_name_range.BaseSz := {self.}BaseSz; f_name_range.XOffset := x; f_name_range.YOffset := y; f_name_range.Calc(); // 需要得到高宽 e_range := new OMathRange(docx_to_pdf_, func_.E); e_range.BaseSz := {self.}BaseSz; e_range.XOffset := x; e_range.YOffset := y; e_range.Calc(); max_h := max(f_name_range.DynamicHeight, e_range.DynamicHeight); e_range.AdjustOffset(f_name_range.Width, (max_h - e_range.DynamicHeight) / 2); f_name_range.AdjustOffset(0, (max_h - f_name_range.DynamicHeight) / 2); range_array_ union= array(f_name_range, e_range); {self.}Width += f_name_range.Width + e_range.Width; {self.}DynamicHeight := max(f_name_range.DynamicHeight, e_range.DynamicHeight); {self.}BaseHeight := f_name_range.BaseHeight; end; end.