Compare commits

..

2 Commits

Author SHA1 Message Date
csh a118ff6c26 update 2025-02-18 10:24:25 +08:00
csh 5c93255461 1. 重构代码
2. 优化中文和西文字符间距
2025-02-18 10:23:49 +08:00
24 changed files with 6202 additions and 2828 deletions

View File

@ -1,116 +1,89 @@
type TSDocxToPdf = class
uses TSPdfEnumerations, DocxML, DocxMLAdapter, DocxMLUnitDecorator, DTPModules, DTPUtils, DTPAdvancedRanges;
public
function Create(alias: string; file: string);
function Destroy();
function SaveToFile(alias: string; file: string): integer;
function Transform();
function GetPdf(): PdfFile;
function GetCurrentSectWare(): TSSectWare;
function GetCurrentTextPoint(): Point;
function GetCurrentHdrPoint(): Point;
function GetCurrentFtrPoint(): Point;
function GetCurrentNoteWare(): TSNoteWare;
function GetCachePath(image_path: string): string;
function GetNextPage(page: TSPage): TSPage;
function GetCurrentXmlFile(): string;
function GetCurrentNoteModule(): NoteModule;
function AddTSPage(flag: boolean): TSPage;
function LinkToToc(anchor: string; page: TSPage; left: real; top: real);
function AddToc(anchor: string; toc: TSToc);
function SetHeaderAndFooter();
function AddPage(flag: boolean): Page;
function ProcessNumpages();
function CalculateTextCoordinates(): array of real;
function GetSymbol(symbol: string);
function AddDocxPage(pg: TSPage; r: R);
function AddColIndex();
function UpdateDocxPageNumpages();
// docx页码扩展
function UpdateDocxPageNumPages();
function SaveDocxFile();overload;
function SaveDocxFile(alias: string; file: string);overload;
property Font read ReadFont;
function ReadFont();
property PdfFile read pdf_;
property Font read font_module_;
property PageManager read page_manager_module_;
property Toc read toc_module_;
property Note read note_module_;
private
function InitDocxComponents(alias: string; file: string);
function InitCachePath(file: string);
function InitPdfEncoder();
function InitSectWare();
function InitSymbol();
function AllocateElementsToSectWare();
function InitSectModule();
function AllocateElementsToSectModule();
function ClassifyCols(var point: Point; cols: Cols);
function SetHdr(type: string);
function SetFtr(type: string);
function TransformP(var point: Point; paragraph: P; w: real; lb: real);
function TransformTbl(var point: Point; table: Tbl; w: real; lb: real);
function TransformSdt(var point: Point; sdt: Sdt; w: real; lb: real);
function PrintGrid(page: PdfPage; sect_ware: TSSectWare); // test
function TransformP(paragraph: P; x: real; y: real; w: real; lb: real): ParagraphRange;
function TransformTbl(table: Tbl; x: real; y: real; w: real; lb: real): TableRange;
function TransformSdt(sdt: Sdt; x: real; y: real; w: real; lb: real): array of ParagraphRange;
private
pdf_: PdfFile;
docx_components_ware_: TSDocxComponentsWare; // TSDocxComponentsWare
docx_components_module_: DocxComponentsModule; // TSDocxComponentsModule
cache_path_: string; // 临时目录,用来存放临时文件
font_ware_: TSFontWare; // 字体部件
sect_ware_array_: array of TSSectWare; // 页面布局部件数组
current_sect_ware_: TSSectWare;
font_module_: FontModule; // 字体模块
sect_module_array_: array of SectModule; // 页面布局模块数组
current_sect_module_: SectModule;
current_sect_pr_adapter_: SectPrAdapter;
symbol_: tableArray;
current_page_: TSPage;
page_array_: array of TSPage;
toc_array_: tableArray;
toc_unmacthed_array_: tableArray;
page_manager_module_: PageManagerModule;
current_page_: Page;
toc_module_: TocModule; // 目录模块
note_module_: NoteModule; // 脚注/尾注
range_page_number_array_: tableArray;
text_point_: Point; // 定位坐标点
hdr_point_: Point; // 页眉坐标
ftr_point_: Point; // 页脚坐标
xml_file_: string;
even_and_odd_flag_: boolean;
note_ware_: TSNoteWare; // 脚注/尾注
// 回写docx
docx_page_arr_: tableArray;
update_docx_pages_: boolean;
end;
type Point = class
function Create();
begin
{self.}X := 0;
{self.}Y := 0;
end
X: real;
Y: real;
end;
function TSDocxToPdf.Create(alias: string; file: string);
begin
pdf_ := new PdfFile();
font_ware_ := new TSFontWare(pdf_);
pdf_.SetCompressionMode(TSPdfEnumerations.COMP_ALL);
font_module_ := new DTPModules.FontModule(pdf_);
{self.}InitPdfEncoder();
{self.}InitDocxComponents(alias, file);
{self.}InitCachePath(file);
{self.}InitSectWare();
{self.}InitSymbol();
{self.}InitSectModule();
current_page_ := nil;
page_array_ := array();
toc_array_ := array();
toc_unmacthed_array_ := array();
page_manager_module_ := new DTPModules.PageManagerModule(pdf_);
toc_module_ := new DTPModules.TocModule();
range_page_number_array_ := array();
text_point_ := new Point();
hdr_point_ := new Point();
ftr_point_ := new Point();
xml_file_ := "document.xml";
settings := docx_components_ware_.Settings;
settings := docx_components_module_.Settings;
settings.XmlChildEvenAndOddHeaders.Deserialize();
even_and_odd_flag_ := settings.EvenAndOddHeaders ? true : false;
note_ware_ := nil;
note_module_ := new ;
// 回写docx
docx_page_arr_ := array();
@ -129,60 +102,48 @@ end;
function TSDocxToPdf.Transform();
begin
for _,sect_ware in sect_ware_array_ do
for _,sect_module in sect_module_array_ do
begin
if current_sect_ware_ <> sect_ware then
if current_sect_module_ <> sect_module then
begin
current_sect_ware_ := sect_ware;
current_sect_pr_adapter_ := new SectPrAdapter(current_sect_ware_.SectPr.GetObject());
{self.}AddTSPage(true);
current_sect_module_ := sect_module;
current_sect_pr_adapter_ := new SectPrAdapter(current_sect_module_.SectPr.GetObject());
{self.}AddPage(true);
xml_file_ := "document.xml";
end
// 分栏
elements := sect_ware.Elements();
cols := current_sect_ware_.SectPr.Cols;
elements := sect_module.Elements();
cols := current_sect_module_.SectPr.Cols;
if cols.Num > 1 then
begin
columns := {self.}ClassifyCols(text_point_, cols);
columns := {self.}ClassifyCols(current_page_.TextPoint, cols);
end
else begin
w := current_sect_ware_.SectPr.PgSz.W - current_sect_ware_.SectPr.PgMar.Right - current_sect_ware_.SectPr.PgMar.Left;
lb := current_sect_ware_.SectPr.PgMar.Bottom;
w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left;
lb := max(current_page_.SectPr.PgMar.Bottom, current_page_.FtrPoint.Y);
for _,element in elements do
begin
// if _ = 8 then break;
// if _ = 3 then
// println("_ = {}, xml_file_ = {}", _, xml_file_);
if element.LocalName = "p" then {self.}TransformP(text_point_, element, w, lb);
else if element.LocalName = "tbl" then {self.}TransformTbl(text_point_, element, w, lb);
else if element.LocalName = "sdt" then {self.}TransformSdt(text_point_, element, w, lb);
x := current_page_.TextPoint.X;
y := current_page_.TextPoint.Y;
// if _ = 266 then break;
// if _ = 20 then
// println("_ = {}, xml_file_ = {}, error = {}", _, xml_file_, pdf_.GetError());
range := nil;
if element.LocalName = "p" then range := {self.}TransformP(element, x, y, w, lb);
else if element.LocalName = "tbl" then range := {self.}TransformTbl(element, x, y, w, lb);
else if element.LocalName = "sdt" then {self.}TransformSdt(element, x, y, w, lb);
if ifObj(range) then
begin
current_page_.TextPoint.Y := range.EndY;
range.Do();
end
end
end
end
{self.}ProcessNumpages();
end;
function TSDocxToPdf.GetCurrentTextPoint(): Point;
begin
return text_point_;
end;
function TSDocxToPdf.GetCurrentHdrPoint(): Point;
begin
return hdr_point_;
end;
function TSDocxToPdf.GetCurrentFtrPoint(): Point;
begin
return ftr_point_;
end;
function TSDocxToPdf.GetCurrentSectWare(): TSSectWare;
begin
return current_sect_ware_;
end;
function TSDocxToPdf.GetCachePath(image_path: string): string;
begin
return cache_path_ + extractFileName(image_path);
@ -193,16 +154,6 @@ begin
return xml_file_;
end;
function TSDocxToPdf.GetPdf(): PdfFile;
begin
return pdf_;
end;
function TSDocxToPdf.ReadFont();
begin
return font_ware_;
end;
function TSDocxToPdf.InitPdfEncoder();
begin
pdf_.UseCNSFonts();
@ -212,9 +163,8 @@ end;
function TSDocxToPdf.InitDocxComponents(alias: string; file: string);
begin
namespace "DOCX";
docx_components_ware_ := new TSDocxComponentsWare();
[err, msg] := docx_components_ware_.Open(alias, file, nil);
docx_components_module_ := new DTPModules.DocxComponentsModule();
[err, msg] := docx_components_module_.Open(alias, file, nil);
if err then raise "Open file error.";
end;
@ -227,78 +177,72 @@ begin
createDir("", cache_path_);
end;
function TSDocxToPdf.InitSectWare();
function TSDocxToPdf.InitSectModule();
begin
sect_ware_array_ := array();
current_sect_ware_ := nil;
sect_module_array_ := array();
current_sect_module_ := nil;
current_sect_pr_adapter_ := nil;
document := docx_components_ware_.Document;
document := docx_components_module_.Document;
document.Deserialize();
{self.}AllocateElementsToSectWare();
{self.}AllocateElementsToSectModule();
end;
function TSDocxToPdf.InitSymbol();
function TSDocxToPdf.AllocateElementsToSectModule();
begin
symbol_ := array(
"": chr(118),
"": chr(110),
"": chr(108),
"": chr(117),
"": chr(108),
"o": chr(109),
"": chr(110),
);
end;
function TSDocxToPdf.AllocateElementsToSectWare();
begin
elements := docx_components_ware_.Document.Body.Elements();
ware := new TSSectWare();
fp := function(ware, sect);
elements := docx_components_module_.Document.Body.Elements();
module := new DTPModules.SectModule();
fp := function(module, sect);
begin
sect := new SectPrUnitDecorator(sect);
sect.PgSz.Orient := sect.PgSz.Orient ? "portrait" : "landscape";
sect.Type.Val := sect.Type.Val ?: "nextPage";
ware.SectPr := sect;
ware.Do();
module.SectPr := sect;
end
for i:=0 to length(elements)-1 do
begin
element := elements[i];
ware.AddElement(element);
module.AddElement(element);
if element.LocalName = "p" and ifObj(element.PPr.SectPr) then
begin
##fp(ware, element.PPr.SectPr);
sect_ware_array_[length(sect_ware_array_)] := ware;
ware := new TSSectWare();
##fp(module, element.PPr.SectPr);
sect_module_array_[length(sect_module_array_)] := module;
module := new DTPModules.SectModule();
end
else if element.LocalName = "sectPr" and i = length(elements)-1 then
begin
##fp(ware, element);
sect_ware_array_[length(sect_ware_array_)] := ware;
##fp(module, element);
sect_module_array_[length(sect_module_array_)] := module;
end
end
// println("sect_ware_array_ = {}", sect_ware_array_);
// println("sect_module_array_ = {}", sect_module_array_);
end;
function TSDocxToPdf.AddTSPage(flag: boolean = false): TSPage;
function TSDocxToPdf.AddPage(flag: boolean = false): Page;
begin
if current_sect_ware_.SectPr.Type.Val = "continuous" and length(page_array_) <> 0 then return;
page := pdf_.AddPage();
page.SetWidth(current_sect_ware_.SectPr.PgSz.W);
page.SetHeight(current_sect_ware_.SectPr.PgSz.H);
// println("W = {}, H = {}", current_sect_ware_.SectPr.PgSz.W, current_sect_ware_.SectPr.PgSz.H);
if current_sect_module_.SectPr.Type.Val = "continuous" and page_manager_module_.Count <> 0 then return;
len := length(page_array_);
current_page_ := new TSPage();
current_page_.Index := len;
current_page_.PdfPage := page;
current_page_.Number := flag ? ifnil(current_sect_ware_.SectPr.PgNumType.Start) ? 1 : current_sect_ware_.SectPr.PgNumType.Start : page_array_[len-1].Number + 1;
// println("len = {}, Number = {}", len, current_page_.Number);
page_array_[len] := current_page_;
page := page_manager_module_.NewPage();
page.SectPr := current_sect_module_.SectPr;
page.Number := flag ? ifnil(current_sect_module_.SectPr.PgNumType.Start) ? 1 : current_sect_module_.SectPr.PgNumType.Start : page_manager_module_[page_manager_module_.Count() - 2].Number + 1;
page.BaseSize := round(page.SectPr.DocGrid.LinePitch * 0.75);
// 正文、页眉页脚坐标
// 页眉:从上往下,不需要调整
page.HdrPoint.X := page.SectPr.PgMar.Left;
page.HdrPoint.Y := page.SectPr.PgSz.H - page.SectPr.PgMar.Header;
// 页脚:从下往上,需要调整
page.FtrPoint.X := page.SectPr.PgMar.Left;
page.FtrPoint.Y := page.SectPr.PgSz.H;
// 正文:运行完页眉页脚后需要再次计算
page.TextPoint.X := page.SectPr.PgMar.Left;
page.TextPoint.Y := page.SectPr.PgSz.H - max(page.SectPr.PgMar.Top, page.SectPr.PgMar.Header);
current_page_ := page;
// println("TextPoint.X = {}, TextPoint.Y = {}", current_page_.TextPoint.X, current_page_.TextPoint.Y);
// println("len = {}, Number = {}", page_manager_module_.Count(), current_page_.Number);
// 页眉页脚
if current_sect_ware_.SectPr.TitlePg and current_page_.Index = 0 then
if current_sect_module_.SectPr.TitlePg and current_page_.Index = 0 then
type_name := "first";
else if not even_and_odd_flag_ then
type_name := "default";
@ -312,217 +256,152 @@ begin
{self.}SetFtr(type_name);
xml_file_ := bk_file;
// 正文坐标
[x, y] := {self.}CalculateTextCoordinates();
text_point_.X := x;
text_point_.Y := y;
if sysparams["_PDF_PAGE_GRID_DEBUG_"] then
{self.}PrintGrid(page, current_sect_ware_);
// println("W = {}, H = {}", current_page_.SectPr.PgSz.W, current_page_.SectPr.PgSz.H);
// println("Top = {}, Bottom = {}", current_page_.SectPr.PgMar.Top, current_page_.SectPr.PgMar.Bottom);
// println("Left = {}, Right = {}", current_page_.SectPr.PgMar.Left, current_page_.SectPr.PgMar.Right);
// println("Header = {}", current_page_.SectPr.PgMar.Header);
// println("TextPoint.X = {}, TextPoint.Y = {}", current_page_.TextPoint.X, current_page_.TextPoint.Y);
// println("HdrPoint.X = {}, HdrPoint.Y = {}", current_page_.HdrPoint.X, current_page_.HdrPoint.Y);
// println("FtrPoint.X = {}, FtrPoint.Y = {}", current_page_.FtrPoint.X, current_page_.FtrPoint.Y);
return current_page_;
end;
function TSDocxToPdf.CalculateTextCoordinates(): array of real;
begin
x := current_sect_ware_.SectPr.PgMar.Left;
y := min(current_sect_ware_.SectPr.PgSz.H - max(current_sect_ware_.SectPr.PgMar.Top, current_sect_ware_.SectPr.PgMar.Header), hdr_point_.Y);
return array(x, y);
end;
function TSDocxToPdf.SetFtr(type: string);
begin
ftr_point_.X := current_sect_ware_.SectPr.PgMar.Left;
ftr_point_.Y := current_sect_ware_.SectPr.PgMar.Bottom;
footer_reference := current_sect_pr_adapter_.GetFooterReferenceByType(type);
ftr_range := array();
if ifObj(footer_reference) then
begin
rels_adapter := docx_components_ware_.GetDocumentRelsAdapter();
rels_adapter := docx_components_module_.GetDocumentRelsAdapter();
rel := rels_adapter.GetRelationshipById(footer_reference.Id);
w := current_sect_ware_.SectPr.PgSz.W - current_sect_ware_.SectPr.PgMar.Right - current_sect_ware_.SectPr.PgMar.Left;
w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left;
lb := 0;
obj := docx_components_ware_.GetFtr(rel.Target);
obj := docx_components_module_.GetFtr(rel.Target);
xml_file_ := rel.Target;
elements := obj.Elements();
for _,element in elements do
begin
if element.LocalName = "p" then {self.}TransformP(ftr_point_, element, w, lb);
x := current_page_.FtrPoint.X;
y := current_page_.FtrPoint.Y;
range := nil;
if element.LocalName = "p" then range := {self.}TransformP(element, x, y, w, lb);
if ifObj(range) then
begin
current_page_.FtrPoint.Y := range.EndY;
ftr_range[length(ftr_range)] := range;
end
end
end
last_range := ftr_range[length(ftr_range)-1];
y_offset := last_range.EndY - current_page_.SectPr.PgMar.Bottom;
height := 0;
for _,range in ftr_range do
begin
range.Offset(0, y_offset);
range.Do();
height += range.DynamicHeight;
end
current_page_.FtrPoint.Y := current_page_.SectPr.PgMar.Bottom + height;
end;
function TSDocxToPdf.SetHdr(type: string);
begin
hdr_point_.X := current_sect_ware_.SectPr.PgMar.Left;
hdr_point_.Y := current_sect_ware_.SectPr.PgSz.H - current_sect_ware_.SectPr.PgMar.Header;
header_reference := current_sect_pr_adapter_.GetHeaderReferenceByType(type);
if ifObj(header_reference) then
begin
rels_adapter := docx_components_ware_.GetDocumentRelsAdapter();
rels_adapter := docx_components_module_.GetDocumentRelsAdapter();
rel := rels_adapter.GetRelationshipById(header_reference.Id);
w := current_sect_ware_.SectPr.PgSz.W - current_sect_ware_.SectPr.PgMar.Right - current_sect_ware_.SectPr.PgMar.Left;
w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left;
lb := 0;
obj := docx_components_ware_.GetHdr(rel.Target);
obj := docx_components_module_.GetHdr(rel.Target);
xml_file_ := rel.Target;
elements := obj.Elements();
for _,element in elements do
begin
if element.LocalName = "p" then {self.}TransformP(hdr_point_, element, w, lb);
end
end
end;
function TSDocxToPdf.TransformP(var point: Point; paragraph: P; w: real; lb: real);
begin
range := new TSPdfParagraphRange(self, current_page_, docx_components_ware_, paragraph);
range.StartX := point.X;
range.StartY := point.Y;
range.Width := w;
range.LowerBound := lb;
r := range.Calc();
if r then range.Do();
else range_page_number_array_[length(range_page_number_array_)] := range;
point.Y := range.EndY;
end;
function TSDocxToPdf.TransformTbl(var point: Point; table: Tbl; w: real; lb: real);
begin
range := new TSPdfTableRange(self, current_page_, docx_components_ware_, table);
range.StartX := point.X;
range.StartY := point.Y;
range.Width := w;
range.LowerBound := lb;
range.Calc();
x := current_page_.HdrPoint.X;
y := current_page_.HdrPoint.Y;
range := nil;
if element.LocalName = "p" then range := {self.}TransformP(element, x, y, w, lb);
if ifObj(range) then
begin
current_page_.HdrPoint.Y := range.EndY;
range.Do();
point.Y := range.EndY;
current_page_.TextPoint.Y := min(current_page_.TextPoint.Y, range.EndY);
end
end
end
end;
function TSDocxToPdf.TransformSdt(var point: Point; sdt: Sdt; w: real; lb: real);
function TSDocxToPdf.TransformP(paragraph: P; x: real; y: real; w: real; lb: real): ParagraphRange;
begin
range := new ParagraphRange(self, current_page_, docx_components_module_, paragraph);
range.StartX := x;
range.StartY := y;
range.Width := w;
range.LowerBound := lb;
range.Parent := self;
r := range.Calc();
if r then return range;
else range_page_number_array_[length(range_page_number_array_)] := range;
return nil;
end;
function TSDocxToPdf.TransformTbl(table: Tbl; x: real; y: real; w: real; lb: real): TableRange;
begin
range := new TableRange(self, current_page_, docx_components_module_, table);
range.StartX := x;
range.StartY := y;
range.Width := w;
range.LowerBound := lb;
range.Parent := self;
range.Calc();
return range;
end;
function TSDocxToPdf.TransformSdt(sdt: Sdt; x: real; y: real; w: real; lb: real): array of ParagraphRange;
begin
ps := sdt.SdtContent.Ps();
arr := array();
for _,p in ps do
{self.}TransformP(point, p, w, lb);
begin
range := {self.}TransformP(p, x, y, w, lb);
if ifObj(range) then arr[length(arr)] := range;
end
return arr;
end;
function TSDocxToPdf.ProcessNumpages();
begin
nums := page_array_[length(page_array_)-1].Number;
nums := page_manager_module_[page_manager_module_.Count() - 1].Number;
for _,range in range_page_number_array_ do
begin
range.SetNumPages(nums);
range.RangesToLines();
range.Offset(0, current_page_.SectPr.PgSz.H - current_page_.SectPr.PgMar.Bottom);
range.Do();
end
end;
function TSDocxToPdf.GetNextPage(page: TSPage);
function TSDocxToPdf.UpdateDocxPageNumPages();
begin
return page_array_[page.Index + 1];
end;
function TSDocxToPdf.PrintGrid(page: PdfPage; sect_ware: TSSectWare);
begin
i := 0;
while true do
begin
y := text_point_.Y - i * sect_ware.SectPr.DocGrid.LinePitch;
if y <= sect_ware.SectPr.PgMar.Bottom then break;
page.SetLineWidth(0.05);
page.SetGrayStroke(0.75);
page.MoveTo(sect_ware.SectPr.PgMar.Left, y);
page.LineTo(sect_ware.SectPr.PgSz.W- sect_ware.SectPr.PgMar.Right, y);
page.Stroke();
i++;
end
x1 := sect_ware.SectPr.PgMar.Left;
y1 := sect_ware.SectPr.PgSz.H - sect_ware.SectPr.PgMar.Top;
x2 := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right;
y2 := y1;
x3 := x1;
y3 := sect_ware.SectPr.PgMar.Bottom;
x4 := x2;
y4 := y3;
page.SetLineWidth(0.05);
page.SetGrayStroke(0.5);
page.MoveTo(x1, y1);
page.LineTo(x2, y2);
page.Stroke();
page.MoveTo(x1, y1);
page.LineTo(x3, y3);
page.Stroke();
page.MoveTo(x2, y2);
page.LineTo(x4, y4);
page.Stroke();
page.MoveTo(x3, y3);
page.LineTo(x4, y4);
page.Stroke();
end;
function TSDocxToPdf.AddToc(anchor: string; toc: TSToc);
begin
if ifarray(toc_array_[anchor]) then toc_array_[anchor] union= array(toc);
else toc_array_[anchor] := array(toc);
if toc_unmacthed_array_[anchor] then
begin
toc := toc_unmacthed_array_[anchor];
{self.}LinkToToc(anchor, toc[0], toc[1], toc[2]);
toc_unmacthed_array_[anchor] := nil;
end
end;
function TSDocxToPdf.LinkToToc(anchor: string; page: TSPage; left: real; top: real);
begin
arr := toc_array_[anchor];
if ifnil(arr) then
begin
toc_unmacthed_array_[anchor] := array(page, left, top);
return;
end
dst := page.PdfPage.CreateDestination();
dst.SetXYZ(left, top, 1);
for _,toc in arr do
toc.LinkAnnot(dst);
toc.AddPageNumber(page);
if update_docx_pages_ then
begin
r := docx_page_arr_[anchor];
r.T.Text := page.Number;
r.Serialize();
end
end;
function TSDocxToPdf.GetSymbol(symbol: string);
begin
// println("symbol = {}, symbol_ = {}", symbol, symbol_);
return symbol_[symbol];
end;
function TSDocxToPdf.AddDocxPage(anchor: string; r: R);
begin
docx_page_arr_[anchor] := r;
end;
function TSDocxToPdf.UpdateDocxPageNumpages();
begin
update_docx_pages_ := true;
toc_module_.UpdateDocxNumPages();
end;
function TSDocxToPdf.SaveDocxFile();overload;
begin
return docx_components_ware_.Save();
return docx_components_module_.Save();
end;
function TSDocxToPdf.SaveDocxFile(alias: string; file: string);overload;
begin
return docx_components_ware_.SaveAs(alias, file);
return docx_components_module_.SaveAs(alias, file);
end;
function TSDocxToPdf.GetCurrentNoteWare(): TSNoteWare;
function TSDocxToPdf.GetCurrentNoteModule(): NoteModule;
begin
if ifnil(note_ware_) then note_ware_ := new TSNoteWare(current_sect_ware_);
return note_ware_;
if ifnil(note_module_) then note_module_ := new NoteModule(current_sect_module_);
return note_module_;
end;
function TSDocxToPdf.ClassifyCols(var point: Point; cols: Cols);
@ -531,8 +410,8 @@ begin
columns := array();
x := point.X;
y := point.Y;
w := current_sect_ware_.SectPr.PgSz.W - current_sect_ware_.SectPr.PgMar.Right - current_sect_ware_.SectPr.PgMar.Left;
lb := current_sect_ware_.SectPr.PgMar.Bottom;
w := current_page_.SectPr.PgSz.W - current_page_.SectPr.PgMar.Right - current_page_.SectPr.PgMar.Left;
lb := current_page_.SectPr.PgMar.Bottom;
w_array := array();
ccols := cols.Cols();
for i:=0 to cols.Num-1 do
@ -547,7 +426,7 @@ begin
rw := w / 3;
x := point.X + i * rw + i * cols.Space;
end
range := new TSPdfColumnRange(self, current_page_, docx_components_ware_);
range := new ColumnRange(self, current_page_, docx_components_module_);
range.StartX := x;
range.StartY := y;
range.Width := rw;
@ -555,7 +434,7 @@ begin
columns[length(columns)] := range;
end
i := 0;
elements := current_sect_ware_.Elements();
elements := current_sect_module_.Elements();
range := columns[0];
for _,element in elements do
begin

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
unit TSColorToolKit;
unit DTPColorToolKit;
interface
function HexToRGB(hex);

