From 3df8ce2be00f7932905d342792ba98a88212395a Mon Sep 17 00:00:00 2001 From: csh Date: Thu, 30 Jul 2026 14:05:16 +0800 Subject: [PATCH] v1.8.7 --- funcext/TSOffice/TOfficeObj.tsf | 2 +- funcext/TSOffice/TSDocxFile.tsf | 2 +- funcext/TSOffice/TSXlsxFile.tsf | 2 +- funcext/TSOffice/document/TDocxCopy.tsf | 6 +- funcext/TSOffice/document/TDocxStyles.tsf | 413 +++++++++++----------- 更新日志.md | 12 +- 6 files changed, 222 insertions(+), 215 deletions(-) diff --git a/funcext/TSOffice/TOfficeObj.tsf b/funcext/TSOffice/TOfficeObj.tsf index cedccef..2aa7621 100644 --- a/funcext/TSOffice/TOfficeObj.tsf +++ b/funcext/TSOffice/TOfficeObj.tsf @@ -1,4 +1,4 @@ -// Version 1.8.6 +// Version 1.8.7 Function TOfficeObj(n); Begin case lowercase(n) of diff --git a/funcext/TSOffice/TSDocxFile.tsf b/funcext/TSOffice/TSDocxFile.tsf index 288705f..f7dcf21 100644 --- a/funcext/TSOffice/TSDocxFile.tsf +++ b/funcext/TSOffice/TSDocxFile.tsf @@ -1,4 +1,4 @@ -// Version 1.8.6 +// Version 1.8.7 Type TSDocxFile = Class ///Version: V1.0 2022-09-20 ///适用于 Microsoft Word docx格式文件 diff --git a/funcext/TSOffice/TSXlsxFile.tsf b/funcext/TSOffice/TSXlsxFile.tsf index f28ff72..2028e9e 100644 --- a/funcext/TSOffice/TSXlsxFile.tsf +++ b/funcext/TSOffice/TSXlsxFile.tsf @@ -1,4 +1,4 @@ -// Version 1.8.6 +// Version 1.8.7 Type TSXlsxFile = Class ///Version: V1.0 2022-08-08 ///适用于 Microsoft Excel? 2007 及以上版本创建的电子表格文档。支持 XLSX / XLSM / XLTM / XLTX 等多种文档格式。 diff --git a/funcext/TSOffice/document/TDocxCopy.tsf b/funcext/TSOffice/document/TDocxCopy.tsf index 21c7555..6f8d399 100644 --- a/funcext/TSOffice/document/TDocxCopy.tsf +++ b/funcext/TSOffice/document/TDocxCopy.tsf @@ -501,18 +501,16 @@ private Function GetNewName(name); Begin new_name := name; - count := 0; while ifObj(old_style_obj_.GetStyle(class(TSXml).Utf8ToCurCodePage(new_name))) or style_name_map2_[new_name] do - new_name := new_name $ count++; + new_name := new_name $ crc32(inttostr(random(2000000))); return new_name; End; Function GetNewId(id); Begin new_id := id; - count := 0; while ifObj(old_style_obj_.GetStyleById(new_id)) or style_id_map2_[new_id] do - new_id := new_id $ count++; + new_id := new_id $ crc32(inttostr(random(2000000))); return new_id; End; diff --git a/funcext/TSOffice/document/TDocxStyles.tsf b/funcext/TSOffice/document/TDocxStyles.tsf index b633e47..32cbda6 100644 --- a/funcext/TSOffice/document/TDocxStyles.tsf +++ b/funcext/TSOffice/document/TDocxStyles.tsf @@ -1,206 +1,207 @@ -Type TDocxStyles = Class - //段落格式 - Function Create(docx); - Begin - docx_ := docx; - stylesXml_ := docx.Zip().Get('word/styles.xml'); - idMap_ := array(); - nameMap_ := array(); - maxStyleId_ := 1; - - if ifObj(stylesXml_) then Begin - stylesNode := stylesXml_.FirstChildElement('w:styles'); - if ifObj(stylesNode) then Begin - node := stylesNode.FirstChildElement('w:style'); - while ifObj(node) do Begin - o := TOfficeObj('TDocxStyle'); - o.Init(node); - id := StrToIntDef(o.StyleId, 0); - if id > 0 and maxStyleId_ <= id then - maxStyleId_ := id + 1; - _addStyle(o); - node := node.NextElement('w:style'); - End; - pNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:pPrDefault'); - if ifObj(pNode) then - defaultPpr_ := Class(TSXml).ReadPprFormat(pNode); - - rNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:rPrDefault'); - if ifObj(rNode) then - defaultRpr_ := Class(TSXml).ReadRprFormat(rNode); - End; - End; - End; - - ///缺省样式 - ///styleType:样式类型(paragraph、character、table) - ///返回:TDocxStyle对象 - Function Default(styleType); - Begin - for k, obj in idMap_ do Begin - if obj.wType = styleType then Begin - v := obj.node_.GetAttribute('w:default'); - if v <> '1' then - return obj; - End; - End - return nil; - End; - - ///返回指定名称的TDocxStyle - ///name:样式名称 - ///返回:TDocxStyle对象 - Function GetStyle(name); - Begin - return nameMap_[ class(TSXml).CurCodePageToUtf8(lowercase(name)) ]; - End; - - ///返回指定StyleId名称的TDocxStyle - ///id:StyleID号(数字ID号或名称字符串) - ///返回:TDocxStyle对象 - Function GetStyleById(id); - Begin - newid := ifnumber(id) ? tostring(id) : id; - return idMap_[ newid ]; - End; - - //返回全部LatentStyles对象列表 - //返回:TDocxStyle对象列表 - Function LatentStyles(); - Begin - r := array(); - node := stylesXml_.FirstChildElement('w:styles'); - if ifObj(node) then - node := node.FirstChildElement('w:latentStyles'); - if ifObj(node) then Begin - node := node.FirstChildElement('w:lsdException'); - while ifObj(node) do Begin - o := TOfficeObj('TDocxStyle'); - o.Init(node); - r[ length(r) ] := o; - node := node.NextElement('w:lsdException'); - End; - End; - return r; - End; - - ///返回全部Styles对象列表 - ///返回:TDocxStyle对象列表 - Function Styles(); - Begin - return idMap_; - End; - - ///插入新的段落样式 - ///styleId:样式ID,可以是自定义名称 - ///xmlStr:InnerXml串 - ///返回:TDocxStyle对象 - Function AddStyleByInnerXml(styleId, xmlStr); - Begin - if ifstring(styleId) and styleId <> '' then Begin - style := GetStyle(styleId); - if ifObj(style) then - return style; - node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr); - node.SetAttribute('w:styleId', styleId); - End - else Begin - node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr); - node.SetAttribute('w:styleId', maxStyleId_++); - End; - o := TOfficeObj('TDocxStyle'); - o.Init(node); - _addStyle(o); - return o; - End; - - ///插入新的段落样式 - ///o:TDocxStyle对象 - ///StyleId:样式ID,可以是自定义名称 - ///返回:TDocxStyle对象 - Function AddStyle(o, StyleId); - Begin - if ifObj(o) then Begin - if ifString(StyleId) and StyleId <> '' and not ifObj(idMap_[ StyleId ]) then - o.StyleId := StyleId; - else - o.StyleId := maxStyleId_++; - node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(o.Marshal()); - obj := TOfficeObj('TDocxStyle'); - obj.Init(node); - _addStyle(obj); - return obj; - End; - return nil; - End; - - ///复制样式 - ///newstyle:样式节点TDocxStyle对象 - ///返回:TDocxStyle对象 - Function CopyStyle(newstyle); - Begin - if ifObj(newstyle) and ifObj(newstyle.node_) then Begin - node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(newstyle.node_.Marshal()[0]); - obj := TOfficeObj('TDocxStyle'); - obj.StyleId := node.GetAttribute('w:styleId'); - obj.Name := node.FirstChildElement('w:name').GetAttribute('w:val'); - obj.Init(node); - _addStyle(obj); - return obj; - End; - return nil; - End; - - ///插入新的LatentStyle段落样式 - ///o:TDocxStyle对象 - ///返回:TDocxStyle对象 - Function AddLatentStyle(o); - Begin - if ifObj(o) then Begin - latentStyles := stylesXml_.FirstChildElement('w:styles').InsertEndChild('w:latentStyles'); - node := latentStyles.InsertEndChild('lsdException'); - node.UnMarshal(o); - latentStyles.SetAttribute('w:count', length(LatentStyles())); - return node; - End; - return nil; - End; - - ///插入缺省的段落样式(Title、Heading1-9) - ///返回:TDocxStyle对象 - Function AddDefaultStyle(Name); - Begin - styleId := AnsiReplaceText(Name, ' ', ''); - charId := StyleId + 'Char'; - styleFname := 'wStyle/' + styleId + '.xml'; - cStyleFname := 'wStyle/' + charId + '.xml'; - xmlData := TOfficeTemplate(styleFname); - if ifnil(xmlData) then - return xmlData; - o := AddStyleByInnerXml(styleId, xmlData); - - charStyle := idMap_[charId]; - if not ifObj(charStyle) then Begin - xmlData := TOfficeTemplate(cStyleFname); - if ifstring(xmlData) then Begin - AddStyleByInnerXml(charId, xmlData); - End; - End; - return o; - End; - - Function _addStyle(o); - Begin - idMap_[ o.StyleId ] := o; - nameMap_[ lowercase(o.Name) ] := o; - End; - - defaultPpr_; - defaultRpr_; -private - [weakref]docx_; - stylesXml_; - idMap_; - nameMap_; - maxStyleId_:integer; -End; +Type TDocxStyles = Class + //段落格式 + Function Create(docx); + Begin + docx_ := docx; + stylesXml_ := docx.Zip().Get('word/styles.xml'); + idMap_ := array(); + nameMap_ := array(); + maxStyleId_ := 1; + + if ifObj(stylesXml_) then Begin + stylesNode := stylesXml_.FirstChildElement('w:styles'); + if ifObj(stylesNode) then Begin + node := stylesNode.FirstChildElement('w:style'); + while ifObj(node) do Begin + o := TOfficeObj('TDocxStyle'); + o.Init(node); + id := StrToIntDef(o.StyleId, 0); + if id > 0 and maxStyleId_ <= id then + maxStyleId_ := id + 1; + _addStyle(o); + node := node.NextElement('w:style'); + End; + pNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:pPrDefault'); + if ifObj(pNode) then + defaultPpr_ := Class(TSXml).ReadPprFormat(pNode); + + rNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:rPrDefault'); + if ifObj(rNode) then + defaultRpr_ := Class(TSXml).ReadRprFormat(rNode); + End; + End; + End; + + ///缺省样式 + ///styleType:样式类型(paragraph、character、table) + ///返回:TDocxStyle对象 + Function Default(styleType); + Begin + for k, obj in idMap_ do Begin + if obj.wType = styleType then Begin + v := obj.node_.GetAttribute('w:default'); + if v <> '1' then + return obj; + End; + End + return nil; + End; + + ///返回指定名称的TDocxStyle + ///name:样式名称 + ///返回:TDocxStyle对象 + Function GetStyle(name); + Begin + return nameMap_[ class(TSXml).CurCodePageToUtf8(lowercase(name)) ]; + End; + + ///返回指定StyleId名称的TDocxStyle + ///id:StyleID号(数字ID号或名称字符串) + ///返回:TDocxStyle对象 + Function GetStyleById(id); + Begin + newid := ifnumber(id) ? tostring(id) : id; + return idMap_[ newid ]; + End; + + //返回全部LatentStyles对象列表 + //返回:TDocxStyle对象列表 + Function LatentStyles(); + Begin + r := array(); + node := stylesXml_.FirstChildElement('w:styles'); + if ifObj(node) then + node := node.FirstChildElement('w:latentStyles'); + if ifObj(node) then Begin + node := node.FirstChildElement('w:lsdException'); + while ifObj(node) do Begin + o := TOfficeObj('TDocxStyle'); + o.Init(node); + r[ length(r) ] := o; + node := node.NextElement('w:lsdException'); + End; + End; + return r; + End; + + ///返回全部Styles对象列表 + ///返回:TDocxStyle对象列表 + Function Styles(); + Begin + return idMap_; + End; + + ///插入新的段落样式 + ///styleId:样式ID,可以是自定义名称 + ///xmlStr:InnerXml串 + ///返回:TDocxStyle对象 + Function AddStyleByInnerXml(styleId, xmlStr); + Begin + if ifstring(styleId) and styleId <> '' then Begin + style := GetStyle(styleId); + if ifObj(style) then + return style; + node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr); + node.SetAttribute('w:styleId', styleId); + End + else Begin + node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr); + node.SetAttribute('w:styleId', maxStyleId_++); + End; + o := TOfficeObj('TDocxStyle'); + o.Init(node); + _addStyle(o); + return o; + End; + + ///插入新的段落样式 + ///o:TDocxStyle对象 + ///StyleId:样式ID,可以是自定义名称 + ///返回:TDocxStyle对象 + Function AddStyle(o, StyleId); + Begin + if ifObj(o) then Begin + if ifString(StyleId) and StyleId <> '' and not ifObj(idMap_[ StyleId ]) then + o.StyleId := StyleId; + else + o.StyleId := maxStyleId_++; + node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(o.Marshal()); + obj := TOfficeObj('TDocxStyle'); + obj.Init(node); + _addStyle(obj); + return obj; + End; + return nil; + End; + + ///复制样式 + ///newstyle:样式节点TDocxStyle对象 + ///返回:TDocxStyle对象 + Function CopyStyle(newstyle); + Begin + if ifObj(newstyle) and ifObj(newstyle.node_) then Begin + node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(newstyle.node_.Marshal()[0]); + node.DeleteAttribute('w:default'); + obj := TOfficeObj('TDocxStyle'); + obj.StyleId := node.GetAttribute('w:styleId'); + obj.Name := node.FirstChildElement('w:name').GetAttribute('w:val'); + obj.Init(node); + _addStyle(obj); + return obj; + End; + return nil; + End; + + ///插入新的LatentStyle段落样式 + ///o:TDocxStyle对象 + ///返回:TDocxStyle对象 + Function AddLatentStyle(o); + Begin + if ifObj(o) then Begin + latentStyles := stylesXml_.FirstChildElement('w:styles').InsertEndChild('w:latentStyles'); + node := latentStyles.InsertEndChild('lsdException'); + node.UnMarshal(o); + latentStyles.SetAttribute('w:count', length(LatentStyles())); + return node; + End; + return nil; + End; + + ///插入缺省的段落样式(Title、Heading1-9) + ///返回:TDocxStyle对象 + Function AddDefaultStyle(Name); + Begin + styleId := AnsiReplaceText(Name, ' ', ''); + charId := StyleId + 'Char'; + styleFname := 'wStyle/' + styleId + '.xml'; + cStyleFname := 'wStyle/' + charId + '.xml'; + xmlData := TOfficeTemplate(styleFname); + if ifnil(xmlData) then + return xmlData; + o := AddStyleByInnerXml(styleId, xmlData); + + charStyle := idMap_[charId]; + if not ifObj(charStyle) then Begin + xmlData := TOfficeTemplate(cStyleFname); + if ifstring(xmlData) then Begin + AddStyleByInnerXml(charId, xmlData); + End; + End; + return o; + End; + + Function _addStyle(o); + Begin + idMap_[ o.StyleId ] := o; + nameMap_[ lowercase(o.Name) ] := o; + End; + + defaultPpr_; + defaultRpr_; +private + [weakref]docx_; + stylesXml_; + idMap_; + nameMap_; + maxStyleId_:integer; +End; diff --git a/更新日志.md b/更新日志.md index b8d5345..f5ca592 100644 --- a/更新日志.md +++ b/更新日志.md @@ -1,8 +1,16 @@ # 更新日志 +## 2026-07-30 + +### V1.8.7 + +#### word + +1. 修复`InsertFile`时,样式重复导致wps/word识别失败从而渲染错误问题 + ## 2026-01-16 -#### V1.8.6 +### V1.8.6 修复语法问题 @@ -12,7 +20,7 @@ ## 2025-12-15 -#### V1.8.5 +### V1.8.5 #### word