PdfConverter/internal/DTPAdvancedRanges.tsf

2409 lines
80 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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); // <r w:anchor>
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.