719
internal/DTPModules.tsf Normal file
View File

@ -0,0 +1,719 @@
unit DTPModules;
interface
uses TSPdfEnumerations, DocxMLAdapter, SharedMLAdapter;
type DocxComponentsModule = class(DocxComponents)
public
function Create();
function GetStyles(): Styles;
function GetStylesAdapter(): StylesAdapter;
function GetDocumentRelsAdapter(): RelationShipsAdapter;
function GetNumberingModule(): NumberingModule;
function GetTblStylePrByType(style_id: string; type: string): TblStylePr;
function GetFtr(target: string): Ftr;
function GetHdr(target: string): Hdr;
function GetFtrRelsAdapter(target: string): RelationShipsAdapter;
function GetHdrRelsAdapter(target: string): RelationShipsAdapter;
function GetFootnotesAdapter(): FootnotesAdapter;
private
styles_deserialize_flag_: boolean;
styles_adapter_: StylesAdapter;
document_rels_adapter_: RelationShipsAdapter;
numbering_module_: NumberingModule;
tbl_style_pr_hash_: array of TblStylePr;
ftr_hash_: array of Ftr;
hdr_hash_: array of Hdr;
hdr_rel_hash_: array of RelationShipsAdapter;
ftr_rel_hash_: array of RelationShipsAdapter;
footnotes_adapter_: FootnotesAdapter;
end;
type FontModule = class
public
function Create(pdf: PdfFile);
function GetAsciiFont(name: string; bold: boolean; italic: boolean): PdfFont;
function GetCNSFont(name: string; bold: boolean; italic: boolean): PdfFont;
function GetSymbolFont(): PdfFont;
function GetZapfDingbatsFont(): PdfFont;
function UseExternalFont();
function SetSubstitutionRules(source: string; target: string);
function SetDefaultSz(value: real);
function GetDefaultSz(): real;
private
function GetExternalFont(name:string; bold: boolean; italic: boolean): PdfFont;
function GetBuiltInCNSFont(name:string; bold: boolean; italic: boolean): PdfFont;
function GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean): PdfFont;
private
[weakref]pdf_: PdfFile;
use_built_in_font_: boolean; // 是否使用内置字体
substitution_rules_: array of string; // 替换规则
external_reference_: array of string;
default_sz_: real;
end;
type NoteModule = class
public
function Create(sect_module: SectModule);
function GetFootnoteOrderNumber(): string;
function GetFootnoteIndex(): string;
function AddFootnote();
private
function CalculateNumber(num_fmt: string; num: integer): string;
function ChineseCountingThousand(n: integer): string;
private
footnote_reference_hash_: hash;
footnote_index_: integer;
[weakref]sect_module_: SectModule;
end;
type NumberingModule = class
public
function Create(number: NumberingAdapter);
function GetNumberLvl(ppr: PPr);
private
function CalculateNumber(num_fmt: string; num: integer): string;
function ChineseCountingThousand(n: integer): string;
private
numbering_adapter_: NumberingAdapter;
num_hash_: hash;
end;
type SectModule = class
public
function Create();
function Destroy();
function Do();
function AddElement(element: tslobj);
public
Elements: array of tslobj;
SectPr: SectPrUnitDecorator;
end;
type Toc = class
public
function Create(ppr: PPrUnitDecorator; rect: array of real; page: Page; x: real; y: real; font: PdfFont);
function LinkAnnot(dst: PdfDestination);
function AddPageNumber(page: Page);
private
[weakref]page_: Page;
ppr_: PPrUnitDecorator;
rect_: array of real;
font_: PdfFont;
x_;
y_;
end;
type TocModule = class
public
function Create();
function UpdateDocxNumPages();
function LinkToToc(anchor: string; pg: Page; left: real; top: real);
function AddToc(anchor: string; toc: Toc);
function AddDocxPage(anchor: string; r: R);
private
toc_hash_: hash;
toc_unmatched_hash_: hash;
update_docx_num_pages_: boolean; // 开放给docx文件是否更新docx文件的页码
docx_page_hash_: hash;
end;
// 坐标
type Point = class
public
function Create();
public
X: real;
Y: real;
end;
// Page延迟建立存基本信息即可
type Page = class
public
function Create(pdf_file: PdfFile);
function OriginalTextCoordinates(): array of real;
function PrintGrid();
property PdfPage read ReadPdfPage;
function ReadPdfPage(): PdfPage;
public
Index: integer;
Number: integer;
SectPr: SectPrUnitDecorator;
BaseSize: real;
TextPoint: Point; // 正文坐标
FtrPoint: Point; // 页脚坐标
HdrPoint: Point; // 页眉坐标
private
[weakref]pdf_file_: PdfFile;
pdf_page_: PdfPage;
end;
type PageManagerModule = class
public
function Create(pdf_file: PdfFile);
function Operator[](index: uinteger): Page;
function NewPage(): Page;
function NextPage(page: Page): Page;
function Count(): integer;
private
[weakref]pdf_file_: PdfFile;
page_array_: array of Page;
end;
implementation
// DocxComponentsModule
function DocxComponentsModule.Create();
begin
class(DocxComponents).Create();
tbl_style_pr_hash_ := array();
ftr_hash_ := array();
hdr_hash_ := array();
hdr_rel_hash_ := array();
ftr_rel_hash_ := array();
end;
function DocxComponentsModule.GetStyles(): Styles;
begin
if styles_deserialize_flag_ then return {self.}Styles;
{self.}Styles.Deserialize();
styles_deserialize_flag_ := true;
return {self.}Styles;
end;
function DocxComponentsModule.GetStylesAdapter(): StylesAdapter;
begin
if styles_adapter_ then return styles_adapter_;
styles_adapter_ := new StylesAdapter({self.}GetStyles());
return styles_adapter_;
end;
function DocxComponentsModule.GetDocumentRelsAdapter(): RelationShipsAdapter;
begin
if document_rels_adapter_ then return document_rels_adapter_;
{self.}DocumentRels.Deserialize();
document_rels_adapter_ := new RelationShipsAdapter({self.}DocumentRels);
return document_rels_adapter_;
end;
function DocxComponentsModule.GetNumberingModule(): NumberingModule;
begin
if numbering_module_ then return numbering_module_;
if not {self.}Numbering then return nil;
{self.}Numbering.Deserialize();
numbering_module_ := new NumberingModule({self.}Numbering);
return numbering_module_;
end;
function DocxComponentsModule.GetTblStylePrByType(style_id: string; type: string): TblStylePr;
begin
if tbl_style_pr_hash_[style_id][type] then return tbl_style_pr_hash_[style_id][type];
styles_adapter := {self.}GetStylesAdapter();
style := styles_adapter.GetStyleByStyleId(style_id);
style := new StyleAdapter(style);
tbl_style_pr := style.GetTblStylePrByType(type);
tbl_style_pr_hash_[style_id][type] := tbl_style_pr;
return tbl_style_pr;
end;
function DocxComponentsModule.GetFtr(target: string): Ftr;
begin
if ftr_hash_[target] then return ftr_hash_[target];
index := replaceStr(replaceStr(target, "footer", ""), ".xml", "");
obj := {self.}Footers(strtoint(index));
obj.Deserialize();
ftr_hash_[target] := obj;
return obj;
end;
function DocxComponentsModule.GetHdr(target: string): Hdr;
begin
if hdr_hash_[target] then return hdr_hash_[target];
index := replaceStr(replaceStr(target, "header", ""), ".xml", "");
obj := {self.}Headers(strtoint(index));
obj.Deserialize();
hdr_hash_[target] := obj;
return obj;
end;
function DocxComponentsModule.GetHdrRelsAdapter(target: string): RelationShipsAdapter;
begin
if hdr_rel_hash_[target] then return hdr_rel_hash_[target];
index := replaceStr(replaceStr(target, "header", ""), ".xml", "");
obj := {self.}HeaderRels(strtoint(index));
obj.Deserialize();
rels_adapter := new RelationShipsAdapter(obj);
hdr_rel_hash_[target] := rels_adapter;
return rels_adapter;
end;
function DocxComponentsModule.GetFtrRelsAdapter(target: string): RelationShipsAdapter;
begin
if ftr_rel_hash_[target] then return ftr_rel_hash_[target];
index := replaceStr(replaceStr(target, "footer", ""), ".xml", "");
obj := {self.}FooterRels(strtoint(index));
obj.Deserialize();
rels_adapter := new RelationShipsAdapter(obj);
ftr_rel_hash_[target] := rels_adapter;
return rels_adapter;
end;
function DocxComponentsModule.GetFootnotesAdapter(): FootnotesAdapter;
begin
if footnotes_adapter_ then return footnotes_adapter_;
obj := {self.}Footnotes;
obj.Deserialize();
footnotes_adapter_ := new FootnotesAdapter(obj);
return footnotes_adapter_;
end;
// FontModule
function FontModule.Create(pdf: PdfFile);
begin
pdf_ := pdf;
use_built_in_font_ := true;
substitution_rules_ := array("宋体": "SimSun",
"黑体": "SimHei",
"Courier New": "Courier",
"Helvetica": "Helvetica",
"Times New Roman": "Times-Roman",
);
external_reference_ := array();
default_sz_ := 10.5;
end;
function FontModule.SetDefaultSz(value: real);
begin
default_sz_ := value;
end;
function FontModule.GetDefaultSz();
begin
return default_sz_;
end;
function FontModule.UseExternalFont();
begin
use_built_in_font_ := false;
end;
function FontModule.GetExternalFont(name:string; bold: boolean; italic: boolean);
begin
if ifnil(name) or name = '' then name := "等线";
if not ifnil(external_font_cache_[name]) then return external_font_cache_[name];
value := external_reference_[name];
if ifnil(value) then return nil;
if value["ext"] = ".ttf" then
font_name := pdf_.LoadTTFontFromFile("", value["path"], true);
else if value["ext"] = ".ttc" then
font_name := pdf_.LoadTTFontFromFile2("", value["path"], 0, true);
if not ifString(font_name) then return nil;
font := pdf_.GetFont(font_name, "UTF-8");
external_font_cache_[name] := font;
return font;
end;
function FontModule.GetCNSFont(name: string; bold: boolean; italic: boolean): PdfFont;
begin
return use_built_in_font_ ? {self.}GetBuiltInCNSFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic);
end;
function FontModule.GetBuiltInCNSFont(name: string; bold: boolean; italic: boolean): PdfFont;
begin
font_name := substitution_rules_[name];
if ifnil(font_name) then font_name := "SimSun";
if bold and italic then
font_name += ",BoldItalic";
else if bold then
font_name += ",Bold";
else if italic then
font_name += ",Italic";
return pdf_.GetFont(font_name, "GBK-EUC-H");
end;
function FontModule.GetAsciiFont(name: string; bold: boolean; italic: boolean): PdfFont;
begin
return use_built_in_font_ ? {self.}GetBuiltInAsciiFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic);
end;
function FontModule.GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean): PdfFont;
begin
font_name := substitution_rules_[name];
if ifnil(font_name) then font_name := "Times-Roman";
if font_name = "Courier" or font_name = "Helvetica" then
begin
if bold and italic then
font_name += "-BoldOblique";
else if bold then
font_name += "-Bold";
else if italic then
font_name += "-Oblique";
end
else if font_name = "Times-Roman" then
begin
if bold and italic then
font_name := "Times-BoldItalic";
else if bold then
font_name += "Times-Bold";
else if italic then
font_name += "Times-Italic";
end
return pdf_.GetFont(font_name, "");
end;
function FontModule.SetSubstitutionRules(source: string; target: string);
begin
substitution_rules_[source] := target;
end;
function FontModule.GetSymbolFont(): PdfFont;
begin
return pdf_.GetFont("Symbol", "");
end;
function FontModule.GetZapfDingbatsFont(): PdfFont;
begin
return pdf_.GetFont("ZapfDingbats", "");
end;
// NoteModule
function NoteModule.Create(sect_module: SectModule);
begin
sect_module_ := sect_module;
footnote_reference_hash_ := array();
footnote_index_ := 0;
end;
function NoteModule.GetFootnoteOrderNumber();
begin
num_fmt := sect_module_.SectPr.FootnotePr.NumFmt.Val;
if ifnil(num_fmt) then num_fmt := "decimal";
return CalculateNumber(num_fmt, ++footnote_index_);
end;
function NoteModule.GetFootnoteIndex(): string;
begin
return inttostr(footnote_index_);
end;
function NoteModule.CalculateNumber(num_fmt: string; num: integer): string;
begin
if num_fmt = "decimal" then
return format("%d", num);
else if num_fmt = "chineseCountingThousand" then
return {self.}ChineseCountingThousand(num);
else
return format("%d", num);
end;
function NoteModule.ChineseCountingThousand(n: integer): string;
begin
chinese_digits := array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九");
chinese_units := array("", "十", "百", "千");
if n < 10 then return chinese_digits[n];
result := "";
num_str := inttostr(n);
len := length(num_str);
for i:=1 to len do
begin
digit_int := strtoint(num_str[i]);
if digit_int <> 0 then
result += chinese_digits[digit_int] + chinese_units[len - i];
end
if length(result) >= 6 and result[:6] = "一十" then result := result[4:];
return result;
end;
// SectModule
function SectModule.Create();
begin
{self.}Elements := array();
{self.}SectPr := nil;
end;
function SectModule.AddElement(element: tslobj);
begin
{self.}Elements[length({self.}Elements)] := element;
end;
// NumberingModule
function NumberingModule.Create(number: NumberingAdapter);
begin
numbering_adapter_ := new NumberingAdapter(number);
num_hash_ := array();
end;
function NumberingModule.GetNumberLvl(ppr: PPr);
begin
num_id := ppr.NumPr.NumId.Val;
if ifnil(num_id) then return array("", nil);
ilvl := ppr.NumPr.Ilvl.Val;
pstyle := ppr.PStyle.Val;
num := numbering_adapter_.GetNumByNumId(num_id);
if ifnil(num) then return array("", nil);
abstract_id := num.AbstractNumId.Val;
abstract_num := numbering_adapter_.GetAbstractNumByAbstractNumId(abstract_id);
lvls := abstract_num.Lvls();
if ifnil(ilvl) then ilvl := "0";
for k,v in lvls do
begin
if ilvl and v.Ilvl = ilvl then
begin
lvl_text := v.LvlText.Val;
if not ifarray(num_hash_[num_id]) then num_hash_[num_id] := array(0, 0, 0, 0, 0, 0, 0, 0, 0);
ilvl_int := strtoint(ilvl);
for i:=0 to ilvl_int do
begin
source_str := "%" $ (i + 1);
n := num_hash_[num_id][i];
if i = ilvl_int then
begin
n := num_hash_[num_id][i] + 1;
for j:=i+1 to length(num_hash_[num_id])-1 do
num_hash_[num_id][j] := 0;
end
n := i = ilvl_int ? num_hash_[num_id][i] + 1 : num_hash_[num_id][i];
dest_str := {self.}CalculateNumber(v.NumFmt.Val, n);
lvl_text := replaceStr(lvl_text, source_str, dest_str);
end
num_hash_[num_id][ilvl_int]++;
if v.Suff.Val = "space" then lvl_text += " ";
return array(lvl_text, v);
end
end
return array("", nil);
end
function NumberingModule.CalculateNumber(num_fmt: string; num: integer): string;
begin
if num_fmt = "decimal" then
return format("%d", num);
else if num_fmt = "chineseCountingThousand" then
return {self.}ChineseCountingThousand(num);
else
return format("%d", num);
end;
function NumberingModule.ChineseCountingThousand(n: integer): string;
begin
chinese_digits := array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九");
chinese_units := array("", "十", "百", "千");
if n < 10 then return chinese_digits[n];
result := "";
num_str := inttostr(n);
len := length(num_str);
for i:=1 to len do
begin
digit_int := strtoint(num_str[i]);
if digit_int <> 0 then
result += chinese_digits[digit_int] + chinese_units[len - i];
end
if length(result) >= 6 and result[:6] = "一十" then result := result[4:];
return result;
end;
// Page
function Page.Create(pdf_file: PdfFile);
begin
pdf_file_ := pdf_file;
{self.}TextPoint := new Point();
{self.}FtrPoint := new Point();
{self.}HdrPoint := new Point();
end;
function Page.OriginalTextCoordinates(): array of real;
begin
x := {self.}SectPr.PgMar.Left;
y := min({self.}SectPr.PgSz.H - max({self.}SectPr.PgMar.Top, {self.}SectPr.PgMar.Header), {self.}HdrPoint.Y);
return array(x, y);
end;
function Page.ReadPdfPage(): PdfPage;
begin
if ifnil(pdf_page_) then
begin
pdf_page_ := pdf_file_.AddPage();
pdf_page_.SetWidth({self.}SectPr.PgSz.W);
pdf_page_.SetHeight({self.}SectPr.PgSz.H);
if sysparams["_PDF_PAGE_GRID_DEBUG_"] then
{self.}PrintGrid();
end
return pdf_page_;
end;
function Page.PrintGrid();
begin
i := 0;
while true do
begin
y := {self.}TextPoint.Y - i * {self.}SectPr.DocGrid.LinePitch;
if y <= {self.}SectPr.PgMar.Bottom then break;
pdf_page_.SetLineWidth(0.05);
pdf_page_.SetGrayStroke(0.75);
pdf_page_.MoveTo({self.}SectPr.PgMar.Left, y);
pdf_page_.LineTo({self.}SectPr.PgSz.W- {self.}SectPr.PgMar.Right, y);
pdf_page_.Stroke();
i++;
end
x1 := {self.}SectPr.PgMar.Left;
y1 := {self.}SectPr.PgSz.H - {self.}SectPr.PgMar.Top;
x2 := {self.}SectPr.PgSz.W - {self.}SectPr.PgMar.Right;
y2 := y1;
x3 := x1;
y3 := {self.}SectPr.PgMar.Bottom;
x4 := x2;
y4 := y3;
pdf_page_.SetLineWidth(0.05);
pdf_page_.SetGrayStroke(0.5);
pdf_page_.MoveTo(x1, y1);
pdf_page_.LineTo(x2, y2);
pdf_page_.Stroke();
pdf_page_.MoveTo(x1, y1);
pdf_page_.LineTo(x3, y3);
pdf_page_.Stroke();
pdf_page_.MoveTo(x2, y2);
pdf_page_.LineTo(x4, y4);
pdf_page_.Stroke();
pdf_page_.MoveTo(x3, y3);
pdf_page_.LineTo(x4, y4);
pdf_page_.Stroke();
end;
// PageManagerModule
function PageManagerModule.Create(pdf_file: PdfFile);
begin
pdf_file_ := pdf_file;
page_array_ := array();
end;
function Operator PageManagerModule.[](index: uinteger): Page;
begin
return page_array_[index];
end;
function PageManagerModule.NewPage(): Page;
begin
len := length(page_array_);
page := new Page(pdf_file_);
page.Index := len;
page_array_[len] := page;
return page;
end;
function PageManagerModule.Count(): integer;
begin
return length(page_array_);
end;
// TocModule
function TocModule.Create();
begin
toc_hash_ := array();
toc_unmatched_hash_ := array();
update_docx_num_pages_ := false;
docx_page_hash_ := array();
end;
function TocModule.UpdateDocxNumPages();
begin
update_docx_num_pages_ := true;
end;
function TocModule.LinkToToc(anchor: string; pg: Page; left: real; top: real);
begin
arr := toc_hash_[anchor];
if ifnil(arr) then
begin
toc_unmatched_hash_[anchor] := array(pg, left, top);
return;
end
dst := pg.PdfPage.CreateDestination();
dst.SetXYZ(left, top, 1);
for _,toc in arr do
toc.LinkAnnot(dst);
toc.AddPageNumber(pg);
if update_docx_num_pages_ then
begin
r := docx_page_hash_[anchor];
r.T.Text := pg.Number;
r.Serialize();
end
end;
function TocModule.AddToc(anchor: string; toc: Toc);
begin
if ifarray(toc_hash_[anchor]) then toc_hash_[anchor] union= array(toc);
else toc_hash_[anchor] := array(toc);
if toc_unmatched_hash_[anchor] then
begin
toc := toc_unmatched_hash_[anchor];
{self.}LinkToToc(anchor, toc[0], toc[1], toc[2]);
toc_unmatched_hash_[anchor] := nil;
end
end;
function TocModule.AddDocxPage(anchor: string; r: R);
begin
docx_page_hash_[anchor] := r;
end;
// Toc
function Toc.Create(ppr: PPrUnitDecorator; rect: array of real; pg: Page; x: real; y: real; font: PdfFont);
begin
ppr_ := ppr;
rect_ := rect;
page_ := pg;
x_ := x;
y_ := y;
font_ := font;
end;
function Toc.LinkAnnot(dst: PdfDestination);
begin
annot := page_.PdfPage.CreateLinkAnnot(rect_, dst);
annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT);
annot.LinkAnnotSetBorderStyle(0, 0, 0);
end;
function Toc.AddPageNumber(pg: Page);
begin
number := tostring(pg.Number);
page_.PdfPage.SetFontAndSize(font_, ppr_.RPr.Sz.Val);
number_sz := page_.PdfPage.TextWidth(number);
x := rect_[2] - number_sz;
page_.PdfPage.BeginText();
page_.PdfPage.TextOut(x, y_, number);
page_.PdfPage.EndText();
page_.PdfPage.SetRGBStroke(0, 0, 0);
page_.PdfPage.SetDash(array(0.5, 2), 2, 0);
page_.PdfPage.SetLineWidth(0.5);
page_.PdfPage.SetLineCap(TSPdfEnumerations.ROUND_END);
page_.PdfPage.MoveTo(x_+1, y_);
page_.PdfPage.LineTo(x-0.5, y_);
page_.PdfPage.Stroke();
end;
end.

