type TSPdfParagraphRange = class(TSPdfBasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; paragraph: P); function Calc(); function Do();override; function SetTblStyleIdAndType(style_id: string; type: string); function SetNumPages(num: integer); function RangesToLines(); function GetLastPage(): TSPage; function AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real); function GetLineRangeArr(): array of TSPdfLineRange; function Empty(): boolean; function Offset(x: real; y: real); private function SetPPr(var ppr: PPr); function SetPPrByStyleId(var ppr: PPr; style_id: string); function SetRPr(var rpr; ppr: PPrUnitDecorator); function SetRPrByStyleId(var rpr: RPr; style_id: string); function SetRPrByTblStyleId(var rpr: RPr; style_id: string); function SetLvlText(); function GetImageFileType(data: binary): string; function GetImageData(id: string): PdfImage; function GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; function BasicRangesToLineRange(): tableArray; function CheckAndAddPage(y: real; offset: real): boolean; function GetUtf8CharLength(byte: string): integer; function SplitTextToTextRange(text: string; rpr: RPrUnitDecorator; link: string); function RToTextRange(r: R; link: string); function RDrawing(r: R); function RAlternateContent(r: R); function RFootnoteReference(r: R); function RObject(r: R); function RFldChar(r: R; stack: Stack); function RFootnoteRef(r: R); function SetLinesAlignment(); function ResetCoordinates(); function NewLineRange(): TSPdfLineRange; function BookMarkLinkToc(); function HyperlinkToToc(); function HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator); function GetXYCordinates(): array of real; function AlignRightBound(); function Init(); private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]docx_components_ware_: TSDocxComponentsWare; [weakref]paragraph_: P; [weakref]page_: TSPage; range_array_: array of TSPdfBasicRange; line_range_array_: array of TSPdfLineRange; hyperlink_array_: tableArray; bookmark_array_: tableArray; ppr_unit_decorator_: PPrUnitDecorator; placeholder_array_: tableArray; table_style_id_: string; table_style_type_: string; empty_: boolean; right_bound_: real; end; type FldStruct = class public function create(); begin FldLock := false; MergeFormat := false; Quote := false; Separate := false; PageArabicMergeFormat := false; NumPages := false; ArabicMergeFormat := false; EndFld := false; end; public FldLock: boolean; MergeFormat: boolean; Quote: boolean; Separate: boolean; PageArabicMergeFormat: boolean; NumPages: boolean; ArabicMergeFormat: boolean; EndFld: boolean; end; type Stack = class public function create(); begin arr_ := array(); index_ := 0; end; function Pop(); begin if index_ = 0 then return nil; index_--; ret := arr_[index_]; arr_[index_] := nil; return ret; end; function Push(element: any); begin arr_[index_++] := element; end; function Empty(): boolean; begin return index_ = 0; end; private arr_: tableArray; index_: integer; end; function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; paragraph: P); begin docx_to_pdf_ := docx_to_pdf; page_ := pg; docx_components_ware_ := components; paragraph_ := paragraph; table_style_id_ := ""; table_style_type_ := ""; range_array_ := array(); line_range_array_ := array(); hyperlink_array_ := array(); bookmark_array_ := array(); empty_ := false; {self.}TSPage := page_; end; function TSPdfParagraphRange.Init(); begin 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; {self.}SetLvlText(); end; function TSPdfParagraphRange.Calc(): tableArray; begin // ppr.rpr是无效的,应该以ppr.pStyle为准 if ifnil(paragraph_.XmlChildPPr) then paragraph_.XmlChildPPr := new PPr(); {self.}SetPPr(paragraph_.PPr); ppr_unit_decorator_ := new PPrUnitDecorator(paragraph_.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(); elements := paragraph_.Elements(); empty_flag := true; bookmark_id := ''; bookmark_name := ''; bookmark_flag := false; fld_stack := new Stack(); for _,element in elements do begin if element.LocalName = "r" then begin empty_flag := false; if ifnil(element.XmlChildRPr) then element.XmlChildRPr := new RPr(); {self.}SetRPr(element.RPr, ppr_unit_decorator_); if element.FldChar.FldCharType = "begin" then begin fld_struct := new FldStruct(); fld_stack.Push(fld_struct); 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; // {self.}CheckAndAddPage({self.}LowerBound, 1); else if ifObj(element.Drawing) then {self.}RDrawing(element); else if ifObj(element.AlternateContent) then {self.}RAlternateContent(element); else if ifObj(element.FootnoteReference) then {self.}RFootnoteReference(element); else if ifObj(element.Object) then {self.}RObject(element); else if element.FootnoteRef then {self.}RFootnoteRef(element); else {self.}RToTextRange(element, bookmark_name); end else if element.LocalName = "fldSimple" then begin if ifString(element.Instr) and trim(element.Instr) = "NUMPAGES \\* Arabic \\* MERGEFORMAT" then begin rpr := new RPrUnitDecorator(element.Rs(0).RPr); numpages_index := length(range_array_); placeholder_array_ := array(numpages_index, rpr); end end else if element.LocalName = "hyperlink" then begin empty_flag := false; {self.}HyperlinkToTextRange(element, ppr_unit_decorator_); 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 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; end; function TSPdfParagraphRange.SetNumPages(num: integer); begin text := tostring(num); last_index := length(range_array_); {self.}SplitTextToTextRange(text, placeholder_array_[1], link); arr := array(); len := length(range_array_); for i:=last_index to len-1 do arr[length(arr)] := range_array_[i]; diff := len - last_index; for i:=len-1 downto placeholder_array_[0] do range_array_[i] := range_array_[i-diff]; k := 0; for i:=placeholder_array_[0] to placeholder_array_[0]+diff-1 do range_array_[i] := arr[k++]; end; function TSPdfParagraphRange.BookMarkLinkToc(); begin for name,arr in bookmark_array_ do if arr[0] then docx_to_pdf_.LinkToToc(name, arr[0].TSPage, arr[0].EndX, arr[0].EndY + arr[0].RPr.Sz.Val); end; function TSPdfParagraphRange.HyperlinkToToc(); begin ppr := ppr_unit_decorator_; max_size := 0; for anchor,arr in hyperlink_array_ do // 整理hyperlink发送到docx_to_pdf_ begin pg := arr[0].TSPage; 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 := docx_to_pdf_.GetCurrentTextPoint().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.TSPage <> pg then begin rect := array(left, bottom, right, top); toc := new TSToc(ppr, rect, pg, x, y); docx_to_pdf_.AddToc(anchor, toc); pg := range.TSPage; 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_.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 TSToc(ppr, rect, pg, x, y, font_obj); docx_to_pdf_.AddToc(anchor, toc); end end; function TSPdfParagraphRange.HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator); begin i := length(range_array_); rs := hyperlink.Rs(); char_type := false; separate := false; for _,r in rs do begin if r.FldChar.FldCharType = "begin" then char_type := true; // TODO:officexml项目是否应该保留赋值接口,如何统一 if char_type then begin if r.FldChar.FldCharType = "separate" then begin separate := true; continue; end if r.FldChar.FldCharType = "end" then separate := char_type := false; if separate then docx_to_pdf_.AddDocxPage(hyperlink.Anchor, r); end else begin if ifnil(r.XmlChildRPr) then r.XmlChildRPr := new RPr(); {self.}SetRPr(r.RPr, ppr_unit_decorator_); r.RPr.Color.Val := nil; {self.}RToTextRange(r, hyperlink.Anchor); end end arr := array(); while i < length(range_array_) do begin arr[length(arr)] := range_array_[i]; i++; end hyperlink_array_[hyperlink.Anchor] := arr; end; function TSPdfParagraphRange.Do();override; begin for _,line_range in line_range_array_ do line_range.Do(); end; function TSPdfParagraphRange.SetTblStyleIdAndType(style_id: string; type: string); begin table_style_id_ := style_id; table_style_type_ := type; end; function TSPdfParagraphRange.NewLineRange(): TSPdfLineRange; begin line_range := new TSPdfLineRange(page_); line_range.StartX := {self.}EndX; line_range.StartY := {self.}EndY; line_range.Width := {self.}Width; return line_range; end; function TSPdfParagraphRange.RangesToLines();overload; begin {self.}BasicRangesToLineRange(); {self.}DynamicHeight += ppr_unit_decorator_.Spacing.After; {self.}EndY -= ppr_unit_decorator_.Spacing.After; if ppr_unit_decorator_.PBdr.Bottom.Val = "single" then begin sect_ware := docx_to_pdf_.GetCurrentSectWare(); page_.PdfPage.SetLineWidth(0.05); page_.PdfPage.SetGrayStroke(0.25); page_.PdfPage.MoveTo(sect_ware.SectPr.PgMar.Left, {self.}EndY); page_.PdfPage.LineTo(sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right, {self.}EndY); page_.PdfPage.Stroke(); end end; function TSPdfParagraphRange.BasicRangesToLineRange(); begin ppr := ppr_unit_decorator_; line_range := {self.}NewLineRange(); i := 0; max_size := 0; max_y := 0; while i <= length(range_array_)-1 do begin range := range_array_[i]; if i = 0 then {self.}EndX += ppr.Ind.FirstLine; if range is class(TSPdfTextRange) and range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; if range.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(TSPdfTextRange)) and (AnsiToUtf8(range.Text) in array(";", ":", "。", "“", "”", "!", "?", ",")) then if_newline := 0; if if_newline and range.Width < {self.}Width then begin offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; max_value := max(line_space, max_y); line_range.TSPage := page_; line_range.EndY := {self.}EndY - max_value; line_range.DynamicHeight := max_value; line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); line_range_array_[length(line_range_array_)] := line_range; line_range := {self.}NewLineRange(); max_size := 0; max_y := 0; {self.}DynamicHeight += max_value; {self.}EndY -= max_value; {self.}EndX := {self.}StartX; // w:hanging if range is class(TSPdfTextRange) 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(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.TSPage := page_; line_range.EndY := {self.}EndY - max_value; line_range.DynamicHeight := max_value; line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); line_range_array_[length(line_range_array_)] := line_range; {self.}DynamicHeight += max_value; {self.}EndY -= max_value; end end {self.}SetLinesAlignment(); {self.}AlignRightBound(); end; function TSPdfParagraphRange.SetLinesAlignment(); begin for _,line_range in line_range_array_ do line_range.Align(ppr_unit_decorator_.Jc.Val); end; function TSPdfParagraphRange.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 TSPdfParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; begin if y - offset < {self.}LowerBound then begin page_ := docx_to_pdf_.GetNextPage(page_); if ifnil(page_) then page_ := docx_to_pdf_.AddTSPage(); point := docx_to_pdf_.GetCurrentTextPoint(); {self.}EndY := point.Y; return true; end return false; end; function TSPdfParagraphRange.GetUtf8CharLength(byte: string): integer; begin if (_and(ord(byte), 0b10000000)) = 0 then return 1; else if (_and(ord(byte), 0b11100000)) = 0b11000000 then return 2; else if (_and(ord(byte), 0b11110000)) = 0b11100000 then return 3; else if (_and(ord(byte), 0b11111000)) = 0b11110000 then return 4; end; function TSPdfParagraphRange.RToTextRange(r: R; link: string); begin if r.Anchor then begin {self.}HyperlinkToTextRange(r); end else begin rpr := new RPrUnitDecorator(r.RPr); text := r.T.Text; if ifString(text) then {self.}SplitTextToTextRange(text, rpr, link); end end; function TSPdfParagraphRange.SplitTextToTextRange(text: string; rpr: RPrUnitDecorator; link: string); begin pos := 1; while pos <= length(text) do begin num := {self.}GetUtf8CharLength(text[pos]); a_word := text[pos : pos+num-1]; word := utf8ToAnsi(a_word); if num <> 1 and word = "?" then begin word := docx_to_pdf_.GetSymbol(a_word); if ifnil(word) then word := "u"; font_obj := docx_to_pdf_.Font.GetSymbolFont(); end else begin font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); word_width := page_.PdfPage.TextWidth(word); text_range := new TSPdfTextRange(); text_range.RPr := rpr; text_range.Text := word; text_range.Font := font_obj; text_range.Width := word_width; range_array_[length(range_array_)] := text_range; if ifarray(bookmark_array_[link]) then bookmark_array_[link] union= array(text_range); pos += num; end end; function TSPdfParagraphRange.RDrawing(r: R); begin if ifObj(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 TSPdfImageRange(); image_range.Image := image; image_range.Type := image_type; image_range.StartX := xfrm.Off.X; image_range.StartY := xfrm.Off.Y; image_range.Width := xfrm.Ext.CX; image_range.DynamicHeight := xfrm.Ext.CY; range_array_[length(range_array_)] := image_range; end else if ifObj(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 TSPdfImageRange(); 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.TSPage := page_; image_range.Do(); end end; function TSPdfParagraphRange.RAlternateContent(r: R); 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 begin range := new TSPdfParagraphRange(docx_to_pdf_, page_, docx_components_ware_, p); range.StartX := x; range.StartY := y; range.Width := w; range.Calc(); range.Do(); y := range.EndY; end end; function TSPdfParagraphRange.RFootnoteReference(r: R); begin id := R.FootnoteReference.Id; footnotes_adapter := docx_components_ware_.GetFootnotesAdapter(); footnote := footnotes_adapter.GetFootnoteById(id); sect_ware := docx_to_pdf_.GetCurrentSectWare(); w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left; lb := {self.}LowerBound; [x, y] := docx_to_pdf_.CalculateTextCoordinates(); elements := footnote.Elements(); for _,element in elements do begin if element.LocalName = "p" then begin range := new TSPdfParagraphRange(docx_to_pdf_, page_, docx_components_ware_, element); range.StartX := x; range.StartY := y; range.Width := w; range.LowerBound := {self.}LowerBound; range.Calc(); range.Offset(0, y - range.DynamicHeight - {self.}LowerBound); range.Do(); {self.}LowerBound += range.DynamicHeight; rpr := new RPrUnitDecorator(r.RPr); text := docx_to_pdf_.GetCurrentNoteWare().GetIndex(); if ifString(text) then {self.}SplitTextToTextRange(text, rpr, nil); return; // break; end end // range := new TSPdfParagraphRange(self, page_, docx_components_ware_, ); end; function TSPdfParagraphRange.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 TSPdfImageRange(); 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; range_array_[length(range_array_)] := image_range; end; function TSPdfParagraphRange.RFldChar(r: R; stack: Stack); 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; if r.FldChar.FldLock then fld_struct.FldLock := 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.}RToTextRange(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(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); end; function TSPdfParagraphRange.GetXYCordinates(): array of real; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); if xml_file = "document.xml" then [x, y] := docx_to_pdf_.CalculateTextCoordinates(); else begin sect_ware := docx_to_pdf_.GetCurrentSectWare(); x := sect_ware.SectPr.PgMar.Left; if ansiContainsStr(xml_file, "footer") then y := sect_ware.SectPr.PgMar.Bottom; else if ansiContainsStr(xml_file, "header") then y := sect_ware.SectPr.PgSz.H - sect_ware.SectPr.PgMar.Header; end return array(x, y); end; function TSPdfParagraphRange.GetImageData(id: string): PdfImage; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); if xml_file = "document.xml" then rels_adapter := docx_components_ware_.GetDocumentRelsAdapter(); else if ansiContainsStr(xml_file, "footer") then rels_adapter := docx_components_ware_.GetFtrRelsAdapter(xml_file); else if ansiContainsStr(xml_file, "header") then rels_adapter := docx_components_ware_.GetHdrRelsAdapter(xml_file); rel := rels_adapter.GetRelationshipById(id); image_path := "word/" + rel.Target; image := docx_components_ware_.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_.GetPdf().LoadPngImageFromFile("", image_path); "jpg": image := docx_to_pdf_.GetPdf().LoadJpegImageFromFile("", image_path); "emf": image := docx_to_pdf_.GetPdf().LoadEmfImageFromFile("", image_path); "wmf": image := docx_to_pdf_.GetPdf().LoadWmfImageFromFile("", image_path); end; fileDelete("", image_path); return array(image_type, image); end; function TSPdfParagraphRange.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 TSPdfParagraphRange.GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; begin sect_ware := docx_to_pdf_.GetCurrentSectWare(); 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 / sect_ware.BaseSize) * lines; return sect_ware.SectPr.DocGrid.LinePitch * multi; end end; function TSPdfParagraphRange.SetPPr(var ppr: PPr); begin new_ppr := new PPr(); styles := docx_components_ware_.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, ppr.PStyle.Val); if ifObj(ppr) then begin new_ppr.Copy(ppr); ppr.Copy(new_ppr); end end; function TSPdfParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string); begin styles := docx_components_ware_.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); end end; function TSPdfParagraphRange.SetRPr(var rpr; ppr: PPrUnitDecorator); begin new_rpr := new RPr(); styles := docx_components_ware_.GetStyles(); new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr); {self.}SetRPrByTblStyleId(new_rpr, table_style_id_); {self.}SetRPrByStyleId(new_rpr, ppr.PStyle.Val); {self.}SetRPrByStyleId(new_rpr, rpr.RStyle.Val); if ifObj(rpr) then begin new_rpr.Copy(rpr); rpr.Copy(new_rpr); end end; function TSPdfParagraphRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string); begin styles := docx_components_ware_.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_ware_.GetTblStylePrByType(table_style_id_, table_style_type_); if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr); end end; function TSPdfParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string); begin styles := docx_components_ware_.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); end end; function TSPdfParagraphRange.SetLvlText(); begin numbering_ware := docx_components_ware_.GetNumberingWare(); if not ifObj(numbering_ware) then return; [lvl_text, lvl] := numbering_ware.GetNumberLvl(paragraph_.PPr); if lvl_text = "" and ifnil(lvl) then return; {self.}SetRPr(lvl.RPr, paragraph_.PPr); rpr := new RPrUnitDecorator(lvl.RPr); {self.}SplitTextToTextRange(lvl_text, rpr); end; function TSPdfParagraphRange.ResetCoordinates(); 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 TSPdfParagraphRange.GetLastPage(): TSPage; begin return page_; end; function TSPdfParagraphRange.AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real); begin for _,line_range in line_range_array_ do line_range.AdjustRangeOffset(page, x_offset, y_offset); end; function TSPdfParagraphRange.GetLineRangeArr(): array of TSPdfLineRange; begin return line_range_array_; end; function TSPdfParagraphRange.Empty(): boolean; begin return empty_; end; function TSPdfParagraphRange.Offset(x: real; y: real); begin for _,line_range in line_range_array_ do line_range.Offset(x, y); end; function TSPdfParagraphRange.RFootnoteRef(r: R); begin note_ware := docx_to_pdf_.GetCurrentNoteWare(); rpr := new RPrUnitDecorator(r.RPr); text := note_ware.GetFootnoteOrderNumber(); if ifString(text) then {self.}SplitTextToTextRange(text, rpr, nil); end;