From a118ff6c26fdaf45a22cf6ec6202595e7e44f2a5 Mon Sep 17 00:00:00 2001 From: csh Date: Tue, 18 Feb 2025 10:24:25 +0800 Subject: [PATCH] update --- internal/DTPAdvancedRanges.tsf | 2408 +++++++++++++++++++++++++++++ internal/DTPAdvancedRanges_bk.tsf | 2407 ++++++++++++++++++++++++++++ internal/DTPColorToolKit.tsf | 23 + internal/DTPModules.tsf | 719 +++++++++ internal/DTPPrimitiveRanges.tsf | 245 +++ internal/DTPUtils.tsf | 248 +++ 6 files changed, 6050 insertions(+) create mode 100644 internal/DTPAdvancedRanges.tsf create mode 100644 internal/DTPAdvancedRanges_bk.tsf create mode 100644 internal/DTPColorToolKit.tsf create mode 100644 internal/DTPModules.tsf create mode 100644 internal/DTPPrimitiveRanges.tsf create mode 100644 internal/DTPUtils.tsf diff --git a/internal/DTPAdvancedRanges.tsf b/internal/DTPAdvancedRanges.tsf new file mode 100644 index 0000000..0c11088 --- /dev/null +++ b/internal/DTPAdvancedRanges.tsf @@ -0,0 +1,2408 @@ +unit DTPAdvancedRanges; +interface +uses DTPPrimitiveRanges, DTPUtils, DTPModules, SharedML, DocxML, DrawingMLUnitDecorator, DocxMLUnitDecorator; + +type RangeCollection = class(BasicRange) +public + function Create(); + function Do();override; + function Add(range: BasicRange); + +private + range_array_: array of BasicRange; +end; + +type ParagraphLineRange = class(BasicRange) +public + function Create(pg: Page); + function Do();override; + function AddRange(range: BasicRange); + function SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); + function Align(jc: string); + function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); + function AlignRightBound(right_bound: real); + function Offset(x_offset: real; y_offset; real); + +private + range_array_: array of BasicRange; +end; + +type ParagraphRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); + function Calc(); + function Do();override; + function SetTblStyleIdAndType(style_id: string; type: string); + function SetNumPages(num: integer); + function RangesToLines(); + function GetLastPage(): Page; + function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); + function GetParagraphLineRangeArr(): array of ParagraphLineRange; + function Empty(): boolean; + function Offset(x: real; y: real); + +private + function SetPPPr(var p: P); + function SetPPrByStyleId(var ppr: PPr; style_id: string); + function SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); + function SetRPrByStyleId(var rpr: RPr; style_id: string); + function SetRPrByTblStyleId(var rpr: RPr; style_id: string); + function SetLvlText(); + function GetImageFileType(data: binary): string; + function GetImageData(id: string): PdfImage; + function GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; + function BasicRangesToParagraphLineRange(): tableArray; + function UpdateTextRangeWidth(); + function CheckAndAddPage(y: real; offset: real): boolean; + function SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: string); + function RAlternateContent(r: R); + function RDrawing(r: R); + function RFldChar(r: R; stack: Stack); + function RFootnoteReference(r: R); + function RFootnoteRef(r: R); + function RObject(r: R); + function RT(r: R; link: string); + function FldSimple(fld_simple: FldSimple); + function Hyperlink(hyperlink: Hyperlink); + + function SetLinesAlignment(); + function ResetCoordinates(); + function NewParagraphLineRange(): ParagraphLineRange; + function BookMarkLinkToc(); + function HyperlinkToToc(); + function HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator); + function GetXYCordinates(): array of real; + function AlignRightBound(); + function Init(); + function OMathPara(element: OMathPara); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]paragraph_: P; + [weakref]page_: Page; + body_range_array_: array of BasicRange; // 正文的range + bullet_range_array_: array of BasicRange; // 项目符号的range + line_range_array_: array of ParagraphLineRange; + + hyperlink_array_: tableArray; + bookmark_array_: tableArray; + ppr_unit_decorator_: PPrUnitDecorator; + placeholder_array_: tableArray; + table_style_id_: string; + table_style_type_: string; + empty_: boolean; + right_bound_: real; + footnote_reference_hash_: hash; +end; + +type TableRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; table: Tbl); + function Do();override; + function Calc(); + function GetLastPage(): Page; + function Rows(): integer; + function Cols(): integer; + function RowLowerBound(row: integer): real; + +private + function CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); + function ComputeMatrixCells(); + function ResetCoordinates(tbl_pr: TblPrUnitDecorator; grid_cols: array of GridCol); + function 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); + function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); + function OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]last_page_: Page; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]table_: Tbl; + tbl_pr_unit_decorator_: TblPrUnitDecorator; + ts_trpr_array_: array of TSTrProperty; + cell_range_matrix_: array of CellRange; + row_lower_bound_: hash; + rows_: integer; + cols_: integer; +end; + +type CellRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); + function Calc(); + function Do();override; + function SetPage(pg: Page); + function GetLastPage(); + function AlignHeight(height: real; lb: real); + function SetVAlign(); + function IsReComputeByCantSplit(): boolean; + function IfRemoveEmptyRectangle(): boolean; + function SetTop(); + + property Tc read tc_; + +private + function GetCellPrType(): string; + function SetBorderRange(range: BordersRange); + +public + RemoveFlag: boolean; + Row: integer; + Col: integer; + VMerge: integer; + [weakref]TSTrPr: TSTrProperty; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]last_page_: Page; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]tc_: Tc; + [weakref]tbl_pr_: TblPr; + tc_pr_unit_decorator_: TcPrUnitDecorator; + region_array_: array of Region; // 单元格可能跨页,所以可能存在多个 + top_: boolean; +end; + +type ColumnRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); + function AddElement(ele: Element); + function Elements(): array of Element; + function GetLastPage(): Page; + function Do();override; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]page_: Page; + elements_: array of Elements; + paragraph_: P; + last_y_: real; +end; + +type MathRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); + function Calc(); + function Do();override; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]o_math_para_: OMathPara; + sub_math_range_: SubMathRange; +end; + +type SubMathRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); + function Do();override; + function Calc(); + +private + function MathR(r: R; sz: real; x: real; y: real): RangeCollection; + function MathF(f: F; sz: real; x: real; y: real): RangeCollection; + function MathRad(rad: Rad; sz: real; x: real; y: real): RangeCollection; + function MathNary(nary: Nary; sz: real; x: real; y: real): RangeCollection; + function MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]ts_page_: Page; + [weakref]openxml_element_: OpenXmlElement; + range_collection_: RangeCollection; + sz_: real; +end; + +implementation + +function MathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); +begin + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + o_math_para_ := o_math_para; + sub_math_range_ := nil; + {self.}Page := pg; +end; + +function MathRange.Calc(); +begin + sub_math_range_ := new SubMathRange(docx_to_pdf_, {self.}Page, o_math_para_.OMath, 11); + sub_math_range_.StartX := {self.}StartX; + sub_math_range_.StartY := {self.}StartY; + sub_math_range_.EndX := {self.}EndX; + sub_math_range_.EndY := {self.}EndY; + sub_math_range_.DynamicHeight := 100; + sub_math_range_.Calc(); + + {self.}EndX := sub_math_range_.EndX; + {self.}EndY := sub_math_range_.EndY; + {self.}Width := sub_math_range_.Width; + {self.}DynamicHeight := sub_math_range_.DynamicHeight; +end; + +function MathRange.Do();override; +begin + sub_math_range_.Do(); +end; + +function SubMathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); +begin + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + ts_page_ := pg; + openxml_element_ := element; + {self.}Page := pg; + range_collection_ := new RangeCollection(); + sz_ := sz; +end; + +function SubMathRange.Do();override; +begin + range_collection_.Do(); +end; + +function SubMathRange.Calc(); +begin + elements := openxml_element_.Elements(); + min_y := {self.}StartY; + max_y := {self.}StartY; + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + for _,element in elements do + begin + range := nil; + if element.LocalName = "r" then + range := {self.}MathR(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "f" then + range := {self.}MathF(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "rad" then + range := {self.}MathRad(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "nary" then + range := {self.}MathNary(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "sSup" then + range := {self.}MathSSup(element, sz_, {self.}EndX, {self.}EndY); + + if not ifObj(range) then + begin + echo forma("Not support <%s>\n", element.ElementName); + continue; + end + if min_y > range.EndY then min_y := range.EndY; + if max_y < range.EndY + range.DynamicHeight then max_y := range.EndY + range.DynamicHeight; + + {self.}EndX := range.EndX; + {self.}EndY := range.EndY; + {self.}Width += range.Width; + range_collection_.Add(range); + end + range_collection_.DynamicHeight := max_y - min_y; + {self.}DynamicHeight := range_collection_.DynamicHeight; +end; + +function SubMathRange.MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; +begin + prange := new RangeCollection(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + e_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.E, sz); + e_range.StartX := x; + e_range.StartY := y; + e_range.Calc(); + + sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.Sup, sz * 0.4); + sup_range.StartX := x + e_range.Width; + sup_range.StartY := y + sz * 0.57; + sup_range.Calc(); + + prange.Add(e_range); + prange.Add(sup_range); + prange.EndX := maxValue(array(e_range.EndX, sup_range.EndX)); + prange.EndY := e_range.EndY; + prange.Width := prange.EndX - prange.StartX; + prange.DynamicHeight := e_range.DynamicHeight + sup_range.DynamicHeight * 0.5; + + return prange; +end; + +function SubMathRange.MathR(r: R; sz: real; x: real; y: real): RangeCollection; +begin + // println("x = {}, y = {}", x, y); + prange := new RangeCollection(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + text := r.T.Text(); + pos := 1; + // println("text = {}", text); + while pos <= length(text) do + begin + num := Utf8CharLengthFromByte(text[pos]); + a_word := text[pos : pos+num-1]; + if num = 1 or DTPUtils.IsChineseChar(a_word) or DTPUtils.IsChinesePunctuation(a_word) then + begin + word := utf8ToAnsi(a_word); + font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", false, true); + end + else begin + word := class(SymbolMapper).SymbolChr(a_word); + if ifnil(word) then raise format("error symbol {{%s}}", a_word); + font_obj := docx_to_pdf_.Font.GetSymbolFont(); + end + rpr := new RPr(); + rpr.Sz.Val := sz; + ts_page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); + word_width := ts_page_.PdfPage.TextWidth(word); + text_range := new TextRange(); + text_range.RPr := rpr; + text_range.Text := word; + text_range.Font := font_obj; + text_range.StartX := prange.EndX; + text_range.StartY := prange.EndY; + text_range.Page := {self.}Page; + text_range.EndX := text_range.StartX; + text_range.EndY := text_range.StartY; + text_range.Width := word_width; + pos += num; + prange.Add(text_range); + prange.EndX += text_range.Width; + prange.Width += text_range.Width; + end + prange.DynamicHeight := sz; + return prange; +end; + +function SubMathRange.MathF(f: F; sz: real; x: real; y: real); +begin + prange := new ParagraphLineRange(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + den_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Den, sz); + den_range.StartX := x; + den_range.StartY := y; + den_range.Calc(); + + num_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Num, sz); + num_range.StartX := x; + num_range.StartY := y + 1.418 * sz; + num_range.Calc(); + + max_len := max(den_range.Width, num_range.Width); + bar := max_len / 0.9; + line_range := new LineRange(); + line_range.StartX := x - (bar - max_len) / 2; + line_range.StartY := y + 0.928 * sz; + line_range.EndX := line_range.StartX; + line_range.EndY := line_range.StartY; + line_range.Width := bar; + line_range.Page := {self.}Page; + line_range.LineWidth := 0.04 * sz; + + prange.EndX := maxValue(array(den_range.EndX, num_range.EndX, line_range.EndX)); + prange.AddRange(den_range); + prange.AddRange(num_range); + prange.AddRange(line_range); + + return prange; + + // TODO: delete + // pg := {self.}Page.PdfPage; + // pg.SetFontAndSize(font, sz); + // len1 := pg.TextWidth(range1.Text); + // len2 := pg.TextWidth(range2.Text); + // max_len := len1 > len2 ? len1 : len2; + // bar := max_len / 0.9; + // pg.SetLineWidth(0.05*sz); + // pg.SetRGBStroke(0, 0, 0); + // x := {self.}StartX - (bar - max_len) / 2; + // y := {self.}StartY + 0.928 * sz; + // pg.MoveTo(x, y); + // pg.LineTo(x + bar, y); + // pg.Stroke(); + + // elements := f.Den.Elements(); + // {self.}TraverseElement(elements); + // elements := f.Num.Elements(); + // {self.}TraverseElement(elements); + + // for _,element in elements do + // begin + // if + // range1 := new TextRange(); + // range1.Text := "a"; + // range1.EndX := {self.}StartX; + // range1.EndY := {self.}StartY; + // rpr := new RPr(); + // rpr.Sz.Val := sz; + // range1.RPr := rpr; + // range1.Page := {self.}Page; + // range1.Font := font; + // range1.Do(); + // end + // for _,element in elements do + // begin + // range2 := new TextRange(); + // range2.Text := "b"; + // range2.EndX := {self.}StartX; + // range2.EndY := {self.}StartY + 1.418*sz; + // rpr := new RPr(); + // rpr.Sz.Val := sz; + // range2.RPr := rpr; + // range2.Page := {self.}Page; + // range2.Font := font; + // range2.Do(); + // // if element.LocalName = "r" then + // // begin + // // range1 := new TextRange(); + // // range1.Text := element.T.Text(); + // // end + // end +end; + +function SubMathRange.MathRad(rad: Rad; sz: real; x: real; y: real): ParagraphLineRange; +begin + prange := new ParagraphLineRange(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + symbol := chr(0xD6); + symbol_font := docx_to_pdf_.Font.GetSymbolFont(); + pg := {self.}Page.PdfPage; + pg.SetFontAndSize(symbol_font, sz); + symbol_range := new TextRange(); + symbol_range.Text := symbol; + symbol_range.EndX := x; + symbol_range.EndY := y; + symbol_range.Font := symbol_font; + symbol_range.Width := pg.TextWidth(symbol); + symbol_range.RPr := new RPr(); + symbol_range.RPr.Sz.Val := sz; + symbol_range.Page := {self.}Page; + + deg_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.Deg, sz * 0.5); + deg_range.StartX := x; + deg_range.StartY := y + sz * 0.57; + deg_range.Calc(); + + e_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.E, sz); + e_range.StartX := x + symbol_range.Width; + e_range.StartY := y; + e_range.Calc(); + + line_range := new LineRange(); + line_range.StartX := x + symbol_range.Width * 0.9; + line_range.StartY := y + sz * 0.9; + line_range.EndX := line_range.StartX; + line_range.EndY := line_range.StartY; + line_range.Width := e_range.Width + symbol_range.Width / 3; + line_range.Page := {self.}Page; + line_range.LineWidth := 0.04 * sz; + + prange.EndX := maxValue(array(symbol_range.EndX, e_range.EndX, deg_range.EndX, line_range.EndX)); + prange.AddRange(symbol_range); + prange.AddRange(deg_range); + prange.AddRange(e_range); + prange.AddRange(line_range); + + return prange; + + // TODO: delete + // range := new TextRange(); + // range.Text := chr_hash_['α']; + // range.EndX := {self.}StartX; + // range.EndY := {self.}StartY + sz * 0.57; + // range.Font := symbol_font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz / 2; + // range.Page := {self.}Page; + // range.Do(); + + // range := new TextRange(); + // range.Text := "abcd"; + // range.EndX := {self.}StartX + symbol_w; + // range.EndY := {self.}StartY; + // range.Font := font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz; + // range.Page := {self.}Page; + // range.Do(); + + // pg.SetFontAndSize(font, sz); + // pg.SetLineWidth(0.04*sz); + // pg.SetRGBStroke(0, 0, 0); + // x := {self.}StartX + symbol_w * 0.9; + // y := {self.}StartY + sz * 0.9; + // pg.MoveTo(x, y); + // pg.LineTo(x + pg.TextWidth(range.Text)+symbol_w/3, y); + // pg.Stroke(); + +end; + +function SubMathRange.MathNary(nary: Nary; sz: real; x: real; y: real): ParagraphLineRange; +begin + prange := new ParagraphLineRange(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + val := nary.NaryPr.Chr.Val ?: "Į"; + symbol := class(SymbolMapper).SymbolChr(val); + if ifnil(symbol) then raise format("error = %s", val); + symbol_font := docx_to_pdf_.Font.GetSymbolFont(); + pg := {self.}Page.PdfPage; + pg.SetFontAndSize(symbol_font, sz * 1.5); + symbol_range := new TextRange(); + symbol_range.Text := symbol; + symbol_range.EndX := x; + symbol_range.EndY := y; + symbol_range.Font := symbol_font; + symbol_range.RPr := new DocxML.RPr(); + symbol_range.RPr.Sz.Val := 1.5 * sz; + symbol_range.Page := {self.}Page; + symbol_range.Width := pg.TextWidth(symbol); + + if nary.NaryPr.LimLoc.Val = "subSup" then + begin + sup_start_x := x + symbol_range.Width * 1.2; + sup_start_y := y + sz * 1.5 * 0.73; + sub_start_x := x + symbol_range.Width * 0.7; + sub_start_y := y - sz * 1.5 * 0.2; + end + // else if nary.Nary.LimLoc.Val = "undOvr" then + else begin // undOvr + sup_start_x := x + symbol_range.Width * 0.5; + sup_start_y := y + sz * 1.5 * 0.8; + sub_start_x := x; + sub_start_y := y - sz * 1.5 * 0.5; + end + + sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sup, sz * 0.7); + sup_range.StartX := sup_start_x; + sup_range.StartY := sup_start_y; + sup_range.Calc(); + + sub_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sub, sz * 0.7); + sub_range.StartX := sub_start_x; + sub_range.StartY := sub_start_y; + sub_range.Calc(); + + if nary.NaryPr.LimLoc.Val = "subSup" then + begin + e_start_x := x + symbol_range.Width * 0.5 + max(sup_range.Width, sub_range.Width); + e_start_y := y + sz * 0.3; + end + else begin + e_start_x := x + symbol_range.Width; + e_start_y := y + sz * 0.3; + end + + e_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.E, sz); + e_range.StartX := e_start_x; + e_range.StartY := e_start_y; + e_range.Calc(); + + prange.EndX := maxValue(array(symbol_range.EndX, sup_range.EndX, sub_range.EndX, e_range.EndX)); + prange.AddRange(symbol_range); + prange.AddRange(sup_range); + prange.AddRange(sub_range); + prange.AddRange(e_range); + + return prange; + // TODO: delete + // val := nary.NaryPr.Chr.Val; + // symbol := class(SymbolMapper).SymbolChr(nary.NaryPr.Chr.Val); + // sz := 11; + // symbol_font := docx_to_pdf_.PdfFile().GetFont("Symbol", ""); + // symbol_range := new TextRange(); + // symbol_range.Text := symbol; + // symbol_range.EndX := {self.}StartX; + // symbol_range.EndY := {self.}StartY; + // symbol_range.Font := symbol_font; + // symbol_range.RPr := new RPr(); + // symbol_range.RPr.Sz.Val := 1.5 * sz; + // symbol_range.Page := {self.}Page; + // symbol_range.Do(); + + // pg := {self.}Page.PdfPage; + // pg.SetFontAndSize(symbol_font, sz * 1.5); + // symbol_w := pg.TextWidth(symbol); + // font := docx_to_pdf_.PdfFile().GetFont("SimSun,Italic", "GBK-EUC-H"); + + // range := new TextRange(); + // range.Text := chr_hash_["∞"]; + // range.EndX := {self.}StartX + symbol_w / 5; + // range.EndY := {self.}StartY + sz * 0.8 * 1.5; + // range.Font := symbol_font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz * 0.7; + // range.Page := {self.}Page; + // range.Do(); + + // range := new TextRange(); + // range.Text := "n=1"; + // pg.SetFontAndSize(font, sz*0.7); + // tw := pg.TextWidth(range.Text); + // range.EndX := {self.}StartX + (symbol_w - tw)/2; + // range.EndY := {self.}StartY - sz * 0.5 * 1.5; + // range.Font := font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz * 0.7; + // range.Page := {self.}Page; + // range.Do(); + + // range := new TextRange(); + // range.Text := chr_hash_["f"]; + // pg.SetFontAndSize(font, sz); + // tw := pg.TextWidth(range.Text); + // range.EndX := {self.}StartX + symbol_w; + // range.EndY := {self.}StartY + sz * 0.3; + // range.Font := symbol_font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz; + // range.Page := {self.}Page; + // range.Do(); + +end; + +// ColumnRange +function ColumnRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); +begin + docx_to_pdf_ := docx_to_pdf; + page_ := pg; + docx_components_module_ := components; + elements_ := array(); + last_y_ := 0; +end; + +function ColumnRange.AddElement(ele: Element); +begin + elements_[length(elements_)] := ele; +end; + +function ColumnRange.Elements(): array of Element; +begin + return elements_; +end; + +function ColumnRange.Do();override; +begin + x := {self.}StartX; + y := {self.}StartY; + for _,element in elements_ do + begin + range := nil; + if element.LocalName = "p" then + range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); + else if element.LocalName = "tbl" then + range := new TableRange(docx_to_pdf_, page_, docx_components_module_, element); + if ifnil(range) then continue; + range.StartX := x; + range.StartY := y; + range.Width := {self.}Width; + range.LowerBound := {self.}LowerBound; + range.Calc(); + range.Do(); + y := range.EndY; + page_ := range.GetLastPage(); + end + {self.}EndY := y; +end; + +function ColumnRange.GetLastPage(): Page; +begin + return page_; +end; + +// TableRange +function TableRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: Components; table: Tbl); +begin + docx_to_pdf_ := docx_to_pdf; + last_page_ := pg; + docx_components_module_ := Components; + table_ := table; + ts_trpr_array_ := array(); + cell_range_matrix_ := array(); + row_lower_bound_ := array(); + rows_ := 0; + cols_ := 0; + {self.}Page := last_page_; +end; + +function TableRange.Calc(); +begin + {self.}SetTblTblPr(table_); + tbl_pr_unit_decorator_ := new TblPrUnitDecorator(table_.TblPr); + tbl_grid_unit_decorator := new TblGridUnitDecorator(table_.TblGrid); + grid_cols := tbl_grid_unit_decorator.GridCols(); + {self.}ResetCoordinates(tbl_pr_unit_decorator_, grid_cols); + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + // 如果是根据内容自适应,应该计算并调整grid_cols的值 + trs := table_.Trs(); + rows_ := length(trs); + cols_ := length(grid_cols); + cell_range_matrix_ := nils(rows_, cols_); + // 先构建一个矩阵 + {self.}CreateTableMatrix(grid_cols, trs); + // 遍历矩阵后进行计算合并 + {self.}ComputeMatrixCells(); +end; + +function TableRange.Do();override; +begin + for _,row in cell_range_matrix_ do + begin + flag := nil; + for __,range in row do + begin + if ifnil(flag) and ifObj(range) then flag := range.IfRemoveEmptyRectangle(); + if not ifObj(range) then continue; + if flag <> range.IfRemoveEmptyRectangle() then + begin + flag := false; + break; + end + end + for __,range in row do + begin + if ifObj(range) then + begin + range.RemoveFlag := flag; + range.Do(); + end + end + end +end; + +function TableRange.CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); +begin + for i,tr in trs do + begin + {self.}SetTrTrPr(tr); + tr_pr := new TrPrUnitDecorator(tr.TrPr); + tc_x := {self.}EndX; + tcs := tr.Tcs(); + trp := new DTPUtils.TrProperty(); + trp.TrPr := tr_pr; + ts_trpr_array_[i] := trp; + pos := 0; + for j,tc in tcs do + begin + {self.}SetTcTcPr(tc); + if i = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "firstRow"); + else if i = length(trs)-1 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "lastRow") + else if (i + 1) % 2 = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band1Horz"); + else {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band2Horz"); + + grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan); + if tc.TcPr.VMerge and tc.TcPr.VMerge <> "restart" then + begin + tc_x += grid_cols[pos++].W; + for k:=grid_span.Val-1 downto 1 do + begin + cell_range_matrix_[i][pos] := 0; + tc_x += grid_cols[pos++].W; + end + continue; + end + cell_range := new CellRange(docx_to_pdf_, last_page_, docx_components_module_, tc, tbl_pr_unit_decorator_, trp); + cell_range.StartX := tc_x; + cell_range.Width := grid_cols[pos].W; + cell_range.LowerBound := {self.}LowerBound; + cell_range.FixedHeight := tr_pr.TrHeight.Val; + cell_range.Parent := self; + cell_range.Row := i; + cell_range.Col := pos; + cell_range_matrix_[i][pos] := cell_range; + pos++; + // 水平合并的单元格,占位需要和垂直的区分 + for k:=grid_span.Val-1 downto 1 do + begin + cell_range_matrix_[i][pos] := 0; + cell_range.Width += grid_cols[pos++].W; + end + tc_x += cell_range.Width; + end + end + + // for i,arr in cell_range_matrix_ do + // println("i = {}, arr = {}", i, arr); + // println("\n"); + return; +end; + +function TableRange.ComputeMatrixCells(); +begin + i := 0; + merge_arr := array(); + vmerge_height := array(); + while i < rows_ do + begin + j := 0; + tc_y := {self.}EndY; + recompute_flag := false; + while j < cols_ do + begin + range := cell_range_matrix_[i][j]; + if not ifObj(range) then + begin + j++; + continue; + end + range.StartY := tc_y; + range.SetPage(last_page_); + range.Calc(); + if range.IsReComputeByCantSplit() then + begin + // 调整上一行的下边界 + arr := cell_range_matrix_[i-1]; + for _,r in arr do + begin + if ifnil(r) then + begin + pos := i-2; + while pos > 0 do + begin + rr := cell_range_matrix_[pos][_]; + pos--; + if ifnil(rr) then continue; + rr.LowerBound := tc_y; + break; + end + end + if not ifnil(r) then r.LowerBound := tc_y; + end + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + [x, y] := docx_to_pdf_.CalculateTextCoordinates(); + {self.}EndY := y; + j := 0; + recompute_flag := true; + arr := cell_range_matrix_[i]; + for _,r in arr do + if not ifnil(r) then r.SetTop(); + break; + end + if range.Tc.TcPr.VMerge then + begin + b_merge_index := i; + e_merge_index := i + 1; + while ifnil(cell_range_matrix_[e_merge_index+1][j]) and e_merge_index < rows_-1 do + e_merge_index++; + merge_arr[e_merge_index][j] := b_merge_index; + range.VMerge := e_merge_index; + if ifnil(vmerge_height[e_merge_index]) or range.DynamicHeight > vmerge_height[e_merge_index] then + vmerge_height[e_merge_index] := range.DynamicHeight; + end + j++; + end + if recompute_flag then continue; + i_height := 0; + for k,v in merge_arr[i] do + begin + i_height := ts_trpr_array_[i].Height; + r := cell_range_matrix_[v][k]; + total_height := 0; + for index:=v to i-1 do + total_height += ts_trpr_array_[index].Height; + h := vmerge_height[i]; + if h > total_height + i_height then + i_height := h - total_height; + else + h := total_height + i_height; + r.AlignHeight(h, row_lower_bound_[i-1]); + r.SetVAlign(); + end + if i_height then ts_trpr_array_[i].Height := i_height; + for _,range in cell_range_matrix_[i] do + begin + if not ifObj(range) or range.Tc.TcPr.VMerge then continue; + range.AlignHeight(ts_trpr_array_[i].Height, row_lower_bound_[i]); + range.SetVAlign(); + {self.}EndY := range.EndY; + last_page_ := range.GetLastPage(); + row_lower_bound_[i] := range.LowerBound; + end + i++; + end +end; + +function TableRange.RowLowerBound(row: integer): real; +begin + return row_lower_bound_[row]; +end; + +function TableRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); +begin + // tc_pr应该是经过外层copy的 + tbl_style_pr := docx_components_module_.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type); + if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr); +end; + +function TableRange.ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol); +begin + total_width := 0; + for _,grid_col in grid_cols do + total_width += grid_col.W; + diff := total_width - {self.}Width; + case tbl_pr.Jc.Val of + "center": + begin + offset := diff/2; + {self.}StartX -= offset; + end + "right": + begin + {self.}StartX -= diff; + end + end; + {self.}Width := total_width; +end; + +function TableRange.SetTblTblPr(var tbl: Tbl); +begin + new_tbl_pr := new TblPr(); + {self.}SetTblPrByStyleId(new_tbl_pr, tbl.TblPr.TblStyle.Val); + new_tbl_pr.Copy(tbl.TblPr); + tbl.TblPr.Copy(new_tbl_pr); +end; + +function TableRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetTblPrByStyleId(tbl_pr, based_on); + tbl_pr.Copy(style.TblPr); + end +end; + +function TableRange.SetTrTrPr(var tr: Tr); +begin + new_tr_pr := new TrPr(); + {self.}SetTrPrByStyleId(new_tr_pr, tbl_pr_unit_decorator_.TblStyle.Val); + new_tr_pr.Copy(tr.TrPr); + tr.TrPr.Copy(new_tr_pr); +end; + +function TableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetTrPrByStyleId(tr_pr, based_on); + tr_pr.Copy(style.TrPr); + end +end; + +function TableRange.SetTcTcPr(var tc: Tc); +begin + new_tc_pr := new TcPr(); + {self.}SetTcPrByStyleId(new_tc_pr, tbl_pr_unit_decorator_.TblStyle.Val); + new_tc_pr.Copy(tc.TcPr); + tc.TcPr.Copy(new_tc_pr); +end; + +function TableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetTcPrByStyleId(tc_pr, based_on); + tc_pr.Copy(style.TcPr); + end +end; + +function TableRange.GetLastPage(): Page; +begin + return last_page_; +end; + +function TableRange.Rows(): integer; +begin + return rows_; +end; + +function TableRange.Cols(): integer; +begin + return cols_; +end; + +// CellRange +function CellRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: TSDocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); +begin + docx_to_pdf_ := docx_to_pdf; + last_page_ := pg; + docx_components_module_ := components; + tc_ := tc; + tbl_pr_ := tbl_pr; + region_array_ := array(); + top_ := false; + tc_pr_unit_decorator_ := new TcPrUnitDecorator(tc_.TcPr); + {self.}TSTrPr := trp; + {self.}Tc := tc; + {self.}VMerge := 1; + {self.}Page := last_page_; +end; + +function CellRange.Calc(); +begin + region_array_ := array(); + region := new DTPUtils.Region(); + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := {self.}StartY; + region.BordersRange.Width := {self.}Width; + region.BordersRange.FixedHeight := {self.}FixedHeight; + region.BordersRange.Page := last_page_; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}DynamicHeight := 0; + cell_x := {self.}EndX + tbl_pr_.TblCellMar.Left.W; + cell_y := {self.}EndY - tbl_pr_.TblCellMar.Top.W; + cell_w := {self.}Width - tbl_pr_.TblCellMar.Right.W - tbl_pr_.TblCellMar.Left.W; + cell_h := {self.}FixedHeight; + elements := tc_.Elements(); + for _,element in elements do + begin + range := nil; + if element.LocalName = "p" then + begin + range := new ParagraphRange(docx_to_pdf_, last_page_, docx_components_module_, element); + range.SetTblStyleIdAndType(tbl_pr_.TblStyle.Val, {self.}GetCellPrType()); + end + else if element.LocalName = "tbl" then + begin + range := new TableRange(docx_to_pdf_, last_page_, docx_components_module_, element); + continue; // TODO:表中表存在不可靠问题 + end + if ifObj(range) then + begin + range.StartX := cell_x; + range.StartY := cell_y; + range.Width := cell_w; + range.FixedHeight := cell_h; + range.LowerBound := {self.}LowerBound; + range.Parent := self; + range.Calc(); + region.RangeArr[length(region.RangeArr)] := range; + {self.}DynamicHeight += range.DynamicHeight; + cell_y := range.EndY; + last_page_ := range.GetLastPage(); + end + end + {self.}EndY := cell_y - tbl_pr_.TblCellMar.Bottom.W; + {self.}DynamicHeight += tbl_pr_.TblCellMar.Top.W + tbl_pr_.TblCellMar.Bottom.W; + + if {self.}EndY < {self.}LowerBound and not range.Empty() then + begin + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + if ifnil(last_page_) then last_page_ := docx_to_pdf_.AddPage(); + {self.}StartY := last_page_.TextPoint.Y; + {self.}Calc(); + end + if {self.}TSTrPr.TrPr.TrHeight.HRule <> "exact" and {self.}DynamicHeight > {self.}FixedHeight then + begin + region.BordersRange.FixedHeight := {self.}DynamicHeight; + {self.}FixedHeight := {self.}DynamicHeight; + end + if not {self.}Tc.TcPr.VMerge and {self.}DynamicHeight > {self.}TSTrPr.Height then + {self.}TSTrPr.Height := {self.}DynamicHeight; +end; + +function CellRange.Do();override; +begin + for _,region in region_array_ do + begin + if _ = 0 and {self.}RemoveFlag then continue; + // println("Row = {}, Col = {}", {self.}Row, {self.}Col); + region.BordersRange.Do(); + for _,range in region.RangeArr do + range.Do(); + end +end; + +function CellRange.SetPage(pg: Page); +begin + last_page_ := pg; + {self.}Page := pg; +end; + +function CellRange.AlignHeight(height: real; lb: real); +begin + region := region_array_[0]; + y_lowerbound := {self.}StartY - {self.}LowerBound; + surplus := height - y_lowerbound; + if surplus < 1e-6 then + begin + region.BordersRange.DynamicHeight := height; + {self.}SetBorderRange(region.BordersRange); + {self.}EndY := {self.}StartY - region.BordersRange.DynamicHeight; + {self.}LowerBound := {self.}StartY - height; + return; + end + // if lb then y_lowerbound := {self.}StartY - lb; + region.BordersRange.DynamicHeight := y_lowerbound; + arr := region.RangeArr; + region.RangeArr := array(); + hash := array(region.BordersRange.Page.Index: region); + last_page_ := {self.}Page; + [x, y] := last_page_.OriginalTextCoordinates(); + span := y - last_page_.FtrPoint.Y; + while surplus > span do + begin + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + region := new DTPUtils.Region(); + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := y; + region.BordersRange.Width := {self.}Width; + region.BordersRange.DynamicHeight := span; + region.BordersRange.Page := last_page_; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + region.BordersRange.Top := true; + region.BordersRange.Bottom := true; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + surplus -= span; + hash[region.BordersRange.Page.Index] := region; + end + if surplus > 1e-6 then + begin + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + region := new DTPUtils.Region(); + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := y; + region.BordersRange.Width := {self.}Width; + region.BordersRange.DynamicHeight := surplus; + region.BordersRange.Page := last_page_; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + region.BordersRange.Top := true; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + hash[region.BordersRange.Page.Index] := region; + {self.}EndY := region.BordersRange.EndY - surplus; + end + for _,range in arr do + begin + if range is class(ParagraphRange) then + begin + line_arr := range.GetParagraphLineRangeArr(); + for _,r in line_arr do + begin + region := hash[r.Page.Index]; + region.RangeArr[length(region.RangeArr)] := r; + end + end + end +end; + +function CellRange.GetLastPage(); +begin + return last_page_; +end; + +function CellRange.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) - tbl_pr_.TblCellMar.Bottom.W; + case val of + "center": + begin + offset /= 2; + for _,range in arr do + range.AdjustRangeOffset(region.BordersRange.Page, nil, -offset); + end + end; +end; + +function CellRange.IsReComputeByCantSplit(): boolean; +begin + if {self.}Tc.TcPr.VMerge then return false; + return {self.}TSTrPr.TrPr.CantSplit and last_page_ <> {self.}Page; +end; + +function CellRange.IfRemoveEmptyRectangle(): boolean; +begin + return; + if length(region_array_) < 2 then return false; + return length(region_array_[0].RangeArr) ? false : true; +end; + +function CellRange.GetCellPrType(): string; +begin + if {self.}Row = 0 then return "firstRow"; + else if ({self.}Row + 1) % 2 = 0 then return "band1Horz"; + else return "band2Horz"; +end; + +function CellRange.SetBorderRange(range: BordersRange); +begin + if top_ then range.Top := true; + if ifObj(tbl_pr_.TblBorders) then + begin + if {self.}Row = 0 then + begin + if tbl_pr_.TblBorders.Top then + begin + if not tc_pr_unit_decorator_.TcBorders.Top then + tc_pr_unit_decorator_.TcBorders.Top.Copy(tbl_pr_.TblBorders.Top); + range.Top := true; + end + if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); + range.Right := true; + end + if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); + range.Bottom := true; + end + end + else if {self.}Row = {self.}Parent.Rows()-1 then + begin + if tbl_pr_.TblBorders.Bottom then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); + range.Right := true; + end + end + else begin + if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); + range.Right := true; + end + end + + if {self.}Col = 0 then + begin + if tbl_pr_.TblBorders.Left then + begin + if not tc_pr_unit_decorator_.TcBorders.Left then + tc_pr_unit_decorator_.TcBorders.Left.Copy(tbl_pr_.TblBorders.Left); + range.Left := true; + end + end + if {self.}Col = {self.}Parent.Cols()-1 then + begin + if tbl_pr_.TblBorders.Right then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.Right); + range.Right := true; + end + end + end + else begin + range.Left := {self.}Col = 0; + range.Top := {self.}Row = 0; + range.Right := true; + range.Bottom := true; + end +end; + +function CellRange.SetTop(); +begin + top_ := true; +end; + +// RangeCollection; +function RangeCollection.Create(); +begin + class(BasicRange).Create(); + range_array_ := array(); +end; + +function RangeCollection.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function RangeCollection.Add(range: BasicRange); +begin + range_array_[length(range_array_)] := range; +end; + +// ParagraphLineRange +function ParagraphLineRange.Create(pg: Page); +begin + class(BasicRange).Create(); + {self.}Page := pg; + range_array_ := array(); +end; + +function ParagraphLineRange.AddRange(range: BasicRange); +begin + range_array_[length(range_array_)] := range; +end; + +function ParagraphLineRange.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function ParagraphLineRange.SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); +begin + for _,range in range_array_ do + begin + if not ifnil(pg) then range.Page := pg; + if not ifnil(sx) then range.StartX := sx; + if not ifnil(sy) then range.StartY := sy; + if not ifnil(ex) then range.EndX := ex; + if not ifnil(ey) then range.EndY := ey; + if not ifnil(w) then range.Width := w; + if not ifnil(fh) then range.FixedHeight := fh; + if not ifnil(dh) then range.DynamicHeight := dh; + end +end; + +function ParagraphLineRange.Align(jc: string); +begin + offset := 0; + first := range_array_[0]; + last := range_array_[length(range_array_)-1]; + case jc of + "center": + offset := ({self.}Width + StartX - last.EndX - last.Width) / 2; + "right": + offset := {self.}Width - last.EndX + first.EndX - last.Width; + end; + if offset <= 0 then return; + for _,range in range_array_ do + range.EndX += offset; +end; + +function ParagraphLineRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); +begin + if pg <> {self.}Page then return; + for _,range in range_array_ do + begin + if not ifnil(x_offset) then range.EndX += x_offset; + if not ifnil(y_offset) then range.EndY += y_offset; + end; +end; + +function ParagraphLineRange.AlignRightBound(right_bound: real); +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 ParagraphLineRange.Offset(x_offset: real; y_offset; real); +begin + for _,range in range_array_ do + begin + range.EndX += x_offset; + range.EndY -= y_offset; + end +end; + + +// ParagraphRange +function ParagraphRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); +begin + docx_to_pdf_ := docx_to_pdf; + page_ := pg; + docx_components_module_ := components; + paragraph_ := paragraph; + table_style_id_ := ""; + table_style_type_ := ""; + body_range_array_ := array(); + bullet_range_array_ := array(); + line_range_array_ := array(); + hyperlink_array_ := array(); + bookmark_array_ := array(); + empty_ := false; + {self.}Page := page_; + footnote_reference_hash_ := array(); +end; + +function ParagraphRange.Init(); +begin + body_range_array_ := array(); + right_bound_ := {self.}StartX + {self.}Width; + {self.}ResetCoordinates(); + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before); + {self.}EndY -= ppr_unit_decorator_.Spacing.Before; + {self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before; + + // TODO:项目符号应该单独写入 + {self.}SetLvlText(); +end; + +function ParagraphRange.Calc(): tableArray; +begin + // ppr.rpr是无效的,应该以ppr.pStyle为准 + {self.}SetPPPr(paragraph_); + ppr_unit_decorator_ := new DocxMLUnitDecorator.PPrUnitDecorator(paragraph_.PPr); + {self.}Init(); + 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); + + elements := paragraph_.Elements(); + empty_flag := true; + bookmark_id := ''; + bookmark_name := ''; + bookmark_flag := false; + fld_stack := new DTPUtils.Stack(); + for _,element in elements do + begin + // println("LocalName = {}", element.LocalName); + if element.LocalName = "r" then + begin + empty_flag := false; + {self.}SetRRPr(element, ppr_unit_decorator_); + + if element.FldChar.FldCharType = "begin" then + begin + fld_struct := new DTPUtils.FldStruct(); + fld_stack.Push(fld_struct); + 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; + else if element.Drawing then {self.}RDrawing(element); + else if element.AlternateContent then {self.}RAlternateContent(element); + else if element.FootnoteReference then {self.}RFootnoteReference(element); + else if element.Object then {self.}RObject(element); + else if element.FootnoteRef then {self.}RFootnoteRef(element); + else if element.Anchor then {self.}Hyperlink(element); // + else if element.T then {self.}RT(element, bookmark_name); + end + else if element.LocalName = "fldSimple" then + begin + {self.}FldSimple(element); + end + else if element.LocalName = "hyperlink" then + begin + empty_flag := false; + {self.}Hyperlink(element); + end + else if element.LocalName = "bookmarkStart" then + begin + bookmark_id := element.Id; + bookmark_name := element.Name; + bookmark_array_[bookmark_name] := array(); + end + else if element.LocalName = "bookmarkEnd" then + begin + bookmark_id := ''; + bookmark_name := ''; + end + else if element.LocalName = "oMathPara" then + begin + {self.}OMathPara(element); + end + else if element.LocalName = "oMath" then + begin + o_math_para := new OMathPara(); + o_math_para.XmlChildOMath := element; + // o_math_para.OMath.Copy(element); + {self.}OMathPara(o_math_para); + end + end + if empty_flag then + begin + line_space := {self.}GetParagraphLineSpace(ppr_unit_decorator_.RPr.Sz.Val, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule); + {self.}DynamicHeight += line_space; + {self.}EndY -= {self.}DynamicHeight; + empty_ := true; + end + if placeholder_array_ then return false; + {self.}RangesToLines(); + if hyperlink_array_ then {self.}HyperlinkToToc(); + if bookmark_array_ then {self.}BookMarkLinkToc(); + return true; +end; + +function ParagraphRange.SetNumPages(num: integer); +begin + text := tostring(num); + last_index := length(body_range_array_); + {self.}SplitTextToTextRange(body_range_array_, text, placeholder_array_[1], link); + arr := array(); + len := length(body_range_array_); + for i:=last_index to len-1 do + arr[length(arr)] := body_range_array_[i]; + diff := len - last_index; + for i:=len-1 downto placeholder_array_[0] do + body_range_array_[i] := body_range_array_[i-diff]; + k := 0; + for i:=placeholder_array_[0] to placeholder_array_[0]+diff-1 do + body_range_array_[i] := arr[k++]; +end; + +function ParagraphRange.BookMarkLinkToc(); +begin + for name,arr in bookmark_array_ do + if arr[0] then docx_to_pdf_.Toc.LinkToToc(name, arr[0].Page, arr[0].EndX, arr[0].EndY + arr[0].RPr.Sz.Val); +end; + +function ParagraphRange.HyperlinkToToc(); +begin + ppr := ppr_unit_decorator_; + max_size := 0; + for anchor,arr in hyperlink_array_ do // 整理hyperlink发送到docx_to_pdf_ + begin + pg := arr[0].Page; + left := {self.}StartX; + right := {self.}StartX + {self.}Width; + top := {self.}StartY; + bottom := {self.}StartY; + x := arr[0].EndX; + y := arr[0].EndY; + if top - {self.}GetParagraphLineSpace(arr[0].RPr.Sz.Val, ppr.Spacing.Line, ppr.Spacing.LineRule) then + begin + top := pg.TextPoint.Y; + bottom := top; + end + for _,range in arr do + begin + if x + range.Width - {self.}StartX > {self.}Width + 1e-6 then // 换行 + begin + line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); + bottom -= line_space; + max_size := 0; + if range.Page <> pg then + begin + rect := array(left, bottom, right, top); + toc := new DTPModules.Toc(ppr, rect, pg, x, y); + docx_to_pdf_.Toc.AddToc(anchor, toc); + pg := range.Page; + bottom := {self.}StartY; + end + end + if range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; + x := range.EndX + range.Width; + y := range.EndY; + end + font_name := ppr.RPr.RFonts.EastAsia ? ppr.RPr.RFonts.EastAsia : ppr.RPr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, ppr.RPr.B, ppr.RPr.I); + line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); + pg.PdfPage.SetFontAndSize(font_obj, max_size); + bottom -= line_space; + num_width := pg.PdfPage.TextWidth("." + tostring(pg.Number)); + if x + num_width - {self.}StartX > {self.}Width + 1e-6 then // 换行 + begin + offset := (line_space - max_size) / 2 + max_size - max_size / 5; + diff := {self.}EndY - {self.}LowerBound; + if {self.}CheckAndAddPage({self.}EndY, line_space) then + begin + {self.}DynamicHeight += diff; + pg := page_; + rect := array(left, bottom, right, top); + toc := new TSToc(ppr, rect, pg, x, y); + docx_to_pdf_.Toc.AddToc(anchor, toc); + bottom := {self.}StartY; + end + else begin + bottom -= line_space; + x := {self.}StartX; + y := {self.}EndY - offset; + {self.}EndY -= line_space; + {self.}DynamicHeight += line_space; + end + end + rect := array(left, bottom, right, top); + toc := new DTPModules.Toc(ppr, rect, pg, x, y, font_obj); + docx_to_pdf_.Toc.AddToc(anchor, toc); + end +end; + +function ParagraphRange.FldSimple(fld_simple: FldSimple); +begin + if fld_simple.Instr then + begin + fields := str2array(fld_simple.Instr, " "); + fld_struct := new DTPUtils.FldStruct2(); + 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_unit_decorator_); + rpr := new RPrUnitDecorator(r.RPr); + if fld_struct.Type.NumPages then + begin + if fld_struct.Arabic then + begin + placeholder_array_ := array(length(body_range_array_), rpr); + end + end +end; + +function ParagraphRange.Hyperlink(hyperlink: Hyperlink); +begin + i := length(body_range_array_); + rs := hyperlink.Rs(); + separate := false; + stack := new DTPUtils.Stack(); + for _,r in rs do + begin + if r.FldChar.FldCharType = "begin" then + begin + fld_struct := new FldStruct2(); + stack.Push(fld_struct); + end + // if r.InstrText.Text + else if r.FldChar.FldCharType = "end" then + begin + 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); + end + else if stack.Empty() then + begin + {self.}SetRRPr(r, ppr_unit_decorator_); + r.RPr.Color.Val := nil; + {self.}RT(r, hyperlink.Anchor); + end + end + arr := array(); + while i < length(body_range_array_) do + begin + arr[length(arr)] := body_range_array_[i]; + i++; + end + hyperlink_array_[hyperlink.Anchor] := arr; +end; + +function ParagraphRange.Do();override; +begin + for _,line_range in line_range_array_ do + line_range.Do(); +end; + +function ParagraphRange.SetTblStyleIdAndType(style_id: string; type: string); +begin + table_style_id_ := style_id; + table_style_type_ := type; +end; + +function ParagraphRange.NewParagraphLineRange(): ParagraphLineRange; +begin + line_range := new ParagraphLineRange(page_); + line_range.StartX := {self.}StartX; + line_range.StartY := {self.}EndY; + line_range.Width := {self.}Width; + return line_range; +end; + +function ParagraphRange.UpdateTextRangeWidth(); +begin + head_range := body_range_array_[0]; + i := 1; + while i < length(body_range_array_) do + begin + 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 last_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 ParagraphRange.RangesToLines();overload; +begin + {self.}UpdateTextRangeWidth(); + {self.}BasicRangesToParagraphLineRange(); + {self.}DynamicHeight += ppr_unit_decorator_.Spacing.After; + {self.}EndY -= ppr_unit_decorator_.Spacing.After; + if not {self.}Empty() and ppr_unit_decorator_.PBdr.Bottom.Val = "single" then + begin + sect_pr := page_.SectPr; + page_.PdfPage.SetLineWidth(0.05); + page_.PdfPage.SetGrayStroke(0.25); + page_.PdfPage.MoveTo(sect_pr.PgMar.Left, {self.}EndY); + page_.PdfPage.LineTo(sect_pr.PgSz.W - sect_pr.PgMar.Right, {self.}EndY); + page_.PdfPage.Stroke(); + end +end; + +function ParagraphRange.BasicRangesToParagraphLineRange(); +begin + ppr := ppr_unit_decorator_; + line_range := {self.}NewParagraphLineRange(); + i := 0; + max_size := 0; + max_y := 0; + while i <= length(body_range_array_)-1 do + begin + range := body_range_array_[i]; + if i = 0 then {self.}EndX += ppr.Ind.FirstLine; + if range is class(TextRange) and range.RPr.Sz.Val > max_size then + max_size := range.RPr.Sz.Val; + if range.DynamicHeight > max_y then max_y := range.DynamicHeight; + line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); + diff := {self.}EndY - {self.}LowerBound; + if {self.}CheckAndAddPage({self.}EndY, max(line_space, range.DynamicHeight)) then + {self.}DynamicHeight += diff; + if_newline := {self.}EndX + range.Width - {self.}StartX > {self.}Width + 1e-6; + if i = 0 then if_newline := 0; + if if_newline and (range is class(TextRange)) and (AnsiToUtf8(range.Text) in array(";", ":", "。", "“", "”", "!", "?", ",")) then + if_newline := 0; + if if_newline and range.Width < {self.}Width then + begin + offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; + max_value := max(line_space, max_y); + line_range.Page := page_; + line_range.EndY := {self.}EndY - max_value; + line_range.DynamicHeight := max_value; + line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); + line_range_array_[length(line_range_array_)] := line_range; + + line_range := {self.}NewParagraphLineRange(); + max_size := 0; + max_y := 0; + {self.}DynamicHeight += max_value; + {self.}EndY -= max_value; + {self.}EndX := {self.}StartX; + // w:hanging + if range is class(TextRange) then + sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); + else + sz := docx_to_pdf_.Font.GetDefaultSz(); + {self.}EndX -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging; + continue; + end + range.EndX := {self.}EndX - range.StartX; + {self.}EndX += range.Width; + line_range.AddRange(range); + i++; + if i = length(body_range_array_) then + begin + offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; + max_value := max(line_space, max_y); + line_range.Page := page_; + line_range.EndY := {self.}EndY - max_value; + line_range.DynamicHeight := max_value; + line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); + line_range_array_[length(line_range_array_)] := line_range; + {self.}DynamicHeight += max_value; + {self.}EndY -= max_value; + end + end + {self.}SetLinesAlignment(); + if not {self.}Parent is class(CellRange) then + {self.}AlignRightBound(); +end; + +function ParagraphRange.SetLinesAlignment(); +begin + for _,line_range in line_range_array_ do + line_range.Align(ppr_unit_decorator_.Jc.Val); +end; + +function ParagraphRange.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 ParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; +begin + if y - offset < {self.}LowerBound then + begin + page_ := docx_to_pdf_.PageManager[page_.Index + 1]; + if ifnil(page_) then page_ := docx_to_pdf_.AddPage(); + {self.}EndY := page_.TextPoint.Y; + return true; + end + return false; +end; + +function ParagraphRange.RT(r: R; link: string); +begin + rpr := new RPrUnitDecorator(r.RPr); + text := r.T.Text; + if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, link); +end; + +function ParagraphRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: 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; + word := a_word; + 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 + else if DTPUtils.IsChineseChar(a_word) then + begin + text_range.Type := 3; + word := utf8ToAnsi(a_word); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + else if DTPUtils.IsChinesePunctuation(a_word) then + begin + text_range.Type := 4; + word := utf8ToAnsi(a_word); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + else begin + word := utf8ToAnsi(a_word); + if word = "?" then + begin + word := class(SymbolMapper).ZapfDingbatsChr(a_word); + if ifnil(word) then word := "u"; + font_obj := docx_to_pdf_.Font.GetZapfDingbatsFont(); + end + else begin + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + end + page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); + word_width := page_.PdfPage.TextWidth(word); + text_range.RPr := rpr; + text_range.Text := word; + text_range.Font := font_obj; + text_range.Width := word_width; + pos += num; + range_arr[length(range_arr)] := text_range; + if ifarray(bookmark_array_[link]) then bookmark_array_[link] union= array(text_range); + end +end; + +function ParagraphRange.RDrawing(r: R); +begin + if r.Drawing._Inline then + begin + id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; + [image_type, image] := {self.}GetImageData(id); + if not image then return; + xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm); + image_range := new ImageRange(); + image_range.Image := image; + image_range.Type := image_type; + image_range.StartX := 0; + image_range.StartY := 0; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; + body_range_array_[length(body_range_array_)] := image_range; + end + else if r.Drawing.Anchor then + begin + anchor := r.Drawing.Anchor; + id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; + [image_type, image] := {self.}GetImageData(id); + if not image then return; + [x, y] := {self.}GetXYCordinates(); + xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm); + position_h := new PositionHUnitDecorator(anchor.PositionH); + position_v := new PositionVUnitDecorator(anchor.PositionV); + if position_h.RelativeFrom = "paragraph" then + x := {self.}StartY; + if position_v.RelativeFrom = "paragraph" then + y := {self.}StartY; + image_range := new ImageRange(); + image_range.Image := image; + image_range.Type := image_type; + image_range.EndX := x + position_h.PosOffset.Text; + image_range.EndY := y - position_v.PosOffset.Text - xfrm.Ext.CY; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; + image_range.Page := page_; + image_range.Do(); + end +end; + +function ParagraphRange.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 ParagraphRange(docx_to_pdf_, page_, docx_components_module_, p); + range.StartX := x; + range.StartY := y; + range.Width := w; + range.Calc(); + range.Do(); + y := range.EndY; + end +end; + +function ParagraphRange.RFootnoteReference(r: R); +begin + return; + id := R.FootnoteReference.Id; + footnotes_adapter := docx_components_module_.GetFootnotesAdapter(); + footnote := footnotes_adapter.GetFootnoteById(id); + sect_pr := page_.SectPr; + w := sect_pr.SectPr.PgSz.W - sect_pr.SectPr.PgMar.Right - sect_pr.SectPr.PgMar.Left; + lb := 0; + x := sect_pr.SectPr.PgMar.Left; + y := sect_pr.SectPr.PgSz.H; + + arr := array(); + elements := footnote.Elements(); + for _,element in elements do + begin + if element.LocalName = "p" then + begin + range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); + range.StartX := x; + range.StartY := y; + range.Width := w; + range.LowerBound := 0; + range.Calc(); + arr[length(arr)] := arr; + end + end + rpr := new RPrUnitDecorator(r.RPr); + note := docx_to_pdf_.Note; + text := docx_to_pdf_.GetCurrentNoteModule().GetIndex(); + i := length(body_range_array_); + if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); + footnote_reference_hash_[body_range_array_[i]] := arr; + + // range := new ParagraphRange(self, page_, docx_components_module_, ); +end; + +function ParagraphRange.RFootnoteRef(r: R); +begin + return; + note_module := docx_to_pdf_.GetCurrentNoteModule(); + rpr := new RPrUnitDecorator(r.RPr); + text := note_module.GetFootnoteOrderNumber(); + if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); +end; + +function ParagraphRange.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.StartX := 0; + image_range.StartY := 0; + image_range.Width := w; + image_range.DynamicHeight := h; + body_range_array_[length(body_range_array_)] := image_range; +end; + +function ParagraphRange.RFldChar(r: R; stack: Stack); +begin + fld_struct := stack.Pop(); + + if r.FldChar.FldCharType = "begin" then + fld_struct.EndFld := false; + else if r.FldChar.FldCharType = "end" then + fld_struct.EndFld := true; + else if r.FldChar.FldCharType = "separate" then + fld_struct.Separate := true; + + instr_text := ifString(r.InstrText.Text) ? trim(r.InstrText.Text) : ""; + if instr_text <> "" then + begin + if instr_text = "QUOTE" then + fld_struct.Quote := true; + else if instr_text = "\\* MERGEFORMAT" then + fld_struct.MergeFormat := true; + else if instr_text = "PAGE \\* Arabic \\* MERGEFORMAT" or instr_text = "PAGE \\* MERGEFORMAT" then + fld_struct.PageArabicMergeFormat := true; + else if instr_text = "NUMPAGES" then + fld_struct.NumPages := true; + else if instr_text = "\\* Arabic \\* MERGEFORMAT" then + fld_struct.ArabicMergeFormat := true; + else if instr_text = "NUMPAGES \\* Arabic \\* MERGEFORMAT" then + fld_struct.NumPages := fld_struct.ArabicMergeFormat := true; + end + if fld_struct.Quote then + begin + if not fld_struct.EndFld and not fld_struct.Separate then + begin + stack.Push(fld_struct); + return; + end + end + else if fld_struct.PageArabicMergeFormat then + begin + if fld_struct.Separate then + begin + r.T.Text := tostring(page_.Number); + {self.}RT(r, nil); + fld_struct.PageArabicMergeFormat := false; + end + end + else if fld_struct.ArabicMergeFormat then + begin + if fld_struct.Separate then + begin + rpr := new RPrUnitDecorator(r.RPr); + numpages_index := length(body_range_array_); + placeholder_array_ := array(numpages_index, rpr); + fld_struct.NumPages := false; + end + end + if not fld_struct.EndFld then + begin + stack.Push(fld_struct); + end + if ifObj(r.Drawing) then {self.}RDrawing(r); + else if ifObj(r.AlternateContent) then {self.}RAlternateContent(r); + else if ifObj(r.FootnoteReference) then {self.}RFootnoteReference(r); + else if ifObj(r.Object) then {self.}RObject(r); +end; + +function ParagraphRange.GetXYCordinates(): array of real; +begin + xml_file := docx_to_pdf_.GetCurrentXmlFile(); + if xml_file = "document.xml" then + begin + [x, y] := page_.OriginalTextPoint(); + end + else begin + x := page_.SectPr.PgMar.Left; + if ansiContainsStr(xml_file, "footer") then + y := page_.SectPr.PgMar.Bottom; + else if ansiContainsStr(xml_file, "header") then + y := page_.SectPr.PgSz.H - page_.SectPr.PgMar.Header; + end + return array(x, y); +end; + +function ParagraphRange.GetImageData(id: string): PdfImage; +begin + xml_file := docx_to_pdf_.GetCurrentXmlFile(); + if xml_file = "document.xml" then + rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); + else if ansiContainsStr(xml_file, "footer") then + rels_adapter := docx_components_module_.GetFtrRelsAdapter(xml_file); + else if ansiContainsStr(xml_file, "header") then + rels_adapter := docx_components_module_.GetHdrRelsAdapter(xml_file); + rel := rels_adapter.GetRelationshipById(id); + image_path := "word/" + rel.Target; + image := docx_components_module_.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 ParagraphRange.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 ParagraphRange.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 / page_.BaseSize); + if (not ifnil(ppr_unit_decorator_.SnapToGrid) and not ppr_unit_decorator_.SnapToGrid) or + ((ifnil(ppr_unit_decorator_.SnapToGrid) or ppr_unit_decorator_.SnapToGrid) and lines > multi) then + multi *= lines; + return page_.SectPr.DocGrid.LinePitch * multi; + end +end; + +function ParagraphRange.SetPPPr(var p: P); +begin + new_ppr := new PPr(); + styles := docx_components_module_.GetStyles(); + new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr); + new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr); + {self.}SetPPrByStyleId(new_ppr, table_style_id_); + {self.}SetPPrByStyleId(new_ppr, p.PPr.PStyle.Val); + new_ppr.Copy(p.PPr); + p.PPr.Copy(new_ppr); +end; + +function ParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetPPrByStyleId(ppr, based_on); + ppr.Copy(style.PPr); + ppr.RPr.Copy(style.RPr); + end +end; + +function ParagraphRange.SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); +begin + new_rpr := new RPr(); + styles := docx_components_module_.GetStyles(); + new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr); + {self.}SetRPrByTblStyleId(new_rpr, table_style_id_); + {self.}SetRPrByStyleId(new_rpr, ppr_unit_decorator.PStyle.Val); + {self.}SetRPrByStyleId(new_rpr, r.RPr.RStyle.Val); + new_rpr.Copy(r.RPr); + r.RPr.Copy(new_rpr); +end; + +function ParagraphRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetRPrByTblStyleId(rpr, based_on); + rpr.Copy(style.RPr); + end + if table_style_type_ then + begin + tbl_style_pr := docx_components_module_.GetTblStylePrByType(table_style_id_, table_style_type_); + if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr); + end +end; + +function ParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetRPrByStyleId(rpr, based_on); + rpr.Copy(style.RPr); + end +end; + +function ParagraphRange.SetLvlText(); +begin + numbering_module := docx_components_module_.GetNumberingModule(); + if not ifObj(numbering_module) then return; + [lvl_text, lvl] := numbering_module.GetNumberLvl(paragraph_.PPr); + if lvl_text = "" and ifnil(lvl) then return; + {self.}SetRRPr(lvl, ppr_unit_decorator_); + rpr := new RPrUnitDecorator(lvl.RPr); + // {self.}SplitTextToTextRange(bullet_range_array_, lvl_text, rpr); + {self.}SplitTextToTextRange(body_range_array_, lvl_text, rpr); +end; + +function ParagraphRange.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 ParagraphRange.GetLastPage(): Page; +begin + return page_; +end; + +function ParagraphRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); +begin + for _,line_range in line_range_array_ do + line_range.AdjustRangeOffset(pg, x_offset, y_offset); +end; + +function ParagraphRange.GetParagraphLineRangeArr(): array of ParagraphLineRange; +begin + return line_range_array_; +end; + +function ParagraphRange.Empty(): boolean; +begin + return empty_; +end; + +function ParagraphRange.Offset(x: real; y: real); +begin + for _,line_range in line_range_array_ do + line_range.Offset(x, y); +end; + +function ParagraphRange.OMathPara(element: OMathPara); +begin + math_range := new MathRange(docx_to_pdf_, page_, element); + math_range.StartX := {self.}StartX; + math_range.StartY := {self.}StartY - 15.6; + math_range.Calc(); + // math_range.Do(); + body_range_array_[length(body_range_array_)] := math_range; +end; + +end. diff --git a/internal/DTPAdvancedRanges_bk.tsf b/internal/DTPAdvancedRanges_bk.tsf new file mode 100644 index 0000000..cc92516 --- /dev/null +++ b/internal/DTPAdvancedRanges_bk.tsf @@ -0,0 +1,2407 @@ +unit DTPAdvancedRanges; +interface +uses DTPPrimitiveRanges, DTPUtils, DTPModules, SharedML, DocxML, DrawingMLUnitDecorator, DocxMLUnitDecorator; + +type RangeCollection = class(BasicRange) +public + function Create(); + function Do();override; + function Add(range: BasicRange); + +private + range_array_: array of BasicRange; +end; + +type ParagraphLineRange = class(BasicRange) +public + function Create(pg: Page); + function Do();override; + function AddRange(range: BasicRange); + function SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); + function Align(jc: string); + function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); + function AlignRightBound(right_bound: real); + function Offset(x_offset: real; y_offset; real); + +private + range_array_: array of BasicRange; +end; + +type ParagraphRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); + function Calc(); + function Do();override; + function SetTblStyleIdAndType(style_id: string; type: string); + function SetNumPages(num: integer); + function RangesToLines(); + function GetLastPage(): Page; + function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); + function GetParagraphLineRangeArr(): array of ParagraphLineRange; + function Empty(): boolean; + function Offset(x: real; y: real); + +private + function SetPPPr(var p: P); + function SetPPrByStyleId(var ppr: PPr; style_id: string); + function SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); + function SetRPrByStyleId(var rpr: RPr; style_id: string); + function SetRPrByTblStyleId(var rpr: RPr; style_id: string); + function SetLvlText(); + function GetImageFileType(data: binary): string; + function GetImageData(id: string): PdfImage; + function GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; + function BasicRangesToParagraphLineRange(): tableArray; + function UpdateTextRangeWidth(); + function CheckAndAddPage(y: real; offset: real): boolean; + function SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: string); + function RAlternateContent(r: R); + function RDrawing(r: R); + function RFldChar(r: R; stack: Stack); + function RFootnoteReference(r: R); + function RFootnoteRef(r: R); + function RObject(r: R); + function RT(r: R; link: string); + function FldSimple(fld_simple: FldSimple); + function Hyperlink(hyperlink: Hyperlink); + + function SetLinesAlignment(); + function ResetCoordinates(); + function NewParagraphLineRange(): ParagraphLineRange; + function BookMarkLinkToc(); + function HyperlinkToToc(); + function HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator); + function GetXYCordinates(): array of real; + function AlignRightBound(); + function Init(); + function OMathPara(element: OMathPara); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]paragraph_: P; + [weakref]page_: Page; + body_range_array_: array of BasicRange; // 正文的range + bullet_range_array_: array of BasicRange; // 项目符号的range + line_range_array_: array of ParagraphLineRange; + + hyperlink_array_: tableArray; + bookmark_array_: tableArray; + ppr_unit_decorator_: PPrUnitDecorator; + placeholder_array_: tableArray; + table_style_id_: string; + table_style_type_: string; + empty_: boolean; + right_bound_: real; + footnote_reference_hash_: hash; +end; + +type TableRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; table: Tbl); + function Do();override; + function Calc(); + function GetLastPage(): Page; + function Rows(): integer; + function Cols(): integer; + function RowLowerBound(row: integer): real; + +private + function CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); + function ComputeMatrixCells(); + function ResetCoordinates(tbl_pr: TblPrUnitDecorator; grid_cols: array of GridCol); + function 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); + function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); + function OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]last_page_: Page; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]table_: Tbl; + tbl_pr_unit_decorator_: TblPrUnitDecorator; + ts_trpr_array_: array of TSTrProperty; + cell_range_matrix_: array of CellRange; + row_lower_bound_: hash; + rows_: integer; + cols_: integer; +end; + +type CellRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); + function Calc(); + function Do();override; + function SetPage(pg: Page); + function GetLastPage(); + function AlignHeight(height: real; lb: real); + function SetVAlign(); + function IsReComputeByCantSplit(): boolean; + function IfRemoveEmptyRectangle(): boolean; + function SetTop(); + + property Tc read tc_; + +private + function GetCellPrType(): string; + function SetBorderRange(range: BordersRange); + +public + RemoveFlag: boolean; + Row: integer; + Col: integer; + VMerge: integer; + [weakref]TSTrPr: TSTrProperty; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]last_page_: Page; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]tc_: Tc; + [weakref]tbl_pr_: TblPr; + tc_pr_unit_decorator_: TcPrUnitDecorator; + region_array_: array of Region; // 单元格可能跨页,所以可能存在多个 + top_: boolean; +end; + +type ColumnRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); + function AddElement(ele: Element); + function Elements(): array of Element; + function GetLastPage(): Page; + function Do();override; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]docx_components_module_: DocxComponentsModule; + [weakref]page_: Page; + elements_: array of Elements; + paragraph_: P; + last_y_: real; +end; + +type MathRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); + function Calc(); + function Do();override; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]o_math_para_: OMathPara; + sub_math_range_: SubMathRange; +end; + +type SubMathRange = class(BasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); + function Do();override; + function Calc(); + +private + function MathR(r: R; sz: real; x: real; y: real): RangeCollection; + function MathF(f: F; sz: real; x: real; y: real): RangeCollection; + function MathRad(rad: Rad; sz: real; x: real; y: real): RangeCollection; + function MathNary(nary: Nary; sz: real; x: real; y: real): RangeCollection; + function MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]ts_page_: Page; + [weakref]openxml_element_: OpenXmlElement; + range_collection_: RangeCollection; + sz_: real; +end; + +implementation + +function MathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); +begin + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + o_math_para_ := o_math_para; + sub_math_range_ := nil; + {self.}Page := pg; +end; + +function MathRange.Calc(); +begin + sub_math_range_ := new SubMathRange(docx_to_pdf_, {self.}Page, o_math_para_.OMath, 11); + sub_math_range_.StartX := {self.}StartX; + sub_math_range_.StartY := {self.}StartY; + sub_math_range_.EndX := {self.}EndX; + sub_math_range_.EndY := {self.}EndY; + sub_math_range_.DynamicHeight := 100; + sub_math_range_.Calc(); + + {self.}EndX := sub_math_range_.EndX; + {self.}EndY := sub_math_range_.EndY; + {self.}Width := sub_math_range_.Width; + {self.}DynamicHeight := sub_math_range_.DynamicHeight; +end; + +function MathRange.Do();override; +begin + sub_math_range_.Do(); +end; + +function SubMathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); +begin + class(BasicRange).Create(); + docx_to_pdf_ := docx_to_pdf; + ts_page_ := pg; + openxml_element_ := element; + {self.}Page := pg; + range_collection_ := new RangeCollection(); + sz_ := sz; +end; + +function SubMathRange.Do();override; +begin + range_collection_.Do(); +end; + +function SubMathRange.Calc(); +begin + elements := openxml_element_.Elements(); + min_y := {self.}StartY; + max_y := {self.}StartY; + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + for _,element in elements do + begin + range := nil; + if element.LocalName = "r" then + range := {self.}MathR(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "f" then + range := {self.}MathF(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "rad" then + range := {self.}MathRad(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "nary" then + range := {self.}MathNary(element, sz_, {self.}EndX, {self.}EndY); + else if element.LocalName = "sSup" then + range := {self.}MathSSup(element, sz_, {self.}EndX, {self.}EndY); + + if not ifObj(range) then + begin + echo forma("Not support <%s>\n", element.ElementName); + continue; + end + if min_y > range.EndY then min_y := range.EndY; + if max_y < range.EndY + range.DynamicHeight then max_y := range.EndY + range.DynamicHeight; + + {self.}EndX := range.EndX; + {self.}EndY := range.EndY; + {self.}Width += range.Width; + range_collection_.Add(range); + end + range_collection_.DynamicHeight := max_y - min_y; + {self.}DynamicHeight := range_collection_.DynamicHeight; +end; + +function SubMathRange.MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; +begin + prange := new RangeCollection(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + e_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.E, sz); + e_range.StartX := x; + e_range.StartY := y; + e_range.Calc(); + + sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.Sup, sz * 0.4); + sup_range.StartX := x + e_range.Width; + sup_range.StartY := y + sz * 0.57; + sup_range.Calc(); + + prange.Add(e_range); + prange.Add(sup_range); + prange.EndX := maxValue(array(e_range.EndX, sup_range.EndX)); + prange.EndY := e_range.EndY; + prange.Width := prange.EndX - prange.StartX; + prange.DynamicHeight := e_range.DynamicHeight + sup_range.DynamicHeight * 0.5; + + return prange; +end; + +function SubMathRange.MathR(r: R; sz: real; x: real; y: real): RangeCollection; +begin + // println("x = {}, y = {}", x, y); + prange := new RangeCollection(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + text := r.T.Text(); + pos := 1; + // println("text = {}", text); + while pos <= length(text) do + begin + num := Utf8CharLengthFromByte(text[pos]); + a_word := text[pos : pos+num-1]; + if num = 1 or DTPUtils.IsChineseChar(a_word) or DTPUtils.IsChinesePunctuation(a_word) then + begin + word := utf8ToAnsi(a_word); + font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", false, true); + end + else begin + word := class(SymbolMapper).SymbolChr(a_word); + if ifnil(word) then raise format("error symbol {{%s}}", a_word); + font_obj := docx_to_pdf_.Font.GetSymbolFont(); + end + rpr := new RPr(); + rpr.Sz.Val := sz; + ts_page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); + word_width := ts_page_.PdfPage.TextWidth(word); + text_range := new TextRange(); + text_range.RPr := rpr; + text_range.Text := word; + text_range.Font := font_obj; + text_range.StartX := prange.EndX; + text_range.StartY := prange.EndY; + text_range.Page := {self.}Page; + text_range.EndX := text_range.StartX; + text_range.EndY := text_range.StartY; + text_range.Width := word_width; + pos += num; + prange.Add(text_range); + prange.EndX += text_range.Width; + prange.Width += text_range.Width; + end + prange.DynamicHeight := sz; + return prange; +end; + +function SubMathRange.MathF(f: F; sz: real; x: real; y: real); +begin + prange := new ParagraphLineRange(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + den_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Den, sz); + den_range.StartX := x; + den_range.StartY := y; + den_range.Calc(); + + num_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Num, sz); + num_range.StartX := x; + num_range.StartY := y + 1.418 * sz; + num_range.Calc(); + + max_len := max(den_range.Width, num_range.Width); + bar := max_len / 0.9; + line_range := new LineRange(); + line_range.StartX := x - (bar - max_len) / 2; + line_range.StartY := y + 0.928 * sz; + line_range.EndX := line_range.StartX; + line_range.EndY := line_range.StartY; + line_range.Width := bar; + line_range.Page := {self.}Page; + line_range.LineWidth := 0.04 * sz; + + prange.EndX := maxValue(array(den_range.EndX, num_range.EndX, line_range.EndX)); + prange.AddRange(den_range); + prange.AddRange(num_range); + prange.AddRange(line_range); + + return prange; + + // TODO: delete + // pg := {self.}Page.PdfPage; + // pg.SetFontAndSize(font, sz); + // len1 := pg.TextWidth(range1.Text); + // len2 := pg.TextWidth(range2.Text); + // max_len := len1 > len2 ? len1 : len2; + // bar := max_len / 0.9; + // pg.SetLineWidth(0.05*sz); + // pg.SetRGBStroke(0, 0, 0); + // x := {self.}StartX - (bar - max_len) / 2; + // y := {self.}StartY + 0.928 * sz; + // pg.MoveTo(x, y); + // pg.LineTo(x + bar, y); + // pg.Stroke(); + + // elements := f.Den.Elements(); + // {self.}TraverseElement(elements); + // elements := f.Num.Elements(); + // {self.}TraverseElement(elements); + + // for _,element in elements do + // begin + // if + // range1 := new TextRange(); + // range1.Text := "a"; + // range1.EndX := {self.}StartX; + // range1.EndY := {self.}StartY; + // rpr := new RPr(); + // rpr.Sz.Val := sz; + // range1.RPr := rpr; + // range1.Page := {self.}Page; + // range1.Font := font; + // range1.Do(); + // end + // for _,element in elements do + // begin + // range2 := new TextRange(); + // range2.Text := "b"; + // range2.EndX := {self.}StartX; + // range2.EndY := {self.}StartY + 1.418*sz; + // rpr := new RPr(); + // rpr.Sz.Val := sz; + // range2.RPr := rpr; + // range2.Page := {self.}Page; + // range2.Font := font; + // range2.Do(); + // // if element.LocalName = "r" then + // // begin + // // range1 := new TextRange(); + // // range1.Text := element.T.Text(); + // // end + // end +end; + +function SubMathRange.MathRad(rad: Rad; sz: real; x: real; y: real): ParagraphLineRange; +begin + prange := new ParagraphLineRange(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + symbol := chr(0xD6); + symbol_font := docx_to_pdf_.Font.GetSymbolFont(); + pg := {self.}Page.PdfPage; + pg.SetFontAndSize(symbol_font, sz); + symbol_range := new TextRange(); + symbol_range.Text := symbol; + symbol_range.EndX := x; + symbol_range.EndY := y; + symbol_range.Font := symbol_font; + symbol_range.Width := pg.TextWidth(symbol); + symbol_range.RPr := new RPr(); + symbol_range.RPr.Sz.Val := sz; + symbol_range.Page := {self.}Page; + + deg_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.Deg, sz * 0.5); + deg_range.StartX := x; + deg_range.StartY := y + sz * 0.57; + deg_range.Calc(); + + e_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.E, sz); + e_range.StartX := x + symbol_range.Width; + e_range.StartY := y; + e_range.Calc(); + + line_range := new LineRange(); + line_range.StartX := x + symbol_range.Width * 0.9; + line_range.StartY := y + sz * 0.9; + line_range.EndX := line_range.StartX; + line_range.EndY := line_range.StartY; + line_range.Width := e_range.Width + symbol_range.Width / 3; + line_range.Page := {self.}Page; + line_range.LineWidth := 0.04 * sz; + + prange.EndX := maxValue(array(symbol_range.EndX, e_range.EndX, deg_range.EndX, line_range.EndX)); + prange.AddRange(symbol_range); + prange.AddRange(deg_range); + prange.AddRange(e_range); + prange.AddRange(line_range); + + return prange; + + // TODO: delete + // range := new TextRange(); + // range.Text := chr_hash_['α']; + // range.EndX := {self.}StartX; + // range.EndY := {self.}StartY + sz * 0.57; + // range.Font := symbol_font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz / 2; + // range.Page := {self.}Page; + // range.Do(); + + // range := new TextRange(); + // range.Text := "abcd"; + // range.EndX := {self.}StartX + symbol_w; + // range.EndY := {self.}StartY; + // range.Font := font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz; + // range.Page := {self.}Page; + // range.Do(); + + // pg.SetFontAndSize(font, sz); + // pg.SetLineWidth(0.04*sz); + // pg.SetRGBStroke(0, 0, 0); + // x := {self.}StartX + symbol_w * 0.9; + // y := {self.}StartY + sz * 0.9; + // pg.MoveTo(x, y); + // pg.LineTo(x + pg.TextWidth(range.Text)+symbol_w/3, y); + // pg.Stroke(); + +end; + +function SubMathRange.MathNary(nary: Nary; sz: real; x: real; y: real): ParagraphLineRange; +begin + prange := new ParagraphLineRange(); + prange.StartX := x; + prange.StartY := y; + prange.EndX := x; + prange.EndY := y; + + val := nary.NaryPr.Chr.Val ?: "Į"; + symbol := class(SymbolMapper).SymbolChr(val); + if ifnil(symbol) then raise format("error = %s", val); + symbol_font := docx_to_pdf_.Font.GetSymbolFont(); + pg := {self.}Page.PdfPage; + pg.SetFontAndSize(symbol_font, sz * 1.5); + symbol_range := new TextRange(); + symbol_range.Text := symbol; + symbol_range.EndX := x; + symbol_range.EndY := y; + symbol_range.Font := symbol_font; + symbol_range.RPr := new DocxML.RPr(); + symbol_range.RPr.Sz.Val := 1.5 * sz; + symbol_range.Page := {self.}Page; + symbol_range.Width := pg.TextWidth(symbol); + + if nary.NaryPr.LimLoc.Val = "subSup" then + begin + sup_start_x := x + symbol_range.Width * 1.2; + sup_start_y := y + sz * 1.5 * 0.73; + sub_start_x := x + symbol_range.Width * 0.7; + sub_start_y := y - sz * 1.5 * 0.2; + end + // else if nary.Nary.LimLoc.Val = "undOvr" then + else begin // undOvr + sup_start_x := x + symbol_range.Width * 0.5; + sup_start_y := y + sz * 1.5 * 0.8; + sub_start_x := x; + sub_start_y := y - sz * 1.5 * 0.5; + end + + sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sup, sz * 0.7); + sup_range.StartX := sup_start_x; + sup_range.StartY := sup_start_y; + sup_range.Calc(); + + sub_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sub, sz * 0.7); + sub_range.StartX := sub_start_x; + sub_range.StartY := sub_start_y; + sub_range.Calc(); + + if nary.NaryPr.LimLoc.Val = "subSup" then + begin + e_start_x := x + symbol_range.Width * 0.5 + max(sup_range.Width, sub_range.Width); + e_start_y := y + sz * 0.3; + end + else begin + e_start_x := x + symbol_range.Width; + e_start_y := y + sz * 0.3; + end + + e_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.E, sz); + e_range.StartX := e_start_x; + e_range.StartY := e_start_y; + e_range.Calc(); + + prange.EndX := maxValue(array(symbol_range.EndX, sup_range.EndX, sub_range.EndX, e_range.EndX)); + prange.AddRange(symbol_range); + prange.AddRange(sup_range); + prange.AddRange(sub_range); + prange.AddRange(e_range); + + return prange; + // TODO: delete + // val := nary.NaryPr.Chr.Val; + // symbol := class(SymbolMapper).SymbolChr(nary.NaryPr.Chr.Val); + // sz := 11; + // symbol_font := docx_to_pdf_.PdfFile().GetFont("Symbol", ""); + // symbol_range := new TextRange(); + // symbol_range.Text := symbol; + // symbol_range.EndX := {self.}StartX; + // symbol_range.EndY := {self.}StartY; + // symbol_range.Font := symbol_font; + // symbol_range.RPr := new RPr(); + // symbol_range.RPr.Sz.Val := 1.5 * sz; + // symbol_range.Page := {self.}Page; + // symbol_range.Do(); + + // pg := {self.}Page.PdfPage; + // pg.SetFontAndSize(symbol_font, sz * 1.5); + // symbol_w := pg.TextWidth(symbol); + // font := docx_to_pdf_.PdfFile().GetFont("SimSun,Italic", "GBK-EUC-H"); + + // range := new TextRange(); + // range.Text := chr_hash_["∞"]; + // range.EndX := {self.}StartX + symbol_w / 5; + // range.EndY := {self.}StartY + sz * 0.8 * 1.5; + // range.Font := symbol_font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz * 0.7; + // range.Page := {self.}Page; + // range.Do(); + + // range := new TextRange(); + // range.Text := "n=1"; + // pg.SetFontAndSize(font, sz*0.7); + // tw := pg.TextWidth(range.Text); + // range.EndX := {self.}StartX + (symbol_w - tw)/2; + // range.EndY := {self.}StartY - sz * 0.5 * 1.5; + // range.Font := font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz * 0.7; + // range.Page := {self.}Page; + // range.Do(); + + // range := new TextRange(); + // range.Text := chr_hash_["f"]; + // pg.SetFontAndSize(font, sz); + // tw := pg.TextWidth(range.Text); + // range.EndX := {self.}StartX + symbol_w; + // range.EndY := {self.}StartY + sz * 0.3; + // range.Font := symbol_font; + // range.RPr := new RPr(); + // range.RPr.Sz.Val := sz; + // range.Page := {self.}Page; + // range.Do(); + +end; + +// ColumnRange +function ColumnRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); +begin + docx_to_pdf_ := docx_to_pdf; + page_ := pg; + docx_components_module_ := components; + elements_ := array(); + last_y_ := 0; +end; + +function ColumnRange.AddElement(ele: Element); +begin + elements_[length(elements_)] := ele; +end; + +function ColumnRange.Elements(): array of Element; +begin + return elements_; +end; + +function ColumnRange.Do();override; +begin + x := {self.}StartX; + y := {self.}StartY; + for _,element in elements_ do + begin + range := nil; + if element.LocalName = "p" then + range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); + else if element.LocalName = "tbl" then + range := new TableRange(docx_to_pdf_, page_, docx_components_module_, element); + if ifnil(range) then continue; + range.StartX := x; + range.StartY := y; + range.Width := {self.}Width; + range.LowerBound := {self.}LowerBound; + range.Calc(); + range.Do(); + y := range.EndY; + page_ := range.GetLastPage(); + end + {self.}EndY := y; +end; + +function ColumnRange.GetLastPage(): Page; +begin + return page_; +end; + +// TableRange +function TableRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: Components; table: Tbl); +begin + docx_to_pdf_ := docx_to_pdf; + last_page_ := pg; + docx_components_module_ := Components; + table_ := table; + ts_trpr_array_ := array(); + cell_range_matrix_ := array(); + row_lower_bound_ := array(); + rows_ := 0; + cols_ := 0; + {self.}Page := last_page_; +end; + +function TableRange.Calc(); +begin + {self.}SetTblTblPr(table_); + tbl_pr_unit_decorator_ := new TblPrUnitDecorator(table_.TblPr); + tbl_grid_unit_decorator := new TblGridUnitDecorator(table_.TblGrid); + grid_cols := tbl_grid_unit_decorator.GridCols(); + {self.}ResetCoordinates(tbl_pr_unit_decorator_, grid_cols); + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + // 如果是根据内容自适应,应该计算并调整grid_cols的值 + trs := table_.Trs(); + rows_ := length(trs); + cols_ := length(grid_cols); + cell_range_matrix_ := nils(rows_, cols_); + // 先构建一个矩阵 + {self.}CreateTableMatrix(grid_cols, trs); + // 遍历矩阵后进行计算合并 + {self.}ComputeMatrixCells(); +end; + +function TableRange.Do();override; +begin + for _,row in cell_range_matrix_ do + begin + flag := nil; + for __,range in row do + begin + if ifnil(flag) and ifObj(range) then flag := range.IfRemoveEmptyRectangle(); + if not ifObj(range) then continue; + if flag <> range.IfRemoveEmptyRectangle() then + begin + flag := false; + break; + end + end + for __,range in row do + begin + if ifObj(range) then + begin + range.RemoveFlag := flag; + range.Do(); + end + end + end +end; + +function TableRange.CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); +begin + for i,tr in trs do + begin + {self.}SetTrTrPr(tr); + tr_pr := new TrPrUnitDecorator(tr.TrPr); + tc_x := {self.}EndX; + tcs := tr.Tcs(); + trp := new DTPUtils.TrProperty(); + trp.TrPr := tr_pr; + ts_trpr_array_[i] := trp; + pos := 0; + for j,tc in tcs do + begin + {self.}SetTcTcPr(tc); + if i = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "firstRow"); + else if i = length(trs)-1 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "lastRow") + else if (i + 1) % 2 = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band1Horz"); + else {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band2Horz"); + + grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan); + if tc.TcPr.VMerge and tc.TcPr.VMerge <> "restart" then + begin + tc_x += grid_cols[pos++].W; + for k:=grid_span.Val-1 downto 1 do + begin + cell_range_matrix_[i][pos] := 0; + tc_x += grid_cols[pos++].W; + end + continue; + end + cell_range := new CellRange(docx_to_pdf_, last_page_, docx_components_module_, tc, tbl_pr_unit_decorator_, trp); + cell_range.StartX := tc_x; + cell_range.Width := grid_cols[pos].W; + cell_range.LowerBound := {self.}LowerBound; + cell_range.FixedHeight := tr_pr.TrHeight.Val; + cell_range.Parent := self; + cell_range.Row := i; + cell_range.Col := pos; + cell_range_matrix_[i][pos] := cell_range; + pos++; + // 水平合并的单元格,占位需要和垂直的区分 + for k:=grid_span.Val-1 downto 1 do + begin + cell_range_matrix_[i][pos] := 0; + cell_range.Width += grid_cols[pos++].W; + end + tc_x += cell_range.Width; + end + end + + // for i,arr in cell_range_matrix_ do + // println("i = {}, arr = {}", i, arr); + // println("\n"); + return; +end; + +function TableRange.ComputeMatrixCells(); +begin + i := 0; + merge_arr := array(); + vmerge_height := array(); + while i < rows_ do + begin + j := 0; + tc_y := {self.}EndY; + recompute_flag := false; + while j < cols_ do + begin + range := cell_range_matrix_[i][j]; + if not ifObj(range) then + begin + j++; + continue; + end + range.StartY := tc_y; + range.SetPage(last_page_); + range.Calc(); + if range.IsReComputeByCantSplit() then + begin + // 调整上一行的下边界 + arr := cell_range_matrix_[i-1]; + for _,r in arr do + begin + if ifnil(r) then + begin + pos := i-2; + while pos > 0 do + begin + rr := cell_range_matrix_[pos][_]; + pos--; + if ifnil(rr) then continue; + rr.LowerBound := tc_y; + break; + end + end + if not ifnil(r) then r.LowerBound := tc_y; + end + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + [x, y] := docx_to_pdf_.CalculateTextCoordinates(); + {self.}EndY := y; + j := 0; + recompute_flag := true; + arr := cell_range_matrix_[i]; + for _,r in arr do + if not ifnil(r) then r.SetTop(); + break; + end + if range.Tc.TcPr.VMerge then + begin + b_merge_index := i; + e_merge_index := i + 1; + while ifnil(cell_range_matrix_[e_merge_index+1][j]) and e_merge_index < rows_-1 do + e_merge_index++; + merge_arr[e_merge_index][j] := b_merge_index; + range.VMerge := e_merge_index; + if ifnil(vmerge_height[e_merge_index]) or range.DynamicHeight > vmerge_height[e_merge_index] then + vmerge_height[e_merge_index] := range.DynamicHeight; + end + j++; + end + if recompute_flag then continue; + i_height := 0; + for k,v in merge_arr[i] do + begin + i_height := ts_trpr_array_[i].Height; + r := cell_range_matrix_[v][k]; + total_height := 0; + for index:=v to i-1 do + total_height += ts_trpr_array_[index].Height; + h := vmerge_height[i]; + if h > total_height + i_height then + i_height := h - total_height; + else + h := total_height + i_height; + r.AlignHeight(h, row_lower_bound_[i-1]); + r.SetVAlign(); + end + if i_height then ts_trpr_array_[i].Height := i_height; + for _,range in cell_range_matrix_[i] do + begin + if not ifObj(range) or range.Tc.TcPr.VMerge then continue; + range.AlignHeight(ts_trpr_array_[i].Height, row_lower_bound_[i]); + range.SetVAlign(); + {self.}EndY := range.EndY; + last_page_ := range.GetLastPage(); + row_lower_bound_[i] := range.LowerBound; + end + i++; + end +end; + +function TableRange.RowLowerBound(row: integer): real; +begin + return row_lower_bound_[row]; +end; + +function TableRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); +begin + // tc_pr应该是经过外层copy的 + tbl_style_pr := docx_components_module_.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type); + if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr); +end; + +function TableRange.ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol); +begin + total_width := 0; + for _,grid_col in grid_cols do + total_width += grid_col.W; + diff := total_width - {self.}Width; + case tbl_pr.Jc.Val of + "center": + begin + offset := diff/2; + {self.}StartX -= offset; + end + "right": + begin + {self.}StartX -= diff; + end + end; + {self.}Width := total_width; +end; + +function TableRange.SetTblTblPr(var tbl: Tbl); +begin + new_tbl_pr := new TblPr(); + {self.}SetTblPrByStyleId(new_tbl_pr, tbl.TblPr.TblStyle.Val); + new_tbl_pr.Copy(tbl.TblPr); + tbl.TblPr.Copy(new_tbl_pr); +end; + +function TableRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetTblPrByStyleId(tbl_pr, based_on); + tbl_pr.Copy(style.TblPr); + end +end; + +function TableRange.SetTrTrPr(var tr: Tr); +begin + new_tr_pr := new TrPr(); + {self.}SetTrPrByStyleId(new_tr_pr, tbl_pr_unit_decorator_.TblStyle.Val); + new_tr_pr.Copy(tr.TrPr); + tr.TrPr.Copy(new_tr_pr); +end; + +function TableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetTrPrByStyleId(tr_pr, based_on); + tr_pr.Copy(style.TrPr); + end +end; + +function TableRange.SetTcTcPr(var tc: Tc); +begin + new_tc_pr := new TcPr(); + {self.}SetTcPrByStyleId(new_tc_pr, tbl_pr_unit_decorator_.TblStyle.Val); + new_tc_pr.Copy(tc.TcPr); + tc.TcPr.Copy(new_tc_pr); +end; + +function TableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetTcPrByStyleId(tc_pr, based_on); + tc_pr.Copy(style.TcPr); + end +end; + +function TableRange.GetLastPage(): Page; +begin + return last_page_; +end; + +function TableRange.Rows(): integer; +begin + return rows_; +end; + +function TableRange.Cols(): integer; +begin + return cols_; +end; + +// CellRange +function CellRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: TSDocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); +begin + docx_to_pdf_ := docx_to_pdf; + last_page_ := pg; + docx_components_module_ := components; + tc_ := tc; + tbl_pr_ := tbl_pr; + region_array_ := array(); + top_ := false; + tc_pr_unit_decorator_ := new TcPrUnitDecorator(tc_.TcPr); + {self.}TSTrPr := trp; + {self.}Tc := tc; + {self.}VMerge := 1; + {self.}Page := last_page_; +end; + +function CellRange.Calc(); +begin + region_array_ := array(); + region := new DTPUtils.Region(); + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := {self.}StartY; + region.BordersRange.Width := {self.}Width; + region.BordersRange.FixedHeight := {self.}FixedHeight; + region.BordersRange.Page := last_page_; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}DynamicHeight := 0; + cell_x := {self.}EndX + tbl_pr_.TblCellMar.Left.W; + cell_y := {self.}EndY - tbl_pr_.TblCellMar.Top.W; + cell_w := {self.}Width - tbl_pr_.TblCellMar.Right.W - tbl_pr_.TblCellMar.Left.W; + cell_h := {self.}FixedHeight; + elements := tc_.Elements(); + for _,element in elements do + begin + range := nil; + if element.LocalName = "p" then + begin + range := new ParagraphRange(docx_to_pdf_, last_page_, docx_components_module_, element); + range.SetTblStyleIdAndType(tbl_pr_.TblStyle.Val, {self.}GetCellPrType()); + end + else if element.LocalName = "tbl" then + begin + range := new TableRange(docx_to_pdf_, last_page_, docx_components_module_, element); + continue; // TODO:表中表存在不可靠问题 + end + if ifObj(range) then + begin + range.StartX := cell_x; + range.StartY := cell_y; + range.Width := cell_w; + range.FixedHeight := cell_h; + range.LowerBound := {self.}LowerBound; + range.Parent := self; + range.Calc(); + region.RangeArr[length(region.RangeArr)] := range; + {self.}DynamicHeight += range.DynamicHeight; + cell_y := range.EndY; + last_page_ := range.GetLastPage(); + end + end + {self.}EndY := cell_y - tbl_pr_.TblCellMar.Bottom.W; + {self.}DynamicHeight += tbl_pr_.TblCellMar.Top.W + tbl_pr_.TblCellMar.Bottom.W; + + if {self.}EndY < {self.}LowerBound and not range.Empty() then + begin + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + if ifnil(last_page_) then last_page_ := docx_to_pdf_.AddPage(); + {self.}StartY := last_page_.TextPoint.Y; + {self.}Calc(); + end + if {self.}TSTrPr.TrPr.TrHeight.HRule <> "exact" and {self.}DynamicHeight > {self.}FixedHeight then + begin + region.BordersRange.FixedHeight := {self.}DynamicHeight; + {self.}FixedHeight := {self.}DynamicHeight; + end + if not {self.}Tc.TcPr.VMerge and {self.}DynamicHeight > {self.}TSTrPr.Height then + {self.}TSTrPr.Height := {self.}DynamicHeight; +end; + +function CellRange.Do();override; +begin + for _,region in region_array_ do + begin + if _ = 0 and {self.}RemoveFlag then continue; + // println("Row = {}, Col = {}", {self.}Row, {self.}Col); + region.BordersRange.Do(); + for _,range in region.RangeArr do + range.Do(); + end +end; + +function CellRange.SetPage(pg: Page); +begin + last_page_ := pg; + {self.}Page := pg; +end; + +function CellRange.AlignHeight(height: real; lb: real); +begin + region := region_array_[0]; + y_lowerbound := {self.}StartY - {self.}LowerBound; + surplus := height - y_lowerbound; + if surplus < 1e-6 then + begin + region.BordersRange.DynamicHeight := height; + {self.}SetBorderRange(region.BordersRange); + {self.}EndY := {self.}StartY - region.BordersRange.DynamicHeight; + {self.}LowerBound := {self.}StartY - height; + return; + end + // if lb then y_lowerbound := {self.}StartY - lb; + region.BordersRange.DynamicHeight := y_lowerbound; + arr := region.RangeArr; + region.RangeArr := array(); + hash := array(region.BordersRange.Page.Index: region); + last_page_ := {self.}Page; + [x, y] := last_page_.OriginalTextCoordinates(); + span := y - last_page_.FtrPoint.Y; + while surplus > span do + begin + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + region := new DTPUtils.Region(); + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := y; + region.BordersRange.Width := {self.}Width; + region.BordersRange.DynamicHeight := span; + region.BordersRange.Page := last_page_; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + region.BordersRange.Top := true; + region.BordersRange.Bottom := true; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + surplus -= span; + hash[region.BordersRange.Page.Index] := region; + end + if surplus > 1e-6 then + begin + last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; + region := new DTPUtils.Region(); + region.BordersRange.EndX := {self.}StartX; + region.BordersRange.EndY := y; + region.BordersRange.Width := {self.}Width; + region.BordersRange.DynamicHeight := surplus; + region.BordersRange.Page := last_page_; + region.BordersRange.TcPr := tc_pr_unit_decorator_; + region.BordersRange.Top := true; + {self.}SetBorderRange(region.BordersRange); + region_array_[length(region_array_)] := region; + hash[region.BordersRange.Page.Index] := region; + {self.}EndY := region.BordersRange.EndY - surplus; + end + for _,range in arr do + begin + if range is class(ParagraphRange) then + begin + line_arr := range.GetParagraphLineRangeArr(); + for _,r in line_arr do + begin + region := hash[r.Page.Index]; + region.RangeArr[length(region.RangeArr)] := r; + end + end + end +end; + +function CellRange.GetLastPage(); +begin + return last_page_; +end; + +function CellRange.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) - tbl_pr_.TblCellMar.Bottom.W; + case val of + "center": + begin + offset /= 2; + for _,range in arr do + range.AdjustRangeOffset(region.BordersRange.Page, nil, -offset); + end + end; +end; + +function CellRange.IsReComputeByCantSplit(): boolean; +begin + if {self.}Tc.TcPr.VMerge then return false; + return {self.}TSTrPr.TrPr.CantSplit and last_page_ <> {self.}Page; +end; + +function CellRange.IfRemoveEmptyRectangle(): boolean; +begin + if length(region_array_) < 2 then return false; + return length(region_array_[0].RangeArr) ? false : true; +end; + +function CellRange.GetCellPrType(): string; +begin + if {self.}Row = 0 then return "firstRow"; + else if ({self.}Row + 1) % 2 = 0 then return "band1Horz"; + else return "band2Horz"; +end; + +function CellRange.SetBorderRange(range: BordersRange); +begin + if top_ then range.Top := true; + if ifObj(tbl_pr_.TblBorders) then + begin + if {self.}Row = 0 then + begin + if tbl_pr_.TblBorders.Top then + begin + if not tc_pr_unit_decorator_.TcBorders.Top then + tc_pr_unit_decorator_.TcBorders.Top.Copy(tbl_pr_.TblBorders.Top); + range.Top := true; + end + if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); + range.Right := true; + end + if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); + range.Bottom := true; + end + end + else if {self.}Row = {self.}Parent.Rows()-1 then + begin + if tbl_pr_.TblBorders.Bottom then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); + range.Right := true; + end + end + else begin + if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Bottom then + tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); + range.Bottom := true; + end + if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); + range.Right := true; + end + end + + if {self.}Col = 0 then + begin + if tbl_pr_.TblBorders.Left then + begin + if not tc_pr_unit_decorator_.TcBorders.Left then + tc_pr_unit_decorator_.TcBorders.Left.Copy(tbl_pr_.TblBorders.Left); + range.Left := true; + end + end + if {self.}Col = {self.}Parent.Cols()-1 then + begin + if tbl_pr_.TblBorders.Right then + begin + if not tc_pr_unit_decorator_.TcBorders.Right then + tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.Right); + range.Right := true; + end + end + end + else begin + range.Left := {self.}Col = 0; + range.Top := {self.}Row = 0; + range.Right := true; + range.Bottom := true; + end +end; + +function CellRange.SetTop(); +begin + top_ := true; +end; + +// RangeCollection; +function RangeCollection.Create(); +begin + class(BasicRange).Create(); + range_array_ := array(); +end; + +function RangeCollection.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function RangeCollection.Add(range: BasicRange); +begin + range_array_[length(range_array_)] := range; +end; + +// ParagraphLineRange +function ParagraphLineRange.Create(pg: Page); +begin + class(BasicRange).Create(); + {self.}Page := pg; + range_array_ := array(); +end; + +function ParagraphLineRange.AddRange(range: BasicRange); +begin + range_array_[length(range_array_)] := range; +end; + +function ParagraphLineRange.Do();override; +begin + for _,range in range_array_ do + range.Do(); +end; + +function ParagraphLineRange.SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); +begin + for _,range in range_array_ do + begin + if not ifnil(pg) then range.Page := pg; + if not ifnil(sx) then range.StartX := sx; + if not ifnil(sy) then range.StartY := sy; + if not ifnil(ex) then range.EndX := ex; + if not ifnil(ey) then range.EndY := ey; + if not ifnil(w) then range.Width := w; + if not ifnil(fh) then range.FixedHeight := fh; + if not ifnil(dh) then range.DynamicHeight := dh; + end +end; + +function ParagraphLineRange.Align(jc: string); +begin + offset := 0; + first := range_array_[0]; + last := range_array_[length(range_array_)-1]; + case jc of + "center": + offset := ({self.}Width + StartX - last.EndX - last.Width) / 2; + "right": + offset := {self.}Width - last.EndX + first.EndX - last.Width; + end; + if offset <= 0 then return; + for _,range in range_array_ do + range.EndX += offset; +end; + +function ParagraphLineRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); +begin + if pg <> {self.}Page then return; + for _,range in range_array_ do + begin + if not ifnil(x_offset) then range.EndX += x_offset; + if not ifnil(y_offset) then range.EndY += y_offset; + end; +end; + +function ParagraphLineRange.AlignRightBound(right_bound: real); +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 ParagraphLineRange.Offset(x_offset: real; y_offset; real); +begin + for _,range in range_array_ do + begin + range.EndX += x_offset; + range.EndY -= y_offset; + end +end; + + +// ParagraphRange +function ParagraphRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); +begin + docx_to_pdf_ := docx_to_pdf; + page_ := pg; + docx_components_module_ := components; + paragraph_ := paragraph; + table_style_id_ := ""; + table_style_type_ := ""; + body_range_array_ := array(); + bullet_range_array_ := array(); + line_range_array_ := array(); + hyperlink_array_ := array(); + bookmark_array_ := array(); + empty_ := false; + {self.}Page := page_; + footnote_reference_hash_ := array(); +end; + +function ParagraphRange.Init(); +begin + body_range_array_ := array(); + right_bound_ := {self.}StartX + {self.}Width; + {self.}ResetCoordinates(); + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before); + {self.}EndY -= ppr_unit_decorator_.Spacing.Before; + {self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before; + + // TODO:项目符号应该单独写入 + {self.}SetLvlText(); +end; + +function ParagraphRange.Calc(): tableArray; +begin + // ppr.rpr是无效的,应该以ppr.pStyle为准 + {self.}SetPPPr(paragraph_); + ppr_unit_decorator_ := new DocxMLUnitDecorator.PPrUnitDecorator(paragraph_.PPr); + {self.}Init(); + 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); + + elements := paragraph_.Elements(); + empty_flag := true; + bookmark_id := ''; + bookmark_name := ''; + bookmark_flag := false; + fld_stack := new DTPUtils.Stack(); + for _,element in elements do + begin + // println("LocalName = {}", element.LocalName); + if element.LocalName = "r" then + begin + empty_flag := false; + {self.}SetRRPr(element, ppr_unit_decorator_); + + if element.FldChar.FldCharType = "begin" then + begin + fld_struct := new DTPUtils.FldStruct(); + fld_stack.Push(fld_struct); + 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; + else if element.Drawing then {self.}RDrawing(element); + else if element.AlternateContent then {self.}RAlternateContent(element); + else if element.FootnoteReference then {self.}RFootnoteReference(element); + else if element.Object then {self.}RObject(element); + else if element.FootnoteRef then {self.}RFootnoteRef(element); + else if element.Anchor then {self.}Hyperlink(element); // + else if element.T then {self.}RT(element, bookmark_name); + end + else if element.LocalName = "fldSimple" then + begin + {self.}FldSimple(element); + end + else if element.LocalName = "hyperlink" then + begin + empty_flag := false; + {self.}Hyperlink(element); + end + else if element.LocalName = "bookmarkStart" then + begin + bookmark_id := element.Id; + bookmark_name := element.Name; + bookmark_array_[bookmark_name] := array(); + end + else if element.LocalName = "bookmarkEnd" then + begin + bookmark_id := ''; + bookmark_name := ''; + end + else if element.LocalName = "oMathPara" then + begin + {self.}OMathPara(element); + end + else if element.LocalName = "oMath" then + begin + o_math_para := new OMathPara(); + o_math_para.XmlChildOMath := element; + // o_math_para.OMath.Copy(element); + {self.}OMathPara(o_math_para); + end + end + if empty_flag then + begin + line_space := {self.}GetParagraphLineSpace(ppr_unit_decorator_.RPr.Sz.Val, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule); + {self.}DynamicHeight += line_space; + {self.}EndY -= {self.}DynamicHeight; + empty_ := true; + end + if placeholder_array_ then return false; + {self.}RangesToLines(); + if hyperlink_array_ then {self.}HyperlinkToToc(); + if bookmark_array_ then {self.}BookMarkLinkToc(); + return true; +end; + +function ParagraphRange.SetNumPages(num: integer); +begin + text := tostring(num); + last_index := length(body_range_array_); + {self.}SplitTextToTextRange(body_range_array_, text, placeholder_array_[1], link); + arr := array(); + len := length(body_range_array_); + for i:=last_index to len-1 do + arr[length(arr)] := body_range_array_[i]; + diff := len - last_index; + for i:=len-1 downto placeholder_array_[0] do + body_range_array_[i] := body_range_array_[i-diff]; + k := 0; + for i:=placeholder_array_[0] to placeholder_array_[0]+diff-1 do + body_range_array_[i] := arr[k++]; +end; + +function ParagraphRange.BookMarkLinkToc(); +begin + for name,arr in bookmark_array_ do + if arr[0] then docx_to_pdf_.Toc.LinkToToc(name, arr[0].Page, arr[0].EndX, arr[0].EndY + arr[0].RPr.Sz.Val); +end; + +function ParagraphRange.HyperlinkToToc(); +begin + ppr := ppr_unit_decorator_; + max_size := 0; + for anchor,arr in hyperlink_array_ do // 整理hyperlink发送到docx_to_pdf_ + begin + pg := arr[0].Page; + left := {self.}StartX; + right := {self.}StartX + {self.}Width; + top := {self.}StartY; + bottom := {self.}StartY; + x := arr[0].EndX; + y := arr[0].EndY; + if top - {self.}GetParagraphLineSpace(arr[0].RPr.Sz.Val, ppr.Spacing.Line, ppr.Spacing.LineRule) then + begin + top := pg.TextPoint.Y; + bottom := top; + end + for _,range in arr do + begin + if x + range.Width - {self.}StartX > {self.}Width + 1e-6 then // 换行 + begin + line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); + bottom -= line_space; + max_size := 0; + if range.Page <> pg then + begin + rect := array(left, bottom, right, top); + toc := new DTPModules.Toc(ppr, rect, pg, x, y); + docx_to_pdf_.Toc.AddToc(anchor, toc); + pg := range.Page; + bottom := {self.}StartY; + end + end + if range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; + x := range.EndX + range.Width; + y := range.EndY; + end + font_name := ppr.RPr.RFonts.EastAsia ? ppr.RPr.RFonts.EastAsia : ppr.RPr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, ppr.RPr.B, ppr.RPr.I); + line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); + pg.PdfPage.SetFontAndSize(font_obj, max_size); + bottom -= line_space; + num_width := pg.PdfPage.TextWidth("." + tostring(pg.Number)); + if x + num_width - {self.}StartX > {self.}Width + 1e-6 then // 换行 + begin + offset := (line_space - max_size) / 2 + max_size - max_size / 5; + diff := {self.}EndY - {self.}LowerBound; + if {self.}CheckAndAddPage({self.}EndY, line_space) then + begin + {self.}DynamicHeight += diff; + pg := page_; + rect := array(left, bottom, right, top); + toc := new TSToc(ppr, rect, pg, x, y); + docx_to_pdf_.Toc.AddToc(anchor, toc); + bottom := {self.}StartY; + end + else begin + bottom -= line_space; + x := {self.}StartX; + y := {self.}EndY - offset; + {self.}EndY -= line_space; + {self.}DynamicHeight += line_space; + end + end + rect := array(left, bottom, right, top); + toc := new DTPModules.Toc(ppr, rect, pg, x, y, font_obj); + docx_to_pdf_.Toc.AddToc(anchor, toc); + end +end; + +function ParagraphRange.FldSimple(fld_simple: FldSimple); +begin + if fld_simple.Instr then + begin + fields := str2array(fld_simple.Instr, " "); + fld_struct := new DTPUtils.FldStruct2(); + 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_unit_decorator_); + rpr := new RPrUnitDecorator(r.RPr); + if fld_struct.Type.NumPages then + begin + if fld_struct.Arabic then + begin + placeholder_array_ := array(length(body_range_array_), rpr); + end + end +end; + +function ParagraphRange.Hyperlink(hyperlink: Hyperlink); +begin + i := length(body_range_array_); + rs := hyperlink.Rs(); + separate := false; + stack := new DTPUtils.Stack(); + for _,r in rs do + begin + if r.FldChar.FldCharType = "begin" then + begin + fld_struct := new FldStruct2(); + stack.Push(fld_struct); + end + // if r.InstrText.Text + else if r.FldChar.FldCharType = "end" then + begin + 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); + end + else if stack.Empty() then + begin + {self.}SetRRPr(r, ppr_unit_decorator_); + r.RPr.Color.Val := nil; + {self.}RT(r, hyperlink.Anchor); + end + end + arr := array(); + while i < length(body_range_array_) do + begin + arr[length(arr)] := body_range_array_[i]; + i++; + end + hyperlink_array_[hyperlink.Anchor] := arr; +end; + +function ParagraphRange.Do();override; +begin + for _,line_range in line_range_array_ do + line_range.Do(); +end; + +function ParagraphRange.SetTblStyleIdAndType(style_id: string; type: string); +begin + table_style_id_ := style_id; + table_style_type_ := type; +end; + +function ParagraphRange.NewParagraphLineRange(): ParagraphLineRange; +begin + line_range := new ParagraphLineRange(page_); + line_range.StartX := {self.}StartX; + line_range.StartY := {self.}EndY; + line_range.Width := {self.}Width; + return line_range; +end; + +function ParagraphRange.UpdateTextRangeWidth(); +begin + head_range := body_range_array_[0]; + i := 1; + while i < length(body_range_array_) do + begin + 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 last_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 ParagraphRange.RangesToLines();overload; +begin + {self.}UpdateTextRangeWidth(); + {self.}BasicRangesToParagraphLineRange(); + {self.}DynamicHeight += ppr_unit_decorator_.Spacing.After; + {self.}EndY -= ppr_unit_decorator_.Spacing.After; + if not {self.}Empty() and ppr_unit_decorator_.PBdr.Bottom.Val = "single" then + begin + sect_pr := page_.SectPr; + page_.PdfPage.SetLineWidth(0.05); + page_.PdfPage.SetGrayStroke(0.25); + page_.PdfPage.MoveTo(sect_pr.PgMar.Left, {self.}EndY); + page_.PdfPage.LineTo(sect_pr.PgSz.W - sect_pr.PgMar.Right, {self.}EndY); + page_.PdfPage.Stroke(); + end +end; + +function ParagraphRange.BasicRangesToParagraphLineRange(); +begin + ppr := ppr_unit_decorator_; + line_range := {self.}NewParagraphLineRange(); + i := 0; + max_size := 0; + max_y := 0; + while i <= length(body_range_array_)-1 do + begin + range := body_range_array_[i]; + if i = 0 then {self.}EndX += ppr.Ind.FirstLine; + if range is class(TextRange) and range.RPr.Sz.Val > max_size then + max_size := range.RPr.Sz.Val; + if range.DynamicHeight > max_y then max_y := range.DynamicHeight; + line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); + diff := {self.}EndY - {self.}LowerBound; + if {self.}CheckAndAddPage({self.}EndY, max(line_space, range.DynamicHeight)) then + {self.}DynamicHeight += diff; + if_newline := {self.}EndX + range.Width - {self.}StartX > {self.}Width + 1e-6; + if i = 0 then if_newline := 0; + if if_newline and (range is class(TextRange)) and (AnsiToUtf8(range.Text) in array(";", ":", "。", "“", "”", "!", "?", ",")) then + if_newline := 0; + if if_newline and range.Width < {self.}Width then + begin + offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; + max_value := max(line_space, max_y); + line_range.Page := page_; + line_range.EndY := {self.}EndY - max_value; + line_range.DynamicHeight := max_value; + line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); + line_range_array_[length(line_range_array_)] := line_range; + + line_range := {self.}NewParagraphLineRange(); + max_size := 0; + max_y := 0; + {self.}DynamicHeight += max_value; + {self.}EndY -= max_value; + {self.}EndX := {self.}StartX; + // w:hanging + if range is class(TextRange) then + sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); + else + sz := docx_to_pdf_.Font.GetDefaultSz(); + {self.}EndX -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging; + continue; + end + range.EndX := {self.}EndX - range.StartX; + {self.}EndX += range.Width; + line_range.AddRange(range); + i++; + if i = length(body_range_array_) then + begin + offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; + max_value := max(line_space, max_y); + line_range.Page := page_; + line_range.EndY := {self.}EndY - max_value; + line_range.DynamicHeight := max_value; + line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); + line_range_array_[length(line_range_array_)] := line_range; + {self.}DynamicHeight += max_value; + {self.}EndY -= max_value; + end + end + {self.}SetLinesAlignment(); + if not {self.}Parent is class(CellRange) then + {self.}AlignRightBound(); +end; + +function ParagraphRange.SetLinesAlignment(); +begin + for _,line_range in line_range_array_ do + line_range.Align(ppr_unit_decorator_.Jc.Val); +end; + +function ParagraphRange.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 ParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; +begin + if y - offset < {self.}LowerBound then + begin + page_ := docx_to_pdf_.PageManager[page_.Index + 1]; + if ifnil(page_) then page_ := docx_to_pdf_.AddPage(); + {self.}EndY := page_.TextPoint.Y; + return true; + end + return false; +end; + +function ParagraphRange.RT(r: R; link: string); +begin + rpr := new RPrUnitDecorator(r.RPr); + text := r.T.Text; + if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, link); +end; + +function ParagraphRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: 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; + word := a_word; + 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 + else if DTPUtils.IsChineseChar(a_word) then + begin + text_range.Type := 3; + word := utf8ToAnsi(a_word); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + else if DTPUtils.IsChinesePunctuation(a_word) then + begin + text_range.Type := 4; + word := utf8ToAnsi(a_word); + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + else begin + word := utf8ToAnsi(a_word); + if word = "?" then + begin + word := class(SymbolMapper).ZapfDingbatsChr(a_word); + if ifnil(word) then word := "u"; + font_obj := docx_to_pdf_.Font.GetZapfDingbatsFont(); + end + else begin + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); + end + end + page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); + word_width := page_.PdfPage.TextWidth(word); + text_range.RPr := rpr; + text_range.Text := word; + text_range.Font := font_obj; + text_range.Width := word_width; + pos += num; + range_arr[length(range_arr)] := text_range; + if ifarray(bookmark_array_[link]) then bookmark_array_[link] union= array(text_range); + end +end; + +function ParagraphRange.RDrawing(r: R); +begin + if r.Drawing._Inline then + begin + id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; + [image_type, image] := {self.}GetImageData(id); + if not image then return; + xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm); + image_range := new ImageRange(); + image_range.Image := image; + image_range.Type := image_type; + image_range.StartX := 0; + image_range.StartY := 0; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; + body_range_array_[length(body_range_array_)] := image_range; + end + else if r.Drawing.Anchor then + begin + anchor := r.Drawing.Anchor; + id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; + [image_type, image] := {self.}GetImageData(id); + if not image then return; + [x, y] := {self.}GetXYCordinates(); + xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm); + position_h := new PositionHUnitDecorator(anchor.PositionH); + position_v := new PositionVUnitDecorator(anchor.PositionV); + if position_h.RelativeFrom = "paragraph" then + x := {self.}StartY; + if position_v.RelativeFrom = "paragraph" then + y := {self.}StartY; + image_range := new ImageRange(); + image_range.Image := image; + image_range.Type := image_type; + image_range.EndX := x + position_h.PosOffset.Text; + image_range.EndY := y - position_v.PosOffset.Text - xfrm.Ext.CY; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; + image_range.Page := page_; + image_range.Do(); + end +end; + +function ParagraphRange.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 ParagraphRange(docx_to_pdf_, page_, docx_components_module_, p); + range.StartX := x; + range.StartY := y; + range.Width := w; + range.Calc(); + range.Do(); + y := range.EndY; + end +end; + +function ParagraphRange.RFootnoteReference(r: R); +begin + return; + id := R.FootnoteReference.Id; + footnotes_adapter := docx_components_module_.GetFootnotesAdapter(); + footnote := footnotes_adapter.GetFootnoteById(id); + sect_pr := page_.SectPr; + w := sect_pr.SectPr.PgSz.W - sect_pr.SectPr.PgMar.Right - sect_pr.SectPr.PgMar.Left; + lb := 0; + x := sect_pr.SectPr.PgMar.Left; + y := sect_pr.SectPr.PgSz.H; + + arr := array(); + elements := footnote.Elements(); + for _,element in elements do + begin + if element.LocalName = "p" then + begin + range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); + range.StartX := x; + range.StartY := y; + range.Width := w; + range.LowerBound := 0; + range.Calc(); + arr[length(arr)] := arr; + end + end + rpr := new RPrUnitDecorator(r.RPr); + note := docx_to_pdf_.Note; + text := docx_to_pdf_.GetCurrentNoteModule().GetIndex(); + i := length(body_range_array_); + if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); + footnote_reference_hash_[body_range_array_[i]] := arr; + + // range := new ParagraphRange(self, page_, docx_components_module_, ); +end; + +function ParagraphRange.RFootnoteRef(r: R); +begin + return; + note_module := docx_to_pdf_.GetCurrentNoteModule(); + rpr := new RPrUnitDecorator(r.RPr); + text := note_module.GetFootnoteOrderNumber(); + if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); +end; + +function ParagraphRange.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.StartX := 0; + image_range.StartY := 0; + image_range.Width := w; + image_range.DynamicHeight := h; + body_range_array_[length(body_range_array_)] := image_range; +end; + +function ParagraphRange.RFldChar(r: R; stack: Stack); +begin + fld_struct := stack.Pop(); + + if r.FldChar.FldCharType = "begin" then + fld_struct.EndFld := false; + else if r.FldChar.FldCharType = "end" then + fld_struct.EndFld := true; + else if r.FldChar.FldCharType = "separate" then + fld_struct.Separate := true; + + instr_text := ifString(r.InstrText.Text) ? trim(r.InstrText.Text) : ""; + if instr_text <> "" then + begin + if instr_text = "QUOTE" then + fld_struct.Quote := true; + else if instr_text = "\\* MERGEFORMAT" then + fld_struct.MergeFormat := true; + else if instr_text = "PAGE \\* Arabic \\* MERGEFORMAT" or instr_text = "PAGE \\* MERGEFORMAT" then + fld_struct.PageArabicMergeFormat := true; + else if instr_text = "NUMPAGES" then + fld_struct.NumPages := true; + else if instr_text = "\\* Arabic \\* MERGEFORMAT" then + fld_struct.ArabicMergeFormat := true; + else if instr_text = "NUMPAGES \\* Arabic \\* MERGEFORMAT" then + fld_struct.NumPages := fld_struct.ArabicMergeFormat := true; + end + if fld_struct.Quote then + begin + if not fld_struct.EndFld and not fld_struct.Separate then + begin + stack.Push(fld_struct); + return; + end + end + else if fld_struct.PageArabicMergeFormat then + begin + if fld_struct.Separate then + begin + r.T.Text := tostring(page_.Number); + {self.}RT(r, nil); + fld_struct.PageArabicMergeFormat := false; + end + end + else if fld_struct.ArabicMergeFormat then + begin + if fld_struct.Separate then + begin + rpr := new RPrUnitDecorator(r.RPr); + numpages_index := length(body_range_array_); + placeholder_array_ := array(numpages_index, rpr); + fld_struct.NumPages := false; + end + end + if not fld_struct.EndFld then + begin + stack.Push(fld_struct); + end + if ifObj(r.Drawing) then {self.}RDrawing(r); + else if ifObj(r.AlternateContent) then {self.}RAlternateContent(r); + else if ifObj(r.FootnoteReference) then {self.}RFootnoteReference(r); + else if ifObj(r.Object) then {self.}RObject(r); +end; + +function ParagraphRange.GetXYCordinates(): array of real; +begin + xml_file := docx_to_pdf_.GetCurrentXmlFile(); + if xml_file = "document.xml" then + begin + [x, y] := page_.OriginalTextPoint(); + end + else begin + x := page_.SectPr.PgMar.Left; + if ansiContainsStr(xml_file, "footer") then + y := page_.SectPr.PgMar.Bottom; + else if ansiContainsStr(xml_file, "header") then + y := page_.SectPr.PgSz.H - page_.SectPr.PgMar.Header; + end + return array(x, y); +end; + +function ParagraphRange.GetImageData(id: string): PdfImage; +begin + xml_file := docx_to_pdf_.GetCurrentXmlFile(); + if xml_file = "document.xml" then + rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); + else if ansiContainsStr(xml_file, "footer") then + rels_adapter := docx_components_module_.GetFtrRelsAdapter(xml_file); + else if ansiContainsStr(xml_file, "header") then + rels_adapter := docx_components_module_.GetHdrRelsAdapter(xml_file); + rel := rels_adapter.GetRelationshipById(id); + image_path := "word/" + rel.Target; + image := docx_components_module_.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 ParagraphRange.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 ParagraphRange.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 / page_.BaseSize); + if (not ifnil(ppr_unit_decorator_.SnapToGrid) and not ppr_unit_decorator_.SnapToGrid) or + ((ifnil(ppr_unit_decorator_.SnapToGrid) or ppr_unit_decorator_.SnapToGrid) and lines > multi) then + multi *= lines; + return page_.SectPr.DocGrid.LinePitch * multi; + end +end; + +function ParagraphRange.SetPPPr(var p: P); +begin + new_ppr := new PPr(); + styles := docx_components_module_.GetStyles(); + new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr); + new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr); + {self.}SetPPrByStyleId(new_ppr, table_style_id_); + {self.}SetPPrByStyleId(new_ppr, p.PPr.PStyle.Val); + new_ppr.Copy(p.PPr); + p.PPr.Copy(new_ppr); +end; + +function ParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetPPrByStyleId(ppr, based_on); + ppr.Copy(style.PPr); + ppr.RPr.Copy(style.RPr); + end +end; + +function ParagraphRange.SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); +begin + new_rpr := new RPr(); + styles := docx_components_module_.GetStyles(); + new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr); + {self.}SetRPrByTblStyleId(new_rpr, table_style_id_); + {self.}SetRPrByStyleId(new_rpr, ppr_unit_decorator.PStyle.Val); + {self.}SetRPrByStyleId(new_rpr, r.RPr.RStyle.Val); + new_rpr.Copy(r.RPr); + r.RPr.Copy(new_rpr); +end; + +function ParagraphRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetRPrByTblStyleId(rpr, based_on); + rpr.Copy(style.RPr); + end + if table_style_type_ then + begin + tbl_style_pr := docx_components_module_.GetTblStylePrByType(table_style_id_, table_style_type_); + if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr); + end +end; + +function ParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string); +begin + styles := docx_components_module_.GetStylesAdapter(); + style := styles.GetStyleByStyleId(style_id); + if ifObj(style) then + begin + based_on := style.BasedOn.Val; + {self.}SetRPrByStyleId(rpr, based_on); + rpr.Copy(style.RPr); + end +end; + +function ParagraphRange.SetLvlText(); +begin + numbering_module := docx_components_module_.GetNumberingModule(); + if not ifObj(numbering_module) then return; + [lvl_text, lvl] := numbering_module.GetNumberLvl(paragraph_.PPr); + if lvl_text = "" and ifnil(lvl) then return; + {self.}SetRRPr(lvl, ppr_unit_decorator_); + rpr := new RPrUnitDecorator(lvl.RPr); + // {self.}SplitTextToTextRange(bullet_range_array_, lvl_text, rpr); + {self.}SplitTextToTextRange(body_range_array_, lvl_text, rpr); +end; + +function ParagraphRange.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 ParagraphRange.GetLastPage(): Page; +begin + return page_; +end; + +function ParagraphRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); +begin + for _,line_range in line_range_array_ do + line_range.AdjustRangeOffset(pg, x_offset, y_offset); +end; + +function ParagraphRange.GetParagraphLineRangeArr(): array of ParagraphLineRange; +begin + return line_range_array_; +end; + +function ParagraphRange.Empty(): boolean; +begin + return empty_; +end; + +function ParagraphRange.Offset(x: real; y: real); +begin + for _,line_range in line_range_array_ do + line_range.Offset(x, y); +end; + +function ParagraphRange.OMathPara(element: OMathPara); +begin + math_range := new MathRange(docx_to_pdf_, page_, element); + math_range.StartX := {self.}StartX; + math_range.StartY := {self.}StartY - 15.6; + math_range.Calc(); + // math_range.Do(); + body_range_array_[length(body_range_array_)] := math_range; +end; + +end. diff --git a/internal/DTPColorToolKit.tsf b/internal/DTPColorToolKit.tsf new file mode 100644 index 0000000..6a7b2d7 --- /dev/null +++ b/internal/DTPColorToolKit.tsf @@ -0,0 +1,23 @@ +unit DTPColorToolKit; +interface + function HexToRGB(hex); + +implementation + + function HexToRGB(hex); + begin + hex_string := ifnumber(hex) ? format("%x", hex) : hex; + if length(hex_string) = 7 then + begin + if hex_string[1] <> "#" then raise "Invalid hexadecimal parameter."; + hex_string := hex_string[1:]; + end + if length(hex_string) <> 6 then raise "Invalid hexadecimal parameter"; + r := eval(&"return 0x" + hex_string[1:2]); + g := eval(&"return 0x" + hex_string[3:4]); + b := eval(&"return 0x" + hex_string[5:6]); + return array(r, g, b); + end; + +end. + diff --git a/internal/DTPModules.tsf b/internal/DTPModules.tsf new file mode 100644 index 0000000..98f9071 --- /dev/null +++ b/internal/DTPModules.tsf @@ -0,0 +1,719 @@ +unit DTPModules; +interface +uses TSPdfEnumerations, DocxMLAdapter, SharedMLAdapter; + +type DocxComponentsModule = class(DocxComponents) +public + function Create(); + function GetStyles(): Styles; + function GetStylesAdapter(): StylesAdapter; + function GetDocumentRelsAdapter(): RelationShipsAdapter; + function GetNumberingModule(): NumberingModule; + function GetTblStylePrByType(style_id: string; type: string): TblStylePr; + function GetFtr(target: string): Ftr; + function GetHdr(target: string): Hdr; + function GetFtrRelsAdapter(target: string): RelationShipsAdapter; + function GetHdrRelsAdapter(target: string): RelationShipsAdapter; + function GetFootnotesAdapter(): FootnotesAdapter; +private + styles_deserialize_flag_: boolean; + styles_adapter_: StylesAdapter; + document_rels_adapter_: RelationShipsAdapter; + numbering_module_: NumberingModule; + tbl_style_pr_hash_: array of TblStylePr; + ftr_hash_: array of Ftr; + hdr_hash_: array of Hdr; + hdr_rel_hash_: array of RelationShipsAdapter; + ftr_rel_hash_: array of RelationShipsAdapter; + footnotes_adapter_: FootnotesAdapter; +end; + +type FontModule = class +public + function Create(pdf: PdfFile); + + function GetAsciiFont(name: string; bold: boolean; italic: boolean): PdfFont; + function GetCNSFont(name: string; bold: boolean; italic: boolean): PdfFont; + function GetSymbolFont(): PdfFont; + function GetZapfDingbatsFont(): PdfFont; + function UseExternalFont(); + function SetSubstitutionRules(source: string; target: string); + function SetDefaultSz(value: real); + function GetDefaultSz(): real; + +private + function GetExternalFont(name:string; bold: boolean; italic: boolean): PdfFont; + function GetBuiltInCNSFont(name:string; bold: boolean; italic: boolean): PdfFont; + function GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean): PdfFont; + +private + [weakref]pdf_: PdfFile; + + use_built_in_font_: boolean; // 是否使用内置字体 + substitution_rules_: array of string; // 替换规则 + external_reference_: array of string; + default_sz_: real; +end; + +type NoteModule = class +public + function Create(sect_module: SectModule); + function GetFootnoteOrderNumber(): string; + function GetFootnoteIndex(): string; + function AddFootnote(); + +private + function CalculateNumber(num_fmt: string; num: integer): string; + function ChineseCountingThousand(n: integer): string; + +private + footnote_reference_hash_: hash; + footnote_index_: integer; + [weakref]sect_module_: SectModule; +end; + +type NumberingModule = class +public + function Create(number: NumberingAdapter); + function GetNumberLvl(ppr: PPr); + +private + function CalculateNumber(num_fmt: string; num: integer): string; + function ChineseCountingThousand(n: integer): string; + +private + numbering_adapter_: NumberingAdapter; + num_hash_: hash; +end; + +type SectModule = class +public + function Create(); + function Destroy(); + function Do(); + function AddElement(element: tslobj); + +public + Elements: array of tslobj; + SectPr: SectPrUnitDecorator; +end; + +type Toc = class +public + function Create(ppr: PPrUnitDecorator; rect: array of real; page: Page; x: real; y: real; font: PdfFont); + function LinkAnnot(dst: PdfDestination); + function AddPageNumber(page: Page); + +private + [weakref]page_: Page; + ppr_: PPrUnitDecorator; + rect_: array of real; + font_: PdfFont; + x_; + y_; +end; + +type TocModule = class +public + function Create(); + function UpdateDocxNumPages(); + function LinkToToc(anchor: string; pg: Page; left: real; top: real); + function AddToc(anchor: string; toc: Toc); + + function AddDocxPage(anchor: string; r: R); + +private + toc_hash_: hash; + toc_unmatched_hash_: hash; + + update_docx_num_pages_: boolean; // 开放给docx文件是否更新docx文件的页码 + docx_page_hash_: hash; +end; + +// 坐标 +type Point = class +public + function Create(); + +public + X: real; + Y: real; +end; + +// Page延迟建立,存基本信息即可 +type Page = class +public + function Create(pdf_file: PdfFile); + function OriginalTextCoordinates(): array of real; + function PrintGrid(); + + property PdfPage read ReadPdfPage; + function ReadPdfPage(): PdfPage; + +public + Index: integer; + Number: integer; + SectPr: SectPrUnitDecorator; + BaseSize: real; + TextPoint: Point; // 正文坐标 + FtrPoint: Point; // 页脚坐标 + HdrPoint: Point; // 页眉坐标 + +private + [weakref]pdf_file_: PdfFile; + pdf_page_: PdfPage; +end; + +type PageManagerModule = class +public + function Create(pdf_file: PdfFile); + function Operator[](index: uinteger): Page; + function NewPage(): Page; + function NextPage(page: Page): Page; + function Count(): integer; + +private + [weakref]pdf_file_: PdfFile; + page_array_: array of Page; +end; + +implementation + +// DocxComponentsModule +function DocxComponentsModule.Create(); +begin + class(DocxComponents).Create(); + tbl_style_pr_hash_ := array(); + ftr_hash_ := array(); + hdr_hash_ := array(); + hdr_rel_hash_ := array(); + ftr_rel_hash_ := array(); +end; + +function DocxComponentsModule.GetStyles(): Styles; +begin + if styles_deserialize_flag_ then return {self.}Styles; + {self.}Styles.Deserialize(); + styles_deserialize_flag_ := true; + return {self.}Styles; +end; + +function DocxComponentsModule.GetStylesAdapter(): StylesAdapter; +begin + if styles_adapter_ then return styles_adapter_; + styles_adapter_ := new StylesAdapter({self.}GetStyles()); + return styles_adapter_; +end; + +function DocxComponentsModule.GetDocumentRelsAdapter(): RelationShipsAdapter; +begin + if document_rels_adapter_ then return document_rels_adapter_; + {self.}DocumentRels.Deserialize(); + document_rels_adapter_ := new RelationShipsAdapter({self.}DocumentRels); + return document_rels_adapter_; +end; + +function DocxComponentsModule.GetNumberingModule(): NumberingModule; +begin + if numbering_module_ then return numbering_module_; + if not {self.}Numbering then return nil; + {self.}Numbering.Deserialize(); + numbering_module_ := new NumberingModule({self.}Numbering); + return numbering_module_; +end; + +function DocxComponentsModule.GetTblStylePrByType(style_id: string; type: string): TblStylePr; +begin + if tbl_style_pr_hash_[style_id][type] then return tbl_style_pr_hash_[style_id][type]; + styles_adapter := {self.}GetStylesAdapter(); + style := styles_adapter.GetStyleByStyleId(style_id); + style := new StyleAdapter(style); + tbl_style_pr := style.GetTblStylePrByType(type); + tbl_style_pr_hash_[style_id][type] := tbl_style_pr; + return tbl_style_pr; +end; + +function DocxComponentsModule.GetFtr(target: string): Ftr; +begin + if ftr_hash_[target] then return ftr_hash_[target]; + index := replaceStr(replaceStr(target, "footer", ""), ".xml", ""); + obj := {self.}Footers(strtoint(index)); + obj.Deserialize(); + ftr_hash_[target] := obj; + return obj; +end; + +function DocxComponentsModule.GetHdr(target: string): Hdr; +begin + if hdr_hash_[target] then return hdr_hash_[target]; + index := replaceStr(replaceStr(target, "header", ""), ".xml", ""); + obj := {self.}Headers(strtoint(index)); + obj.Deserialize(); + hdr_hash_[target] := obj; + return obj; +end; + +function DocxComponentsModule.GetHdrRelsAdapter(target: string): RelationShipsAdapter; +begin + if hdr_rel_hash_[target] then return hdr_rel_hash_[target]; + index := replaceStr(replaceStr(target, "header", ""), ".xml", ""); + obj := {self.}HeaderRels(strtoint(index)); + obj.Deserialize(); + rels_adapter := new RelationShipsAdapter(obj); + hdr_rel_hash_[target] := rels_adapter; + return rels_adapter; +end; + +function DocxComponentsModule.GetFtrRelsAdapter(target: string): RelationShipsAdapter; +begin + if ftr_rel_hash_[target] then return ftr_rel_hash_[target]; + index := replaceStr(replaceStr(target, "footer", ""), ".xml", ""); + obj := {self.}FooterRels(strtoint(index)); + obj.Deserialize(); + rels_adapter := new RelationShipsAdapter(obj); + ftr_rel_hash_[target] := rels_adapter; + return rels_adapter; +end; + +function DocxComponentsModule.GetFootnotesAdapter(): FootnotesAdapter; +begin + if footnotes_adapter_ then return footnotes_adapter_; + obj := {self.}Footnotes; + obj.Deserialize(); + footnotes_adapter_ := new FootnotesAdapter(obj); + return footnotes_adapter_; +end; + +// FontModule +function FontModule.Create(pdf: PdfFile); +begin + pdf_ := pdf; + use_built_in_font_ := true; + substitution_rules_ := array("宋体": "SimSun", + "黑体": "SimHei", + "Courier New": "Courier", + "Helvetica": "Helvetica", + "Times New Roman": "Times-Roman", + ); + external_reference_ := array(); + default_sz_ := 10.5; +end; + +function FontModule.SetDefaultSz(value: real); +begin + default_sz_ := value; +end; + +function FontModule.GetDefaultSz(); +begin + return default_sz_; +end; + +function FontModule.UseExternalFont(); +begin + use_built_in_font_ := false; +end; + +function FontModule.GetExternalFont(name:string; bold: boolean; italic: boolean); +begin + if ifnil(name) or name = '' then name := "等线"; + if not ifnil(external_font_cache_[name]) then return external_font_cache_[name]; + value := external_reference_[name]; + if ifnil(value) then return nil; + if value["ext"] = ".ttf" then + font_name := pdf_.LoadTTFontFromFile("", value["path"], true); + else if value["ext"] = ".ttc" then + font_name := pdf_.LoadTTFontFromFile2("", value["path"], 0, true); + if not ifString(font_name) then return nil; + font := pdf_.GetFont(font_name, "UTF-8"); + external_font_cache_[name] := font; + return font; +end; + +function FontModule.GetCNSFont(name: string; bold: boolean; italic: boolean): PdfFont; +begin + return use_built_in_font_ ? {self.}GetBuiltInCNSFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic); +end; + +function FontModule.GetBuiltInCNSFont(name: string; bold: boolean; italic: boolean): PdfFont; +begin + font_name := substitution_rules_[name]; + if ifnil(font_name) then font_name := "SimSun"; + if bold and italic then + font_name += ",BoldItalic"; + else if bold then + font_name += ",Bold"; + else if italic then + font_name += ",Italic"; + return pdf_.GetFont(font_name, "GBK-EUC-H"); +end; + +function FontModule.GetAsciiFont(name: string; bold: boolean; italic: boolean): PdfFont; +begin + return use_built_in_font_ ? {self.}GetBuiltInAsciiFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic); +end; + +function FontModule.GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean): PdfFont; +begin + font_name := substitution_rules_[name]; + if ifnil(font_name) then font_name := "Times-Roman"; + if font_name = "Courier" or font_name = "Helvetica" then + begin + if bold and italic then + font_name += "-BoldOblique"; + else if bold then + font_name += "-Bold"; + else if italic then + font_name += "-Oblique"; + end + else if font_name = "Times-Roman" then + begin + if bold and italic then + font_name := "Times-BoldItalic"; + else if bold then + font_name += "Times-Bold"; + else if italic then + font_name += "Times-Italic"; + end + return pdf_.GetFont(font_name, ""); +end; + +function FontModule.SetSubstitutionRules(source: string; target: string); +begin + substitution_rules_[source] := target; +end; + +function FontModule.GetSymbolFont(): PdfFont; +begin + return pdf_.GetFont("Symbol", ""); +end; + +function FontModule.GetZapfDingbatsFont(): PdfFont; +begin + return pdf_.GetFont("ZapfDingbats", ""); +end; + +// NoteModule +function NoteModule.Create(sect_module: SectModule); +begin + sect_module_ := sect_module; + footnote_reference_hash_ := array(); + footnote_index_ := 0; +end; + +function NoteModule.GetFootnoteOrderNumber(); +begin + num_fmt := sect_module_.SectPr.FootnotePr.NumFmt.Val; + if ifnil(num_fmt) then num_fmt := "decimal"; + return CalculateNumber(num_fmt, ++footnote_index_); +end; + +function NoteModule.GetFootnoteIndex(): string; +begin + return inttostr(footnote_index_); +end; + +function NoteModule.CalculateNumber(num_fmt: string; num: integer): string; +begin + if num_fmt = "decimal" then + return format("%d", num); + else if num_fmt = "chineseCountingThousand" then + return {self.}ChineseCountingThousand(num); + else + return format("%d", num); +end; + +function NoteModule.ChineseCountingThousand(n: integer): string; +begin + chinese_digits := array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九"); + chinese_units := array("", "十", "百", "千"); + if n < 10 then return chinese_digits[n]; + result := ""; + num_str := inttostr(n); + len := length(num_str); + for i:=1 to len do + begin + digit_int := strtoint(num_str[i]); + if digit_int <> 0 then + result += chinese_digits[digit_int] + chinese_units[len - i]; + end + if length(result) >= 6 and result[:6] = "一十" then result := result[4:]; + return result; +end; + +// SectModule +function SectModule.Create(); +begin + {self.}Elements := array(); + {self.}SectPr := nil; +end; + +function SectModule.AddElement(element: tslobj); +begin + {self.}Elements[length({self.}Elements)] := element; +end; + +// NumberingModule +function NumberingModule.Create(number: NumberingAdapter); +begin + numbering_adapter_ := new NumberingAdapter(number); + num_hash_ := array(); +end; + +function NumberingModule.GetNumberLvl(ppr: PPr); +begin + num_id := ppr.NumPr.NumId.Val; + if ifnil(num_id) then return array("", nil); + ilvl := ppr.NumPr.Ilvl.Val; + pstyle := ppr.PStyle.Val; + num := numbering_adapter_.GetNumByNumId(num_id); + if ifnil(num) then return array("", nil); + abstract_id := num.AbstractNumId.Val; + abstract_num := numbering_adapter_.GetAbstractNumByAbstractNumId(abstract_id); + lvls := abstract_num.Lvls(); + if ifnil(ilvl) then ilvl := "0"; + for k,v in lvls do + begin + if ilvl and v.Ilvl = ilvl then + begin + lvl_text := v.LvlText.Val; + if not ifarray(num_hash_[num_id]) then num_hash_[num_id] := array(0, 0, 0, 0, 0, 0, 0, 0, 0); + ilvl_int := strtoint(ilvl); + for i:=0 to ilvl_int do + begin + source_str := "%" $ (i + 1); + n := num_hash_[num_id][i]; + if i = ilvl_int then + begin + n := num_hash_[num_id][i] + 1; + for j:=i+1 to length(num_hash_[num_id])-1 do + num_hash_[num_id][j] := 0; + end + n := i = ilvl_int ? num_hash_[num_id][i] + 1 : num_hash_[num_id][i]; + dest_str := {self.}CalculateNumber(v.NumFmt.Val, n); + lvl_text := replaceStr(lvl_text, source_str, dest_str); + end + num_hash_[num_id][ilvl_int]++; + if v.Suff.Val = "space" then lvl_text += " "; + return array(lvl_text, v); + end + end + return array("", nil); +end + +function NumberingModule.CalculateNumber(num_fmt: string; num: integer): string; +begin + if num_fmt = "decimal" then + return format("%d", num); + else if num_fmt = "chineseCountingThousand" then + return {self.}ChineseCountingThousand(num); + else + return format("%d", num); +end; + +function NumberingModule.ChineseCountingThousand(n: integer): string; +begin + chinese_digits := array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九"); + chinese_units := array("", "十", "百", "千"); + if n < 10 then return chinese_digits[n]; + result := ""; + num_str := inttostr(n); + len := length(num_str); + for i:=1 to len do + begin + digit_int := strtoint(num_str[i]); + if digit_int <> 0 then + result += chinese_digits[digit_int] + chinese_units[len - i]; + end + if length(result) >= 6 and result[:6] = "一十" then result := result[4:]; + return result; +end; + +// Page +function Page.Create(pdf_file: PdfFile); +begin + pdf_file_ := pdf_file; + {self.}TextPoint := new Point(); + {self.}FtrPoint := new Point(); + {self.}HdrPoint := new Point(); +end; + +function Page.OriginalTextCoordinates(): array of real; +begin + x := {self.}SectPr.PgMar.Left; + y := min({self.}SectPr.PgSz.H - max({self.}SectPr.PgMar.Top, {self.}SectPr.PgMar.Header), {self.}HdrPoint.Y); + return array(x, y); +end; + +function Page.ReadPdfPage(): PdfPage; +begin + if ifnil(pdf_page_) then + begin + pdf_page_ := pdf_file_.AddPage(); + pdf_page_.SetWidth({self.}SectPr.PgSz.W); + pdf_page_.SetHeight({self.}SectPr.PgSz.H); + +if sysparams["_PDF_PAGE_GRID_DEBUG_"] then + {self.}PrintGrid(); + + end + return pdf_page_; +end; + +function Page.PrintGrid(); +begin + i := 0; + while true do + begin + y := {self.}TextPoint.Y - i * {self.}SectPr.DocGrid.LinePitch; + if y <= {self.}SectPr.PgMar.Bottom then break; + pdf_page_.SetLineWidth(0.05); + pdf_page_.SetGrayStroke(0.75); + pdf_page_.MoveTo({self.}SectPr.PgMar.Left, y); + pdf_page_.LineTo({self.}SectPr.PgSz.W- {self.}SectPr.PgMar.Right, y); + pdf_page_.Stroke(); + i++; + end + + x1 := {self.}SectPr.PgMar.Left; + y1 := {self.}SectPr.PgSz.H - {self.}SectPr.PgMar.Top; + x2 := {self.}SectPr.PgSz.W - {self.}SectPr.PgMar.Right; + y2 := y1; + x3 := x1; + y3 := {self.}SectPr.PgMar.Bottom; + x4 := x2; + y4 := y3; + pdf_page_.SetLineWidth(0.05); + pdf_page_.SetGrayStroke(0.5); + pdf_page_.MoveTo(x1, y1); + pdf_page_.LineTo(x2, y2); + pdf_page_.Stroke(); + pdf_page_.MoveTo(x1, y1); + pdf_page_.LineTo(x3, y3); + pdf_page_.Stroke(); + pdf_page_.MoveTo(x2, y2); + pdf_page_.LineTo(x4, y4); + pdf_page_.Stroke(); + pdf_page_.MoveTo(x3, y3); + pdf_page_.LineTo(x4, y4); + pdf_page_.Stroke(); +end; + +// PageManagerModule +function PageManagerModule.Create(pdf_file: PdfFile); +begin + pdf_file_ := pdf_file; + page_array_ := array(); +end; + +function Operator PageManagerModule.[](index: uinteger): Page; +begin + return page_array_[index]; +end; + +function PageManagerModule.NewPage(): Page; +begin + len := length(page_array_); + page := new Page(pdf_file_); + page.Index := len; + page_array_[len] := page; + return page; +end; + +function PageManagerModule.Count(): integer; +begin + return length(page_array_); +end; + +// TocModule +function TocModule.Create(); +begin + toc_hash_ := array(); + toc_unmatched_hash_ := array(); + + update_docx_num_pages_ := false; + docx_page_hash_ := array(); +end; + +function TocModule.UpdateDocxNumPages(); +begin + update_docx_num_pages_ := true; +end; + +function TocModule.LinkToToc(anchor: string; pg: Page; left: real; top: real); +begin + arr := toc_hash_[anchor]; + if ifnil(arr) then + begin + toc_unmatched_hash_[anchor] := array(pg, left, top); + return; + end + dst := pg.PdfPage.CreateDestination(); + dst.SetXYZ(left, top, 1); + for _,toc in arr do + toc.LinkAnnot(dst); + toc.AddPageNumber(pg); + + if update_docx_num_pages_ then + begin + r := docx_page_hash_[anchor]; + r.T.Text := pg.Number; + r.Serialize(); + end +end; + +function TocModule.AddToc(anchor: string; toc: Toc); +begin + if ifarray(toc_hash_[anchor]) then toc_hash_[anchor] union= array(toc); + else toc_hash_[anchor] := array(toc); + if toc_unmatched_hash_[anchor] then + begin + toc := toc_unmatched_hash_[anchor]; + {self.}LinkToToc(anchor, toc[0], toc[1], toc[2]); + toc_unmatched_hash_[anchor] := nil; + end +end; + +function TocModule.AddDocxPage(anchor: string; r: R); +begin + docx_page_hash_[anchor] := r; +end; + +// Toc +function Toc.Create(ppr: PPrUnitDecorator; rect: array of real; pg: Page; x: real; y: real; font: PdfFont); +begin + ppr_ := ppr; + rect_ := rect; + page_ := pg; + x_ := x; + y_ := y; + font_ := font; +end; + +function Toc.LinkAnnot(dst: PdfDestination); +begin + annot := page_.PdfPage.CreateLinkAnnot(rect_, dst); + annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT); + annot.LinkAnnotSetBorderStyle(0, 0, 0); +end; + +function Toc.AddPageNumber(pg: Page); +begin + number := tostring(pg.Number); + page_.PdfPage.SetFontAndSize(font_, ppr_.RPr.Sz.Val); + number_sz := page_.PdfPage.TextWidth(number); + x := rect_[2] - number_sz; + page_.PdfPage.BeginText(); + page_.PdfPage.TextOut(x, y_, number); + page_.PdfPage.EndText(); + + page_.PdfPage.SetRGBStroke(0, 0, 0); + page_.PdfPage.SetDash(array(0.5, 2), 2, 0); + page_.PdfPage.SetLineWidth(0.5); + page_.PdfPage.SetLineCap(TSPdfEnumerations.ROUND_END); + page_.PdfPage.MoveTo(x_+1, y_); + page_.PdfPage.LineTo(x-0.5, y_); + page_.PdfPage.Stroke(); +end; + +end. diff --git a/internal/DTPPrimitiveRanges.tsf b/internal/DTPPrimitiveRanges.tsf new file mode 100644 index 0000000..95ff70e --- /dev/null +++ b/internal/DTPPrimitiveRanges.tsf @@ -0,0 +1,245 @@ +unit DTPPrimitiveRanges; +interface +uses DTPColorToolKit, DTPUtils; + +type TextRange = class(BasicRange) +public + function Create(); + function Do();override; + +public + RPr: RPr; + Text: string; + Font: PdfFont; + Type: integer; // 0:默认,1: 数字,2:英文,3:中文,4:中文标点 +end; + +type BordersRange = class(BasicRange) +public + function Create(); + function Do();override; +public + TcPr: TcPr; + Left: boolean; + Top: boolean; + Right: boolean; + Bottom: boolean; + +private + function SetDash(val: string); + function DrawLine(border: Border; x1: real; y1: real; x2: real; y2: real); +end; + +type ImageRange = class(BasicRange) +public + function Create(); + function Do();override; + +public + Image: PdfImage; + Type: string; + +end; + +type LineRange = class(BasicRange) +public + function Create(); + function Do();override; + +public + LineWidth: real; +end; + +type BasicRange = class +public + function Create(); + function Do();virtual; + +public + StartX: real; + StartY: real; // range的起始坐标(x,y) + EndX: real; + EndY: real; // range的结束坐标(x,y) + Width: real; + FixedHeight: real; + DynamicHeight: real; + LowerBound: real; + [weakref]Parent: tslobj; + [weakref]Page: Page; +end; + +implementation + +// BasicRange +function BasicRange.Create(); +begin + {self.}StartX := 0; + {self.}StartY := 0; + {self.}EndX := 0; + {self.}EndY := 0; + {self.}Width := 0; + {self.}DynamicHeight := 0; + {self.}LowerBound := 0; + {self.}FixedHeight := 0; + {self.}Page := nil; +end; + +// ImageRange +function ImageRange.Create(); +begin + class(BasicRange).Create(); + {self.}Image := nil; + {self.}Type := ""; +end; + +function ImageRange.Do();override; +begin + // println("image = {}, type = {}, x = {}, y = {}, w = {}, h = {}", {self.}image, {self.}Type, {self.}endx, {self.}endy, {self.}width, {self.}DynamicHeight); + if {self.}Type = "emf" then + {self.}Page.PdfPage.DrawEmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + else if {self.}Type = "wmf" then + {self.}Page.PdfPage.DrawWmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + else + {self.}Page.PdfPage.DrawImage({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + +if sysparams["_PDF_IMAGE_DEBUG_"] then +begin + {self.}Page.PdfPage.SetLineWidth(0.1); + {self.}Page.PdfPage.SetRGBStroke(0.8, 0.8, 0); + {self.}Page.PdfPage.Rectangle({self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight); + {self.}Page.PdfPage.Stroke(); +end +end; + +// BordersRange +function BordersRange.Create(); +begin + class(BasicRange).Create(); + {self.}TcPr := nil; + {self.}Left := false; + {self.}Top := false; + {self.}Right := false; + {self.}Bottom := false; +end; + +function BordersRange.Do();override; +begin + // println("Left = {}, Top = {}, Right = {}, Bottom = {}, Tl2Br = {}, Tr2Bl = {}", Left, Top, Right, Bottom, Tl2Br, Tr2Bl); + borders := {self.}TcPr.TcBorders; + if {self.}TcPr.Shd.Fill and {self.}TcPr.Shd.Fill <> "auto" then + begin + [r, g, b] := DTPColorToolKit.HexToRGB({self.}TcPr.Shd.Fill); + {self.}Page.PdfPage.SetRGBFill(r/255, g/255, b/255); + x := {self.}EndX; + y := {self.}EndY - {self.}DynamicHeight; + w := {self.}Width; + h := {self.}DynamicHeight; + tmp := borders.Left.Sz ? borders.Left.Sz / 2 : 0.25; + x += tmp; + w -= tmp; + w -= borders.Right.Sz ? borders.Right.Sz / 2 : 0.25; + tmp := borders.Bottom.Sz ? borders.Bottom.Sz / 2 : 0.25; + y += tmp; + h -= tmp; + h -= borders.Top.Sz ? borders.Top.Sz / 2 : 0.25; + + {self.}Page.PdfPage.Rectangle(x, y, w, h); + {self.}Page.PdfPage.Fill(); + {self.}Page.PdfPage.SetRGBFill(0, 0, 0); + {self.}Left := true; + end + if {self.}Left then + {self.}DrawLine(borders.Left, {self.}EndX, {self.}EndY, {self.}EndX, {self.}EndY - {self.}DynamicHeight); + if {self.}Top then + {self.}DrawLine(borders.Top, {self.}EndX, {self.}EndY, {self.}EndX + {self.}Width, {self.}EndY); + if {self.}Right then + {self.}DrawLine(borders.Right, {self.}EndX + {self.}Width, {self.}EndY, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight); + if {self.}Bottom then + {self.}DrawLine(borders.Bottom, {self.}EndX, {self.}EndY - {Self.}DynamicHeight, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight); + if borders.Tl2Br then + {self.}DrawLine(borders.Tl2Br, {self.}EndX, {self.}Y, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight); + if borders.Tr2Bl then + {self.}DrawLine(borders.Tr2Bl, {self.}EndX + {self.}Width, {self.}Y, {self.}EndX, {self.}EndY - {self.}DynamicHeight); +end; + +function BordersRange.SetDash(val: string); +begin + if val = "single" or ifnil(val) then + {self.}Page.PdfPage.SetDash(array(), 0, 0); + if val = "dashed" then + {self.}Page.PdfPage.SetDash(array(1), 1, 0); +end; + +function BordersRange.DrawLine(border: Border; x1: real; y1: real; x2: real; y2: real); +begin + [r, g, b] := array(0, 0, 0); + line_width := border.Sz ?: 0.5; + {self.}SetDash(border.Val); + if border.Color and border.Color <> "auto" then [r, g, b] := DTPColorToolKit.HexToRGB(border.Color); + {self.}Page.PdfPage.SetRGBStroke(r, g, b); + {self.}Page.PdfPage.SetLineWidth(line_width); + {self.}Page.PdfPage.MoveTo(x1, y1); + {self.}Page.PdfPage.LineTo(x2, y2); + {self.}Page.PdfPage.Stroke(); + {self.}Page.PdfPage.SetRGBStroke(0, 0, 0); +end; + +// TextRange +function TextRange.Create(); +begin + class(BasicRange).Create(); + {self.}RPr := nil; + {self.}Text := ""; + {self.}Font := nil; + {self.}Type := -1; +end; + +function TextRange.Do();override; +begin + // println("text = {}, endx = {}, endy = {}, width = {}, page = {}", ansiToUtf8(text), endx, endy, width, page); + // println("Text = {}, sz = {}, szcs = {}, rpr.I = {}, rpr.B = {}, color = {}", ansiToUtf8({self.}Text), {self.}RPr.Sz.Val, {self.}RPr.SzCs.Val, {self.}RPr.I, {self.}RPr.B, {self.}RPr.Color.Val); + [r, g, b] := array(0, 0, 0); + if {self.}RPr.Color.Val and {self.}RPr.Color.Val <> "auto" then [r, g, b] := DTPColorToolKit.HexToRGB({self.}RPr.Color.Val); + y := {self.}EndY; + sz := {self.}RPr.Sz.Val; + if {self.}RPr.VertAlign.Val = "superscript" then + begin + y += sz / 3; + sz := sz * 2 / 3; + end + {self.}Page.PdfPage.SetRGBFill(r / 255, g / 255, b / 255); + {self.}Page.PdfPage.SetFontAndSize({self.}Font, sz); + {self.}Page.PdfPage.BeginText(); + {self.}Page.PdfPage.TextOut({self.}EndX, y, {self.}Text); + {self.}Page.PdfPage.EndText(); + {self.}Page.PdfPage.SetRGBFill(0, 0, 0); + + +if sysparams["_PDF_TEXT_DEBUG_"] then +begin + {self.}Page.PdfPage.SetLineWidth(0.1); + {self.}Page.PdfPage.SetRGBStroke(1.0, 0.5, 0.0); + {self.}Page.PdfPage.MoveTo(0, {self.}EndY); + {self.}Page.PdfPage.LineTo(600, {self.}EndY); + {self.}Page.PdfPage.Stroke(); +end +end; + +// LineRange +function LineRange.Create(); +begin + class(BasicRange).Create(); + {self.}LineWidth := 0; +end; + +function LineRange.Do();override; +begin + // println("endx = {}, endy = {}, width = {}", EndX, EndY, Width); + {self.}Page.PdfPage.SetLineWidth({self.}LineWidth); + {self.}Page.PdfPage.SetRGBStroke(0, 0, 0); + {self.}Page.PdfPage.MoveTo({self.}EndX, {self.}EndY); + {self.}Page.PdfPage.LineTo({self.}EndX + {self.}Width, {self.}EndY); + {self.}Page.PdfPage.Stroke(); +end; + +end. diff --git a/internal/DTPUtils.tsf b/internal/DTPUtils.tsf new file mode 100644 index 0000000..868ed33 --- /dev/null +++ b/internal/DTPUtils.tsf @@ -0,0 +1,248 @@ +unit DTPUtils; +interface +uses DTPPrimitiveRanges; + +function Utf8CharLengthFromByte(byte: char): integer; +function IsChineseChar(str: utf8_string): boolean; +function IsChinesePunctuation(str: utf8_string): boolean; + +type Point = class +public + function Create(); + +public + X: real; + Y: real; +end; + +type Stack = class +public + function Create(); + function Pop(); + function Push(element: any); + function Empty(): boolean; + +private + arr_: tableArray; + index_: integer; +end; + +type FldStruct = class +public + function Create(); +public + FldLock: boolean; + MergeFormat: boolean; + Quote: boolean; + Separate: boolean; + PageArabicMergeFormat: boolean; + NumPages: boolean; + ArabicMergeFormat: boolean; + EndFld: boolean; +end; + +type FldType = class +public + function Create(); + +public + Page: boolean; + NumPages: boolean; + Quote: boolean; + PageRef: boolean; +end; + +type FldStruct2 = class +public + function Create(); + +public + Type: FldType; + Arabic: boolean; + MergeFormat: boolean; +end; + +type TrProperty = class +public + function Create(); + +public + TrPr: TrPrUnitDecorator; + Height: real; +end; + +type Region = class +public + function Create(); + +public + BordersRange: BordersRange; + RangeArr: array of BasicRange; +end; + +type SymbolMapper = class + class function SymbolChr(symbol: string): string; + class function ZapfDingbatsChr(str: string): string; +private + static symbol_chr_hash_: array of chr; + static zapfdingbats_chr_hash_: array of chr; +end; + +implementation + +function Utf8CharLengthFromByte(byte: char): 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 IsChineseChar(str: utf8_string): boolean; +begin + unicode_str := utf8ToUnicode(str); + codepoint := ord(unicode_str[1]); + return (codepoint >= 0x4E00 && codepoint <= 0x9FFF) or + (codepoint >= 0x3400 && codepoint <= 0x4DBF) or + (codepoint >= 0x20000 && codepoint <= 0x2A6DF); +end; + +function IsChinesePunctuation(str: utf8_string): boolean; +begin + unicode_str := utf8ToUnicode(str); + codepoint := ord(unicode_str[1]); + return (codepoint >= 0x3000 && codepoint <= 0x303F) or + (codepoint >= 0xFF00 && codepoint <= 0xFFEF) or + (codepoint = 0x2018 || codepoint = 0x2019) or + (codepoint = 0x201C || codepoint = 0x201D) or + (codepoint = 0x2026 || codepoint = 0x2027); +end; + +// Point +function Point.Create(); +begin + {self.}X := 0; + {self.}Y := 0; +end; + +// Stack +function Stack.Create(); +begin + arr_ := array(); + index_ := 0; +end; + +function Stack.Pop(); +begin + if index_ = 0 then return nil; + index_--; + ret := arr_[index_]; + arr_[index_] := nil; + return ret; +end; + +function Stack.Push(element: any); +begin + arr_[index_++] := element; +end; + +function Stack.Empty(): boolean; +begin + return index_ = 0; +end; + +// FldStruct +function FldStruct.Create(); +begin + FldLock := false; + MergeFormat := false; + Quote := false; + Separate := false; + PageArabicMergeFormat := false; + NumPages := false; + ArabicMergeFormat := false; + EndFld := false; +end; + +// FldType +function FldType.Create(); +begin + {self.}Page := false; + {self.}NumPages := false; + {self.}Quote := false; + {self.}PageRef := false; +end; + +// FldStruct +function FldStruct2.Create(); +begin + {self.}Type := new FldType(); + {self.}Arabic := false; + {self.}MergeFormat := false; +end; + +// TrProperty +function TrProperty.Create(); +begin + {self.}TrPr := nil; + {self.}Height := 0; +end; + +// Region +function Region.Create(); +begin + BordersRange := new DTPPrimitiveRanges.BordersRange(); + RangeArr := array(); +end + +// SymbolMapper +class function SymbolMapper.SymbolChr(symbol: string); +begin + if ifnil(symbol_chr_hash_) then + begin + symbol_chr_hash_ := array( + "−": chr(0x2D), + "α": chr(0x61), + "β": chr(0x62), + "ε": chr(0x65), + "γ": chr(0x67), + "θ": chr(0x71), + "{": chr(0x7B), + "}": chr(0x7D), + "∞": chr(0xA5), + "f": chr(0xA6), + "±": chr(0xB1), + "∂": chr(0xB6), + "∏": chr(0xD5), + "〈": chr(0xE1), + "∑": chr(0xE5), + "〉": chr(0xF1), + "Į": chr(0xF2), + // "": chr(0x), + ); + end + return symbol_chr_hash_[symbol]; +end; + +class function SymbolMapper.ZapfDingbatsChr(str: string): string; +begin + if ifnil(zapfdingbats_chr_hash_) then + begin + zapfdingbats_chr_hash_ := array( + "": chr(118), + "": chr(110), + "": chr(108), + "": chr(117), + "": chr(108), + "o": chr(109), + "": chr(110), + ); + end + return zapfdingbats_chr_hash_[symbol]; +end; + +end.