View File

@ -0,0 +1,245 @@
unit DTPPrimitiveRanges;
interface
uses DTPColorToolKit, DTPUtils;
type TextRange = class(BasicRange)
public
function Create();
function Do();override;
public
RPr: RPr;
Text: string;
Font: PdfFont;
Type: integer; // 0默认1: 数字2英文3中文4中文标点
end;
type BordersRange = class(BasicRange)
public
function Create();
function Do();override;
public
TcPr: TcPr;
Left: boolean;
Top: boolean;
Right: boolean;
Bottom: boolean;
private
function SetDash(val: string);
function DrawLine(border: Border; x1: real; y1: real; x2: real; y2: real);
end;
type ImageRange = class(BasicRange)
public
function Create();
function Do();override;
public
Image: PdfImage;
Type: string;
end;
type LineRange = class(BasicRange)
public
function Create();
function Do();override;
public
LineWidth: real;
end;
type BasicRange = class
public
function Create();
function Do();virtual;
public
StartX: real;
StartY: real; // range的起始坐标(x,y)
EndX: real;
EndY: real; // range的结束坐标(x,y)
Width: real;
FixedHeight: real;
DynamicHeight: real;
LowerBound: real;
[weakref]Parent: tslobj;
[weakref]Page: Page;
end;
implementation
// BasicRange
function BasicRange.Create();
begin
{self.}StartX := 0;
{self.}StartY := 0;
{self.}EndX := 0;
{self.}EndY := 0;
{self.}Width := 0;
{self.}DynamicHeight := 0;
{self.}LowerBound := 0;
{self.}FixedHeight := 0;
{self.}Page := nil;
end;
// ImageRange
function ImageRange.Create();
begin
class(BasicRange).Create();
{self.}Image := nil;
{self.}Type := "";
end;
function ImageRange.Do();override;
begin
// println("image = {}, type = {}, x = {}, y = {}, w = {}, h = {}", {self.}image, {self.}Type, {self.}endx, {self.}endy, {self.}width, {self.}DynamicHeight);
if {self.}Type = "emf" then
{self.}Page.PdfPage.DrawEmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
else if {self.}Type = "wmf" then
{self.}Page.PdfPage.DrawWmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
else
{self.}Page.PdfPage.DrawImage({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
if sysparams["_PDF_IMAGE_DEBUG_"] then
begin
{self.}Page.PdfPage.SetLineWidth(0.1);
{self.}Page.PdfPage.SetRGBStroke(0.8, 0.8, 0);
{self.}Page.PdfPage.Rectangle({self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
{self.}Page.PdfPage.Stroke();
end
end;
// BordersRange
function BordersRange.Create();
begin
class(BasicRange).Create();
{self.}TcPr := nil;
{self.}Left := false;
{self.}Top := false;
{self.}Right := false;
{self.}Bottom := false;
end;
function BordersRange.Do();override;
begin
// println("Left = {}, Top = {}, Right = {}, Bottom = {}, Tl2Br = {}, Tr2Bl = {}", Left, Top, Right, Bottom, Tl2Br, Tr2Bl);
borders := {self.}TcPr.TcBorders;
if {self.}TcPr.Shd.Fill and {self.}TcPr.Shd.Fill <> "auto" then
begin
[r, g, b] := DTPColorToolKit.HexToRGB({self.}TcPr.Shd.Fill);
{self.}Page.PdfPage.SetRGBFill(r/255, g/255, b/255);
x := {self.}EndX;
y := {self.}EndY - {self.}DynamicHeight;
w := {self.}Width;
h := {self.}DynamicHeight;
tmp := borders.Left.Sz ? borders.Left.Sz / 2 : 0.25;
x += tmp;
w -= tmp;
w -= borders.Right.Sz ? borders.Right.Sz / 2 : 0.25;
tmp := borders.Bottom.Sz ? borders.Bottom.Sz / 2 : 0.25;
y += tmp;
h -= tmp;
h -= borders.Top.Sz ? borders.Top.Sz / 2 : 0.25;
{self.}Page.PdfPage.Rectangle(x, y, w, h);
{self.}Page.PdfPage.Fill();
{self.}Page.PdfPage.SetRGBFill(0, 0, 0);
{self.}Left := true;
end
if {self.}Left then
{self.}DrawLine(borders.Left, {self.}EndX, {self.}EndY, {self.}EndX, {self.}EndY - {self.}DynamicHeight);
if {self.}Top then
{self.}DrawLine(borders.Top, {self.}EndX, {self.}EndY, {self.}EndX + {self.}Width, {self.}EndY);
if {self.}Right then
{self.}DrawLine(borders.Right, {self.}EndX + {self.}Width, {self.}EndY, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight);
if {self.}Bottom then
{self.}DrawLine(borders.Bottom, {self.}EndX, {self.}EndY - {Self.}DynamicHeight, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight);
if borders.Tl2Br then
{self.}DrawLine(borders.Tl2Br, {self.}EndX, {self.}Y, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight);
if borders.Tr2Bl then
{self.}DrawLine(borders.Tr2Bl, {self.}EndX + {self.}Width, {self.}Y, {self.}EndX, {self.}EndY - {self.}DynamicHeight);
end;
function BordersRange.SetDash(val: string);
begin
if val = "single" or ifnil(val) then
{self.}Page.PdfPage.SetDash(array(), 0, 0);
if val = "dashed" then
{self.}Page.PdfPage.SetDash(array(1), 1, 0);
end;
function BordersRange.DrawLine(border: Border; x1: real; y1: real; x2: real; y2: real);
begin
[r, g, b] := array(0, 0, 0);
line_width := border.Sz ?: 0.5;
{self.}SetDash(border.Val);
if border.Color and border.Color <> "auto" then [r, g, b] := DTPColorToolKit.HexToRGB(border.Color);
{self.}Page.PdfPage.SetRGBStroke(r, g, b);
{self.}Page.PdfPage.SetLineWidth(line_width);
{self.}Page.PdfPage.MoveTo(x1, y1);
{self.}Page.PdfPage.LineTo(x2, y2);
{self.}Page.PdfPage.Stroke();
{self.}Page.PdfPage.SetRGBStroke(0, 0, 0);
end;
// TextRange
function TextRange.Create();
begin
class(BasicRange).Create();
{self.}RPr := nil;
{self.}Text := "";
{self.}Font := nil;
{self.}Type := -1;
end;
function TextRange.Do();override;
begin
// println("text = {}, endx = {}, endy = {}, width = {}, page = {}", ansiToUtf8(text), endx, endy, width, page);
// println("Text = {}, sz = {}, szcs = {}, rpr.I = {}, rpr.B = {}, color = {}", ansiToUtf8({self.}Text), {self.}RPr.Sz.Val, {self.}RPr.SzCs.Val, {self.}RPr.I, {self.}RPr.B, {self.}RPr.Color.Val);
[r, g, b] := array(0, 0, 0);
if {self.}RPr.Color.Val and {self.}RPr.Color.Val <> "auto" then [r, g, b] := DTPColorToolKit.HexToRGB({self.}RPr.Color.Val);
y := {self.}EndY;
sz := {self.}RPr.Sz.Val;
if {self.}RPr.VertAlign.Val = "superscript" then
begin
y += sz / 3;
sz := sz * 2 / 3;
end
{self.}Page.PdfPage.SetRGBFill(r / 255, g / 255, b / 255);
{self.}Page.PdfPage.SetFontAndSize({self.}Font, sz);
{self.}Page.PdfPage.BeginText();
{self.}Page.PdfPage.TextOut({self.}EndX, y, {self.}Text);
{self.}Page.PdfPage.EndText();
{self.}Page.PdfPage.SetRGBFill(0, 0, 0);
if sysparams["_PDF_TEXT_DEBUG_"] then
begin
{self.}Page.PdfPage.SetLineWidth(0.1);
{self.}Page.PdfPage.SetRGBStroke(1.0, 0.5, 0.0);
{self.}Page.PdfPage.MoveTo(0, {self.}EndY);
{self.}Page.PdfPage.LineTo(600, {self.}EndY);
{self.}Page.PdfPage.Stroke();
end
end;
// LineRange
function LineRange.Create();
begin
class(BasicRange).Create();
{self.}LineWidth := 0;
end;
function LineRange.Do();override;
begin
// println("endx = {}, endy = {}, width = {}", EndX, EndY, Width);
{self.}Page.PdfPage.SetLineWidth({self.}LineWidth);
{self.}Page.PdfPage.SetRGBStroke(0, 0, 0);
{self.}Page.PdfPage.MoveTo({self.}EndX, {self.}EndY);
{self.}Page.PdfPage.LineTo({self.}EndX + {self.}Width, {self.}EndY);
{self.}Page.PdfPage.Stroke();
end;
end.

248
internal/DTPUtils.tsf Normal file
View File

@ -0,0 +1,248 @@
unit DTPUtils;
interface
uses DTPPrimitiveRanges;
function Utf8CharLengthFromByte(byte: char): integer;
function IsChineseChar(str: utf8_string): boolean;
function IsChinesePunctuation(str: utf8_string): boolean;
type Point = class
public
function Create();
public
X: real;
Y: real;
end;
type Stack = class
public
function Create();
function Pop();
function Push(element: any);
function Empty(): boolean;
private
arr_: tableArray;
index_: integer;
end;
type FldStruct = class
public
function Create();
public
FldLock: boolean;
MergeFormat: boolean;
Quote: boolean;
Separate: boolean;
PageArabicMergeFormat: boolean;
NumPages: boolean;
ArabicMergeFormat: boolean;
EndFld: boolean;
end;
type FldType = class
public
function Create();
public
Page: boolean;
NumPages: boolean;
Quote: boolean;
PageRef: boolean;
end;
type FldStruct2 = class
public
function Create();
public
Type: FldType;
Arabic: boolean;
MergeFormat: boolean;
end;
type TrProperty = class
public
function Create();
public
TrPr: TrPrUnitDecorator;
Height: real;
end;
type Region = class
public
function Create();
public
BordersRange: BordersRange;
RangeArr: array of BasicRange;
end;
type SymbolMapper = class
class function SymbolChr(symbol: string): string;
class function ZapfDingbatsChr(str: string): string;
private
static symbol_chr_hash_: array of chr;
static zapfdingbats_chr_hash_: array of chr;
end;
implementation
function Utf8CharLengthFromByte(byte: char): integer;
begin
if (_and(ord(byte), 0b10000000)) = 0 then
return 1;
else if (_and(ord(byte), 0b11100000)) = 0b11000000 then
return 2;
else if (_and(ord(byte), 0b11110000)) = 0b11100000 then
return 3;
else if (_and(ord(byte), 0b11111000)) = 0b11110000 then
return 4;
end;
function IsChineseChar(str: utf8_string): boolean;
begin
unicode_str := utf8ToUnicode(str);
codepoint := ord(unicode_str[1]);
return (codepoint >= 0x4E00 && codepoint <= 0x9FFF) or
(codepoint >= 0x3400 && codepoint <= 0x4DBF) or
(codepoint >= 0x20000 && codepoint <= 0x2A6DF);
end;
function IsChinesePunctuation(str: utf8_string): boolean;
begin
unicode_str := utf8ToUnicode(str);
codepoint := ord(unicode_str[1]);
return (codepoint >= 0x3000 && codepoint <= 0x303F) or
(codepoint >= 0xFF00 && codepoint <= 0xFFEF) or
(codepoint = 0x2018 || codepoint = 0x2019) or
(codepoint = 0x201C || codepoint = 0x201D) or
(codepoint = 0x2026 || codepoint = 0x2027);
end;
// Point
function Point.Create();
begin
{self.}X := 0;
{self.}Y := 0;
end;
// Stack
function Stack.Create();
begin
arr_ := array();
index_ := 0;
end;
function Stack.Pop();
begin
if index_ = 0 then return nil;
index_--;
ret := arr_[index_];
arr_[index_] := nil;
return ret;
end;
function Stack.Push(element: any);
begin
arr_[index_++] := element;
end;
function Stack.Empty(): boolean;
begin
return index_ = 0;
end;
// FldStruct
function FldStruct.Create();
begin
FldLock := false;
MergeFormat := false;
Quote := false;
Separate := false;
PageArabicMergeFormat := false;
NumPages := false;
ArabicMergeFormat := false;
EndFld := false;
end;
// FldType
function FldType.Create();
begin
{self.}Page := false;
{self.}NumPages := false;
{self.}Quote := false;
{self.}PageRef := false;
end;
// FldStruct
function FldStruct2.Create();
begin
{self.}Type := new FldType();
{self.}Arabic := false;
{self.}MergeFormat := false;
end;
// TrProperty
function TrProperty.Create();
begin
{self.}TrPr := nil;
{self.}Height := 0;
end;
// Region
function Region.Create();
begin
BordersRange := new DTPPrimitiveRanges.BordersRange();
RangeArr := array();
end
// SymbolMapper
class function SymbolMapper.SymbolChr(symbol: string);
begin
if ifnil(symbol_chr_hash_) then
begin
symbol_chr_hash_ := array(
"": chr(0x2D),
"α": chr(0x61),
"β": chr(0x62),
"ε": chr(0x65),
"γ": chr(0x67),
"θ": chr(0x71),
"{": chr(0x7B),
"}": chr(0x7D),
"∞": chr(0xA5),
"f": chr(0xA6),
"±": chr(0xB1),
"∂": chr(0xB6),
"∏": chr(0xD5),
"〈": chr(0xE1),
"∑": chr(0xE5),
"〉": chr(0xF1),
"Į": chr(0xF2),
// "": chr(0x),
);
end
return symbol_chr_hash_[symbol];
end;
class function SymbolMapper.ZapfDingbatsChr(str: string): string;
begin
if ifnil(zapfdingbats_chr_hash_) then
begin
zapfdingbats_chr_hash_ := array(
"": chr(118),
"": chr(110),
"": chr(108),
"": chr(117),
"": chr(108),
"o": chr(109),
"": chr(110),
);
end
return zapfdingbats_chr_hash_[symbol];
end;
end.

View File

@ -1,360 +0,0 @@
type TSPdfCellRange = class(TSPdfBasicRange)
public
function Create(table_range: TSPdfTableRange; docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty);
function Calc();
function Do();override;
function SetTSPage(page: TSPage);
function GetLastPage();
function AlignHeight(height: real);
function SetVAlign();
function IsReComputeByCantSplit(): boolean;
function IfRemoveEmptyRectangle(): boolean;
function SetTop();
property Tc read tc_;
private
function GetCellPrType(): string;
function SetBorderRange(range: TSPdfBordersRange);
public
RemoveFlag: boolean;
Row: integer;
Col: integer;
VMerge: integer;
[weakref]TSTrPr: TSTrProperty;
private
[weakref]parent_: TSPdfTableRange;
[weakref]docx_to_pdf_: TSDocxToPdf;
[weakref]last_page_: TSPage;
[weakref]docx_components_ware_: TSDocxComponentsWare;
[weakref]tc_: Tc;
[weakref]tbl_pr_: TblPr;
tc_pr_unit_decorator_: TcPrUnitDecorator;
region_array_: array of Region; // 单元格可能跨页,所以可能存在多个
top_: boolean;
end;
type Region = class
function Create();
begin
BordersRange := new TSPdfBordersRange();
RangeArr := array();
end
BordersRange: TSPdfBordersRange;
RangeArr: array of TSPdfBasicRange;
end;
function TSPdfCellRange.Create(table_range: TSPdfTableRange; docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty);
begin
parent_ := table_range;
docx_to_pdf_ := docx_to_pdf;
last_page_ := pg;
docx_components_ware_ := 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.}TSPage := last_page_;
end;
function TSPdfCellRange.Calc();
begin
region_array_ := array();
region := new Region();
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := {self.}StartY;
region.BordersRange.Width := {self.}Width;
region.BordersRange.FixedHeight := {self.}FixedHeight;
region.BordersRange.TSPage := 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 TSPdfParagraphRange(docx_to_pdf_, last_page_, docx_components_ware_, element);
range.SetTblStyleIdAndType(tbl_pr_.TblStyle.Val, {self.}GetCellPrType());
end
else if element.LocalName = "tbl" then
begin
range := new TSPdfTableRange(docx_to_pdf_, last_page_, docx_components_ware_, 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.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_.GetNextPage(last_page_);
if ifnil(last_page_) then last_page_ := docx_to_pdf_.AddTSPage();
point := docx_to_pdf_.GetCurrentTextPoint();
{self.}StartY := point.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 TSPdfCellRange.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 TSPdfCellRange.SetTSPage(page: TSPage);
begin
last_page_ := page;
{self.}TSPage := page;
end;
function TSPdfCellRange.AlignHeight(height: 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;
return;
end
region.BordersRange.DynamicHeight := y_lowerbound;
arr := region.RangeArr;
region.RangeArr := array();
hash := array(region.BordersRange.TSPage.Index: region);
last_page_ := {self.}TSPage;
[x, y] := docx_to_pdf_.CalculateTextCoordinates();
ftr_point := docx_to_pdf_.GetCurrentFtrPoint();
span := y - ftr_point.Y;
while surplus > span do
begin
last_page_ := docx_to_pdf_.GetNextPage(last_page_);
region := new Region();
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := y;
region.BordersRange.Width := {self.}Width;
region.BordersRange.DynamicHeight := span;
region.BordersRange.TSPage := 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.TSPage.Index] := region;
end
if surplus > 1e-6 then
begin
last_page_ := docx_to_pdf_.GetNextPage(last_page_);
region := new Region();
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := y;
region.BordersRange.Width := {self.}Width;
region.BordersRange.DynamicHeight := surplus;
region.BordersRange.TSPage := 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.TSPage.Index] := region;
{self.}EndY := region.BordersRange.EndY - surplus;
end
for _,range in arr do
begin
if range is class(TSPdfParagraphRange) then
begin
line_arr := range.GetLineRangeArr();
for _,r in line_arr do
begin
region := hash[r.TSPage.Index];
region.RangeArr[length(region.RangeArr)] := r;
end
end
end
end;
function TSPdfCellRange.GetLastPage();
begin
return last_page_;
end;
function TSPdfCellRange.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.TSPage, nil, -offset);
end
end;
end;
function TSPdfCellRange.IsReComputeByCantSplit(): boolean;
begin
if {self.}Tc.TcPr.VMerge then return false;
return {self.}TSTrPr.TrPr.CantSplit and last_page_ <> {self.}TSPage;
end;
function TSPdfCellRange.IfRemoveEmptyRectangle(): boolean;
begin
if length(region_array_) < 2 then return false;
return length(region_array_[0].RangeArr) ? false : true;
end;
function TSPdfCellRange.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 TSPdfCellRange.SetBorderRange(range: TSPdfBordersRange);
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 <> 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 <> 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 = 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 = 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 <> 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 = 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 <> 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 <> 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 = 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 TSPdfCellRange.SetTop();
begin
top_ := true;
end;

View File

@ -1,64 +0,0 @@
type TSPdfColumnRange = class(TSPdfBasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare);
function AddElement(ele: Element);
function Elements(): array of Element;
function GetLastPage(): TSPage;
function Do();override;
private
[weakref]docx_to_pdf_: TSDocxToPdf;
[weakref]docx_components_ware_: TSDocxComponentsWare;
[weakref]page_: TSPage;
elements_: array of Elements;
paragraph_: P;
last_y_: real;
end;
function TSPdfColumnRange.Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare);
begin
docx_to_pdf_ := docx_to_pdf;
page_ := pg;
docx_components_ware_ := components;
elements_ := array();
last_y_ := 0;
end;
function TSPdfColumnRange.AddElement(ele: Element);
begin
elements_[length(elements_)] := ele;
end;
function TSPdfColumnRange.Elements(): array of Element;
begin
return elements_;
end;
function TSPdfColumnRange.Do();override;
begin
x := {self.}StartX;
y := {self.}StartY;
for _,element in elements_ do
begin
range := nil;
if element.LocalName = "p" then
range := new TSPdfParagraphRange(docx_to_pdf_, page_, docx_components_ware_, element);
else if element.LocalName = "tbl" then
range := new TSPdfTableRange(docx_to_pdf_, page_, docx_components_ware_, 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 TSPdfColumnRange.GetLastPage(): TSPage;
begin
return page_;
end;

View File

@ -1,93 +0,0 @@
type TSPdfLineRange = class(TSPdfBasicRange)
public
function Create(pg: TSPage);
function Do();override;
function AddRange(range: TSPdfBasicRange);
function SetAllRangeProp(pg: TSPage; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real);
function Align(jc: string);
function AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
function AlignRightBound(right_bound: real);
function Offset(x_offset: real; y_offset; real);
private
range_array_: array of TSPdfBasicRange;
end;
function TSPdfLineRange.Create(pg: TSPage);
begin
{self.}TSPage := pg;
range_array_ := array();
end;
function TSPdfLineRange.AddRange(range: TSPdfBasicRange);
begin
range_array_[length(range_array_)] := range;
end;
function TSPdfLineRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function TSPdfLineRange.SetAllRangeProp(pg: TSPage; 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.TSPage := 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 TSPdfLineRange.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 TSPdfLineRange.AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real);
begin
if page <> {self.}TSPage 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 TSPdfLineRange.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 TSPdfLineRange.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;

View File

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

View File

@ -1,342 +0,0 @@
type TSPdfTableRange = class(TSPdfBasicRange)
public
function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: Components; table: Tbl);
function Do();override;
function Calc();
function GetLastPage(): TSPage;
function Rows(): integer;
function Cols(): integer;
private
function GetCellMatrix(grid_cols: array of GridColUnitDecorator);
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_: TSPage;
[weakref]docx_components_ware_: Components;
[weakref]table_: Tbl;
tbl_pr_unit_decorator_: TblPrUnitDecorator;
ts_trpr_array_: array of TSTrProperty;
cell_range_matrix_: array of TSPdfCellRange;
rows_: integer;
cols_: integer;
end;
function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; pg: PdfPage; components: Components; table: Tbl);
begin
docx_to_pdf_ := docx_to_pdf;
last_page_ := pg;
docx_components_ware_ := Components;
table_ := table;
ts_trpr_array_ := array();
cell_range_matrix_ := array();
rows_ := 0;
cols_ := 0;
{self.}TSPage := last_page_;
end;
function TSPdfTableRange.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的值
{self.}GetCellMatrix(grid_cols);
end;
function TSPdfTableRange.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 ifnil(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 TSPdfTableRange.GetCellMatrix(grid_cols: array of GridColUnitDecorator);
begin
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 TSPdfTableRange.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 TSTrProperty();
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
tc_x += grid_cols[pos++].W;
continue;
end
cell_range := new TSPdfCellRange(self, docx_to_pdf_, last_page_, docx_components_ware_, 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.Row := i;
cell_range.Col := pos;
cell_range_matrix_[i][pos] := cell_range;
pos++;
for k:=grid_span.Val-1 downto 1 do
cell_range.Width += grid_cols[pos++].W;
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 TSPdfTableRange.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 ifnil(range) then
begin
j++;
continue;
end
range.StartY := tc_y;
range.SetTSPage(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_.GetNextPage(last_page_);
[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);
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);
range.SetVAlign();
{self.}EndY := range.EndY;
last_page_ := range.GetLastPage();
end
i++;
end
end;
function TSPdfTableRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string);
begin
// tc_pr应该是经过外层copy的
tbl_style_pr := docx_components_ware_.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type);
if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr);
end;
function TSPdfTableRange.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 TSPdfTableRange.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 TSPdfTableRange.SetTblPrByStyleId(var tbl_pr: TblPr; 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.}SetTblPrByStyleId(tbl_pr, based_on);
tbl_pr.Copy(style.TblPr);
end
end;
function TSPdfTableRange.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 TSPdfTableRange.SetTrPrByStyleId(var tr_pr: TrPr; 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.}SetTrPrByStyleId(tr_pr, based_on);
tr_pr.Copy(style.TrPr);
end
end;
function TSPdfTableRange.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 TSPdfTableRange.SetTcPrByStyleId(var tc_pr: TcPr; 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.}SetTcPrByStyleId(tc_pr, based_on);
tc_pr.Copy(style.TcPr);
end
end;
function TSPdfTableRange.GetLastPage(): TSPage;
begin
return last_page_;
end;
function TSPdfTableRange.Rows(): integer;
begin
return rows_;
end;
function TSPdfTableRange.Cols(): integer;
begin
return cols_;
end;

