type TSDocxToPdf = class 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 GetCachePath(image_path: string): string; function GetNextPage(page: TSPage): TSPage; function GetCurrentXmlFile(): string; function AddTSPage(flag: boolean): TSPage; function AdjustPageNumber(page: TSPage; num: integer); function LinkToToc(anchor: string; page: TSPage; left: real; top: real); function AddToc(anchor: string; toc: TSToc); function SetHeaderAndFooter(); function ProcessNumpages(); function CalculateTextCoordinates(): array of real; property Font read ReadFont; function ReadFont(); private function InitDocxComponents(alias: string; file: string); function InitCachePath(file: string); function InitPdfEncoder(); function InitSectWare(); function AllocateElementsToSectWare(); 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 private pdf_: PdfFile; docx_components_ware_: TSDocxComponentsWare; // TSDocxComponentsWare cache_path_: string; // 临时目录,用来存放临时文件 sect_ware_array_: array of TSSectWare; // 页面布局组件数组 font_ware_: TSFontWare; // 字体部件 current_page_: TSPage; page_array_: array of TSPage; sect_ware_: TSSectWare; sect_pr_adapter_: SectPrAdapter; toc_array_: tableArray; toc_unmacthed_array_: tableArray; range_page_number_array_: tableArray; text_point_: Point; // 定位坐标点 hdr_point_: Point; // 页眉坐标 ftr_point_: Point; // 页脚坐标 even_and_odd_flag_: boolean; xml_file_: string; 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(); {self.}InitPdfEncoder(); {self.}InitDocxComponents(alias, file); {self.}InitCachePath(file); {self.}InitSectWare(); font_ware_ := new TSFontWare(pdf_); current_page_ := nil; page_array_ := array(); toc_array_ := array(); toc_unmacthed_array_ := array(); 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.XmlChildEvenAndOddHeaders.Deserialize(); even_and_odd_flag_ := settings.EvenAndOddHeaders ? true : false; 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 for _,sect_ware in sect_ware_array_ do begin if sect_ware_ <> sect_ware then begin sect_ware_ := sect_ware; sect_pr_adapter_ := new SectPrAdapter(sect_ware_.SectPr.GetObject()); {self.}AddTSPage(true); xml_file_ := "document.xml"; end w := sect_ware_.SectPr.PgSz.W - sect_ware_.SectPr.PgMar.Right - sect_ware_.SectPr.PgMar.Left; lb := sect_ware_.SectPr.PgMar.Bottom; elements := sect_ware.Elements(); for _,element in elements do begin // if _ = 4 then break; // if _ = 624 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(sect_ware, element); 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 sect_ware_; end; function TSDocxToPdf.GetCachePath(image_path: string): string; begin return cache_path_ + extractFileName(image_path); end; function TSDocxToPdf.GetCurrentXmlFile(): string; 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(); pdf_.UseCNSEncodings(); // pdf_.UseUTFEncodings(); end; function TSDocxToPdf.InitDocxComponents(alias: string; file: string); begin namespace "DOCX"; docx_components_ware_ := new TSDocxComponentsWare(); [err, msg] := docx_components_ware_.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_ware_.Document; document.Deserialize(); sect_ware_array_ := array(); {self.}AllocateElementsToSectWare(); end; function TSDocxToPdf.AllocateElementsToSectWare(); begin elements := docx_components_ware_.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.AddTSPage(flag: boolean = false): TSPage; begin page := pdf_.AddPage(); page.SetWidth(sect_ware_.SectPr.PgSz.W); page.SetHeight(sect_ware_.SectPr.PgSz.H); // println("W = {}, H = {}", sect_ware_.SectPr.PgSz.W, sect_ware_.SectPr.PgSz.H); len := length(page_array_); current_page_ := new TSPage(); current_page_.Index := len; current_page_.PdfPage := page; current_page_.Number := flag ? sect_ware_.SectPr.PgNumType.Start : page_array_[len-1].Number + 1; page_array_[len] := current_page_; // 页眉页脚 if sect_ware_.SectPr.TitlePg and current_page_.Index = 0 then type_name := "first"; else if not even_and_odd_flag_ then type_name := "default"; else if not odd(current_page_.Index) then type_name := "even" else type_name := "default"; bk_file := xml_file_; {self.}SetHdr(type_name); {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, sect_ware_); return current_page_; end; function TSDocxToPdf.CalculateTextCoordinates(): array of real; begin x := sect_ware_.SectPr.PgMar.Left; y := min(sect_ware_.SectPr.PgSz.H - max(sect_ware_.SectPr.PgMar.Top, sect_ware_.SectPr.PgMar.Header), hdr_point_.Y); return array(x, y); end; function TSDocxToPdf.SetFtr(type: string); begin ftr_point_.X := sect_ware_.SectPr.PgMar.Left; ftr_point_.Y := sect_ware_.SectPr.PgMar.Bottom; footer_reference := sect_pr_adapter_.GetFooterReferenceByType(type); if ifObj(footer_reference) then begin rels_adapter := docx_components_ware_.GetDocumentRelsAdapter(); rel := rels_adapter.GetRelationshipById(footer_reference.Id); w := sect_ware_.SectPr.PgSz.W - sect_ware_.SectPr.PgMar.Right - sect_ware_.SectPr.PgMar.Left; lb := 0; obj := docx_components_ware_.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); end end end; function TSDocxToPdf.SetHdr(type: string); begin hdr_point_.X := sect_ware_.SectPr.PgMar.Left; hdr_point_.Y := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Header; header_reference := sect_pr_adapter_.GetHeaderReferenceByType(type); if ifObj(header_reference) then begin rels_adapter := docx_components_ware_.GetDocumentRelsAdapter(); rel := rels_adapter.GetRelationshipById(header_reference.Id); w := sect_ware_.SectPr.PgSz.W - sect_ware_.SectPr.PgMar.Right - sect_ware_.SectPr.PgMar.Left; lb := 0; obj := docx_components_ware_.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(); range.Do(); point.Y := range.EndY; end; function TSDocxToPdf.TransformSdt(var point: Point; sdt: Sdt; w: real; lb: real); begin ps := sdt.SdtContent.Ps(); for _,p in ps do {self.}TransformP(point, p, w, lb); end; function TSDocxToPdf.ProcessNumpages(); begin nums := page_array_[length(page_array_)-1].Number; for _,range in range_page_number_array_ do begin range.SetNumPages(nums); range.RangesToLines(); range.Do(); end 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.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); end;