PdfConverter/TSDocxToPdf.tsf

306 lines
8.8 KiB
Plaintext

type TSDocxToPdf = class
public
function Create(alias: string; file: string);
function Destroy();
function SaveToFile(alias: string; file: string): integer;
function Transform();
function GetCurrentPoint(): Point;
function GetCachePath(image_path: string): string;
function GetPdf(): PdfFile;
function GetNextPage(page: TSPage): TSPage;
function AddPage(sect_ware: TSSectWare): TSPage;
function AdjustPageNumber(page: TSPage; num: integer);
function LinkToToc(anchor: string; page: TSPage);
function AddToc(anchor: string; toc: TSToc);
property Font read ReadFont;
function ReadFont();
private
function InitDocxComponents(alias: string; file: string);
function InitCachePath(file: string);
function InitPdfEncoder();
function InitSectWare();
function AllocateElementsToSectWare();
function ResetCoordinates(sect_ware: TSSectWare);
function TransformP(sect_ware: TSSectWare; paragraph: P);
function TransformTbl(sect_ware: TSSectWare; table: Tbl);
function TransformSdt(sect_ware: TSSectWare; sdt: Sdt);
function PrintGrid(page: PdfPage; sect_ware: TSSectWare); // test
private
pdf_: PdfFile;
docx_components_: TSDocxComponentsWare; // TSDocxComponentsWare
cache_path_: string; // 临时目录,用来存放临时文件
sect_ware_array_: array of TSSectWare; // 页面布局组件数组
font_ware_: TSFontWare; // 字体部件
current_page_: TSPage;
point_: TSPoint; // 定位坐标点
page_array_: array of TSPage;
toc_array_: tableArray;
end;
type TSPoint = 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();
{self.}InitPdfEncoder();
{self.}InitDocxComponents(alias, file);
{self.}InitCachePath(file);
{self.}InitSectWare();
font_ware_ := new TSFontWare(pdf_);
current_page_ := nil;
point_ := new TSPoint();
page_array_ := array();
toc_array_ := array();
end;
function TSDocxToPdf.Destroy();
begin
removeDir("", cache_path_);
end;
function TSDocxToPdf.SaveToFile(alias: string; file: string): integer;
begin
return pdf_.SaveToFile(alias, file);
end;
function TSDocxToPdf.Transform();
begin
prev := nil;
for _,sect_ware in sect_ware_array_ do
begin
if prev <> sect_ware then
begin
{self.}AddPage(sect_ware);
prev := sect_ware;
end
elements := sect_ware.Elements;
for _,element in elements do
begin
// println("_ = {}", _);
if element.LocalName = "p" then {self.}TransformP(sect_ware, element);
else if element.LocalName = "tbl" then {self.}TransformTbl(sect_ware, element);
else if element.LocalName = "sdt" then {self.}TransformSdt(sect_ware, element);
end
end
end;
function TSDocxToPdf.GetCurrentPoint(): Point;
begin
return point_;
end;
function TSDocxToPdf.GetCachePath(image_path: string): string;
begin
return cache_path_ + extractFileName(image_path);
end;
function TSDocxToPdf.GetPdf(): PdfFile;
begin
return pdf_;
end;
function TSDocxToPdf.ReadFont();
begin
return font_ware_;
end;
function TSDocxToPdf.InitPdfEncoder();
begin
pdf_.UseCNSFonts();
pdf_.UseCNSEncodings();
// pdf_.UseUTFEncodings();
end;
function TSDocxToPdf.InitDocxComponents(alias: string; file: string);
begin
namespace "DOCX";
docx_components_ := new TSDocxComponentsWare();
[err, msg] := docx_components_.OpenFile(alias, file, nil);
if err then raise "Open file error.";
end;
function TSDocxToPdf.InitCachePath(file: string);
begin
path := format("%s_%s", extractFileName(file), formatDatetime("YYYYMMDDHHNNSSZZZ", now()));
cache_dir := format("%s/funcext/PdfConverter/.cache", extractFileDir(sysExecName()));
createDir("", cache_dir);
cache_path_ := format("%s/%s/", cache_dir, path);
createDir("", cache_path_);
end;
function TSDocxToPdf.InitSectWare();
begin
document := docx_components_.Document;
document.Deserialize();
sect_ware_array_ := array();
{self.}AllocateElementsToSectWare();
end;
function TSDocxToPdf.AllocateElementsToSectWare();
begin
elements := docx_components_.Document.Body.Elements();
ware := new TSSectWare();
fp := function(ware, sect);
begin
sect := new SectPrUnitDecorator(sect);
sect.PgSz.Orient := sect.PgSz.Orient ? "portrait" : "landscape";
ware.SectPr := sect;
ware.Do();
end
for i:=0 to length(elements)-1 do
begin
element := elements[i];
ware.AddElement(element);
if element.LocalName = "p" and ifObj(element.PPr.SectPr.XmlNode) then
begin
##fp(ware, element.PPr.SectPr);
sect_ware_array_[length(sect_ware_array_)] := ware;
ware := new TSSectWare();
end
else if element.LocalName = "sectPr" and i = length(elements)-1 then
begin
##fp(ware, element);
sect_ware_array_[length(sect_ware_array_)] := ware;
end
end
// println("sect_ware_array_ = {}", sect_ware_array_);
end;
function TSDocxToPdf.AddPage(sect_ware: TSSectWare): TSPage;
begin
page := pdf_.AddPage();
page.SetWidth(sect_ware.SectPr.PgSz.W);
page.SetHeight(sect_ware.SectPr.PgSz.H);
{self.}ResetCoordinates(sect_ware);
len := length(page_array_);
start := ifString(sect_ware.SectPr.PgNumType.Start) and trystrtoint(sect_ware.SectPr.PgNumType.Start, r) ? r : 0;
current_page_ := new TSPage();
current_page_.Index := len;
current_page_.PdfPage := page;
current_page_.Number := len = 0 ? start : page_array_[len-1].Number + 1;
page_array_[len] := current_page_;
if sysparams["_PDF_PAGE_GRID_DEBUG_"] then
{self.}PrintGrid(page, sect_ware);
return current_page_;
end;
function TSDocxToPdf.AdjustPageNumber(page: TSPage; num: integer);
begin
for i:=page.Index to length(page_array_)-1 do
page_array_[i].Number := num++;
end;
function TSDocxToPdf.GetNextPage(page: TSPage);
begin
return page_array_[page.Index + 1];
end;
function TSDocxToPdf.ResetCoordinates(sect_ware: TSSectWare);
begin
point_.X := sect_ware.SectPr.PgMar.Left;
point_.Y := sect_ware.SectPr.PgSz.H - max(sect_ware.SectPr.PgMar.Top, sect_ware.SectPr.PgMar.Header);
end;
function TSDocxToPdf.PrintGrid(page: PdfPage; sect_ware: TSSectWare);
begin
i := 0;
while true do
begin
y := 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.TransformP(sect_ware: TSSectWare; paragraph: P);
begin
w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left;
range := new TSPdfParagraphRange(self, current_page_, docx_components_, sect_ware, paragraph);
range.StartX := point_.X;
range.StartY := point_.Y;
range.Width := w;
range.Calc();
range.Do();
point_.Y := range.EndY;
end;
function TSDocxToPdf.TransformTbl(sect_ware: TSSectWare; table: Tbl);
begin
w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left;
range := new TSPdfTableRange(self, current_page_, docx_components_, sect_ware, table);
range.StartX := point_.X;
range.StartY := point_.Y;
range.Width := w;
range.Calc();
range.Do();
point_.Y := range.EndY;
end;
function TSDocxToPdf.TransformSdt(sect_ware: TSSectWare; sdt: Sdt);
begin
ps := sdt.SdtContent.Ps();
for _,p in ps do
{self.}TransformP(sect_ware, p);
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);
end;
function TSDocxToPdf.LinkToToc(anchor: string; page: TSPage);
begin
arr := toc_array_[anchor];
if ifnil(arr) then return;
dst := page.PdfPage.CreateDestination();
for _,toc in arr do
toc.LinkAnnot(dst);
toc.AddPageNumber(page);
end;