View File

@ -1,29 +0,0 @@
type TSPdfBasicRange = class
public
function Create();
function Do();virtual;
public
StartX: real;
StartY: real; // range的起始坐标(x,y)
EndX: real;
EndY: real; // range的结束坐标(x,y)
Width: real;
FixedHeight: real;
DynamicHeight: real;
LowerBound: real;
[weakref]TSPage: TSPage;
end;
function TSPdfBasicRange.Create();
begin
{self.}StartX := 0;
{self.}StartY := 0;
{self.}EndX := 0;
{self.}EndY := 0;
{self.}Width := 0;
{self.}FixedHeight := 0;
{self.}DynamicHeight := 0;
{self.}LowerBound := 0;
{self.}TSPage := nil;
end;

View File

@ -1,88 +0,0 @@
type TSPdfBordersRange = class(TSPdfBasicRange)
uses TSColorToolKit;
public
function Create();
function Do();override;
public
TcPr: TcPr;
Left: boolean;
Top: boolean;
Right: boolean;
Bottom: boolean;
private
function SetDash(val: string);
function DrawLine(border: Border; x1: real; y1: real; x2: real; y2: real);
end;
function TSPdfBordersRange.Create();
begin
class(TSPdfBasicRange).Create();
{self.}TcPr := nil;
{self.}Left := false;
{self.}Top := false;
{self.}Right := false;
{self.}Bottom := false;
end;
function TSPdfBordersRange.Do();override;
begin
// println("Left = {}, Top = {}, Right = {}, Bottom = {}, Tl2Br = {}, Tr2Bl = {}", Left, Top, Right, Bottom, Tl2Br, Tr2Bl);
borders := {self.}TcPr.TcBorders;
if {self.}TcPr.Shd.Fill and {self.}TcPr.Shd.Fill <> "auto" then
begin
[r, g, b] := TSColorToolKit.HexToRGB({self.}TcPr.Shd.Fill);
{self.}TSPage.PdfPage.SetRGBFill(r/255, g/255, b/255);
x := {self.}EndX;
y := {self.}EndY - {self.}DynamicHeight;
w := {self.}Width;
h := {self.}DynamicHeight;
tmp := borders.Left.Sz ? borders.Left.Sz / 2 : 0.25;
x += tmp;
w -= tmp;
w -= borders.Right.Sz ? borders.Right.Sz / 2 : 0.25;
tmp := borders.Bottom.Sz ? borders.Bottom.Sz / 2 : 0.25;
y += tmp;
h -= tmp;
h -= borders.Top.Sz ? borders.Top.Sz / 2 : 0.25;
{self.}TSPage.PdfPage.Rectangle(x, y, w, h);
{self.}TSPage.PdfPage.Fill();
{self.}TSPage.PdfPage.SetRGBFill(0, 0, 0);
{self.}Left := true;
end
if {self.}Left then
{self.}DrawLine(borders.Left, {self.}EndX, {self.}EndY, {self.}EndX, {self.}EndY - {self.}DynamicHeight);
if {self.}Top then
{self.}DrawLine(borders.Top, {self.}EndX, {self.}EndY, {self.}EndX + {self.}Width, {self.}EndY);
if {self.}Right then
{self.}DrawLine(borders.Right, {self.}EndX + {self.}Width, {self.}EndY, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight);
if {self.}Bottom then
{self.}DrawLine(borders.Bottom, {self.}EndX, {self.}EndY - {Self.}DynamicHeight, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight);
if borders.Tl2Br then
{self.}DrawLine(borders.Tl2Br, {self.}EndX, {self.}Y, {self.}EndX + {self.}Width, {self.}EndY - {self.}DynamicHeight);
if borders.Tr2Bl then
{self.}DrawLine(borders.Tr2Bl, {self.}EndX + {self.}Width, {self.}Y, {self.}EndX, {self.}EndY - {self.}DynamicHeight);
end;
function TSPdfBordersRange.SetDash(val: string);
begin
if val = "single" or ifnil(val) then
{self.}TSPage.PdfPage.SetDash(array(), 0, 0);
if val = "dashed" then
{self.}TSPage.PdfPage.SetDash(array(1), 1, 0);
end;
function TSPdfBordersRange.DrawLine(border: Border; x1: real; y1: real; x2: real; y2: real);
begin
[r, g, b] := array(0, 0, 0);
line_width := border.Sz ?: 0.5;
{self.}SetDash(border.Val);
if border.Color and border.Color <> "auto" then [r, g, b] := TSColorToolKit.HexToRGB(border.Color);
{self.}TSPage.PdfPage.SetRGBStroke(r, g, b);
{self.}TSPage.PdfPage.SetLineWidth(line_width);
{self.}TSPage.PdfPage.MoveTo(x1, y1);
{self.}TSPage.PdfPage.LineTo(x2, y2);
{self.}TSPage.PdfPage.Stroke();
{self.}TSPage.PdfPage.SetRGBStroke(0, 0, 0);
end;

