diff --git a/TSDocxToPdf.tsf b/TSDocxToPdf.tsf index c4c17f7..1334941 100644 --- a/TSDocxToPdf.tsf +++ b/TSDocxToPdf.tsf @@ -20,6 +20,7 @@ public function SetHeaderAndFooter(); function ProcessNumpages(); function CalculateTextCoordinates(): array of real; + function GetSymbol(symbol: string); property Font read ReadFont; function ReadFont(); @@ -29,6 +30,7 @@ private function InitCachePath(file: string); function InitPdfEncoder(); function InitSectWare(); + function InitSymbol(); function AllocateElementsToSectWare(); function SetHdr(type: string); @@ -57,6 +59,7 @@ private ftr_point_: Point; // 页脚坐标 even_and_odd_flag_: boolean; xml_file_: string; + symbol_: tableArray; end; type Point = class @@ -76,6 +79,7 @@ begin {self.}InitDocxComponents(alias, file); {self.}InitCachePath(file); {self.}InitSectWare(); + {self.}InitSymbol(); font_ware_ := new TSFontWare(pdf_); current_page_ := nil; page_array_ := array(); @@ -118,8 +122,8 @@ begin elements := sect_ware.Elements(); for _,element in elements do begin - // if _ = 4 then break; - // if _ = 624 then + // if _ = 31 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); @@ -201,6 +205,19 @@ begin {self.}AllocateElementsToSectWare(); end; +function TSDocxToPdf.InitSymbol(); +begin + symbol_ := array( + "": "※", + "": "■", + "": "●", + "": "◆", + + "": "●", + "": "■", + ); +end; + function TSDocxToPdf.AllocateElementsToSectWare(); begin elements := docx_components_ware_.Document.Body.Elements(); @@ -440,3 +457,9 @@ begin toc.LinkAnnot(dst); toc.AddPageNumber(page); end; + +function TSDocxToPdf.GetSymbol(symbol: string); +begin + // println("symbol = {}, symbol_ = {}", symbol, symbol_); + return symbol_[symbol]; +end; diff --git a/range/Advanced/TSPdfParagraphRange.tsf b/range/Advanced/TSPdfParagraphRange.tsf index 5c7c70e..06dec03 100644 --- a/range/Advanced/TSPdfParagraphRange.tsf +++ b/range/Advanced/TSPdfParagraphRange.tsf @@ -6,8 +6,6 @@ public function SetTblStyleIdAndType(style_id: string; type: string); function SetNumPages(num: integer); function RangesToLines(); - function FirstValidTSPage(): TSPage; - function IsSamePage(): boolean; function GetLastPage(): TSPage; function AdjustRangeOffset(page: TSPage; x_offset: real; y_offset: real); function GetLineRangeArr(): array of TSPdfLineRange; @@ -72,17 +70,17 @@ end; function TSPdfParagraphRange.Calc(): tableArray; begin // ppr.rpr是无效的,应该以ppr.pStyle为准 + if ifnil(paragraph_.XmlChildPPr) then paragraph_.XmlChildPPr := new PPr(); {self.}SetPPr(paragraph_.PPr); - {self.}SetLvlText(); 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; {self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before); - {self.}TSPage := page_; {self.}EndY -= ppr_unit_decorator_.Spacing.Before; {self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before; + {self.}SetLvlText(); elements := paragraph_.Elements(); empty_flag := true; @@ -94,6 +92,7 @@ begin if element.LocalName = "r" then begin empty_flag := false; + if ifnil(element.XmlChildRPr) then element.XmlChildRPr := new RPr(); {self.}SetRPr(element.RPr, ppr_unit_decorator_); if element.FldChar.FldCharType = "begin" then continue; @@ -119,6 +118,7 @@ begin numpages := false; end else if element.Br.Type = "page" then + // {self.}EndY := {self.}LowerBound; {self.}CheckAndAddPage({self.}LowerBound, 1); else if ifObj(element.Drawing.XmlNode) then {self.}RToDrawingRange(element); else if ifObj(element.AlternateContent.XmlNode) then {self.}RAlternateContentToRange(element); @@ -228,7 +228,7 @@ begin y := range.EndY; end 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); + font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, ppr.RPr.B, ppr.RPr.I); line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line); pg.PdfPage.SetFontAndSize(font_obj, max_size); bottom -= line_space; @@ -268,7 +268,7 @@ begin begin if r.FldChar.FldCharType = "begin" then break; // TODO:officexml项目是否应该保留赋值接口,如何统一 - r.RPr.Lang.Val := "zh-CN"; + if ifnil(r.XmlChildRPr) then r.XmlChildRPr := new RPr(); // r.RPr := new RPr(); {self.}SetRPr(r.RPr, ppr_unit_decorator_); r.RPr.Color.Val := nil; @@ -339,6 +339,7 @@ begin if {self.}CheckAndAddPage({self.}EndY, max(line_space, range.DynamicHeight)) then {self.}DynamicHeight += diff; if_newline := {self.}EndX + range.Width - {self.}StartX > {self.}Width + 1e-6; + if i = 0 then if_newline := 0; 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; @@ -356,7 +357,10 @@ begin {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(); + if range is class(TSPdfTextRange) then + sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); + else + sz := docx_to_pdf_.Font.GetDefaultSz(); {self.}EndX -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging; continue; end @@ -430,11 +434,13 @@ begin while pos <= length(text) do begin num := {self.}GetUtf8CharLength(text[pos]); - word := text[pos : pos+num-1]; - word := utf8ToAnsi(word); + a_word := text[pos : pos+num-1]; + word := utf8ToAnsi(a_word); + if num <> 1 and word = "?" then + word := utf8ToAnsi(docx_to_pdf_.GetSymbol(a_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); + font_obj := docx_to_pdf_.Font.GetCNSFont(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); @@ -474,6 +480,10 @@ begin xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm); position_h := new PositionHUnitDecorator(anchor.PositionH); position_v := new PositionVUnitDecorator(anchor.PositionV); + if position_h.RelativeFrom = "paragraph" then + x := {self.}StartY; + if position_v.RelativeFrom = "paragraph" then + y := {self.}StartY; image_range := new TSPdfImageRange(); image_range.Image := image; image_range.EndX := x + position_h.PosOffset.Text; @@ -493,6 +503,10 @@ begin xfrm := new XfrmUnitDecorator(wsp.SpPr.Xfrm); position_h := new PositionHUnitDecorator(anchor.PositionH); position_v := new PositionVUnitDecorator(anchor.PositionV); + if position_h.RelativeFrom = "paragraph" then + x := {self.}StartY; + if position_v.RelativeFrom = "paragraph" then + y := {self.}StartY; x += position_h.PosOffset.Text; y -= position_v.PosOffset.Text; w := xfrm.Ext.CX; @@ -576,20 +590,11 @@ begin data := image.Data(); image_path := docx_to_pdf_.GetCachePath(image_path); writeFile(rwBinary(), "", image_path, 0, length(data), data); - image_type := extractFileExt(image_path); - if image_type = ".emf" then - begin - image_old_path := image_path; - image_path := replaceStr(image_path, "emf", "png"); - gdipconvimagetype("", image_old_path, "", image_path, "image/png"); - image_type := ".png"; - fileDelete("", image_old_path); - end image := nil; - case image_type of - ".png": + case GetImageFileType(data) of + "png": image := docx_to_pdf_.GetPdf().LoadPngImageFromFile("", image_path); - ".jpg", ".jpeg": + "jpg": image := docx_to_pdf_.GetPdf().LoadJpegImageFromFile("", image_path); end; fileDelete("", image_path); @@ -604,6 +609,7 @@ begin def := array( ('name': 'png', 'position': 0, 'value': array(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)), ('name': 'jpg', 'position': 0, 'value': array(0xFF, 0xD8)), + ('name': 'emf', 'position': 40, 'value': array(0x20, 0x45, 0x4d, 0x46)), ); for i:=0 to length(def)-1 do begin @@ -681,7 +687,7 @@ begin based_on := style.BasedOn.Val; {self.}SetRPrByTblStyleId(rpr, based_on); rpr.Copy(style.RPr); - end; + end if table_style_type_ then begin tbl_style_pr := docx_components_ware_.GetTblStylePrByType(table_style_id_, table_style_type_); @@ -722,18 +728,6 @@ begin {self.}Width -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right; end; -function TSPdfParagraphRange.FirstValidTSPage(): TSPage; -begin - range := range_array_[0]; - return ifObj(range) ? range.TSPage : page_; -end; - -function TSPdfParagraphRange.IsSamePage(): boolean; -begin - pg := range_array_[0] ? range.TSPage : {self.}TSPage; - return page_ = pg; -end; - function TSPdfParagraphRange.GetLastPage(): TSPage; begin return page_; diff --git a/ware/TSFontWare.tsf b/ware/TSFontWare.tsf index c679867..d9c036d 100644 --- a/ware/TSFontWare.tsf +++ b/ware/TSFontWare.tsf @@ -1,7 +1,9 @@ type TSFontWare = class public function Create(pdf: PdfFile); - function GetFont(name: string; bold: boolean; italic: boolean); + function GetFontByText(text: string; name: string; bold: boolean; italic: boolean); + function GetAsciiFont(name: string; bold: boolean; italic: boolean); + function GetCNSFont(name: string; bold: boolean; italic: boolean); function UseExternalFont(); function SetSubstitutionRules(source: string; target: string); function SetDefaultSz(value: real); @@ -9,7 +11,8 @@ public private function GetExternalFont(name:string; bold: boolean; italic: boolean); - function GetBuiltInFont(name:string; bold: boolean; italic: boolean); + function GetBuiltInCNSFont(name:string; bold: boolean; italic: boolean); + function GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean); private [weakref]pdf_: PdfFile; @@ -25,7 +28,12 @@ function TSFontWare.Create(pdf: PdfFile); begin pdf_ := pdf; use_built_in_font_ := true; - substitution_rules_ := array("宋体": "SimSun", "黑体": "SimHei"); + substitution_rules_ := array("宋体": "SimSun", + "黑体": "SimHei", + "Courier New": "Courier", + "Helvetica": "Helvetica", + "Times New Roman": "Times-Roman", + ); external_reference_ := array(); default_sz_ := 10.5; end; @@ -63,12 +71,21 @@ begin return font; end; -function TSFontWare.GetFont(name: string; bold: boolean; italic: boolean); +function TSFontWare.GetFontByText(text: string; name: string; bold: boolean; italic: boolean); begin - return use_built_in_font_ ? {self.}GetBuiltInFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic); + len := length(text); + if len > 1 then + return {self.}GetCNSFont(name, bold, italic); + else + return {self.}GetAsciiFont(name, bold, italic); end; -function TSFontWare.GetBuiltInFont(name: string; bold: boolean; italic: boolean); +function TSFontWare.GetCNSFont(name: string; bold: boolean; italic: boolean); +begin + return use_built_in_font_ ? {self.}GetBuiltInCNSFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic); +end; + +function TSFontWare.GetBuiltInCNSFont(name: string; bold: boolean; italic: boolean); begin font_name := substitution_rules_[name]; if ifnil(font_name) then font_name := "SimSun"; @@ -82,6 +99,37 @@ begin return font; end; +function TSFontWare.GetAsciiFont(name: string; bold: boolean; italic: boolean); +begin + return use_built_in_font_ ? {self.}GetBuiltInAsciiFont(name, bold, italic) : {self.}GetExternalFont(name, bold, italic); +end; + +function TSFontWare.GetBuiltInAsciiFont(name:string; bold: boolean; italic: boolean); +begin + font_name := substitution_rules_[name]; + if ifnil(font_name) then font_name := "Times-Roman"; + if font_name = "Courier" or font_name = "Helvetica" then + begin + if bold and italic then + font_name += "-BoldOblique"; + else if bold then + font_name += "-Bold"; + else if italic then + font_name += "-Oblique"; + end + else if font_name = "Times-Roman" then + begin + if bold and italic then + font_name := "Times-BoldItalic"; + else if bold then + font_name += "Times-Bold"; + else if italic then + font_name += "Times-Italic"; + end + font := pdf_.GetFont(font_name, ""); + return font; +end; + function TSFontWare.SetSubstitutionRules(source: string; target: string); begin substitution_rules_[source] := target;