type TSDocxToPdf = class public function Create(alias: string; file: string); function Destroy(); function SaveToFile(alias: string; file: string): integer; function Transform(); function GetCurrentPage(): PdfPage; function GetCurrentPoint(): Point; function GetCachePath(image_path: string): string; function GetPdf(): PdfFile; function GetNextPage(page: PdfPage): PdfPage; function AddPage(sect_ware: TSSectWare): PdfPage; 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 TransformParagraph(sect_ware: TSSectWare; paragraph: P); function TransformTable(sect_ware: TSSectWare; table: Tbl); function PrintGrid(page: PdfPage; sect_ware: TSSectWare); // test private pdf_: PdfFile; docx_components_: Components; // Components@DOCX cache_path_: string; // 临时目录,用来存放临时文件 sect_ware_array_: array of TSSectWare; // 页面布局组件数组 font_ware_: TSFontWare; // 字体部件 current_page_: PdfPage; point_: TSPoint; // 定位坐标点 page_array_: array of PdfPage; page_index_: tableArray; 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(); page_index_ := 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 _ = 266 then return; if element.LocalName = "p" then self.TransformParagraph(sect_ware, element); else if element.LocalName = "tbl" then self.TransformTable(sect_ware, element); end end end; function TSDocxToPdf.GetCurrentPage(): PdfPage; begin return current_page_; 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 Components(); [err, msg] := docx_components_.OpenFile(alias, file, nil); if err then raise "Create obejct 'TSDocxFile' failed."; 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.Elements[length(ware.Elements)] := 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): PdfPage; begin current_page_ := pdf_.AddPage(); current_page_.SetWidth(sect_ware.SectPr.PgSz.W); current_page_.SetHeight(sect_ware.SectPr.PgSz.H); self.ResetCoordinates(sect_ware); len := length(page_array_); page_array_[len] := current_page_; page_index_[current_page_] := len; if sysparams["_PDF_PAGE_GRID_DEBUG_"] then self.PrintGrid(current_page_, sect_ware); return current_page_; end; function TSDocxToPdf.GetNextPage(page: PdfPage); begin pos := page_index_[page]; return page_array_[pos + 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.TransformParagraph(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.X := point_.X; range.Y := point_.Y; range.W := w; range.H := 0; range.Calc(); range.Do(); point_.Y := range.Y; end; function TSDocxToPdf.TransformTable(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.X := point_.X; range.Y := point_.Y; range.W := w; range.H := 0; range.Calc(); range.Do(); point_.Y := range.Y; end;