View File

@ -1,35 +0,0 @@
type TSPdfImageRange = class(TSPdfBasicRange)
public
function Create();
function Do();override;
public
Image: PdfImage;
Type: string;
end;
function TSPdfImageRange.Create();
begin
class(TSPdfBasicRange).Create();
{self.}Image := nil;
{self.}Type := "";
end;
function TSPdfImageRange.Do();
begin
// println("image = {}, type = {}, x = {}, y = {}, w = {}, h = {}", {self.}image, {self.}Type, {self.}endx, {self.}endy, {self.}width, {self.}DynamicHeight);
if {self.}Type = "emf" then
{self.}TSPage.PdfPage.DrawEmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
else if {self.}Type = "wmf" then
{self.}TSPage.PdfPage.DrawWmf({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
else
{self.}TSPage.PdfPage.DrawImage({self.}Image, {self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
if sysparams["_PDF_IMAGE_DEBUG_"] then
begin
{self.}TSPage.PdfPage.SetLineWidth(0.1);
{self.}TSPage.PdfPage.SetRGBStroke(0.8, 0.8, 0);
{self.}TSPage.PdfPage.Rectangle({self.}EndX, {self.}EndY, {self.}Width, {self.}DynamicHeight);
{self.}TSPage.PdfPage.Stroke();
end
end;

View File

@ -1,51 +0,0 @@
type TSPdfTextRange = class(TSPdfBasicRange)
uses TSColorToolKit;
public
function Create();
function Do();override;
public
RPr: RPr;
Text: string;
Font: PdfFont;
end;
function TSPdfTextRange.Create();
begin
class(TSPdfBasicRange).Create();
{self.}RPr := nil;
{self.}Text := "";
{self.}Font := nil;
end;
function TSPdfTextRange.Do();
begin
// println("text = {}, endx = {}, endy = {}, width = {}, page = {}", ansiToUtf8(text), endx, endy, width, page);
// println("Text = {}, sz = {}, szcs = {}, rpr.I = {}, color = {}", ansiToUtf8({self.}Text), {self.}RPr.Sz.Val, {self.}RPr.SzCs.Val, {self.}RPr.I, {self.}RPr.Color.Val);
[r, g, b] := array(0, 0, 0);
if {self.}RPr.Color.Val and {self.}RPr.Color.Val <> "auto" then [r, g, b] := TSColorToolKit.HexToRGB({self.}RPr.Color.Val);
y := {self.}EndY;
sz := {self.}RPr.Sz.Val;
if {self.}RPr.VertAlign.Val = "superscript" then
begin
y += sz / 3;
sz := sz * 2 / 3;
end
{self.}TSPage.PdfPage.SetRGBFill(r / 255, g / 255, b / 255);
{self.}TSPage.PdfPage.SetFontAndSize({self.}Font, sz);
{self.}TSPage.PdfPage.BeginText();
{self.}TSPage.PdfPage.TextOut({self.}EndX, y, {self.}Text);
{self.}TSPage.PdfPage.EndText();
{self.}TSPage.PdfPage.SetRGBFill(0, 0, 0);
if sysparams["_PDF_TEXT_DEBUG_"] then
begin
{self.}TSPage.PdfPage.SetLineWidth(0.1);
{self.}TSPage.PdfPage.SetRGBStroke(1.0, 0.5, 0.0);
{self.}TSPage.PdfPage.MoveTo(0, {self.}EndY);
{self.}TSPage.PdfPage.LineTo(600, {self.}EndY);
{self.}TSPage.PdfPage.Stroke();
end
end;

View File

@ -1,6 +0,0 @@
type TSPage = class
public
PdfPage: PdfPage;
Index: integer;
Number: integer; // 页码
end;

View File

@ -1,51 +0,0 @@
type TSToc = class
uses TSPdfEnumerations;
public
function Create(ppr: PPrUnitDecorator; rect: array of real; page: TSPage; x: real; y: real; font: PdfFont);
function LinkAnnot(dst: PdfDestination);
function AddPageNumber(page: TSPage);
private
ppr_: PPrUnitDecorator;
rect_: array of real;
font_: PdfFont;
[weakref]tspage_: TSPage;
x_;
y_;
end;
function TSToc.Create(ppr: PPrUnitDecorator; rect: array of real; page: TSPage; x: real; y: real; font: PdfFont);
begin
ppr_ := ppr;
rect_ := rect;
tspage_ := page;
x_ := x;
y_ := y;
font_ := font;
end;
function TSToc.LinkAnnot(dst: PdfDestination);
begin
annot := tspage_.PdfPage.CreateLinkAnnot(rect_, dst);
annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT);
annot.LinkAnnotSetBorderStyle(0, 0, 0);
end;
function TSToc.AddPageNumber(page: TSPage);
begin
number := tostring(page.Number);
tspage_.PdfPage.SetFontAndSize(font_, ppr_.RPr.Sz.Val);
number_sz := tspage_.PdfPage.TextWidth(number);
x := rect_[2] - number_sz;
tspage_.PdfPage.BeginText();
tspage_.PdfPage.TextOut(x, y_, number);
tspage_.PdfPage.EndText();
tspage_.PdfPage.SetRGBStroke(0, 0, 0);
tspage_.PdfPage.SetDash(array(0.5, 2), 2, 0);
tspage_.PdfPage.SetLineWidth(0.5);
tspage_.PdfPage.SetLineCap(TSPdfEnumerations.ROUND_END);
tspage_.PdfPage.MoveTo(x_+1, y_);
tspage_.PdfPage.LineTo(x-0.5, y_);
tspage_.PdfPage.Stroke();
end;

View File

@ -1,12 +0,0 @@
type TSTrProperty = class
function Create();
public
TrPr: TrPrUnitDecorator;
Height: real;
end;
function TSTrProperty.Create();
begin
{self.}TrPr := nil;
{self.}Height := 0;
end;

View File

@ -1,129 +0,0 @@
type TSDocxComponentsWare = class(Components)
public
function Create();
function GetStyles(): Styles;
function GetStylesAdapter(): StylesAdapter;
function GetDocumentRelsAdapter(): RelationShipsAdapter;
function GetNumberingWare(): TSNumberingWare;
function GetTblStylePrByType(style_id: string; type: string): TblStylePr;
function GetFtr(target: string): Ftr;
function GetHdr(target: string): Hdr;
function GetFtrRelsAdapter(target: string): RelationShipsAdapter;
function GetHdrRelsAdapter(target: string): RelationShipsAdapter;
function GetFootnotesAdapter(): FootnotesAdapter;
private
styles_deserialize_flag_: boolean;
styles_adapter_: StylesAdapter;
document_rels_adapter_: RelationShipsAdapter;
numbering_ware_: TSNumberingWare;
tbl_style_pr_hash_: array of TblStylePr;
ftr_hash_: array of Ftr;
hdr_hash_: array of Hdr;
hdr_rel_hash_: array of RelationShipsAdapter;
ftr_rel_hash_: array of RelationShipsAdapter;
footnotes_adapter_: FootnotesAdapter;
end;
function TSDocxComponentsWare.Create();
begin
class(Components).Create();
tbl_style_pr_hash_ := array();
ftr_hash_ := array();
hdr_hash_ := array();
hdr_rel_hash_ := array();
ftr_rel_hash_ := array();
end;
function TSDocxComponentsWare.GetStyles(): Styles;
begin
if styles_deserialize_flag_ then return {self.}Styles;
{self.}Styles.Deserialize();
styles_deserialize_flag_ := true;
return {self.}Styles;
end;
function TSDocxComponentsWare.GetStylesAdapter(): StylesAdapter;
begin
if styles_adapter_ then return styles_adapter_;
styles_adapter_ := new StylesAdapter({self.}GetStyles());
return styles_adapter_;
end;
function TSDocxComponentsWare.GetDocumentRelsAdapter(): RelationShipsAdapter;
begin
if document_rels_adapter_ then return document_rels_adapter_;
{self.}DocumentRels.Deserialize();
document_rels_adapter_ := new RelationShipsAdapter({self.}DocumentRels);
return document_rels_adapter_;
end;
function TSDocxComponentsWare.GetNumberingWare(): TSNumberingWare;
begin
if numbering_ware_ then return numbering_ware_;
if not {self.}Numbering then return nil;
{self.}Numbering.Deserialize();
numbering_ware_ := new TSNumberingWare({self.}Numbering);
return numbering_ware_;
end;
function TSDocxComponentsWare.GetTblStylePrByType(style_id: string; type: string): TblStylePr;
begin
if tbl_style_pr_hash_[style_id][type] then return tbl_style_pr_hash_[style_id][type];
styles_adapter := {self.}GetStylesAdapter();
style := styles_adapter.GetStyleByStyleId(style_id);
style := new StyleAdapter(style);
tbl_style_pr := style.GetTblStylePrByType(type);
tbl_style_pr_hash_[style_id][type] := tbl_style_pr;
return tbl_style_pr;
end;
function TSDocxComponentsWare.GetFtr(target: string): Ftr;
begin
if ftr_hash_[target] then return ftr_hash_[target];
index := replaceStr(replaceStr(target, "footer", ""), ".xml", "");
obj := {self.}Footers(strtoint(index));
obj.Deserialize();
ftr_hash_[target] := obj;
return obj;
end;
function TSDocxComponentsWare.GetHdr(target: string): Hdr;
begin
if hdr_hash_[target] then return hdr_hash_[target];
index := replaceStr(replaceStr(target, "header", ""), ".xml", "");
obj := {self.}Headers(strtoint(index));
obj.Deserialize();
hdr_hash_[target] := obj;
return obj;
end;
function TSDocxComponentsWare.GetHdrRelsAdapter(target: string): RelationShipsAdapter;
begin
if hdr_rel_hash_[target] then return hdr_rel_hash_[target];
index := replaceStr(replaceStr(target, "header", ""), ".xml", "");
obj := {self.}HeaderRels(strtoint(index));
obj.Deserialize();
rels_adapter := new RelationShipsAdapter(obj);
hdr_rel_hash_[target] := rels_adapter;
return rels_adapter;
end;
function TSDocxComponentsWare.GetFtrRelsAdapter(target: string): RelationShipsAdapter;
begin
if ftr_rel_hash_[target] then return ftr_rel_hash_[target];
index := replaceStr(replaceStr(target, "footer", ""), ".xml", "");
obj := {self.}FooterRels(strtoint(index));
obj.Deserialize();
rels_adapter := new RelationShipsAdapter(obj);
ftr_rel_hash_[target] := rels_adapter;
return rels_adapter;
end;
function TSDocxComponentsWare.GetFootnotesAdapter(): FootnotesAdapter;
begin
if footnotes_adapter_ then return footnotes_adapter_;
obj := {self.}Footnotes;
obj.Deserialize();
footnotes_adapter_ := new FootnotesAdapter(obj);
return footnotes_adapter_;
end;

View File

@ -1,127 +0,0 @@
type TSFontWare = class
public
function Create(pdf: PdfFile);
function GetAsciiFont(name: string; bold: boolean; italic: boolean): PdfFont;
function GetCNSFont(name: string; bold: boolean; italic: boolean): PdfFont;
function GetSymbolFont(): PdfFont;
function UseExternalFont();
function SetSubstitutionRules(source: string; target: string);
function SetDefaultSz(value: real);
function GetDefaultSz(): real;
private
function GetExternalFont(name:string; bold: boolean; italic: boolean): PdfFont;
function GetBuiltInCNSFont(name:string; bold: boolean; italic: boolean): PdfFont;
function GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean): PdfFont;
private
[weakref]pdf_: PdfFile;
use_built_in_font_: boolean; // 是否使用内置字体
substitution_rules_: array of string; // 替换规则
external_reference_: array of string;
default_sz_: real;
end;
function TSFontWare.Create(pdf: PdfFile);
begin
pdf_ := pdf;
use_built_in_font_ := true;
substitution_rules_ := array("宋体": "SimSun",
"黑体": "SimHei",
"Courier New": "Courier",
"Helvetica": "Helvetica",
"Times New Roman": "Times-Roman",
);
external_reference_ := array();
default_sz_ := 10.5;
end;
function TSFontWare.SetDefaultSz(value: real);
begin
default_sz_ := value;
end;
function TSFontWare.GetDefaultSz();
begin
return default_sz_;
end;
function TSFontWare.UseExternalFont();
begin
use_built_in_font_ := false;
end;
function TSFontWare.GetExternalFont(name:string; bold: boolean; italic: boolean);
begin
if ifnil(name) or name = '' then name := "等线";
if not ifnil(external_font_cache_[name]) then return external_font_cache_[name];
value := external_reference_[name];
if ifnil(value) then return nil;
if value["ext"] = ".ttf" then
font_name := pdf_.LoadTTFontFromFile("", value["path"], true);
else if value["ext"] = ".ttc" then
font_name := pdf_.LoadTTFontFromFile2("", value["path"], 0, true);
if not ifString(font_name) then return nil;
font := pdf_.GetFont(font_name, "UTF-8");
external_font_cache_[name] := font;
return font;
end;
function TSFontWare.GetCNSFont(name: string; bold: boolean; italic: boolean): PdfFont;
begin
return use_built_in_font_ ? {self.}GetBuiltInCNSFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic);
end;
function TSFontWare.GetBuiltInCNSFont(name: string; bold: boolean; italic: boolean): PdfFont;
begin
font_name := substitution_rules_[name];
if ifnil(font_name) then font_name := "SimSun";
if bold and italic then
font_name += ",BoldItalic";
else if bold then
font_name += ",Bold";
else if italic then
font_name += ",Italic";
return pdf_.GetFont(font_name, "GBK-EUC-H");
end;
function TSFontWare.GetAsciiFont(name: string; bold: boolean; italic: boolean): PdfFont;
begin
return use_built_in_font_ ? {self.}GetBuiltInAsciiFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic);
end;
function TSFontWare.GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean): PdfFont;
begin
font_name := substitution_rules_[name];
if ifnil(font_name) then font_name := "Times-Roman";
if font_name = "Courier" or font_name = "Helvetica" then
begin
if bold and italic then
font_name += "-BoldOblique";
else if bold then
font_name += "-Bold";
else if italic then
font_name += "-Oblique";
end
else if font_name = "Times-Roman" then
begin
if bold and italic then
font_name := "Times-BoldItalic";
else if bold then
font_name += "Times-Bold";
else if italic then
font_name += "Times-Italic";
end
return pdf_.GetFont(font_name, "");
end;
function TSFontWare.SetSubstitutionRules(source: string; target: string);
begin
substitution_rules_[source] := target;
end;
function TSFontWare.GetSymbolFont(): PdfFont;
begin
return pdf_.GetFont("ZapfDingbats", "");
end;

