From 4c002f803f4b963c5096058c10953aa37fcacf9b Mon Sep 17 00:00:00 2001 From: csh Date: Fri, 13 Dec 2024 17:19:52 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E6=94=AF=E6=8C=81=E5=88=86=E6=A0=8F=202.?= =?UTF-8?q?=20=E6=94=AF=E6=8C=81=E7=AE=80=E5=8D=95=E7=9A=84=E5=8D=95?= =?UTF-8?q?=E4=B8=AA=E8=84=9A=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TSDocxToPdf.tsf | 200 ++++++++++++++++++++----- range/Advanced/TSPdfColumnRange.tsf | 64 ++++++++ range/Advanced/TSPdfLineRange.tsf | 10 ++ range/Advanced/TSPdfParagraphRange.tsf | 66 ++++++-- range/basic/TSPdfTextRange.tsf | 11 +- ware/TSDocxComponentsWare.tsf | 3 +- ware/TSFontWare.tsf | 13 -- ware/TSNoteWare.tsf | 60 ++++++++ 8 files changed, 359 insertions(+), 68 deletions(-) create mode 100644 range/Advanced/TSPdfColumnRange.tsf create mode 100644 ware/TSNoteWare.tsf diff --git a/TSDocxToPdf.tsf b/TSDocxToPdf.tsf index 5e6e56c..26b8372 100644 --- a/TSDocxToPdf.tsf +++ b/TSDocxToPdf.tsf @@ -10,9 +10,13 @@ public 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 AddTSPageWare(flag: boolean): TSPage; + function AddTSPage(flag: boolean): TSPage; function LinkToToc(anchor: string; page: TSPage; left: real; top: real); function AddToc(anchor: string; toc: TSToc); @@ -21,6 +25,8 @@ public function CalculateTextCoordinates(): array of real; function GetSymbol(symbol: string); function AddDocxPage(pg: TSPage; r: R); + function CalcParams(): real; + function AddColIndex(); function UpdateDocxPageNumpages(); function SaveDocxFile();overload; @@ -36,6 +42,7 @@ private function InitSectWare(); function InitSymbol(); function AllocateElementsToSectWare(); + function ClassifyCols(var point: Point; cols: Cols); function SetHdr(type: string); function SetFtr(type: string); @@ -49,22 +56,26 @@ private pdf_: PdfFile; docx_components_ware_: TSDocxComponentsWare; // TSDocxComponentsWare cache_path_: string; // 临时目录,用来存放临时文件 - sect_ware_array_: array of TSSectWare; // 页面布局组件数组 font_ware_: TSFontWare; // 字体部件 + sect_ware_array_: array of TSSectWare; // 页面布局部件数组 + current_sect_ware_: TSSectWare; + current_sect_pr_adapter_: SectPrAdapter; + symbol_: tableArray; + 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; - symbol_: tableArray; + xml_file_: string; + even_and_odd_flag_: boolean; + note_ware_: TSNoteWare; // 脚注/尾注 + + // 回写docx docx_page_arr_: tableArray; update_docx_pages_: boolean; end; @@ -82,12 +93,13 @@ end; function TSDocxToPdf.Create(alias: string; file: string); begin pdf_ := new PdfFile(); + font_ware_ := new TSFontWare(pdf_); {self.}InitPdfEncoder(); {self.}InitDocxComponents(alias, file); {self.}InitCachePath(file); {self.}InitSectWare(); {self.}InitSymbol(); - font_ware_ := new TSFontWare(pdf_); + current_page_ := nil; page_array_ := array(); toc_array_ := array(); @@ -96,12 +108,14 @@ begin text_point_ := new Point(); hdr_point_ := new Point(); ftr_point_ := new Point(); - xml_file_ := "document.xml"; + xml_file_ := "document.xml"; settings := docx_components_ware_.Settings; settings.XmlChildEvenAndOddHeaders.Deserialize(); even_and_odd_flag_ := settings.EvenAndOddHeaders ? true : false; + note_ware_ := nil; + // 回写docx docx_page_arr_ := array(); update_docx_pages_ := false; end; @@ -116,28 +130,55 @@ begin return pdf_.SaveToFile(alias, file); end; +function TSDocxToPdf.CalcParams(): real; +begin + cols := current_sect_ware_.SectPr.Cols.Cols(); + // println("cols = {}", cols); + w := 0; + if cols then + begin + for i:=0 to col_index_ do + begin + w := cols[i].W; + if i > 0 then text_point_.X += (cols[i-1].W + cols[i-1].Space); + end + end + else + w := current_sect_ware_.SectPr.PgSz.W - current_sect_ware_.SectPr.PgMar.Right - current_sect_ware_.SectPr.PgMar.Left; + return w; +end; + function TSDocxToPdf.Transform(); begin for _,sect_ware in sect_ware_array_ do begin - if sect_ware_ <> sect_ware then + if current_sect_ware_ <> sect_ware then begin - sect_ware_ := sect_ware; - sect_pr_adapter_ := new SectPrAdapter(sect_ware_.SectPr.GetObject()); + current_sect_ware_ := sect_ware; + current_sect_pr_adapter_ := new SectPrAdapter(current_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 + cols := current_sect_ware_.SectPr.Cols; + if cols.Num > 1 then 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); + columns := {self.}ClassifyCols(text_point_, 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; + 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); + end end end {self.}ProcessNumpages(); @@ -160,7 +201,7 @@ end; function TSDocxToPdf.GetCurrentSectWare(): TSSectWare; begin - return sect_ware_; + return current_sect_ware_; end; function TSDocxToPdf.GetCachePath(image_path: string): string; @@ -194,7 +235,7 @@ function TSDocxToPdf.InitDocxComponents(alias: string; file: string); begin namespace "DOCX"; docx_components_ware_ := new TSDocxComponentsWare(); - [err, msg] := docx_components_ware_.OpenFile(alias, file, nil); + [err, msg] := docx_components_ware_.Open(alias, file, nil); if err then raise "Open file error."; end; @@ -209,9 +250,11 @@ end; function TSDocxToPdf.InitSectWare(); begin + sect_ware_array_ := array(); + current_sect_ware_ := nil; + current_sect_pr_adapter_ := nil; document := docx_components_ware_.Document; document.Deserialize(); - sect_ware_array_ := array(); {self.}AllocateElementsToSectWare(); end; @@ -236,6 +279,7 @@ begin 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(); end @@ -243,7 +287,7 @@ begin begin element := elements[i]; ware.AddElement(element); - if element.LocalName = "p" and ifObj(element.PPr.SectPr.XmlNode) then + if element.LocalName = "p" and ifObj(element.PPr.SectPr) then begin ##fp(ware, element.PPr.SectPr); sect_ware_array_[length(sect_ware_array_)] := ware; @@ -260,21 +304,22 @@ end; function TSDocxToPdf.AddTSPage(flag: boolean = false): TSPage; begin + if current_sect_ware_.SectPr.Type.Val = "continuous" and length(page_array_) <> 0 then return; 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); + 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); len := length(page_array_); current_page_ := new TSPage(); current_page_.Index := len; current_page_.PdfPage := page; - current_page_.Number := flag ? ifnil(sect_ware_.SectPr.PgNumType.Start) ? 1 : sect_ware_.SectPr.PgNumType.Start : page_array_[len-1].Number + 1; + 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_; // 页眉页脚 - if sect_ware_.SectPr.TitlePg and current_page_.Index = 0 then + if current_sect_ware_.SectPr.TitlePg and current_page_.Index = 0 then type_name := "first"; else if not even_and_odd_flag_ then type_name := "default"; @@ -294,28 +339,28 @@ begin text_point_.Y := y; if sysparams["_PDF_PAGE_GRID_DEBUG_"] then - {self.}PrintGrid(page, sect_ware_); + {self.}PrintGrid(page, current_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); + 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 := sect_ware_.SectPr.PgMar.Left; - ftr_point_.Y := sect_ware_.SectPr.PgMar.Bottom; - footer_reference := sect_pr_adapter_.GetFooterReferenceByType(type); + 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); 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; + w := current_sect_ware_.SectPr.PgSz.W - current_sect_ware_.SectPr.PgMar.Right - current_sect_ware_.SectPr.PgMar.Left; lb := 0; obj := docx_components_ware_.GetFtr(rel.Target); xml_file_ := rel.Target; @@ -329,14 +374,14 @@ 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); + 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(); rel := rels_adapter.GetRelationshipById(header_reference.Id); - w := sect_ware_.SectPr.PgSz.W - sect_ware_.SectPr.PgMar.Right - sect_ware_.SectPr.PgMar.Left; + w := current_sect_ware_.SectPr.PgSz.W - current_sect_ware_.SectPr.PgMar.Right - current_sect_ware_.SectPr.PgMar.Left; lb := 0; obj := docx_components_ware_.GetHdr(rel.Target); xml_file_ := rel.Target; @@ -495,3 +540,78 @@ begin return docx_components_ware_.SaveAs(alias, file); end; +function TSDocxToPdf.GetCurrentNoteWare(): TSNoteWare; +begin + if ifnil(note_ware_) then note_ware_ := new TSNoteWare(current_sect_ware_); + return note_ware_; +end; + +function TSDocxToPdf.ClassifyCols(var point: Point; cols: Cols); +begin + bk_page := current_page_; + 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_array := array(); + ccols := cols.Cols(); + for i:=0 to cols.Num-1 do + begin + rw := 0; + if cols.EqualWidth = "0" then + begin + rw := ccols[i].W; + if i > 0 then x += ccols[i-1].W + ccols[i-1].Space; + end + else begin + rw := w / 3; + x := point.X + i * rw + i * cols.Space; + end + range := new TSPdfColumnRange(self, current_page_, docx_components_ware_); + range.StartX := x; + range.StartY := y; + range.Width := rw; + range.LowerBound := lb; + columns[length(columns)] := range; + end + i := 0; + elements := current_sect_ware_.Elements(); + range := columns[0]; + for _,element in elements do + begin + if element.LocalName = "p" then + begin + p := new P(); + sub_elements := element.Elements(); + for _,sub in sub_elements do + begin + p.AppendChild(sub); + if sub.LocalName = "r" and sub.Br.Type = "column" then + begin + range.AddElement(p); + p := new P(); + p.PPr.Copy(element.PPr); + range := columns[++i]; + end + end + range.AddElement(p); + end + else begin + range.AddElement(element); + end + end + pg := nil; + max_y := nil; + for _,column in columns do + begin + column.Do(); + page := column.GetLastPage(); + if ifnil(pg) then pg := page; + if ifnil(max_y) then max_y := range.EndY; + if page.Index > pg.Index then max_y := range.EndY; + else if page.Index = pg.Index and max_y > range.EndY then max_y := range.EndY; + end + current_page_ := bk_page; + point.Y := max_y; +end; diff --git a/range/Advanced/TSPdfColumnRange.tsf b/range/Advanced/TSPdfColumnRange.tsf new file mode 100644 index 0000000..ce264ee --- /dev/null +++ b/range/Advanced/TSPdfColumnRange.tsf @@ -0,0 +1,64 @@ +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; diff --git a/range/Advanced/TSPdfLineRange.tsf b/range/Advanced/TSPdfLineRange.tsf index f59f5c4..c646980 100644 --- a/range/Advanced/TSPdfLineRange.tsf +++ b/range/Advanced/TSPdfLineRange.tsf @@ -7,6 +7,7 @@ public 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; @@ -81,3 +82,12 @@ begin 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; diff --git a/range/Advanced/TSPdfParagraphRange.tsf b/range/Advanced/TSPdfParagraphRange.tsf index ce98a20..cc7fddd 100644 --- a/range/Advanced/TSPdfParagraphRange.tsf +++ b/range/Advanced/TSPdfParagraphRange.tsf @@ -10,6 +10,7 @@ public 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); @@ -31,6 +32,7 @@ private 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; @@ -39,6 +41,7 @@ private function HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator); function GetXYCordinates(): array of real; function AlignRightBound(); + function Init(); private [weakref]docx_to_pdf_: TSDocxToPdf; @@ -125,14 +128,10 @@ begin {self.}TSPage := page_; end; -function TSPdfParagraphRange.Calc(): tableArray; +function TSPdfParagraphRange.Init(); begin - // ppr.rpr是无效的,应该以ppr.pStyle为准 + range_array_ := array(); right_bound_ := {self.}StartX + {self.}Width; - if ifnil(paragraph_.XmlChildPPr) then paragraph_.XmlChildPPr := new PPr(); - {self.}SetPPr(paragraph_.PPr); - ppr_unit_decorator_ := new PPrUnitDecorator(paragraph_.PPr); - if not ppr_unit_decorator_.RPr.Sz.Val then ppr_unit_decorator_.RPr.Sz.Val := docx_to_pdf_.Font.GetDefaultSz(); {self.}ResetCoordinates(); {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; @@ -140,9 +139,18 @@ begin {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); + 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); + {self.}Init(); elements := paragraph_.Elements(); empty_flag := true; @@ -170,12 +178,13 @@ begin end if element.Br.Type = "page" then - // {self.}EndY := {self.}LowerBound; - {self.}CheckAndAddPage({self.}LowerBound, 1); + {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 @@ -540,7 +549,7 @@ end; function TSPdfParagraphRange.RDrawing(r: R); begin - if ifObj(r.Drawing._Inline.XmlNode) then + if ifObj(r.Drawing._Inline) then begin id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; [image_type, image] := {self.}GetImageData(id); @@ -555,7 +564,7 @@ begin image_range.DynamicHeight := xfrm.Ext.CY; range_array_[length(range_array_)] := image_range; end - else if ifObj(r.Drawing.Anchor.XmlNode) then + else if ifObj(r.Drawing.Anchor) then begin anchor := r.Drawing.Anchor; id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; @@ -619,8 +628,29 @@ begin footnote := footnotes_adapter.GetFootnoteById(id); sect_ware := docx_to_pdf_.GetCurrentSectWare(); w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left; - lb := 0; + 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; @@ -914,3 +944,17 @@ 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; diff --git a/range/basic/TSPdfTextRange.tsf b/range/basic/TSPdfTextRange.tsf index 91552ba..0611ffc 100644 --- a/range/basic/TSPdfTextRange.tsf +++ b/range/basic/TSPdfTextRange.tsf @@ -24,10 +24,17 @@ begin // 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, {self.}RPr.Sz.Val); + {self.}TSPage.PdfPage.SetFontAndSize({self.}Font, sz); {self.}TSPage.PdfPage.BeginText(); - {self.}TSPage.PdfPage.TextOut({self.}EndX, {self.}EndY, {self.}Text); + {self.}TSPage.PdfPage.TextOut({self.}EndX, y, {self.}Text); {self.}TSPage.PdfPage.EndText(); {self.}TSPage.PdfPage.SetRGBFill(0, 0, 0); diff --git a/ware/TSDocxComponentsWare.tsf b/ware/TSDocxComponentsWare.tsf index 2ca7f5e..14753a8 100644 --- a/ware/TSDocxComponentsWare.tsf +++ b/ware/TSDocxComponentsWare.tsf @@ -11,7 +11,6 @@ public function GetFtrRelsAdapter(target: string): RelationShipsAdapter; function GetHdrRelsAdapter(target: string): RelationShipsAdapter; function GetFootnotesAdapter(): FootnotesAdapter; - private styles_deserialize_flag_: boolean; styles_adapter_: StylesAdapter; @@ -125,6 +124,6 @@ begin if footnotes_adapter_ then return footnotes_adapter_; obj := {self.}Footnotes; obj.Deserialize(); - footnotes_adapter_ := new FootnotesAdapter(); + footnotes_adapter_ := new FootnotesAdapter(obj); return footnotes_adapter_; end; diff --git a/ware/TSFontWare.tsf b/ware/TSFontWare.tsf index 8cab086..49624fa 100644 --- a/ware/TSFontWare.tsf +++ b/ware/TSFontWare.tsf @@ -1,7 +1,6 @@ type TSFontWare = class public function Create(pdf: PdfFile); - function GetFontByText(text: string; name: string; bold: boolean; italic: boolean): PdfFont; function GetAsciiFont(name: string; bold: boolean; italic: boolean): PdfFont; function GetCNSFont(name: string; bold: boolean; italic: boolean): PdfFont; function GetSymbolFont(): PdfFont; @@ -18,7 +17,6 @@ private private [weakref]pdf_: PdfFile; - is_linux_: boolean; // 是否是linux use_built_in_font_: boolean; // 是否使用内置字体 substitution_rules_: array of string; // 替换规则 external_reference_: array of string; @@ -60,27 +58,16 @@ begin if not ifnil(external_font_cache_[name]) then return external_font_cache_[name]; value := external_reference_[name]; if ifnil(value) then return nil; - // if ifnil(value) then raise name + " is unsupported font."; 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 raise "Load font error : " + format("%x", font_name); 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.GetFontByText(text: string; name: string; bold: boolean; italic: boolean): PdfFont; -begin - len := length(text); - if len > 1 then - return {self.}GetCNSFont(name, bold, italic); - else - return {self.}GetAsciiFont(name, bold, italic); -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); diff --git a/ware/TSNoteWare.tsf b/ware/TSNoteWare.tsf new file mode 100644 index 0000000..39e6086 --- /dev/null +++ b/ware/TSNoteWare.tsf @@ -0,0 +1,60 @@ +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;