PdfConverter/range/Advanced/TSPdfParagraphRange.tsf

879 lines
31 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.

type TSPdfParagraphRange = class(TSPdfBasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; paragraph: P);
function Calc();
function Do();override;
function SetTblStyleIdAndType(style_id: string; type: string);
function SetNumPages(num: integer);
function RangesToLines();
function GetLastPage(): TSPage;
function AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
function GetLineRangeArr(): array of TSPdfLineRange;
function Empty(): boolean;
private
function SetPPr(var ppr: PPr);
function SetPPrByStyleId(var ppr: PPr; style_id: string);
function SetRPr(var rpr; ppr: PPrUnitDecorator);
function SetRPrByStyleId(var rpr: RPr; style_id: string);
function SetRPrByTblStyleId(var rpr: RPr; style_id: string);
function SetLvlText();
function GetImageFileType(data: binary): string;
function GetImageData(id: string): PdfImage;
function GetParagraphLineSpace(size: real; line: integer): real;
function BasicRangesToLineRange(): tableArray;
function CheckAndAddPage(y: real; offset: real): boolean;
function GetUtf8CharLength(byte: string): integer;
function SplitTextToTextRange(text: string; rpr: RPrUnitDecorator; link: string);
function RToTextRange(r: R; link: string);
function RDrawing(r: R);
function RAlternateContent(r: R);
function RFootnoteReference(r: R);
function RObject(r: R);
function RFldChar(r: R; stack: Stack);
function SetLinesAlignment();
function ResetCoordinates();
function NewLineRange(): TSPdfLineRange;
function BookMarkLinkToc();
function HyperlinkToToc();
function HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator);
function GetXYCordinates(): array of real;
function AlignRightBound();
private
[weakref]docx_to_pdf_: TSDocxToPdf;
[weakref]docx_components_ware_: TSDocxComponentsWare;
[weakref]paragraph_: P;
[weakref]page_: TSPage;
range_array_: array of TSPdfBasicRange;
line_range_array_: array of TSPdfLineRange;
hyperlink_array_: tableArray;
bookmark_array_: tableArray;
ppr_unit_decorator_: PPrUnitDecorator;
placeholder_array_: tableArray;
table_style_id_: string;
table_style_type_: string;
empty_: boolean;
right_bound_: real;
end;
type FldStruct = class
public
function create();
begin
FldLock := false;
MergeFormat := false;
Quote := false;
Separate := false;
PageArabicMergeFormat := false;
NumPages := false;
ArabicMergeFormat := false;
EndFld := false;
end;
public
FldLock: boolean;
MergeFormat: boolean;
Quote: boolean;
Separate: boolean;
PageArabicMergeFormat: boolean;
NumPages: boolean;
ArabicMergeFormat: boolean;
EndFld: boolean;
end;
type Stack = class
public
function create();
begin
arr_ := array();
index_ := 0;
end;
function Pop();
begin
if index_ = 0 then return nil;
index_--;
ret := arr_[index_];
arr_[index_] := nil;
return ret;
end;
function Push(element: any);
begin
arr_[index_++] := element;
end;
function Empty(): boolean;
begin
return index_ = 0;
end;
private
arr_: tableArray;
index_: integer;
end;
function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; paragraph: P);
begin
docx_to_pdf_ := docx_to_pdf;
page_ := pg;
docx_components_ware_ := components;
paragraph_ := paragraph;
table_style_id_ := "";
table_style_type_ := "";
range_array_ := array();
line_range_array_ := array();
hyperlink_array_ := array();
bookmark_array_ := array();
empty_ := false;
{self.}TSPage := page_;
end;
function TSPdfParagraphRange.Calc(): tableArray;
begin
// ppr.rpr是无效的应该以ppr.pStyle为准
right_bound_ := {self.}StartX + {self.}Width;
if ifnil(paragraph_.XmlChildPPr) then paragraph_.XmlChildPPr := new PPr();
{self.}SetPPr(paragraph_.PPr);
ppr_unit_decorator_ := new PPrUnitDecorator(paragraph_.PPr);
if not ppr_unit_decorator_.RPr.Sz.Val then ppr_unit_decorator_.RPr.Sz.Val := docx_to_pdf_.Font.GetDefaultSz();
{self.}ResetCoordinates();
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before);
{self.}EndY -= ppr_unit_decorator_.Spacing.Before;
{self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before;
{self.}SetLvlText();
elements := paragraph_.Elements();
empty_flag := true;
bookmark_id := '';
bookmark_name := '';
bookmark_flag := false;
fld_stack := new Stack();
for _,element in elements do
begin
if element.LocalName = "r" then
begin
empty_flag := false;
if ifnil(element.XmlChildRPr) then element.XmlChildRPr := new RPr();
{self.}SetRPr(element.RPr, ppr_unit_decorator_);
if element.FldChar.FldCharType = "begin" then
begin
fld_struct := new FldStruct();
fld_stack.Push(fld_struct);
end
if not fld_stack.Empty() then
begin
{self.}RFldChar(element, fld_stack);
continue;
end
if element.Br.Type = "page" then
// {self.}EndY := {self.}LowerBound;
{self.}CheckAndAddPage({self.}LowerBound, 1);
else if ifObj(element.Drawing) then {self.}RDrawing(element);
else if ifObj(element.AlternateContent) then {self.}RAlternateContent(element);
else if ifObj(element.FootnoteReference) then {self.}RFootnoteReference(element);
else if ifObj(element.Object) then {self.}RObject(element);
else {self.}RToTextRange(element, bookmark_name);
end
else if element.LocalName = "fldSimple" then
begin
if ifString(element.Instr) and trim(element.Instr) = "NUMPAGES \\* Arabic \\* MERGEFORMAT" then
begin
rpr := new RPrUnitDecorator(element.Rs(0).RPr);
numpages_index := length(range_array_);
placeholder_array_ := array(numpages_index, rpr);
end
end
else if element.LocalName = "hyperlink" then
begin
empty_flag := false;
{self.}HyperlinkToTextRange(element, ppr_unit_decorator_);
end
else if element.LocalName = "bookmarkStart" then
begin
bookmark_id := element.Id;
bookmark_name := element.Name;
bookmark_array_[bookmark_name] := array();
end
else if element.LocalName = "bookmarkEnd" then
begin
bookmark_id := '';
bookmark_name := '';
end
end
if empty_flag then
begin
line_space := {self.}GetParagraphLineSpace(ppr_unit_decorator_.RPr.Sz.Val, ppr_unit_decorator_.Spacing.Line);
{self.}DynamicHeight += line_space;
{self.}EndY -= {self.}DynamicHeight;
empty_ := true;
end
if placeholder_array_ then return false;
{self.}RangesToLines();
if hyperlink_array_ then {self.}HyperlinkToToc();
if bookmark_array_ then {self.}BookMarkLinkToc();
return true;
end;
function TSPdfParagraphRange.SetNumPages(num: integer);
begin
text := tostring(num);
last_index := length(range_array_);
{self.}SplitTextToTextRange(text, placeholder_array_[1], link);
arr := array();
len := length(range_array_);
for i:=last_index to len-1 do
arr[length(arr)] := range_array_[i];
diff := len - last_index;
for i:=len-1 downto placeholder_array_[0] do
range_array_[i] := range_array_[i-diff];
k := 0;
for i:=placeholder_array_[0] to placeholder_array_[0]+diff-1 do
range_array_[i] := arr[k++];
end;
function TSPdfParagraphRange.BookMarkLinkToc();
begin
for name,arr in bookmark_array_ do
if arr[0] then docx_to_pdf_.LinkToToc(name, arr[0].TSPage, arr[0].EndX, arr[0].EndY + arr[0].RPr.Sz.Val);
end;
function TSPdfParagraphRange.HyperlinkToToc();
begin
ppr := ppr_unit_decorator_;
max_size := 0;
for anchor,arr in hyperlink_array_ do // 整理hyperlink发送到docx_to_pdf_
begin
pg := arr[0].TSPage;
left := {self.}StartX;
right := {self.}StartX + {self.}Width;
top := {self.}StartY;
bottom := {self.}StartY;
x := arr[0].EndX;
y := arr[0].EndY;
if top - {self.}GetParagraphLineSpace(arr[0].RPr.Sz.Val, ppr.Spacing.Line) then
begin
top := docx_to_pdf_.GetCurrentTextPoint().Y;
bottom := top;
end
for _,range in arr do
begin
if x + range.Width - {self.}StartX > {self.}Width + 1e-6 then // 换行
begin
line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line);
bottom -= line_space;
max_size := 0;
if range.TSPage <> pg then
begin
rect := array(left, bottom, right, top);
toc := new TSToc(ppr, rect, pg, x, y);
docx_to_pdf_.AddToc(anchor, toc);
pg := range.TSPage;
bottom := {self.}StartY;
end
end
if range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val;
x := range.EndX + range.Width;
y := range.EndY;
end
font_name := ppr.RPr.RFonts.EastAsia ? ppr.RPr.RFonts.EastAsia : ppr.RPr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, ppr.RPr.B, ppr.RPr.I);
line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line);
pg.PdfPage.SetFontAndSize(font_obj, max_size);
bottom -= line_space;
num_width := pg.PdfPage.TextWidth("." + tostring(pg.Number));
if x + num_width - {self.}StartX > {self.}Width + 1e-6 then // 换行
begin
offset := (line_space - max_size) / 2 + max_size - max_size / 5;
diff := {self.}EndY - {self.}LowerBound;
if {self.}CheckAndAddPage({self.}EndY, line_space) then
begin
{self.}DynamicHeight += diff;
pg := page_;
rect := array(left, bottom, right, top);
toc := new TSToc(ppr, rect, pg, x, y);
docx_to_pdf_.AddToc(anchor, toc);
bottom := {self.}StartY;
end
else begin
bottom -= line_space;
x := {self.}StartX;
y := {self.}EndY - offset;
{self.}EndY -= line_space;
{self.}DynamicHeight += line_space;
end
end
rect := array(left, bottom, right, top);
toc := new TSToc(ppr, rect, pg, x, y, font_obj);
docx_to_pdf_.AddToc(anchor, toc);
end
end;
function TSPdfParagraphRange.HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator);
begin
i := length(range_array_);
rs := hyperlink.Rs();
for _,r in rs do
begin
if r.FldChar.FldCharType = "begin" then break;
// TODOofficexml项目是否应该保留赋值接口如何统一
if ifnil(r.XmlChildRPr) then r.XmlChildRPr := new RPr();
// r.RPr := new RPr();
{self.}SetRPr(r.RPr, ppr_unit_decorator_);
r.RPr.Color.Val := nil;
{self.}RToTextRange(r, hyperlink.Anchor);
end
arr := array();
while i < length(range_array_) do
begin
arr[length(arr)] := range_array_[i];
i++;
end
hyperlink_array_[hyperlink.Anchor] := arr;
end;
function TSPdfParagraphRange.Do();override;
begin
for _,line_range in line_range_array_ do
line_range.Do();
end;
function TSPdfParagraphRange.SetTblStyleIdAndType(style_id: string; type: string);
begin
table_style_id_ := style_id;
table_style_type_ := type;
end;
function TSPdfParagraphRange.NewLineRange(): TSPdfLineRange;
begin
line_range := new TSPdfLineRange(page_);
line_range.StartX := {self.}EndX;
line_range.StartY := {self.}EndY;
line_range.Width := {self.}Width;
return line_range;
end;
function TSPdfParagraphRange.RangesToLines();overload;
begin
{self.}BasicRangesToLineRange();
{self.}DynamicHeight += ppr_unit_decorator_.Spacing.After;
{self.}EndY -= ppr_unit_decorator_.Spacing.After;
if ppr_unit_decorator_.PBdr.Bottom.Val = "single" then
begin
sect_ware := docx_to_pdf_.GetCurrentSectWare();
page_.PdfPage.SetLineWidth(0.05);
page_.PdfPage.SetGrayStroke(0.25);
page_.PdfPage.MoveTo(sect_ware.SectPr.PgMar.Left, {self.}EndY);
page_.PdfPage.LineTo(sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right, {self.}EndY);
page_.PdfPage.Stroke();
end
end;
function TSPdfParagraphRange.BasicRangesToLineRange();
begin
ppr := ppr_unit_decorator_;
line_range := {self.}NewLineRange();
i := 0;
max_size := 0;
max_y := 0;
while i <= length(range_array_)-1 do
begin
range := range_array_[i];
if i = 0 then {self.}EndX += ppr.Ind.FirstLine;
if range is class(TSPdfTextRange) and range.RPr.Sz.Val > max_size then
max_size := range.RPr.Sz.Val;
if range.DynamicHeight > max_y then max_y := range.DynamicHeight;
line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line);
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.Width < {self.}Width then
begin
offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y;
max_value := max(line_space, max_y);
line_range.TSPage := page_;
line_range.EndY := {self.}EndY - max_value;
line_range.DynamicHeight := max_value;
line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset);
line_range_array_[length(line_range_array_)] := line_range;
line_range := {self.}NewLineRange();
max_size := 0;
max_y := 0;
{self.}DynamicHeight += max_value;
{self.}EndY -= max_value;
{self.}EndX := {self.}StartX;
// w:hanging
if range is class(TSPdfTextRange) then
sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz();
else
sz := docx_to_pdf_.Font.GetDefaultSz();
{self.}EndX -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging;
continue;
end
range.EndX := {self.}EndX - range.StartX;
{self.}EndX += range.Width;
line_range.AddRange(range);
i++;
if i = length(range_array_) then
begin
offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y;
max_value := max(line_space, max_y);
line_range.TSPage := page_;
line_range.EndY := {self.}EndY - max_value;
line_range.DynamicHeight := max_value;
line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset);
line_range_array_[length(line_range_array_)] := line_range;
{self.}DynamicHeight += max_value;
{self.}EndY -= max_value;
end
end
{self.}SetLinesAlignment();
{self.}AlignRightBound();
end;
function TSPdfParagraphRange.SetLinesAlignment();
begin
for _,line_range in line_range_array_ do
line_range.Align(ppr_unit_decorator_.Jc.Val);
end;
function TSPdfParagraphRange.AlignRightBound();
begin
len := length(line_range_array_);
if len = 1 then return;
for i:=0 to len-2 do
line_range_array_[i].AlignRightBound(right_bound_);
end;
function TSPdfParagraphRange.CheckAndAddPage(y: real; offset: real): boolean;
begin
if y - offset < {self.}LowerBound then
begin
page_ := docx_to_pdf_.GetNextPage(page_);
if ifnil(page_) then page_ := docx_to_pdf_.AddTSPage();
point := docx_to_pdf_.GetCurrentTextPoint();
{self.}EndY := point.Y;
return true;
end
return false;
end;
function TSPdfParagraphRange.GetUtf8CharLength(byte: string): integer;
begin
if (_and(ord(byte), 0b10000000)) = 0 then
return 1;
else if (_and(ord(byte), 0b11100000)) = 0b11000000 then
return 2;
else if (_and(ord(byte), 0b11110000)) = 0b11100000 then
return 3;
else if (_and(ord(byte), 0b11111000)) = 0b11110000 then
return 4;
end;
function TSPdfParagraphRange.RToTextRange(r: R; link: string);
begin
if r.Anchor then
begin
{self.}HyperlinkToTextRange(r);
end
else begin
rpr := new RPrUnitDecorator(r.RPr);
text := r.T.Text;
if ifString(text) then {self.}SplitTextToTextRange(text, rpr, link);
end
end;
function TSPdfParagraphRange.SplitTextToTextRange(text: string; rpr: RPrUnitDecorator; link: string);
begin
pos := 1;
while pos <= length(text) do
begin
num := {self.}GetUtf8CharLength(text[pos]);
a_word := text[pos : pos+num-1];
word := utf8ToAnsi(a_word);
if num <> 1 and word = "?" then
word := utf8ToAnsi(docx_to_pdf_.GetSymbol(a_word));
pos += num;
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I);
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val);
word_width := page_.PdfPage.TextWidth(word);
text_range := new TSPdfTextRange();
text_range.RPr := rpr;
text_range.Text := word;
text_range.Font := font_obj;
text_range.Width := word_width;
range_array_[length(range_array_)] := text_range;
if ifarray(bookmark_array_[link]) then bookmark_array_[link] union= array(text_range);
end
end;
function TSPdfParagraphRange.RDrawing(r: R);
begin
if ifObj(r.Drawing._Inline.XmlNode) then
begin
id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed;
[image_type, image] := {self.}GetImageData(id);
if not image then return;
xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm);
image_range := new TSPdfImageRange();
image_range.Image := image;
image_range.Type := image_type;
image_range.StartX := xfrm.Off.X;
image_range.StartY := xfrm.Off.Y;
image_range.Width := xfrm.Ext.CX;
image_range.DynamicHeight := xfrm.Ext.CY;
range_array_[length(range_array_)] := image_range;
end
else if ifObj(r.Drawing.Anchor.XmlNode) then
begin
anchor := r.Drawing.Anchor;
id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed;
[image_type, image] := {self.}GetImageData(id);
if not image then return;
[x, y] := {self.}GetXYCordinates();
xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm);
position_h := new PositionHUnitDecorator(anchor.PositionH);
position_v := new PositionVUnitDecorator(anchor.PositionV);
if position_h.RelativeFrom = "paragraph" then
x := {self.}StartY;
if position_v.RelativeFrom = "paragraph" then
y := {self.}StartY;
image_range := new TSPdfImageRange();
image_range.Image := image;
image_range.Type := image_type;
image_range.EndX := x + position_h.PosOffset.Text;
image_range.EndY := y - position_v.PosOffset.Text - xfrm.Ext.CY;
image_range.Width := xfrm.Ext.CX;
image_range.DynamicHeight := xfrm.Ext.CY;
image_range.TSPage := page_;
image_range.Do();
end
end;
function TSPdfParagraphRange.RAlternateContent(r: R);
begin
anchor := r.AlternateContent.Choice.Drawing.Anchor;
wsp := anchor.Graphic.GraphicData.Wsp;
[x, y] := {self.}GetXYCordinates();
xfrm := new XfrmUnitDecorator(wsp.SpPr.Xfrm);
position_h := new PositionHUnitDecorator(anchor.PositionH);
position_v := new PositionVUnitDecorator(anchor.PositionV);
if position_h.RelativeFrom = "paragraph" then
x := {self.}StartY;
if position_v.RelativeFrom = "paragraph" then
y := {self.}StartY;
x += position_h.PosOffset.Text;
y -= position_v.PosOffset.Text;
w := xfrm.Ext.CX;
body_pr := new BodyPrUnitDecorator(wsp.BodyPr);
x += body_pr.LIns;
w -= (body_pr.LIns + body_pr.RIns);
ps := wsp.Txbx.TxbxContent.Ps();
for _,p in ps do
begin
range := new TSPdfParagraphRange(docx_to_pdf_, page_, docx_components_ware_, p);
range.StartX := x;
range.StartY := y;
range.Width := w;
range.Calc();
range.Do();
y := range.EndY;
end
end;
function TSPdfParagraphRange.RFootnoteReference(r: R);
begin
id := R.FootnoteReference.Id;
footnotes_adapter := docx_components_ware_.GetFootnotesAdapter();
footnote := footnotes_adapter.GetFootnoteById(id);
sect_ware := docx_to_pdf_.GetCurrentSectWare();
w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left;
lb := 0;
[x, y] := docx_to_pdf_.CalculateTextCoordinates();
// range := new TSPdfParagraphRange(self, page_, docx_components_ware_, );
end;
function TSPdfParagraphRange.RObject(r: R);
begin
id := r.Object.Shape.Imagedata.Id;
[image_type, image] := {self.}GetImageData(id);
if not image then return;
style := r.Object.Shape.Style;
style_arr := str2array(style, ";");
for _,str in style_arr do
begin
if startsStr("width:", str) then w := strtofloat(str[7:length(str)-2]);
else if startsStr("height:", str) then h := strtofloat(str[8:length(str)-2]);
end
image_range := new TSPdfImageRange();
image_range.Image := image;
image_range.Type := image_type;
image_range.StartX := 0;
image_range.StartY := 0;
image_range.Width := w;
image_range.DynamicHeight := h;
range_array_[length(range_array_)] := image_range;
end;
function TSPdfParagraphRange.RFldChar(r: R; stack: Stack);
begin
fld_struct := stack.Pop();
if r.FldChar.FldCharType = "begin" then
fld_struct.EndFld := false;
else if r.FldChar.FldCharType = "end" then
fld_struct.EndFld := true;
else if r.FldChar.FldCharType = "separate" then
fld_struct.Separate := true;
if r.FldChar.FldLock then
fld_struct.FldLock := true;
instr_text := ifString(r.InstrText.Text) ? trim(r.InstrText.Text) : "";
if instr_text <> "" then
begin
if instr_text = "QUOTE" then
fld_struct.Quote := true;
else if instr_text = "\\* MERGEFORMAT" then
fld_struct.MergeFormat := true;
else if instr_text = "PAGE \\* Arabic \\* MERGEFORMAT" 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;
end
if fld_struct.Quote then
begin
if not fld_struct.EndFld and not fld_struct.Separate then
begin
stack.Push(fld_struct);
return;
end
end
else if fld_struct.PageArabicMergeFormat then
begin
if fld_struct.Separate then
begin
r.T.Text := tostring(page_.Number);
{self.}RToTextRange(r, nil);
fld_struct.PageArabicMergeFormat := false;
end
end
else if fld_struct.ArabicMergeFormat then
begin
if fld_struct.Separate then
begin
rpr := new RPrUnitDecorator(r.RPr);
numpages_index := length(range_array_);
placeholder_array_ := array(numpages_index, rpr);
fld_struct.NumPages := false;
end
end
if not fld_struct.EndFld then
begin
stack.Push(fld_struct);
end
if ifObj(r.Drawing) then {self.}RDrawing(r);
else if ifObj(r.AlternateContent) then {self.}RAlternateContent(r);
else if ifObj(r.FootnoteReference) then {self.}RFootnoteReference(r);
else if ifObj(r.Object) then {self.}RObject(r);
end;
function TSPdfParagraphRange.GetXYCordinates(): array of real;
begin
xml_file := docx_to_pdf_.GetCurrentXmlFile();
if xml_file = "document.xml" then
[x, y] := docx_to_pdf_.CalculateTextCoordinates();
else begin
sect_ware := docx_to_pdf_.GetCurrentSectWare();
x := sect_ware.SectPr.PgMar.Left;
if ansiContainsStr(xml_file, "footer") then
y := sect_ware.SectPr.PgMar.Bottom;
else if ansiContainsStr(xml_file, "header") then
y := sect_ware.SectPr.PgSz.H - sect_ware.SectPr.PgMar.Header;
end
return array(x, y);
end;
function TSPdfParagraphRange.GetImageData(id: string): PdfImage;
begin
xml_file := docx_to_pdf_.GetCurrentXmlFile();
if xml_file = "document.xml" then
rels_adapter := docx_components_ware_.GetDocumentRelsAdapter();
else if ansiContainsStr(xml_file, "footer") then
rels_adapter := docx_components_ware_.GetFtrRelsAdapter(xml_file);
else if ansiContainsStr(xml_file, "header") then
rels_adapter := docx_components_ware_.GetHdrRelsAdapter(xml_file);
rel := rels_adapter.GetRelationshipById(id);
image_path := "word/" + rel.Target;
image := docx_components_ware_.Zip().Get(image_path);
data := image.Data();
image_path := docx_to_pdf_.GetCachePath(image_path);
writeFile(rwBinary(), "", image_path, 0, length(data), data);
image := nil;
image_type := GetImageFileType(data);
case image_type of
"png":
image := docx_to_pdf_.GetPdf().LoadPngImageFromFile("", image_path);
"jpg":
image := docx_to_pdf_.GetPdf().LoadJpegImageFromFile("", image_path);
"emf":
image := docx_to_pdf_.GetPdf().LoadEmfImageFromFile("", image_path);
end;
fileDelete("", image_path);
return array(image_type, image);
end;
function TSPdfParagraphRange.GetImageFileType(data: binary): string;
begin
stream := new TMemoryStream();
size := length(data);
stream.Write(data[0:size-1], size);
def := array(
('name': 'png', 'position': 0, 'value': array(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)),
('name': 'jpg', 'position': 0, 'value': array(0xFF, 0xD8)),
('name': 'emf', 'position': 40, 'value': array(0x20, 0x45, 0x4d, 0x46)),
);
for i:=0 to length(def)-1 do
begin
value := def[i]['value'];
stream.Seek(def[i]['position']);
for j:=0 to length(value)-1 do
begin
r := 0;
stream.Read(r, 1);
if r <> value[j] then break;
if j = length(value)-1 then return def[i]['name'];
end
end
return '';
end;
function TSPdfParagraphRange.GetParagraphLineSpace(size: real; line: integer): real;
begin
sect_ware := docx_to_pdf_.GetCurrentSectWare();
if not line then line := 12;
lines := roundto(line / 12, -1);
multi := ceil(size / sect_ware.BaseSize) * lines;
return sect_ware.SectPr.DocGrid.LinePitch * multi;
end;
function TSPdfParagraphRange.SetPPr(var ppr: PPr);
begin
new_ppr := new PPr();
styles := docx_components_ware_.GetStyles();
new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr);
new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr);
{self.}SetPPrByStyleId(new_ppr, table_style_id_);
{self.}SetPPrByStyleId(new_ppr, ppr.PStyle.Val);
if ifObj(ppr) then
begin
new_ppr.Copy(ppr);
ppr.Copy(new_ppr);
end
end;
function TSPdfParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string);
begin
styles := docx_components_ware_.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetPPrByStyleId(ppr, based_on);
ppr.Copy(style.PPr);
ppr.RPr.Copy(style.RPr);
end
end;
function TSPdfParagraphRange.SetRPr(var rpr; ppr: PPrUnitDecorator);
begin
new_rpr := new RPr();
styles := docx_components_ware_.GetStyles();
new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr);
{self.}SetRPrByTblStyleId(new_rpr, table_style_id_);
{self.}SetRPrByStyleId(new_rpr, ppr.PStyle.Val);
{self.}SetRPrByStyleId(new_rpr, rpr.RStyle.Val);
if ifObj(rpr) then
begin
new_rpr.Copy(rpr);
rpr.Copy(new_rpr);
end
end;
function TSPdfParagraphRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string);
begin
styles := docx_components_ware_.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetRPrByTblStyleId(rpr, based_on);
rpr.Copy(style.RPr);
end
if table_style_type_ then
begin
tbl_style_pr := docx_components_ware_.GetTblStylePrByType(table_style_id_, table_style_type_);
if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr);
end
end;
function TSPdfParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string);
begin
styles := docx_components_ware_.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
based_on := style.BasedOn.Val;
{self.}SetRPrByStyleId(rpr, based_on);
rpr.Copy(style.RPr);
end
end;
function TSPdfParagraphRange.SetLvlText();
begin
numbering_ware := docx_components_ware_.GetNumberingWare();
if not ifObj(numbering_ware) then return;
[lvl_text, lvl] := numbering_ware.GetNumberLvl(paragraph_.PPr);
if lvl_text = "" and ifnil(lvl) then return;
{self.}SetRPr(lvl.RPr, paragraph_.PPr);
rpr := new RPrUnitDecorator(lvl.RPr);
{self.}SplitTextToTextRange(lvl_text, rpr);
end;
function TSPdfParagraphRange.ResetCoordinates();
begin
// 根据段落的间距确定新的坐标
ppr := ppr_unit_decorator_;
sz := ppr.RPr.SzCs.Val ? ppr.RPr.SzCs.Val : ppr.RPr.Sz.Val ? ppr.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz();
{self.}StartX += ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
{self.}Width -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
{self.}Width -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right;
end;
function TSPdfParagraphRange.GetLastPage(): TSPage;
begin
return page_;
end;
function TSPdfParagraphRange.AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
begin
for _,line_range in line_range_array_ do
line_range.AdjustRangeOffset(page, x_offset, y_offset);
end;
function TSPdfParagraphRange.GetLineRangeArr(): array of TSPdfLineRange;
begin
return line_range_array_;
end;
function TSPdfParagraphRange.Empty(): boolean;
begin
return empty_;
end;