View File

@ -1,60 +0,0 @@
type TSNoteWare = class
public
function Create(sect_ware: TSSectWare);
function GetFootnoteOrderNumber(): string;
function GetIndex(): string;
private
function CalculateNumber(num_fmt: string; num: integer): string;
function ChineseCountingThousand(n: integer): string;
private
[weakref]sect_ware_: TSSectWare;
index_: integer;
end;
function TSNoteWare.Create(sect_ware: TSSectWare);
begin
sect_ware_ := sect_ware;
index_ := 0;
end;
function TSNoteWare.GetFootnoteOrderNumber();
begin
num_fmt := sect_ware_.SectPr.FootnotePr.NumFmt.Val;
if ifnil(num_fmt) then num_fmt := "decimal";
return CalculateNumber(num_fmt, ++index_);
end;
function TSNoteWare.GetIndex(): string;
begin
return inttostr(index_);
end;
function TSNoteWare.CalculateNumber(num_fmt: string; num: integer): string;
begin
if num_fmt = "decimal" then
return format("%d", num);
else if num_fmt = "chineseCountingThousand" then
return {self.}ChineseCountingThousand(num);
else
return format("%d", num);
end;
function TSNoteWare.ChineseCountingThousand(n: integer): string;
begin
chinese_digits := array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九");
chinese_units := array("", "十", "百", "千");
if n < 10 then return chinese_digits[n];
result := "";
num_str := inttostr(n);
len := length(num_str);
for i:=1 to len do
begin
digit_int := strtoint(num_str[i]);
if digit_int <> 0 then
result += chinese_digits[digit_int] + chinese_units[len - i];
end
if length(result) >= 6 and result[:6] = "一十" then result := result[4:];
return result;
end;

