PdfConverter/internal/DTPAdvancedRanges.tsf

2281 lines
75 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, TSPdfEnumerations;
type TocRange = class(BasicRange)
public
function Create();
function CalculateRect();
function LinkAnnot(dst: PdfDestination);
function AddPageNumber(pg: Page);
public
TextRange: TextRange;
BaseLine: real; // 目录...基线
[weakref]StartRange: BasicRange;
[weakref]EndRange: BasicRange;
private
rect_: array of real;
end;
type HdrRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr);
function Calc(): boolean;
function Do();override;
function ProcessRealtimeArray();
private
function Traverse(obj: OpenXmlElement);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
hdr_: Hdr;
range_array_: array of Range;
end;
type FtrRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr);
function Calc(): boolean;
function Do();override;
function ProcessRealtimeArray();
private
function Traverse(obj: OpenXmlElement);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
ftr_: Ftr;
range_array_: array of Range;
y_offset_: real;
end;
type PLineRange = class(BasicRange)
public
function Create();
function Do();override;
function CanFitInLine(range: BasicRange): boolean;
function AddRange(range: BasicRange);
function AdjustPosition();
function Offset(x: real; y: real);
function Align(val: string);
function AlignRightBound(right_bound: real);
function Arrange();
function RangeArr(): array of BasicRange;
public
TextMaxSize: real; // 行的文字最大size
LineSpace: real; // 行间距
Index: integer;
private
range_array_: array of BasicRange;
end;
type PRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; p: P);
function Init();
function Do();override;
function Calc(): boolean;
function Run();
function DeterminePosition();
function ProcessRealtimeArray();
function IsFirstLineOnNextPage(): boolean;
function Offset(x: real; y: real);
function PLineRanges(): array of PLineRange;
property PPrUnitDecorator read ppr_unit_decorator_;
private
function RangesToLines();
function BasicRangesToPLineRange();
function UpdateTextRangeWidth();
function CheckAndAddPage(y: real; offset: real): boolean;
function AlignRightBound();
function HyperlinkToToc();
function DoDrawingAnchor();
function DoAlternateContentAnchor();
function DoToc();
function SetPPPr(var p: P);
function SetPPrByStyleId(var ppr: PPr; style_id: string);
function SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator);
function SetRPrByStyleId(var rpr: RPr; style_id: string);
function SetRPrByTblStyleId(var rpr: RPr; style_id: string);
function SetLvlText();
function GetXYCordinates(): array of real;
function GetImageFileType(data: binary): string;
function GetImageData(id: string): PdfImage;
function GetParagraphLineSpace(size: real; line: integer; line_rule: string): real;
function SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; anchor: string);
function RBr(r: R);
function RFootnoteReference(r: R);
function RT(r: R; anchor: string);
function RDrawing(r: R);
function RFldChar(r: R; stack: Stack);
function RAlternateContent(r: R);
function FldSimple(fld_simple: fldSimple);
function Hyperlink(hyperlink: Hyperlink);
function OMathPara(o_math_para: OMathPara);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
p_: P;
ppr_unit_decorator_: PPrUnitDecorator;
body_range_array_: array of BasicRange; // 正文range
bullet_range_array_: array of BasicRange; // 项目符号的range
line_range_array_: array of PLineRange; // 行range
drawing_anchor_array_: array of Anchor; // 浮动对象节点比如浮动型图片r.Drawing.Anchor
alternate_content_array_: array of AlternateContent; // 文本框
right_bound_: real; // 右对齐边界
br_type_: string;
bookmark_hash_: hash;
hyperlink_hash_: hash;
footnote_reference_hash_: hash; // 脚注
// 存放一些需要实时计算的值,比如页码
realtime_page_array_: hash;
realtime_numpages_array_: hash;
end;
type TcRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty);
function Do();override;
function DoBordersRangeFill();
function Calc();
function Run();
function GetTblStyleId(): string;
function GetPrType(): string;
function ContentNextPage(): boolean;
function AlignHeight(height: real);
function SetVAlign();
function SetTop();
property Tc Read tc_;
public
Row: integer;
Col: integer;
OffsetX: real;
private
function GetLowerBound(pg: Page): real;
function SetBorderRange(range: BordersRange);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
tc_: Tc;
trp_: TrProperty;
tc_pr_unit_decorator_: TcPrUnitDecorator;
content_next_page_: boolean;
range_array_: array of BasicRange;
region_array_: array of Region;
top_: boolean;
end;
type TblRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; tbl: Tbl);
function Do();override;
function Calc();
function Run();
property TblPr read tbl_pr_unit_decorator_;
property Rows read rows_;
property Cols read cols_;
private
function CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr);
function ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol);
function SetTblTblPr(var table: Tbl);
function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string);
function SetTrTrPr(var tr_pr: TrPr);
function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string);
function SetTcTcPr(var tc: Tc);
function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string);
function OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
tbl_: Tbl;
tbl_pr_unit_decorator_: TblPrUnitDecorator;
grid_cols_: array of GridColUnitDecorator;
rows_: integer;
cols_: integer;
tc_range_matrix_: array of TcRange;
tr_pr_array_: array of TrProperty;
end;
type OMathParaRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara);
function Do();override;
function Run();
function Calc();
private
[weakref]docx_to_pdf_: TSDocxToPdf;
o_math_para_: OMathPara;
o_math_range_: OMathRange;
end;
type OMathRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement);
function Do();override;
function Run();
function Calc();
function SetMathSize();
property Sz read sz_ write sz_;
private
function MR(r: R; sz: real; x: real; y: real);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
element_: OMath;
sz_: real;
range_array_: array of BasicRange;
end;
type OMathFRange = class(BasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; f: F);
function Do();override;
function Calc();
function Run();
private
[weakref]docx_to_pdf_: TSDocxToPdf;
f_: F;
range_array_: array of BasicRange;
end;
implementation
function TocRange.Create();
begin
class(BasicRange).Create();
{self.}TextRange := nil;
{self.}BaseLine := 0;
end;
function TocRange.LinkAnnot(dst: PdfDestination);
begin
annot := {self.}EndPage.PdfPage.CreateLinkAnnot(rect_, dst);
annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT);
annot.LinkAnnotSetBorderStyle(0, 0, 0);
end;
function TocRange.AddPageNumber(pg: Page);
begin
number_str := tostring(pg.Number);
{self.}EndPage.PdfPage.SetFontAndSize({self.}TextRange.Font, {self.}TextRange.RPr.Sz.Val);
number_sz := {self.}EndPage.PdfPage.TextWidth(number_str);
x := rect_[2] - number_sz;
y := {self.}BaseLine;
{self.}TextRange.EndPage := {self.}EndPage;
{self.}TextRange.Text := number_str;
{self.}TextRange.EndX := x;
{self.}TextRange.EndY := y;
{self.}TextRange.Do();
// 目录......
sx := {self.}EndX;
{self.}EndPage.PdfPage.SetRGBStroke(0, 0, 0);
{self.}EndPage.PdfPage.SetDash(array(0.5, 2), 2, 0);
{self.}EndPage.PdfPage.SetLineWidth(0.5);
{self.}EndPage.PdfPage.SetLineCap(TSPdfEnumerations.ROUND_END);
{self.}EndPage.PdfPage.MoveTo(sx, y);
{self.}EndPage.PdfPage.LineTo(x-0.5, y);
{self.}EndPage.PdfPage.Stroke();
end;
function TocRange.CalculateRect();
begin
pline_range := {self.}Parent;
{self.}EndPage := pline_range.EndPage;
if {self.}StartRange then
begin
rect_ := array({self.}StartRange.StartX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY);
end
else begin
rect_ := array(pline_range.StartX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY);
end
offset := pline_range.LineSpace >= pline_range.DynamicHeight ? (pline_range.LineSpace - pline_range.TextMaxSize) / 2 + pline_range.TextMaxSize - pline_range.TextMaxSize / 5 : pline_range.DynamicHeight;
y := pline_range.StartY - offset;
{self.}BaseLine := y;
{self.}EndX := ifObj({self.}EndRange) ? {self.}EndRange.EndX + {self.}EndRange.Width + 1 : {self.}Parent.StartX;
end;
function HdrRange.Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr);
begin
class(BasicRange).Create();
docx_to_pdf_ := docx_to_pdf;
hdr_ := hdr;
range_array_ := array();
end;
function HdrRange.Calc();
begin
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}EndPage := {self.}StartPage;
{self.}DynamicHeight := 0;
return {self.}Traverse(hdr_);
end;
function HdrRange.Traverse(obj: OpenXmlElement);
begin
flag := true;
elements := obj.Elements();
for _,element in elements do
begin
if element.LocalName = "p" then
begin
range := new PRange(docx_to_pdf_, element);
range.Width := {self.}Width;
range.Parent := self;
fg := range.Calc();
if not fg then flag := fg;
range.StartX := {self.}EndX;
range.StartY := {self.}EndY;
range.StartPage := {self.}EndPage;
range.LowerBound := {self.}LowerBound;
range.Run();
range_array_[length(range_array_)] := range;
{self.}EndY := range.EndY;
{self.}DynamicHeight += range.DynamicHeight;
end
else if element.LocalName = "sdt" then
begin
{self.}Traverse(element.SdtContent);
end
end
return flag;
end;
function HdrRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function HdrRange.ProcessRealtimeArray();
begin
for _,range in range_array_ do
range.ProcessRealtimeArray();
end;
function FtrRange.Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr);
begin
docx_to_pdf_ := docx_to_pdf;
ftr_ := ftr;
range_array_ := array();
y_offset_ := 0;
end;
function FtrRange.Calc();
begin
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}EndPage := {self.}StartPage;
{self.}DynamicHeight := 0;
flag := {self.}Traverse(ftr_);
for _,range in range_array_ do
begin
range.StartX := {self.}EndX;
range.StartY := {self.}EndY;
range.StartPage := {self.}EndPage;
range.LowerBound := {self.}LowerBound;
range.Run();
{self.}EndY := range.EndY;
{self.}DynamicHeight += range.DynamicHeight;
end
y_offset_ := {self.}EndY - {self.}EndPage.FtrPoint.Y;
for _,range in range_array_ do
range.Offset(0, -y_offset_);
{self.}EndY := {self.}EndPage.FtrPoint.Y + {self.}DynamicHeight;
return flag;
end;
function FtrRange.Traverse(obj: OpenXmlElement);
begin
flag := true;
elements := obj.Elements();
for _,element in elements do
begin
// println("LocalName = {}", element.LocalName);
if element.LocalName = "p" then
begin
range := new PRange(docx_to_pdf_, element);
range.Width := {self.}Width;
range.Parent := self;
fg := range.Calc();
if not fg then flag := fg;
range_array_[length(range_array_)] := range;
end
else if element.LocalName = "sdt" then
begin
flag := {self.}Traverse(element.SdtContent);
end
end
return flag;
end;
function FtrRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function FtrRange.ProcessRealtimeArray();
begin
for _,range in range_array_ do
begin
range.ProcessRealtimeArray();
range.Offset(0, -y_offset_);
end
end;
function PLineRange.Create();
begin
class(BasicRange).Create();
{self.}TextMaxSize := 0;
{self.}LineSpace := 0;
range_array_ := array();
end
function PLineRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function PLineRange.CanFitInLine(range: BasicRange): boolean;
begin
if range.Width > {self.}Width then return false; // 单一宽度比行宽还宽
if {self.}EndX + range.Width < {self.}Width + 1e-6 then return false; // 未超过行宽
if range is class(TextRange) and range.Type = 4 and not {self.}Parent.Parent is class(TcRange) then return false; // 中文标点不换行
return true;
end;
function PLineRange.AddRange(range: BasicRange);
begin
range_array_[length(range_array_)] := range;
end;
function PLineRange.Offset(x: real; y: real);
begin
{self.}EndX += x;
{self.}EndY += y;
{self.}BaseSize += y;
for _,range in range_array_ do
begin
range.EndX += x;
range.EndY += y;
end;
end;
function PLineRange.AdjustPosition();
begin
{self.}EndX += {self.}StartX;
{self.}EndY := {self.}StartY - {self.}DynamicHeight;
{self.}EndPage := {self.}StartPage;
y_offset := {self.}LineSpace >= {self.}DynamicHeight ? ({self.}LineSpace - {self.}TextMaxSize) / 2 + {self.}TextMaxSize - {self.}TextMaxSize / 5 : {self.}DynamicHeight;
y := {self.}StartY - y_offset;
for _,range in range_array_ do
begin
range.EndPage := {self.}EndPage;
range.EndX += {self.}StartX;
range.EndY := y;
end
end;
function PLineRange.Align(val: string);
begin
offset := 0;
last := range_array_[length(range_array_)-1];
case val of
"center":
offset := ({self.}Width + {self.}StartX - {self.}EndX) / 2;
"right":
offset := {self.}Width + {self.}StartX - {self.}EndX;
end;
if offset <= 0 then return;
for _,range in range_array_ do
range.EndX += offset;
end;
function PLineRange.AlignRightBound(right_bound: real);
begin
last := range_array_[length(range_array_)-1];
diff := right_bound - (last.EndX + last.Width);
if diff > 1e-6 then
begin
avg := diff / (length(range_array_) - 1);
for i:=1 to length(range_array_)-1 do
range_array_[i].EndX += avg * i;
end
end;
function PLineRange.RangeArr(): array of BasicRange;
begin
return range_array_;
end;
function PRange.Create(docx_to_pdf: TSDocxToPdf; p: P);
begin
class(BasicRange).Create();
docx_to_pdf_ := docx_to_pdf;
p_ := p;
end;
function PRange.Init();
begin
br_type_ := "";
body_range_array_ := array();
bullet_range_array_ := array();
line_range_array_ := array();
drawing_anchor_array_ := array();
alternate_content_array_ := array();
bookmark_hash_ := array();
hyperlink_hash_ := array();
footnote_reference_hash_ := array();
realtime_page_array_ := array();
realtime_numpages_array_ := array();
// 根据段落的间距确定新的坐标
ppr := ppr_unit_decorator_;
sz := ppr.RPr.SzCs.Val ? : ppr.RPr.Sz.Val;
{self.}Width -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
{self.}Width -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right;
end
function PRange.Do();override;
begin
for _,line_range in line_range_array_ do
line_range.Do();
// 段落边框
if length(line_range_array_) > 0 and ppr_unit_decorator_.PBdr.Bottom.Val = "single" then
begin
{self.}EndPage.PdfPage.SetLineWidth(0.5);
{self.}EndPage.PdfPage.SetGrayStroke(0.25);
{self.}EndPage.PdfPage.MoveTo({self.}StartX, {self.}EndY);
{self.}EndPage.PdfPage.LineTo({self.}StartX + {self.}Width, {self.}EndY);
{self.}EndPage.PdfPage.Stroke();
end
// 处理bookmark
for anchor,arr in bookmark_hash_ do
if arr[0] then docx_to_pdf_.Toc.LinkToToc(anchor, arr[0]);
end;
function PRange.Calc();
begin
// ppr.rpr是无效的应该以ppr.pStyle为准
{self.}SetPPPr(p_);
ppr_unit_decorator_ := new DocxMLUnitDecorator.PPrUnitDecorator(p_.PPr);
if not ppr_unit_decorator_.RPr.Sz.Val then ppr_unit_decorator_.RPr.Sz.Val := docx_to_pdf_.Font.GetDefaultSz();
{self.}Init();
{self.}SetLvlText();
bookmark_name := "";
elements := p_.Elements();
fld_stack := new DTPUtils.Stack();
for _, element in elements do
begin
if element.LocalName = "pPr" then continue;
else if element.LocalName = "bookmarkStart" then
begin
bookmark_name := element.Name;
bookmark_hash_[bookmark_name] := array();
end
else if element.LocalName = "bookmarkEnd" then
begin
bookmark_name := "";
end
else if element.LocalName = "r" then
begin
{self.}SetRRPr(element, ppr_unit_decorator_);
if element.FldChar.FldCharType = "begin" then
begin
fld_struct := new DTPUtils.FldStruct();
fld_stack.Push(fld_struct);
continue;
end
if not fld_stack.Empty() then
begin
{self.}RFldChar(element, fld_stack);
continue;
end
if element.T then {self.}RT(element, bookmark_name);
else if element.Br then {self.}RBr(element);
else if element.Drawing then {self.}RDrawing(element);
else if element.AlternateContent then {self.}RAlternateContent(element);
else if element.FootnoteReference then {self.}RFootnoteReference(element);
end
else if element.LocalName = "fldSimple" then
begin
{self.}FldSimple(element);
end
else if element.LocalName = "hyperlink" then
begin
{self.}Hyperlink(element);
end
else if element.LocalName = "oMathPara" then
begin
{self.}OMathPara(element);
end
else if element.LocalName = "oMath" then
begin
o_math_para := new OMathPara();
o_math_para.XmlChildOMath := element;
// o_math_para.OMath.Copy(element);
{self.}OMathPara(o_math_para);
end
end
{self.}RangesToLines();
// 需要实时计算总页码的情况是需要最后处理的
return length(realtime_numpages_array_) ? false : true;
end;
function PRange.RBr(r: R);
begin
br_type_ := r.Br.Type;
end;
function PRange.RFootnoteReference(r: R);
begin
return;
docx_to_pdf_.Note.AddFootnoteId(r.FootnoteReference.Id);
rpr := new RPrUnitDecorator(r.RPr);
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.Ascii ?: rpr.RFonts.EastAsia;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
text := new TextRange();
text.RPr := rpr;
text.Font := font_obj;
text.Text := docx_to_pdf_.Note.GetFootnoteOrderNumber();
text.Width := docx_to_pdf_.PageManager[0].PdfPage.TextWidth(text.Text);
body_range_array_[length(body_range_array_)] := text;
footnote_reference_hash_[text] := id;
end;
function PRange.RDrawing(r: R);
begin
if r.Drawing.Anchor then
begin
anchor := r.Drawing.Anchor;
drawing_anchor_array_[length(drawing_anchor_array_)] := anchor;
end
else if r.Drawing._Inline then
begin
id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed;
[image_type, image] := {self.}GetImageData(id);
if not image then return;
xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm);
image_range := new ImageRange();
image_range.Image := image;
image_range.Type := image_type;
image_range.Width := xfrm.Ext.CX;
image_range.DynamicHeight := xfrm.Ext.CY;
body_range_array_[length(body_range_array_)] := image_range;
end
end;
function PRange.RFldChar(r: R; stack: Stack);
begin
fld_struct := stack.Pop();
if r.FldChar.FldCharType = "separate" then
begin
fld_struct.Status := 1;
stack.Push(fld_struct);
return;
end
// else if r.FldChar.FldCharType = "end" then
// fld_struct.Status = 2;
if fld_struct.Status = 2 then return;
if r.InstrText.Text then
begin
fields := str2array(r.InstrText.Text, " ");
for _,field in fields do
begin
fld := trim(field);
if fld = "NUMPAGES" then
fld_struct.Type.NumPages := true;
else if fld = "PAGE" then
fld_struct.Type.Page := true;
else if fld = "QUOTE" then
fld_struct.Type.Quote := true;
else if fld = "PAGEREF" then
fld_struct.Type.PageRef := true;
else if fld = "Arabic" then
fld_struct.Arabic := true;
else if fld = "MERGEFORMAT" then
fld_struct.MergeFormat := true;
end
end
if fld_struct.Status = 1 then
begin
if fld_struct.Type.Page then
begin
rpr := new RPrUnitDecorator(r.RPr);
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
text := new TextRange();
text.RPr := rpr;
// text.Type := 1;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
realtime_page_array_[length(realtime_page_array_)] := text;
body_range_array_[length(body_range_array_)] := text;
end
else if fld_struct.Type.NumPages then
begin
rpr := new RPrUnitDecorator(r.RPr);
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
text := new TextRange();
text.RPr := rpr;
// text.Type := 1;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
realtime_numpages_array_[length(realtime_numpages_array_)] := text;
body_range_array_[length(body_range_array_)] := text;
end
fld_struct.Status := 2;
end
if fld_struct.Status <> 2 then stack.Push(fld_struct);
end;
function PRange.RAlternateContent(r: R);
begin
anchor := r.AlternateContent.Choice.Drawing.Anchor;
alternate_content_array_[length(alternate_content_array_)] := anchor;
end;
function PRange.FldSimple(fld_simple: fldSimple);
begin
if fld_simple.Instr then
begin
fields := str2array(fld_simple.Instr, " ");
fld_struct := new DTPUtils.FldStruct();
for _,field in fields do
begin
fld := trim(field);
if fld = "NUMPAGES" then
fld_struct.Type.NumPages := true;
else if fld = "Arabic" then
fld_struct.Arabic := true;
else if fld = "MERGEFORMAT" then
fld_struct.MergeFormat := true;
end
end
r := fld_simple.Rs(0);
{self.}SetRRPr(r, ppr_unit_decorator_);
if fld_struct.Type.NumPages then
begin
if fld_struct.Arabic then
begin
rpr := new RPrUnitDecorator(r.RPr);
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
text := new TextRange();
text.RPr := rpr;
// text.Type := 1;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
realtime_numpages_array_[length(realtime_numpages_array_)] := text;
body_range_array_[length(body_range_array_)] := text;
end
end
end;
function PRange.Hyperlink(hyperlink: Hyperlink);
begin
i := length(body_range_array_);
rs := hyperlink.Rs();
fld_stack := new DTPUtils.Stack();
for _,r in rs do
begin
if r.FldChar.FldCharType = "begin" then
begin
fld_struct := new DTPUtils.FldStruct();
fld_stack.Push(fld_struct);
end
else if r.FldChar.FldCharType = "end" then
begin
fld_stack.Pop();
end
else if r.FldChar.FldCharType = "separate" then
begin
separate := true;
end
else if separate then
begin
docx_to_pdf_.Toc.AddDocxPage(hyperlink.Anchor, r);
rpr := new RPrUnitDecorator(r.RPr);
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
text := new TextRange();
text.RPr := rpr;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
end
if not fld_stack.Empty() then continue;
if r.T then
begin
{self.}SetRRPr(r, ppr_unit_decorator_);
r.RPr.Color.Val := nil;
{self.}RT(r);
end
end
arr := array();
while i < length(body_range_array_) do
begin
arr[length(arr)] := body_range_array_[i];
i++;
end
hyperlink_hash_[hyperlink.Anchor] := array(text, arr);
end;
function PRange.OMathPara(o_math_para: OMathPara);
begin
return;
math_range := new OMathParaRange(docx_to_pdf_, o_math_para);
math_range.Width := {self.}Width;
math_range.Parent := self;
math_range.Calc();
body_range_array_[length(body_range_array_)] := math_range;
end;
function PRange.HyperlinkToToc();
begin
ppr_ := ppr_unit_decorator_;
for anchor, arr in hyperlink_hash_ do
begin
text := arr[0];
r_arr := arr[1];
range0 := r_arr[0];
range1 := r_arr[length(r_arr)-1];
if range0.Parent.Index = range1.Parent.Index then // 同一行
begin
if range1.Parent.EndX + text.Width < {self.}Width then // 页码不需要换行
begin
toc := new TocRange();
toc.Parent := range0.Parent;
toc.TextRange := text;
toc.StartRange := range0;
toc.EndRange := range1;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
else begin // 需要新增一行
pline_range := new PLineRange();
pline_range.Parent := self;
pline_range.Width := {self.}Width;
pline_range.EndX := 0;
pline_range.DynamicHeight := range1.Parent.DynamicHeight;
pline_range.LineSpace := range1.Parent.LineRule;
index := range1.Parent.Index + 1;
for i:=length(line_range_array_) downto index do
begin
line_range := line_range_array_[i];
line_range.Index++;
line_range_array_[i+1] := line_range;
end
line_range_array_[index] := pline_range;
toc := new TocRange();
toc.Parent := pline_range;
toc.TextRange := text;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
end
else begin
for i:=range0.Parent.Index to range1.Parent.Index do
begin
if i = range1.Parent.Index then
begin
if range1.Parent.EndX + text.Width < {self.}Width then // 页码不需要换行
begin
toc := new TocRange();
toc.Parent := range1.Parent;
toc.TextRange := text;
toc.EndRange := range1;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
else begin // 需要新增一行
pline_range := new PLineRange();
pline_range.Parent := self;
pline_range.Width := {self.}Width;
pline_range.EndX := 0;
pline_range.DynamicHeight := range1.Parent.DynamicHeight;
pline_range.LineSpace := range1.Parent.LineRule;
index := range1.Parent.Index + 1;
for i:=length(line_range_array_) downto index do
begin
line_range := line_range_array_[i];
line_range.Index++;
line_range_array_[i+1] := line_range;
end
line_range_array_[index] := pline_range;
toc := new TocRange();
toc.Parent := pline_range;
toc.TextRange := text;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
end
else begin
toc := new TocRange();
toc.Parent := line_range_array_[i];
toc.TextRange := text;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
end
end
end
end;
function PRange.PLineRanges(): array of PLineRange;
begin
return line_range_array_;
end;
function PRange.RangesToLines();
begin
line_range_array_ := array();
{self.}UpdateTextRangeWidth();
{self.}BasicRangesToPLineRange();
{self.}HyperlinkToToc();
end;
function PRange.BasicRangesToPLineRange();
begin
pline_range := new PLineRange();
pline_range.Parent := self;
pline_range.Width := {self.}Width;
pline_range.EndX := 0;
i := 0;
anchor := nil;
while i < length(body_range_array_) do
begin
range := body_range_array_[i];
if i = 0 then
pline_range.EndX += ppr_unit_decorator_.Ind.FirstLine;
if_newline := pline_range.CanFitInLine(range);
if if_newline then
begin
pline_range.LineSpace := {self.}GetParagraphLineSpace(pline_range.TextMaxSize, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule);
pline_range.DynamicHeight := max(pline_range.LineSpace, pline_range.DynamicHeight);
pline_range.Index := length(line_range_array_);
line_range_array_[length(line_range_array_)] := pline_range;
pline_range := new PLineRange();
pline_range.Parent := self;
pline_range.Width := {self.}Width;
pline_range.EndX := 0;
end
if range is class(TextRange) and range.RPr.Sz.Val > pline_range.TextMaxSize then
pline_range.TextMaxSize := range.RPr.Sz.Val;
if range.DynamicHeight > pline_range.DynamicHeight then pline_range.DynamicHeight := range.DynamicHeight;
range.EndX := pline_range.EndX + range.StartX; // range.StartX是偏移值
range.Parent := pline_range;
pline_range.AddRange(range);
pline_range.EndX += range.Width;
i++;
if i = length(body_range_array_) then
begin
pline_range.LineSpace := {self.}GetParagraphLineSpace(pline_range.TextMaxSize, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule);
pline_range.DynamicHeight := max(pline_range.LineSpace, pline_range.DynamicHeight);
pline_range.Index := length(line_range_array_);
line_range_array_[length(line_range_array_)] := pline_range;
end
end
// println("line_range_array_ = {}", line_range_array_);
end;
function PRange.UpdateTextRangeWidth();
begin
if length(realtime_page_array_) > 0 or length(realtime_numpages_array_) > 0 then return;
head_range := body_range_array_[0];
i := 1;
while i < length(body_range_array_) do
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 PRange.Run();
begin
// 检查是否需要实时计算页码
if length(realtime_page_array_) > 0 then
begin
pg := {self.}StartPage;
for _,range in realtime_page_array_ do
begin
pg.PdfPage.SetFontAndSize(range.Font, range.RPr.Sz.Val);
range.Text := tostring(pg.Number);
range.Width := pg.PdfPage.TextWidth(range.Text);
range.Type := 1;
end
realtime_page_array_ := array();
{self.}RangesToLines();
end
{self.}DeterminePosition();
end;
function PRange.DeterminePosition();
begin
x := {self.}StartX;
y := {self.}StartY;
right_bound_ := x + {self.}Width;
{self.}StartX := x;
{self.}StartY := y;
ppr := ppr_unit_decorator_;
sz := ppr.RPr.SzCs.Val ? ppr.RPr.SzCs.Val : ppr.RPr.Sz.Val ? ppr.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz();
{self.}StartX += ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}EndPage := {self.}StartPage;
// 检查是否有分页,分一栏
if br_type_ = "page" then
{self.}EndY := {self.}LowerBound;
else if br_type_ = "column" and (ifnil(docx_to_pdf_.CurrentSect.SectPr.Cols.Num) or docx_to_pdf_.CurrentSect.SectPr.Cols.Num <= 1) then
{self.}EndY := {self.}LowerBound;
{self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before);
{self.}EndY -= ppr_unit_decorator_.Spacing.Before;
{self.}DynamicHeight := ppr_unit_decorator_.Spacing.Before;
// 检查是否有段前分页
if ppr_unit_decorator_.PageBreakBefore then
{self.}CheckAndAddPage({self.}LowerBound, 1);
for _,line_range in line_range_array_ do
begin
{self.}CheckAndAddPage({self.}EndY, line_range.DynamicHeight);
line_range.StartX := {self.}EndX;
line_range.StartY := {self.}EndY;
line_range.StartPage := {self.}EndPage;
line_range.AdjustPosition();
line_range.Align(ppr_unit_decorator_.Jc.Val);
{self.}DynamicHeight += line_range.DynamicHeight;
{self.}EndY := line_range.EndY;
end
if not {self.}Parent is class(TcRange) then
{self.}AlignRightBound();
if length(line_range_array_) = 0 then // 空段落
begin
line_space := {self.}GetParagraphLineSpace(ppr_unit_decorator_.RPr.Sz.Val, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule);
{self.}DynamicHeight += line_space;
{self.}EndY -= {self.}DynamicHeight;
end
{self.}DoDrawingAnchor();
{self.}DoAlternateContentAnchor();
{self.}DoToc();
{self.}DynamicHeight += ppr_unit_decorator_.Spacing.After;
{self.}EndY -= ppr_unit_decorator_.Spacing.After;
end;
function PRange.DoToc();
begin
for anchor,_ in hyperlink_hash_ do
docx_to_pdf_.Toc.CalculateRect(anchor);
end;
function PRange.DoDrawingAnchor();
begin
for _,anchor in drawing_anchor_array_ do
begin
id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed;
[image_type, image] := {self.}GetImageData(id);
if not image then return;
xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm);
position_h := new PositionHUnitDecorator(anchor.PositionH);
position_v := new PositionVUnitDecorator(anchor.PositionV);
[x, y] := {self.}GetXYCordinates();
if position_h.RelativeFrom = "paragraph" then
x := {self.}StartY;
if position_v.RelativeFrom = "paragraph" then
y := {self.}StartY;
image_range := new ImageRange();
image_range.Image := image;
image_range.Type := image_type;
image_range.EndX := x + position_h.PosOffset.Text;
image_range.EndY := y - position_v.PosOffset.Text - xfrm.Ext.CY;
image_range.Width := xfrm.Ext.CX;
image_range.DynamicHeight := xfrm.Ext.CY;
image_range.EndPage := {self.}EndPage;
image_range.Do();
end
end;
function PRange.DoAlternateContentAnchor();
begin
for _,anchor in alternate_content_array_ do
begin
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 PRange(docx_to_pdf_, p);
range.Width := w;
range.Parent := self;
fg := range.Calc();
if not fg then flag := fg;
range.StartPage := {self.}EndPage;
range.StartX := x;
range.StartY := y;
range.LowerBound := 0;
range.Run();
range.Do();
y := range.EndY;
end
end
end;
function PRange.ProcessRealtimeArray();
begin
for _,range in realtime_numpages_array_ do
begin
range.Text := tostring(docx_to_pdf_.PageManager[docx_to_pdf_.PageManager.Count-1].Number);
first_page := docx_to_pdf_.PageManager[0];
range.Width := first_page.PdfPage.TextWidth(range.Text);
range.Type := 1;
end
realtime_numpages_array_ := array();
{self.}RangesToLines();
{self.}DeterminePosition();
end;
function PRange.IsFirstLineOnNextPage(): boolean;
begin
lrange := line_range_array_[0];
return ifnil(lrange) ? false : lrange.EndPage <> {self.}StartPage;
end;
function PRange.Offset(x: real; y: real);
begin
{self.}EndX += x;
{self.}EndY += y;
for _,line_range in line_range_array_ do
line_range.Offset(x, y);
end;
function PRange.AlignRightBound();
begin
len := length(line_range_array_);
if len = 1 then return;
for i:=0 to len-2 do
line_range_array_[i].AlignRightBound(right_bound_);
end;
function PRange.CheckAndAddPage(y: real; offset: real): boolean;
begin
lb := {self.}LowerBound;
if lb > 0 then
lb := lb > {self.}EndPage.LowerBound ? lb : {self.}EndPage.LowerBound;
if y - offset < lb then
begin
{self.}DynamicHeight += y - lb;
{self.}EndPage := docx_to_pdf_.PageManager[{self.}EndPage.Index + 1];
if ifnil({self.}EndPage) then {self.}EndPage := docx_to_pdf_.AddPage();
{self.}EndY := {self.}EndPage.OriginalTextCoordinates()[1];
return true;
end
return false;
end;
function PRange.RT(r: R; anchor: string);
begin
rpr := new DocxMLUnitDecorator.RPrUnitDecorator(r.RPr);
text := r.T.Text;
if text then {self.}SplitTextToTextRange(body_range_array_, text, rpr, anchor);
end;
function PRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; anchor: string);
begin
pos := 1;
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
while pos <= length(text) do
begin
text_range := new TextRange();
num := DTPUtils.Utf8CharLengthFromByte(text[pos]);
a_word := text[pos : pos+num-1];
if num = 1 then
begin
char := ord(a_word);
if char >= 0x30 and char <= 0x39 then
text_range.Type := 1;
else if char >= 0x41 and char <= 0x5A then
text_range.Type := 2;
else if char >= 0x61 and char <= 0x7A then
text_range.Type := 2;
else if char = 0x44 or char = 0x46 then
text_range.Type := 5;
word := a_word;
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
// font_name := rpr.RFonts.Ascii ?: rpr.RFonts.EastAsia;
// font_obj := docx_to_pdf_.Font.GetAsciiFont(font_name, rpr.B, rpr.I);
end
else if DTPUtils.IsChineseChar(a_word) then
begin
text_range.Type := 3;
word := utf8ToAnsi(a_word);
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
end
else if DTPUtils.IsChinesePunctuation(a_word) then
begin
text_range.Type := 4;
word := utf8ToAnsi(a_word);
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
end
else begin
word := utf8ToAnsi(a_word);
if word = "?" then
begin
word := class(SymbolMapper).ZapfDingbatsChr(a_word);
if ifnil(word) then word := "u";
font_obj := docx_to_pdf_.Font.GetZapfDingbatsFont();
end
else begin
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
end
end
first_page := docx_to_pdf_.PageManager[0];
pdf_page := first_page.PdfPage;
pdf_page.SetFontAndSize(font_obj, rpr.Sz.Val);
text_range.RPr := rpr;
text_range.Text := word;
text_range.Font := font_obj;
text_range.Width := pdf_page.TextWidth(word);
text_range.DynamicHeight := rpr.Sz.Val;
pos += num;
range_arr[length(range_arr)] := text_range;
if ifarray(bookmark_hash_[anchor]) then bookmark_hash_[anchor] union= array(text_range);
end
end;
function PRange.SetPPPr(var p: P);
begin
new_ppr := new PPr();
styles := docx_to_pdf_.DocxComponents.GetStyles();
new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr);
new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr);
if {self.}Parent is class(TcRange) then
{self.}SetPPrByStyleId(new_ppr, {self.}Parent.GetTblStyleId());
{self.}SetPPrByStyleId(new_ppr, p.PPr.PStyle.Val);
new_ppr.Copy(p.PPr);
p.PPr.Copy(new_ppr);
end;
function PRange.SetPPrByStyleId(var ppr: PPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetPPrByStyleId(ppr, based_on);
ppr.Copy(style.PPr);
ppr.RPr.Copy(style.RPr);
end
end;
function PRange.SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator);
begin
new_rpr := new RPr();
styles := docx_to_pdf_.DocxComponents.GetStyles();
new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr);
if {self.}Parent is class(TcRange) then
{self.}SetRPrByTblStyleId(new_rpr, {self.}Parent.GetTblStyleId());
{self.}SetRPrByStyleId(new_rpr, ppr_unit_decorator.PStyle.Val);
{self.}SetRPrByStyleId(new_rpr, r.RPr.RStyle.Val);
new_rpr.Copy(r.RPr);
r.RPr.Copy(new_rpr);
end;
function PRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetRPrByTblStyleId(rpr, based_on);
rpr.Copy(style.RPr);
end
if {self.}Parent is class(TcRange) then
begin
pr_type := {self.}Parent.GetPrType();
tbl_style_pr := docx_to_pdf_.DocxComponents.GetTblStylePrByType(style_id, pr_type);
if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr);
end
end;
function PRange.SetRPrByStyleId(var rpr: RPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetRPrByStyleId(rpr, based_on);
rpr.Copy(style.RPr);
end
end;
function PRange.SetLvlText();
begin
numbering_module := docx_to_pdf_.DocxComponents.GetNumberingModule();
if not ifObj(numbering_module) then return;
[lvl_text, lvl] := numbering_module.GetNumberLvl(p_.PPr);
if lvl_text = "" and ifnil(lvl) then return;
{self.}SetRRPr(lvl, ppr_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 PRange.GetXYCordinates(): array of real;
begin
xml_file := docx_to_pdf_.GetCurrentXmlFile();
if xml_file = "document.xml" then
begin
[x, y] := {self.}EndPage.OriginalTextCoordinates();
end
else begin
x := {self.}EndPage.SectPr.PgMar.Left;
if ansiContainsStr(xml_file, "footer") then
y := {self.}EndPage.SectPr.PgMar.Bottom;
else if ansiContainsStr(xml_file, "header") then
y := {self.}EndPage.SectPr.PgSz.H - {self.}EndPage.SectPr.PgMar.Header;
end
return array(x, y);
end;
function PRange.GetImageData(id: string): PdfImage;
begin
xml_file := docx_to_pdf_.GetCurrentXmlFile();
if {self.}Parent is class(HdrRange) then
rels_adapter := docx_to_pdf_.DocxComponents.GetHdrRelsAdapter(xml_file);
else if {self.}Parent is class(FtrRange) then
rels_adapter := docx_to_pdf_.DocxComponents.GetFtrRelsAdapter(xml_file);
else
rels_adapter := docx_to_pdf_.DocxComponents.GetDocumentRelsAdapter();
rel := rels_adapter.GetRelationshipById(id);
image_path := "word/" + rel.Target;
image := docx_to_pdf_.DocxComponents.Zip().Get(image_path);
data := image.Data();
image_path := docx_to_pdf_.GetCachePath(image_path);
writeFile(rwBinary(), "", image_path, 0, length(data), data);
image := nil;
image_type := GetImageFileType(data);
case image_type of
"png":
image := docx_to_pdf_.PdfFile().LoadPngImageFromFile("", image_path);
"jpg":
image := docx_to_pdf_.PdfFile().LoadJpegImageFromFile("", image_path);
"emf":
image := docx_to_pdf_.PdfFile().LoadEmfImageFromFile("", image_path);
"wmf":
image := docx_to_pdf_.PdfFile().LoadWmfImageFromFile("", image_path);
end;
fileDelete("", image_path);
return array(image_type, image);
end;
function PRange.GetImageFileType(data: binary): string;
begin
stream := new TMemoryStream();
size := length(data);
stream.Write(data[0:size-1], size);
def := array(
('name': 'png', 'position': 0, 'value': array(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)),
('name': 'jpg', 'position': 0, 'value': array(0xFF, 0xD8)),
('name': 'emf', 'position': 40, 'value': array(0x20, 0x45, 0x4d, 0x46)),
('name': 'wmf', 'position': 0, 'value': array(0xd7, 0xcd, 0xc6, 0x9a)),
);
for i:=0 to length(def)-1 do
begin
value := def[i]['value'];
stream.Seek(def[i]['position']);
for j:=0 to length(value)-1 do
begin
r := 0;
stream.Read(r, 1);
if r <> value[j] then break;
if j = length(value)-1 then return def[i]['name'];
end
end
return '';
end;
function PRange.GetParagraphLineSpace(size: real; line: integer; line_rule: string): real;
begin
if not line then line := 240;
if line_rule = "exact" or line_rule = "atLeast" then
begin
lines := line / 240;
return size + lines;
end
else begin
lines := roundto(line / 240, -1);
multi := ceil(size / docx_to_pdf_.CurrentSect.BaseSize);
if (not ifnil(ppr_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 docx_to_pdf_.CurrentSect.SectPr.DocGrid.LinePitch * multi;
end
end;
function TcRange.Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty);
begin
class(BasicRange).Create();
docx_to_pdf_ := docx_to_pdf;
tc_ := tc;
trp_ := trp;
tc_pr_unit_decorator_ := new TcPrUnitDecorator(tc_.TcPr);
content_next_page_ := false;
top_ := false;
end;
function TcRange.Do();
begin
for _,region in region_array_ do
begin
region.BordersRange.Do();
for __,range in region.RangeArr do
range.Do();
end
end;
function TcRange.DoBordersRangeFill();
begin
for _,region in region_array_ do
begin
region.BordersRange.DoFill();
end
end;
function TcRange.Calc();
begin
range_array_ := array();
cell_w := {self.}Width - {self.}Parent.TblPr.TblCellMar.Right.W - {self.}Parent.TblPr.TblCellMar.Left.W;
elements := tc_.Elements();
for _,element in elements do
begin
if element.LocalName = "p" then
begin
range := new PRange(docx_to_pdf_, element);
range.Width := cell_w;
range.Parent := self;
range.Calc();
range_array_[length(range_array_)] := range;
end
end
end;
function TcRange.Run();
begin
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}EndPage := {self.}StartPage;
{self.}DynamicHeight := 0;
content_next_page_ := false;
cell_x := {self.}EndX + {self.}Parent.TblPr.TblCellMar.Left.W;
cell_y := {self.}EndY - {self.}Parent.TblPr.TblCellMar.Top.W;
cell_h := {self.}FixedHeight;
for _,range in range_array_ do
begin
range.StartX := cell_x;
range.StartY := cell_y;
range.LowerBound := {self.}LowerBound;
range.StartPage := {self.}EndPage;
range.Run();
if _ = 0 and range.IsFirstLineOnNextPage() then
begin
content_next_page_ := true;
break;
end
cell_y := range.EndY;
{self.}EndPage := range.EndPage;
{self.}DynamicHeight += range.DynamicHeight;
end
{self.}EndY := cell_y - {self.}Parent.TblPr.TblCellMar.Bottom.W;
{self.}DynamicHeight += {self.}Parent.TblPr.TblCellMar.Bottom.W + {self.}Parent.TblPr.TblCellMar.Top.W;
// 同步行高
if not tc_.TcPr.VMerge and {self.}DynamicHeight > trp_.Height then
trp_.Height := {self.}DynamicHeight;
end;
function TcRange.SetTop();
begin
top_ := true;
end;
function TcRange.ContentNextPage(): boolean;
begin
return content_next_page_;
end;
function TcRange.AlignHeight(height: real);
begin
region_array_ := array();
region := new DTPUtils.Region();
region.BordersRange.Width := {self.}Width;
region.BordersRange.FixedHeight := {self.}FixedHeight;
region.BordersRange.TcPr := tc_pr_unit_decorator_;
{self.}SetBorderRange(region.BordersRange);
region_array_[length(region_array_)] := region;
pg := {self.}StartPage;
y := {self.}StartY;
page_remaining_height := y - {self.}GetLowerBound(pg);
surplus := height - page_remaining_height;
if surplus < 1e-6 then // 一页就够
begin
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := {self.}StartY;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := height;
region.RangeArr union= range_array_;
{self.}EndY := {self.}StartY - height;
end
else begin
page_hash := array();
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := {self.}StartY;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := page_remaining_height;
page_hash[pg.Index] := region;
// surplus -= page_remaining_height;
pg := docx_to_pdf_.PageManager[{self.}pg.Index + 1];
y := pg.OriginalTextCoordinates()[1];
page_remaining_height := y - {self.}GetLowerBound(pg);
while surplus > page_remaining_height do
begin
region := new DTPUtils.Region();
region.BordersRange.Width := {self.}Width;
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := y;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := page_remaining_height;
region.BordersRange.TcPr := tc_pr_unit_decorator_;
region.BordersRange.Top := true;
region.BordersRange.Bottom := true;
{self.}SetBorderRange(region.BordersRange);
region_array_[length(region_array_)] := region;
page_hash[pg.Index] := region;
surplus -= page_remaining_height;
pg := docx_to_pdf_.PageManager[{self.}pg.Index + 1];
y := pg.OriginalTextCoordinates()[1];
page_remaining_height := y - {self.}GetLowerBound(pg);
end
if surplus > 1e-6 then
begin
region := new DTPUtils.Region();
region.BordersRange.Width := {self.}Width;
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := y;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := surplus;
region.BordersRange.TcPr := tc_pr_unit_decorator_;
region.BordersRange.Top := true;
page_hash[pg.Index] := region;
{self.}SetBorderRange(region.BordersRange);
region_array_[length(region_array_)] := region;
{self.}EndY := y - surplus;
end
// 对应page分散到对应region
ranges := array();
for _,range in range_array_ do
ranges union= range.PLineRanges();
for _,range in ranges do
begin
region := page_hash[range.EndPage.Index];
region.RangeArr[length(region.RangeArr)] := range;
end
end
end;
function TcRange.GetLowerBound(pg: Page): real;
begin
return {self.}LowerBound = 0 ? pg.LowerBound : max({self.}LowerBound, pg.LowerBound);
end;
function TcRange.SetVAlign();
begin
val := tc_.TcPr.VAlign.Val;
region := region_array_[0];
arr := region.RangeArr;
if length(arr) = 0 then return;
last_y := arr[length(arr)-1].EndY;
offset := last_y - (region.BordersRange.EndY - region.BordersRange.DynamicHeight) - {self.}Parent.TblPr.TblCellMar.Bottom.W;
case val of
"center":
begin
offset /= 2;
for _,range in arr do
range.Offset(0, -offset);
end
end;
end;
function TcRange.SetBorderRange(range: BordersRange);
begin
tbl_pr := {self.}Parent.TblPr;
if ifObj(tbl_pr.TblBorders) then
begin
if {self.}Row = 0 then
begin
if tbl_pr.TblBorders.Top then
begin
if not tc_pr_unit_decorator_.TcBorders.Top then
tc_pr_unit_decorator_.TcBorders.Top.Copy(tbl_pr.TblBorders.Top);
range.Top := true;
end
if tbl_pr.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows-1 then
begin
if not tc_pr_unit_decorator_.TcBorders.Bottom then
tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.InsideH);
range.Bottom := true;
end
if tbl_pr.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then
begin
if not tc_pr_unit_decorator_.TcBorders.Right then
tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.InsideV);
range.Right := true;
end
if tbl_pr.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows-1 then
begin
if not tc_pr_unit_decorator_.TcBorders.Bottom then
tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.Bottom);
range.Bottom := true;
end
end
else if {self.}Row = {self.}Parent.Rows-1 then
begin
if tbl_pr.TblBorders.Bottom then
begin
if not tc_pr_unit_decorator_.TcBorders.Bottom then
tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.Bottom);
range.Bottom := true;
end
if tbl_pr.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then
begin
if not tc_pr_unit_decorator_.TcBorders.Right then
tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.InsideV);
range.Right := true;
end
end
else begin
if tbl_pr.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows-1 then
begin
if not tc_pr_unit_decorator_.TcBorders.Bottom then
tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.Bottom);
range.Bottom := true;
end
if tbl_pr.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows-1 then
begin
if not tc_pr_unit_decorator_.TcBorders.Bottom then
tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr.TblBorders.InsideH);
range.Bottom := true;
end
if tbl_pr.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then
begin
if not tc_pr_unit_decorator_.TcBorders.Right then
tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.InsideV);
range.Right := true;
end
end
if {self.}Col = 0 then
begin
if tbl_pr.TblBorders.Left then
begin
if not tc_pr_unit_decorator_.TcBorders.Left then
tc_pr_unit_decorator_.TcBorders.Left.Copy(tbl_pr.TblBorders.Left);
range.Left := true;
end
end
if {self.}Col = {self.}Parent.Cols()-1 then
begin
if tbl_pr.TblBorders.Right then
begin
if not tc_pr_unit_decorator_.TcBorders.Right then
tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr.TblBorders.Right);
range.Right := true;
end
end
end
else begin
range.Left := {self.}Col = 0;
range.Top := {self.}Row = 0;
range.Right := true;
range.Bottom := true;
end
if top_ then range.Top := true;
end;
function TcRange.GetTblStyleId(): string;
begin
return {self.}Parent.TblPr.TblStyle.Val;
end;
function TcRange.GetPrType(): string;
begin
if {self.}Row = 0 then return "firstRow";
else if ({self.}Row + 1) % 2 = 0 then return "band1Horz";
else return "band2Horz";
end;
function TblRange.Create(docx_to_pdf: TSDocxToPdf; tbl: Tbl);
begin
class(BasicRange).Create();
docx_to_pdf_ := docx_to_pdf;
tbl_ := tbl;
end;
function TblRange.Do();
begin
for _,r in tc_range_matrix_ do
for __,range in r do
if ifObj(range) then
range.DoBordersRangeFill();
for _,r in tc_range_matrix_ do
for __,range in r do
if ifObj(range) then
range.Do();
end;
function TblRange.Calc();
begin
{self.}SetTblTblPr(tbl_);
tbl_pr_unit_decorator_ := new TblPrUnitDecorator(tbl_.TblPr);
tbl_grid_unit_decorator := new TblGridUnitDecorator(tbl_.TblGrid);
grid_cols_ := tbl_grid_unit_decorator.GridCols();
// 如果是根据内容自适应应该计算并调整grid_cols的值
trs := tbl_.Trs();
rows_ := length(trs);
cols_ := length(grid_cols_);
tr_pr_array_ := array();
tc_range_matrix_ := nils(rows_, cols_);
// 先构建一个矩阵
{self.}CreateTableMatrix(grid_cols_, trs);
end;
function TblRange.CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr);
begin
for i,tr in trs do
begin
{self.}SetTrTrPr(tr);
tr_pr := new TrPrUnitDecorator(tr.TrPr);
tc_x := 0;
trp := new DTPUtils.TrProperty();
trp.TrPr := tr_pr;
tr_pr_array_[i] := trp;
tcs := tr.Tcs();
pos := 0;
for j,tc in tcs do
begin
{self.}SetTcTcPr(tc);
if i = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "firstRow");
else if i = length(trs)-1 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "lastRow")
else if (i + 1) % 2 = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band1Horz");
else {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band2Horz");
grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan);
if tc.TcPr.VMerge and tc.TcPr.VMerge <> "restart" then
begin
tc_x += grid_cols[pos++].W;
for k:=grid_span.Val-1 downto 1 do
begin
tc_range_matrix_[i][pos] := 0;
tc_x += grid_cols[pos++].W;
end
continue;
end
tc_range := new TcRange(docx_to_pdf_, tc, trp);
tc_range.Width := grid_cols[pos].W;
tc_range.FixedHeight := tr_pr.TrHeight.Val;
tc_range.Parent := self;
tc_range.OffsetX := tc_x;
tc_range.Row := i;
tc_range.Col := pos;
tc_range_matrix_[i][pos] := tc_range;
pos++;
// 水平合并的单元格,占位需要和垂直的区分
for k:=grid_span.Val-1 downto 1 do
begin
tc_range_matrix_[i][pos] := 0; // 水平合并占位0
tc_range.Width += grid_cols[pos++].W;
end
tc_x += tc_range.Width;
end
end
// for i,arr in tc_range_matrix_ do
// println("i = {}, arr = {}", i, arr);
// println("\n");
end;
function TblRange.Run();
begin
{self.}ResetCoordinates(tbl_pr_unit_decorator_, grid_cols_);
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}EndPage := {self.}StartPage;
i := 0;
merge_arr := array();
vmerge_height := array();
vmerge_info := array();
while i < rows_ do
begin
// println("i = {}", i);
// if i = 11 then return;
// if i = 10 then
// println(">>>>>>>>>>>>>>>>");
j := 0;
tc_y := {self.}EndY;
top := recompute_flag;
recompute_flag := false;
while j < cols_ do
begin
range := tc_range_matrix_[i][j];
if not ifObj(range) then
begin
j++;
continue;
end
range.StartX := {self.}EndX + range.OffsetX;
range.StartY := tc_y;
range.StartPage := {self.}EndPage;
range.LowerBound := {self.}LowerBound;
if top then range.SetTop();
range.Calc();
range.Run();
if range.ContentNextPage() then // 单元格新页开始,调整上一页的下边界,并重新计算
begin
top := true;
recompute_flag := true;
{self.}EndPage.LowerBound := tc_y;
{self.}EndPage := docx_to_pdf_.PageManager[{self.}EndPage.Index + 1];
[x, y] := {self.}EndPage.OriginalTextCoordinates();
{self.}EndY := y;
break;
end
if range.Tc.TcPr.VMerge then
begin
b_merge_index := i;
e_merge_index := i + 1;
while ifnil(tc_range_matrix_[e_merge_index+1][j]) and e_merge_index < rows_-1 do
e_merge_index++;
merge_arr[e_merge_index][j] := b_merge_index;
if ifnil(vmerge_height[e_merge_index]) or range.DynamicHeight > vmerge_height[e_merge_index] then
vmerge_height[e_merge_index] := range.DynamicHeight;
vmerge_info[e_merge_index] := b_merge_index;
end
j++;
end
if recompute_flag then continue;
top := false;
i_height := 0;
for k,v in merge_arr[i] do
begin
i_height := tr_pr_array_[i].Height;
r := tc_range_matrix_[v][k];
total_height := 0;
for index:=v to i-1 do
total_height += tr_pr_array_[index].Height;
h := vmerge_height[i];
if h > total_height + i_height then
i_height := h - total_height;
else
h := total_height + i_height;
r.AlignHeight(h);
r.SetVAlign();
end
if i_height then tr_pr_array_[i].Height := i_height;
for _,range in tc_range_matrix_[i] do
begin
if not ifObj(range) or range.Tc.TcPr.VMerge then continue;
range.AlignHeight(tr_pr_array_[i].Height);
range.SetVAlign();
{self.}EndY := range.EndY;
if {self.}EndPage.Index < range.EndPage.Index then
{self.}EndPage := range.EndPage;
end
i++;
end
end;
function TblRange.ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol);
begin
total_width := 0;
for _,grid_col in grid_cols do
total_width += grid_col.W;
diff := total_width - {self.}Width;
case tbl_pr.Jc.Val of
"center":
begin
offset := diff/2;
{self.}StartX -= offset;
end
"right":
begin
{self.}StartX -= diff;
end
end;
{self.}Width := total_width;
end;
function TblRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string);
begin
// tc_pr应该是经过外层copy的
tbl_style_pr := docx_to_pdf_.DocxComponents.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type);
if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr);
end;
function TblRange.SetTblTblPr(var tbl: Tbl);
begin
new_tbl_pr := new TblPr();
{self.}SetTblPrByStyleId(new_tbl_pr, tbl.TblPr.TblStyle.Val);
new_tbl_pr.Copy(tbl.TblPr);
tbl.TblPr.Copy(new_tbl_pr);
end;
function TblRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetTblPrByStyleId(tbl_pr, based_on);
tbl_pr.Copy(style.TblPr);
end
end;
function TblRange.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 TblRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetTrPrByStyleId(tr_pr, based_on);
tr_pr.Copy(style.TrPr);
end
end;
function TblRange.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 TblRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetTcPrByStyleId(tc_pr, based_on);
tc_pr.Copy(style.TcPr);
end
end;
function OMathParaRange.Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara);
begin
class(BasicRange).Create();
docx_to_pdf_ := docx_to_pdf;
o_math_para_ := o_math_para;
end;
function OMathParaRange.Do();override;
begin
end;
function OMathParaRange.Run();override;
begin
end;
function OMathParaRange.Calc();
begin
o_math_ := new OMathRange(docx_to_pdf_, o_math_para_.OMath);
o_math_.Width := {self.}Width;
o_math_.Parent := self;
o_math_.StartX := 0;
o_math_.StartY := 0;
o_math_.SetMathSize();
o_math_.Calc();
end;
function OMathRange.Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement);
begin
class(BasicRange).Create();
docx_to_pdf_ := docx_to_pdf;
element_ := element;
sz_ := 0;
end;
function OMathRange.Do();override;
begin
end;
function OMathRange.Calc();
begin
range_array_ := array();
elements := element_.Elements();
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
for _,element in elements do
begin
range := nil;
if element.LocalName = "r" then
range := {self.}MR(element, sz_, {self.}EndX, {self.}EndY);
else if element.LocalName = "f" then
range := {self.}MF(element, sz_, {self.}EndX, {self.}EndY);
else if element.LocalName = "rad" then
range := {self.}MRad(element, sz_, {self.}EndX, {self.}EndY);
else if element.LocalName = "nary" then
range := {self.}MNary(element, sz_, {self.}EndX, {self.}EndY);
else if element.LocalName = "sSup" then
range := {self.}MSSup(element, sz_, {self.}EndX, {self.}EndY);
if not ifObj(range) then
begin
echo format("Math do not support <%s>\n", element.ElementName);
continue;
end
{self.}EndX := range.EndX;
{self.}EndY := range.EndY;
range_array_[length(range_array_)] := range;
end
end;
function OMathRange.SetMathSize();
begin
elements := element_.Elements();
element := elements[0];
rpr := nil;
if element.LocalName = "r" then
rpr := element.RPr;
else if element.LocalName = "f" then
rpr := element.FPr.CtrlPr.RPr;
else if element.LocalName = "nary" then
rpr := element.NaryPr.CtrlPr.RPr;
else if element.LocalName = "rad" then
rpr := element.RadPr.CtrlPr.RPr;
else if element.LocalName = "sSup" then
rpr := element.SSupPr.CtrlPr.RPr;
styles := docx_to_pdf_.DocxComponents.GetStyles();
default_rpr := styles.DocDefaults.RPrDefault.RPr();
if rpr then default_rpr.Copy(rpr);
sz_ := default_rpr.Sz.Val;
end;
function OMathRange.MR(r: R; sz: real; x: real; y: real): PLineRange;
begin
if not r.T then return;
line_range := new PLineRange();
line_range.Parent := self;
line_range.EndX := x;
line_range.EndY := y - sz;
line_range.Width := 0;
line_range.TextMaxSize := sz;
line_range.DynamicHeight := sz;
text := r.T.Text;
pos := 1;
while pos <= length(text) do
begin
text_range := new TextRange();
num := DTPUtils.Utf8CharLengthFromByte(text[pos]);
a_word := text[pos : pos+num-1];
if num = 1 then
begin
char := ord(a_word);
if char >= 0x30 and char <= 0x39 then
text_range.Type := 1;
else if char >= 0x41 and char <= 0x5A then
text_range.Type := 2;
else if char >= 0x61 and char <= 0x7A then
text_range.Type := 2;
else if char = 0x44 or char = 0x46 then
text_range.Type := 5;
word := a_word;
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
end
else if DTPUtils.IsChineseChar(a_word) then
begin
text_range.Type := 3;
word := utf8ToAnsi(a_word);
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
end
else if DTPUtils.IsChinesePunctuation(a_word) then
begin
text_range.Type := 4;
word := utf8ToAnsi(a_word);
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
end
else begin
word := utf8ToAnsi(a_word);
if word = "?" then
begin
word := class(SymbolMapper).ZapfDingbatsChr(a_word);
if ifnil(word) then word := "u";
font_obj := docx_to_pdf_.Font.GetZapfDingbatsFont();
end
else begin
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
end
end
first_page := docx_to_pdf_.PageManager[0];
pdf_page := first_page.PdfPage;
pdf_page.SetFontAndSize(font_obj, rpr.Sz.Val);
rpr := new RPr();
rpr.Sz.Val := sz;
text_range.RPr := rpr;
text_range.Text := word;
text_range.Font := font_obj;
text_range.Width := pdf_page.TextWidth(word);
text_range.Parent := line_range;
text_range.DynamicHeight := rpr.Sz.Val;
text_range.EndX := line_range.EndX;
text_range.EndY := line_range.EndY;
line_range.EndX += text_range.Width;
line_range.Width += text_range.Width;
pos += num;
line_range.AddRange(text_range);
end
return line_range;
end;
function OMathFRange.Create(docx_to_pdf: TSDocxToPdf; f: F);
begin
class(BasicRange).Create();
docx_to_pdf_ := docx_to_pdf;
f_ := f;
range_array_ := array();
end;
function OMathFRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathFRange.Calc();
begin
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
den_range := new OMathRange(docx_to_pdf_, f.Den);
den_range.Sz := sz_;
den_range.StartX := {self.}EndX;
den_range.StartY := {self.}EndY;
den_range.Calc(); // 需要得到高宽
num_range := new OMathRange(docx_to_pdf_, f.Num);
num_range.Sz := sz_;
num_range.StartX := {self.}EndX;
num_range.StartY := {self.}EndY + 1.418 * sz;
num_range.Calc(); // 需要得到高宽
max_len := max(den_range.Width, num_range.Width);
bar := max_len / 0.9;
line_range := new LineRange();
line_range.StartX := x - (bar - max_len) / 2;
line_range.StartY := y + 0.928 * sz;
line_range.EndX := line_range.
line_range.Width := bar;
line_range.LineWidth := 0.04 * sz;
range_array_ union= array(den_range, num_range, line_range);
end;
end.