From 1eee1efc3ace1f7528627dd39f156c7096099d51 Mon Sep 17 00:00:00 2001 From: csh Date: Mon, 5 Aug 2024 11:32:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=AE=80=E5=8D=95=E7=9A=84?= =?UTF-8?q?=E9=A1=B5=E7=9C=89=E9=A1=B5=E8=84=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TSDocxToPdf.tsf | 119 ++++++- range/Advanced/TSPdfParagraphRange.tsf | 58 +++- range/Advanced/TSPdfParagraphRange2.tsf | 411 ++++++++++++++++++++++++ range/Advanced/TSPdfTableRange.tsf | 6 +- range/Advanced/TSPdfTocRange.tsf | 12 - ware/TSNumberingWare.tsf | 11 +- ware/TSSectWare.tsf | 2 +- 7 files changed, 573 insertions(+), 46 deletions(-) create mode 100644 range/Advanced/TSPdfParagraphRange2.tsf delete mode 100644 range/Advanced/TSPdfTocRange.tsf diff --git a/TSDocxToPdf.tsf b/TSDocxToPdf.tsf index 2b2a99d..4b184a2 100644 --- a/TSDocxToPdf.tsf +++ b/TSDocxToPdf.tsf @@ -9,10 +9,13 @@ public function GetCachePath(image_path: string): string; function GetPdf(): PdfFile; function GetNextPage(page: TSPage): TSPage; - function AddPage(sect_ware: TSSectWare): TSPage; + function AddPage(): TSPage;overload; + function AddPage(sect_ware: TSSectWare): TSPage;overload; function AdjustPageNumber(page: TSPage; num: integer); function LinkToToc(anchor: string; page: TSPage); function AddToc(anchor: string; toc: TSToc); + function SetHeaderAndFooter(); + function ProcessNumpages(); property Font read ReadFont; function ReadFont(); @@ -28,12 +31,13 @@ private function TransformP(sect_ware: TSSectWare; paragraph: P); function TransformTbl(sect_ware: TSSectWare; table: Tbl); function TransformSdt(sect_ware: TSSectWare; sdt: Sdt); + function TransformHeaderAndFooter(paragraph: P; type: string); function PrintGrid(page: PdfPage; sect_ware: TSSectWare); // test private pdf_: PdfFile; - docx_components_: TSDocxComponentsWare; // TSDocxComponentsWare + docx_components_ware_: TSDocxComponentsWare; // TSDocxComponentsWare cache_path_: string; // 临时目录,用来存放临时文件 sect_ware_array_: array of TSSectWare; // 页面布局组件数组 font_ware_: TSFontWare; // 字体部件 @@ -42,6 +46,9 @@ private page_array_: array of TSPage; toc_array_: tableArray; toc_unmacthed_array_: tableArray; + sect_ware_: TSSectWare; + sect_pr_adapter_: SectPrAdapter; + range_page_number_array_: tableArray; end; type TSPoint = class @@ -67,6 +74,7 @@ begin page_array_ := array(); toc_array_ := array(); toc_unmacthed_array_ := array(); + range_page_number_array_ := array(); end; function TSDocxToPdf.Destroy(); @@ -81,23 +89,24 @@ end; function TSDocxToPdf.Transform(); begin - prev := nil; for _,sect_ware in sect_ware_array_ do begin - if prev <> sect_ware then + if sect_ware_ <> sect_ware then begin + sect_ware_ := sect_ware; + sect_pr_adapter_ := new SectPrAdapter(sect_ware_.SectPr.GetObject()); {self.}AddPage(sect_ware); - prev := sect_ware; end elements := sect_ware.Elements; for _,element in elements do begin - // println("_ = {}", _); + // if _ = 150 then return; 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 + ProcessNumpages(); end; function TSDocxToPdf.GetCurrentPoint(): Point; @@ -130,8 +139,8 @@ end; function TSDocxToPdf.InitDocxComponents(alias: string; file: string); begin namespace "DOCX"; - docx_components_ := new TSDocxComponentsWare(); - [err, msg] := docx_components_.OpenFile(alias, file, nil); + docx_components_ware_ := new TSDocxComponentsWare(); + [err, msg] := docx_components_ware_.OpenFile(alias, file, nil); if err then raise "Open file error."; end; @@ -146,7 +155,7 @@ end; function TSDocxToPdf.InitSectWare(); begin - document := docx_components_.Document; + document := docx_components_ware_.Document; document.Deserialize(); sect_ware_array_ := array(); {self.}AllocateElementsToSectWare(); @@ -154,7 +163,7 @@ end; function TSDocxToPdf.AllocateElementsToSectWare(); begin - elements := docx_components_.Document.Body.Elements(); + elements := docx_components_ware_.Document.Body.Elements(); ware := new TSSectWare(); fp := function(ware, sect); begin @@ -182,7 +191,89 @@ begin // println("sect_ware_array_ = {}", sect_ware_array_); end; -function TSDocxToPdf.AddPage(sect_ware: TSSectWare): TSPage; +function TSDocxToPdf.AddPage(): TSPage;overload; +begin + page := pdf_.AddPage(); + page.SetWidth(sect_ware_.SectPr.PgSz.W); + page.SetHeight(sect_ware_.SectPr.PgSz.H); + + 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_; + + // 页眉页脚 + {self.}SetHeaderAndFooter(); +end; + +function TSDocxToPdf.SetHeaderAndFooter(); +begin + type_name := "default"; + if current_page_.Index = 0 then + type_name := "first"; + header_reference := sect_pr_adapter_.GetHeaderReferenceByType(type_name); + footer_reference := sect_pr_adapter_.GetFooterReferenceByType(type_name); + if ifObj(header_reference) then + begin + rels_adapter := docx_components_ware_.GetDocumentRelsAdapter(); + rel := rels_adapter.GetRelationshipById(header_reference.Id); + target := rel.Target; + index := replaceStr(target, "header", ""); + index := replaceStr(index, ".xml", ""); + header := docx_components_ware_.Headers(strtoint(index)); + elements := header.Elements(); + for _,element in elements do + begin + // if _ = 150 then return; + if element.LocalName = "p" then {self.}TransformHeaderAndFooter(element, "header"); + end + end + if ifObj(footer_reference) then + begin + rels_adapter := docx_components_ware_.GetDocumentRelsAdapter(); + rel := rels_adapter.GetRelationshipById(footer_reference.Id); + target := rel.Target; + index := replaceStr(target, "footer", ""); + index := replaceStr(index, ".xml", ""); + header := docx_components_ware_.Footers(strtoint(index)); + elements := header.Elements(); + for _,element in elements do + begin + // if _ = 150 then return; + if element.LocalName = "p" then {self.}TransformHeaderAndFooter(element, "footer"); + end + end +end; + +function TSDocxToPdf.TransformHeaderAndFooter(paragraph: P; type: string); +begin + paragraph.Deserialize(); + w := sect_ware_.SectPr.PgSz.W - sect_ware_.SectPr.PgMar.Right - sect_ware_.SectPr.PgMar.Left; + range := new TSPdfParagraphRange2(self, current_page_, docx_components_ware_, sect_ware_, paragraph); + y := type = "header" ? sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Header : sect_ware_.SectPr.PgMar.Footer; + range.StartX := point_.X; + range.StartY := y; + range.Width := w; + r := range.Calc(); + if r then range.Do(); + else range_page_number_array_[length(range_page_number_array_)] := range; +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.AddPage(sect_ware: TSSectWare): TSPage;overload; begin page := pdf_.AddPage(); page.SetWidth(sect_ware.SectPr.PgSz.W); @@ -197,6 +288,8 @@ begin current_page_.Number := len = 0 ? start : page_array_[len-1].Number + 1; page_array_[len] := current_page_; + {self.}SetHeaderAndFooter(); + if sysparams["_PDF_PAGE_GRID_DEBUG_"] then {self.}PrintGrid(page, sect_ware); @@ -262,7 +355,7 @@ 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 := new TSPdfParagraphRange(self, current_page_, docx_components_ware_, sect_ware, paragraph); range.StartX := point_.X; range.StartY := point_.Y; range.Width := w; @@ -274,7 +367,7 @@ 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 := new TSPdfTableRange(self, current_page_, docx_components_ware_, sect_ware, table); range.StartX := point_.X; range.StartY := point_.Y; range.Width := w; diff --git a/range/Advanced/TSPdfParagraphRange.tsf b/range/Advanced/TSPdfParagraphRange.tsf index 12a5472..ccf30bc 100644 --- a/range/Advanced/TSPdfParagraphRange.tsf +++ b/range/Advanced/TSPdfParagraphRange.tsf @@ -104,12 +104,15 @@ begin if empty_flag then begin line_space := {self.}GetParagraphLineSpace(ppr.RPr.Sz.Val, ppr.Spacing.Line); - {self.}DynamicHeight += ppr.Spacing.After + line_space; + {self.}DynamicHeight += line_space; {self.}EndY -= {self.}DynamicHeight; end {self.}RangesToLines(ppr); if hyperlink_array_ then {self.}HyperlinkToToc(ppr); if bookmark_array_ then {self.}BookMarkLinkToc(); + {self.}DynamicHeight += ppr.Spacing.After; + {self.}EndY -= ppr.Spacing.After; + return true; end; function TSPdfParagraphRange.BookMarkLinkToc(); @@ -120,37 +123,62 @@ end; function TSPdfParagraphRange.HyperlinkToToc(ppr: PPrUnitDecorator); begin + max_size := 0; for anchor,arr in hyperlink_array_ do // 整理hyperlink发送到docx_to_pdf_ begin pg := arr[0].TSPage; left := {self.}StartX; - bottom := arr[0].EndY; + bottom := {self.}StartY; right := left + {self.}Width; - top := bottom + arr[0].RPr.Sz.Val; + top := bottom; x := arr[0].EndX + arr[0].Width; y := arr[0].EndY; for _,range in arr do begin - if range.TSPage <> pg then // 说明目录文字换页 + if x + range.Width - {self.}StartX > {self.}Width + 1e-6 then // 换行 begin - rect := array(left, bottom, right, top); + top += max_size; + max_size := 0; + end + if range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; + if range.TSPage <> pg then + begin + rect := array(left, bottom, right, top + max_size); toc := new TSToc(ppr, rect, pg, x, y); docx_to_pdf_.AddToc(anchor, toc); + top := bottom; pg := range.TSPage; - left := range.EndX; - top := range.EndY + range.RPr.Sz.Val; - right := left; - bottom := range.EndY; continue; end - top := range.EndY + arr[0].RPr.Sz.Val; x := range.EndX + range.Width; + y := range.EndY; end - rect := array(left, bottom, right, top); font_name := ppr.RPr.RFonts.EastAsia ? ppr.RPr.RFonts.EastAsia : ppr.RPr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetFont(font_name, ppr.RPr.B, ppr.RPr.I); + rect := array(left, bottom, right, top + max_size); toc := new TSToc(ppr, rect, pg, x, y, font_obj); docx_to_pdf_.AddToc(anchor, toc); + + pg.PdfPage.SetFontAndSize(font_obj, max_size); + 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; + line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line); + diff := {self.}EndY - sect_ware_.SectPr.PgMar.Bottom; + if {self.}CheckAndAddPage({self.}EndY, line_space) then + begin + {self.}DynamicHeight += diff; + pg := page_; + end + else begin + {self.}EndY -= line_space; + {self.}DynamicHeight += line_space; + end + rect := array({self.}StartX, {self.}StartY - line_space, {self.}StartX + {self.}Width, {self.}StartY); + toc := new TSToc(ppr, rect, pg, {self.}StartX, {self.}EndY + offset, font_obj); + docx_to_pdf_.AddToc(anchor, toc); + end end end; @@ -240,7 +268,7 @@ begin 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) + ppr.Spacing.After; + max_value := max(line_space, max_y); line_range.TSPage := page_; line_range.EndY := {self.}EndY - max_value; line_range.DynamicHeight := max_value; @@ -328,7 +356,7 @@ begin xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm); rels_adapter := docx_components_ware_.GetDocumentRelsAdapter(); id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; - rel := rels_adapter.Id(id); + rel := rels_adapter.GetRelationshipById(id); image_path := "word/" + rel.Target; image := docx_components_ware_.Zip().Get(image_path); data := image.Data(); @@ -398,7 +426,7 @@ end; function TSPdfParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); - style := styles.StyleId(style_id); + style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; @@ -422,7 +450,7 @@ end; function TSPdfParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); - style := styles.StyleId(style_id); + style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; diff --git a/range/Advanced/TSPdfParagraphRange2.tsf b/range/Advanced/TSPdfParagraphRange2.tsf new file mode 100644 index 0000000..4c8f02f --- /dev/null +++ b/range/Advanced/TSPdfParagraphRange2.tsf @@ -0,0 +1,411 @@ +type TSPdfParagraphRange2 = class(TSPdfBasicRange) +public + function Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; sect_ware: TSSectWare; paragraph: P); + function Calc(); + function Do();override; + function SetExtraStyleId(style_id: string); + function RangesToLines();overload; + function SetNumPages(num: integer); + +private + function SetPPr(var ppr: PPr); + function SetPPrByStyleId(var ppr: PPr; style_id: string); + function SetRPr(var rpr; ppr: PPr); + function SetRPrByStyleId(var rpr: RPr; style_id: string); + function SetLvlText(); + function GetImageFileType(data: binary): string; + function GetParagraphLineSpace(size: real; line: integer): real; + function CheckAndAddPage(y: real; offset: real): boolean; + function GetUtf8CharLength(byte: string): integer; + function RToTextRange(r: R; ppr: PPrUnitDecorator; link: string); + function SplitTextToTextRange(text: string; rpr: RPrUnitDecorator; link: string); + function RToDrawingRange(r: R; ppr: PPrUnitDecorator); + function SetLinesAlignment(ppr: PPrUnitDecorator); + function ResetCoordinates(ppr: PPrUnitDecorator); + function NewLineRange(): TSPdfLineRange; + function RangesToLines(ppr: PPrUnitDecorator);overload; + +private + [weakref]docx_to_pdf_: TSDocxToPdf; + [weakref]docx_components_ware_: TSDocxComponentsWare; + [weakref]sect_ware_: TSSectWare; + [weakref]paragraph_: P; + [weakref]page_: TSPage; + extra_style_id_: string; + range_array_: array of TSPdfBasicRange; + line_range_array_: array of TSPdfLineRange; + hyperlink_array_: tableArray; + bookmark_array_: tableArray; + ppr_unit_decorator_: PPrUnitDecorator; + placeholder_array_: tableArray; +end; + +function TSPdfParagraphRange2.Create(docx_to_pdf: TSDocxToPdf; pg: TSPage; components: TSDocxComponentsWare; sect_ware: TSSectWare; paragraph: P); +begin + docx_to_pdf_ := docx_to_pdf; + page_ := pg; + docx_components_ware_ := components; + paragraph_ := paragraph; + sect_ware_ := sect_ware; + extra_style_id_ := ""; + range_array_ := array(); + line_range_array_ := array(); + hyperlink_array_ := array(); + bookmark_array_ := array(); + placeholder_array_ := array(); + {self.}TSPage := page_; +end; + +function TSPdfParagraphRange2.Calc(): tableArray; +begin + // ppr.rpr是无效的,应该以ppr.pStyle为准 + {self.}SetPPr(paragraph_.PPr); + {self.}SetLvlText(); + ppr_unit_decorator_ := new PPrUnitDecorator(paragraph_.PPr); + ppr := ppr_unit_decorator_; + {self.}ResetCoordinates(ppr); + {self.}EndX := {self.}StartX; + {self.}EndY := {self.}StartY; + {self.}EndY -= ppr.Spacing.Before; + {self.}DynamicHeight += ppr.Spacing.Before; + + elements := paragraph_.Elements(); + for _,element in elements do + begin + if not ifObj(element.XmlNode) then continue; + if element.LocalName = "r" then + begin + {self.}SetRPr(element.RPr, ppr); + if element.FldChar.FldCharType = "separate" then + fld := true; + else if element.FldChar.FldCharType = "end" then + fld := false; + else if element.InstrText.Text = "PAGE \\* Arabic \\* MERGEFORMAT" then + page_number := true; + else if element.InstrText.Text = " NUMPAGES " then + numpages := true; + else if fld and page_number then + begin + element.T.Text := tostring(page_.Number); + {self.}RToTextRange(element, ppr, nil); + page_number := false; + end + else if fld and numpages then + begin + rpr := new RPrUnitDecorator(element.RPr); + numpages_index := length(range_array_); + placeholder_array_ := array(numpages_index, rpr); + numpages := false; + end + else if not fld then {self.}RToTextRange(element, ppr, bookmark_name); + end + end + if placeholder_array_ then return false; + {self.}RangesToLines(); + return true; +end; + +function TSPdfParagraphRange2.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 TSPdfParagraphRange2.Do();override; +begin + for _,line_range in line_range_array_ do + line_range.Do(); +end; + +function TSPdfParagraphRange2.SetExtraStyleId(style_id: string); +begin + extra_style_id_ := style_id; +end; + +function TSPdfParagraphRange2.NewLineRange(): TSPdfLineRange; +begin + line_range := new TSPdfLineRange(page_); + line_range.StartX := {self.}EndX; + line_range.StartY := {self.}EndY; + line_range.Width := {self.}Width; + return line_range; +end; + +function TSPdfParagraphRange2.RangesToLines();overload; +begin + {self.}RangesToLines(ppr_unit_decorator_); + {self.}DynamicHeight += ppr_unit_decorator_.Spacing.After; + {self.}EndY -= ppr_unit_decorator_.Spacing.After; + if ppr_unit_decorator_.PBdr.Bottom.Val = "single" then + begin + 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 TSPdfParagraphRange2.RangesToLines(ppr: PPrUnitDecorator);overload; +begin + 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); + if_newline := {self.}EndX + range.Width - {self.}StartX > {self.}Width + 1e-6; + 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 + sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : 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(ppr); +end; + +function TSPdfParagraphRange2.SetLinesAlignment(ppr: PPrUnitDecorator); +begin + if length(line_range_array_) = 0 then return; + idx := length(line_range_array_)-1; + line_range := line_range_array_[idx]; + line_range.Align(ppr.Jc.Val); +end; + +function TSPdfParagraphRange2.CheckAndAddPage(y: real; offset: real): boolean; +begin + if y - offset < sect_ware_.SectPr.PgMar.Bottom then + begin + page_ := docx_to_pdf_.GetNextPage(page_); + if ifnil(page_) then page_ := docx_to_pdf_.AddPage(sect_ware_); + point := docx_to_pdf_.GetCurrentPoint(); + {self.}EndY := point.Y; + return true; + end + return false; +end; + +function TSPdfParagraphRange2.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 TSPdfParagraphRange2.RToTextRange(r: R; ppr: PPrUnitDecorator; link: string); +begin + if r.Anchor then + begin + {self.}HyperlinkToTextRange(r, ppr); + end + else begin + rpr := new RPrUnitDecorator(r.RPr); + text := r.T.Text; + if ifString(text) then {self.}SplitTextToTextRange(text, rpr, link); + end +end; + +function TSPdfParagraphRange2.SplitTextToTextRange(text: string; rpr: RPrUnitDecorator; link: string); +begin + pos := 1; + while pos <= length(text) do + begin + num := {self.}GetUtf8CharLength(text[pos]); + word := text[pos : pos+num-1]; + word := utf8ToAnsi(word); + pos += num; + font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; + font_obj := docx_to_pdf_.Font.GetFont(font_name, rpr.B, rpr.I); + 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; + end +end; + +function TSPdfParagraphRange2.RToDrawingRange(r: R; ppr: PPrUnitDecorator); +begin + xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm); + rels_adapter := docx_components_ware_.GetDocumentRelsAdapter(); + id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; + 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)-1, data); + image := nil; + case {self.}GetImageFileType(data) of + "png": + image := docx_to_pdf_.GetPdf().LoadPngImageFromFile("", image_path); + "jpg": + image := docx_to_pdf_.GetPdf().LoadJpegImageFromFile("", image_path); + end; + image_range := new TSPdfImageRange(); + image_range.Image := image; + image_range.StartX := xfrm.Off.X; + image_range.StartY := xfrm.Off.Y; + image_range.Width := xfrm.Ext.CX; + image_range.DynamicHeight := xfrm.Ext.CY; + fileDelete("", image_path); + range_array_[length(range_array_)] := image_range; +end; + +function TSPdfParagraphRange2.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)), + ); + 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 TSPdfParagraphRange2.GetParagraphLineSpace(size: real; line: integer): real; +begin + if not line then line := 12; + lines := roundto(line / 12, -1); + multi := ceil(size / sect_ware_.BaseSize) * lines; + return sect_ware_.SectPr.DocGrid.LinePitch * multi; +end; + +function TSPdfParagraphRange2.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, extra_style_id_); + {self.}SetPPrByStyleId(new_ppr, ppr.PStyle.Val); + new_ppr.Copy(ppr); + ppr.Copy(new_ppr); +end; + +function TSPdfParagraphRange2.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 TSPdfParagraphRange2.SetRPr(var rpr; ppr: PPr); +begin + new_rpr := new RPr(); + styles := docx_components_ware_.GetStyles(); + new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr); + {self.}SetRPrByStyleId(new_rpr, ppr.PStyle.Val); + {self.}SetRPrByStyleId(new_rpr, rpr.RStyle.Val); + new_rpr.Copy(rpr); + rpr.Copy(new_rpr); +end; + +function TSPdfParagraphRange2.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 TSPdfParagraphRange2.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 TSPdfParagraphRange2.ResetCoordinates(ppr: PPrUnitDecorator); +begin + // 根据段落的间距确定新的坐标 + 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; diff --git a/range/Advanced/TSPdfTableRange.tsf b/range/Advanced/TSPdfTableRange.tsf index 58be50e..f0d2638 100644 --- a/range/Advanced/TSPdfTableRange.tsf +++ b/range/Advanced/TSPdfTableRange.tsf @@ -128,7 +128,7 @@ end; function TSPdfTableRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); - style := styles.StyleId(style_id); + style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; @@ -148,7 +148,7 @@ end; function TSPdfTableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); - style := styles.StyleId(style_id); + style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; @@ -168,7 +168,7 @@ end; function TSPdfTableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); begin styles := docx_components_ware_.GetStylesAdapter(); - style := styles.StyleId(style_id); + style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; diff --git a/range/Advanced/TSPdfTocRange.tsf b/range/Advanced/TSPdfTocRange.tsf deleted file mode 100644 index dc3ccfc..0000000 --- a/range/Advanced/TSPdfTocRange.tsf +++ /dev/null @@ -1,12 +0,0 @@ -type TSPdfTocRange = class(TSPdfBasicRange) -public - function Create(); - -public - TSPage: TSPage; -end; - -function TSPdfTocRange.Create(); -begin -end; - diff --git a/ware/TSNumberingWare.tsf b/ware/TSNumberingWare.tsf index 76ad419..5665023 100644 --- a/ware/TSNumberingWare.tsf +++ b/ware/TSNumberingWare.tsf @@ -20,10 +20,10 @@ begin if ifnil(num_id) then return array("", nil); ilvl := ppr.NumPr.Ilvl.Val; pstyle := ppr.PStyle.Val; - num := numbering_adapter_.NumId(num_id); + num := numbering_adapter_.GetNumByNumId(num_id); if ifnil(num) then return array("", nil); abstract_id := num.AbstractNumId.Val; - abstract_num := numbering_adapter_.AbstractNumId(abstract_id); + abstract_num := numbering_adapter_.GetAbstractNumByAbstractNumId(abstract_id); lvls := abstract_num.Lvls(); if ifnil(ilvl) then ilvl := "0"; for k,v in lvls do @@ -36,6 +36,13 @@ begin 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 := format("%d", n); lvl_text := replaceStr(lvl_text, source_str, dest_str); diff --git a/ware/TSSectWare.tsf b/ware/TSSectWare.tsf index 36d4b4f..b283c89 100644 --- a/ware/TSSectWare.tsf +++ b/ware/TSSectWare.tsf @@ -7,7 +7,7 @@ public public Elements: array of tslobj; - SectPr: SectPr; + SectPr: SectPrUnitDecorator; BaseSize: integer; end;