View File

@ -1,88 +0,0 @@
type TSNumberingWare = class
public
function Create(number: NumberingAdapter);
function GetNumberLvl(ppr: PPr);
private
function CalculateNumber(num_fmt: string; num: integer): string;
function ChineseCountingThousand(n: integer): string;
private
numbering_adapter_: NumberingAdapter;
num_hash_: array of tslobj;
end;
function TSNumberingWare.Create(number: NumberingAdapter);
begin
numbering_adapter_ := new NumberingAdapter(number);
num_hash_ := array();
end;
function TSNumberingWare.GetNumberLvl(ppr: PPr);
begin
num_id := ppr.NumPr.NumId.Val;
if ifnil(num_id) then return array("", nil);
ilvl := ppr.NumPr.Ilvl.Val;
pstyle := ppr.PStyle.Val;
num := numbering_adapter_.GetNumByNumId(num_id);
if ifnil(num) then return array("", nil);
abstract_id := num.AbstractNumId.Val;
abstract_num := numbering_adapter_.GetAbstractNumByAbstractNumId(abstract_id);
lvls := abstract_num.Lvls();
if ifnil(ilvl) then ilvl := "0";
for k,v in lvls do
begin
if ilvl and v.Ilvl = ilvl then
begin
lvl_text := v.LvlText.Val;
if not ifarray(num_hash_[num_id]) then num_hash_[num_id] := array(0, 0, 0, 0, 0, 0, 0, 0, 0);
ilvl_int := strtoint(ilvl);
for i:=0 to ilvl_int do
begin
source_str := "%" $ (i + 1);
n := num_hash_[num_id][i];
if i = ilvl_int then
begin
n := num_hash_[num_id][i] + 1;
for j:=i+1 to length(num_hash_[num_id])-1 do
num_hash_[num_id][j] := 0;
end
n := i = ilvl_int ? num_hash_[num_id][i] + 1 : num_hash_[num_id][i];
dest_str := {self.}CalculateNumber(v.NumFmt.Val, n);
lvl_text := replaceStr(lvl_text, source_str, dest_str);
end
num_hash_[num_id][ilvl_int]++;
if v.Suff.Val = "space" then lvl_text += " ";
return array(lvl_text, v);
end
end
return array("", nil);
end
function TSNumberingWare.CalculateNumber(num_fmt: string; num: integer): string;
begin
if num_fmt = "decimal" then
return format("%d", num);
else if num_fmt = "chineseCountingThousand" then
return {self.}ChineseCountingThousand(num);
else
return format("%d", num);
end;
function TSNumberingWare.ChineseCountingThousand(n: integer): string;
begin
chinese_digits := array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九");
chinese_units := array("", "十", "百", "千");
if n < 10 then return chinese_digits[n];
result := "";
num_str := inttostr(n);
len := length(num_str);
for i:=1 to len do
begin
digit_int := strtoint(num_str[i]);
if digit_int <> 0 then
result += chinese_digits[digit_int] + chinese_units[len - i];
end
if length(result) >= 6 and result[:6] = "一十" then result := result[4:];
return result;
end;

View File

@ -1,34 +0,0 @@
type TSSectWare = class
public
function Create();
function Destroy();
function Do();
function AddElement(element: tslobj);
public
Elements: array of tslobj;
SectPr: SectPrUnitDecorator;
BaseSize: integer;
end;
function TSSectWare.Create();
begin
{self.}Elements := array();
{self.}SectPr := nil;
{self.}BaseSize := 0;
end;
function TSSectWare.Do();
begin
if ifObj({self.}SectPr) then
{self.}BaseSize := round({self.}SectPr.DocGrid.LinePitch * 0.75);
// println("LinePitch = {}, Type = {}", {self.}SectPr.DocGrid.LinePitch, {self.}SectPr.DocGrid.Type);
// println("Width = {}, Height = {}", {self.}SectPr.PgSz.W, {self.}SectPr.PgSz.H);
// println("Top = {}, Right = {}, Bottom = {}, Left = {}, Header = {}, Footer = {}\n",
// {self.}SectPr.PgMar.Top, {self.}SectPr.PgMar.Right, {self.}SectPr.PgMar.Bottom, {self.}SectPr.PgMar.Left, {self.}SectPr.PgMar.Header, {self.}SectPr.PgMar.Footer);
end;
function TSSectWare.AddElement(element: tslobj);
begin
{self.}Elements[length({self.}Elements)] := element;
end;