HtexMath.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using DocumentFormat.OpenXml.Drawing;
  2. using DocumentFormat.OpenXml.Math;
  3. using HTEXLib.Helpers.ShapeHelpers;
  4. using HTEXLib.Models.Inner;
  5. using HTEXLib.Models.PPTX;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Xml;
  12. using System.Xml.Linq;
  13. using System.Xml.Xsl;
  14. namespace HTEXLib.Models.HTEX
  15. {
  16. public class HtexMath: HtexElement
  17. {
  18. public PPTMath pptMath { get; set; }
  19. // public double Rotate { get; set; }
  20. public string HyperLink { get; set; }
  21. private int slideIndex;
  22. public HtexMath(string id, double rot, double width, double height,
  23. double top, double left, bool invisible,
  24. bool animatable, int slideIndex, int index, PPTMath shape, PPTSlide slide, string partForm, string timingId)
  25. {
  26. base.sid = timingId;
  27. base.slide = slide;
  28. this.rot = rot;
  29. this.pptMath = shape;
  30. base.id = id;
  31. base.top = top;
  32. base.left = left;
  33. base.width = width;
  34. base.height = height;
  35. base.invisible = invisible;
  36. base.animatable = animatable;
  37. this.slideIndex = slideIndex;
  38. base.index = index;
  39. base.type = "Math";
  40. base.partForm = partForm;
  41. }
  42. public override List<Item> DrawElement() {
  43. Position position = new Position { cx = width, cy = height, x = left, y = top, rot = rot };
  44. var ShapeStyle = PPTXHelper.DoShapeProperties(pptMath.element.ShapeProperties, slide, type, partForm);
  45. var shapeTypeNode = pptMath.element.ShapeProperties.GetFirstChild<PresetGeometry>();
  46. Math math = new Math { sid = sid, id = this.id, type = type, index = index/*, animatable = animatable, invisible = invisible*/ };
  47. math.style.position = position;
  48. math.style.effect = ShapeStyle.effect;
  49. SlideColor slideColor = PPTXHelper.DoShapeStyle(pptMath.element.ShapeStyle, slide, type);
  50. //从ShapeProperties 获取 p:spPr
  51. //再从 ShapeStyle 获取 p:spPr
  52. if (ShapeStyle.border == null || ShapeStyle.border.color == null || ShapeStyle.border.color.type == -1)
  53. {
  54. if (slideColor != null)
  55. {
  56. math.style.border.color.solidFill = slideColor.LineColor;
  57. math.style.border.color.type = 2;
  58. }
  59. }
  60. else
  61. {
  62. math.style.border = ShapeStyle.border;
  63. }
  64. if (ShapeStyle.fill == null || ShapeStyle.fill.type == -1)
  65. {
  66. if (slideColor != null)
  67. {
  68. math.style.fill.solidFill = slideColor.FillColor;
  69. math.style.fill.type = 2;
  70. }
  71. }
  72. else
  73. {
  74. math.style.fill = ShapeStyle.fill;
  75. }
  76. if (shapeTypeNode != null && shapeTypeNode.Preset != null && !string.IsNullOrEmpty(shapeTypeNode.Preset.InnerText))
  77. {
  78. var shapeType = shapeTypeNode.Preset.InnerText;
  79. Svg svg = PPTXSvg.GenShapeSvg(pptMath.element, index, shapeType, position, math.style.border);
  80. math.svg = svg;
  81. math.shapeType = shapeType;
  82. }
  83. var AlternateContentChoice= pptMath.AlternateContentChoice;
  84. var shp = AlternateContentChoice.GetFirstChild<DocumentFormat.OpenXml.Presentation.Shape>();
  85. var Paragraphs = shp.TextBody.Elements<DocumentFormat.OpenXml.Drawing.Paragraph>();
  86. foreach (var pa in Paragraphs)
  87. { // OfficeMath
  88. ///公式插入 线性 专用,普通文本区别
  89. var oMath = shp.GetTextByPath("//p:txBody/a:p/a14:m/m:oMathPara/m:oMath");
  90. double pitchFamily = 18.0;
  91. string typeface = "";
  92. OfficeMath officeMath = new OfficeMath(oMath.ToString());
  93. var rRr = oMath.GetTextByPath("//a:rPr");
  94. if (rRr != null) {
  95. var TextCharacterPropertiesType = new DocumentFormat.OpenXml.Drawing.RunProperties(rRr.ToString());
  96. if (TextCharacterPropertiesType != null) {
  97. //TODO 计算拿到的相关属性的个数,遵循多数的样式。
  98. /*
  99. .Outline
  100. .NoFill
  101. .SolidFill
  102. .GradientFill
  103. .BlipFill
  104. .PatternFill
  105. .GroupFill
  106. .EffectList
  107. .EffectDag
  108. .Highlight
  109. .UnderlineFollowsText
  110. .Underline
  111. .UnderlineFillText
  112. .UnderlineFill
  113. .LatinFont
  114. .EastAsianFont
  115. .ComplexScriptFont
  116. .SymbolFont
  117. .HyperlinkOnClick
  118. .HyperlinkOnMouseOver
  119. .RightToLeft
  120. */
  121. LatinFont LatinFont = TextCharacterPropertiesType.GetFirstChild<LatinFont>();
  122. if (LatinFont != null) {
  123. pitchFamily = LatinFont.PitchFamily.Value;
  124. typeface = LatinFont.Typeface.Value;
  125. }
  126. }
  127. }
  128. var els = XElement.Parse(officeMath.OuterXml);
  129. UTF32Encoding encoding = new UTF32Encoding();
  130. Dictionary<string, string> dict = new Dictionary<string, string>();
  131. DoXml(els, dict,encoding);
  132. els = ProcessOMath(els);
  133. DoMathXml(els,dict,encoding);
  134. var mathML = els.ToString().Replace("\r\n","").Replace(" ","");
  135. math.mathML=new MathML { formula=mathML,typeface=typeface,pitchFamily=pitchFamily};
  136. }
  137. var AlternateContentFallback= pptMath.AlternateContentFallback;
  138. if (AlternateContentFallback.ChildElements.First() is DocumentFormat.OpenXml.Presentation.Shape shapea)
  139. {
  140. PPTShape baseShape = new PPTShape(slide.SlidePart, shapea, slide);
  141. double left = baseShape.VisualShapeProp.Left();
  142. double width = baseShape.VisualShapeProp.PixelWidth();
  143. double top = baseShape.VisualShapeProp.Top();
  144. double height = baseShape.VisualShapeProp.PixelHeight();
  145. double rot = baseShape.VisualShapeProp.Rotate;
  146. string Id = baseShape.NonVisualShapeProp.Id;
  147. bool invisible = baseShape.Invisible;
  148. bool animatable = baseShape.Animatable;
  149. string clickLinkUrl = baseShape.ClickLinkUrl;
  150. HtexShape htmlShape = new HtexShape(Id, rot, width, height, top,
  151. left, invisible, animatable, slideIndex, index, baseShape, slide, baseShape.PartForm,sid)
  152. {
  153. Shape = baseShape,
  154. //rot = baseShape.VisualShapeProp.Rotate,
  155. HyperLink = clickLinkUrl
  156. };
  157. var elmt= htmlShape.DrawElement();
  158. if (elmt != null && elmt.Count > 0) {
  159. math.back = elmt[0];
  160. }
  161. }
  162. math.uid = pptMath.suid;
  163. if (math.style.fill.type == -1 || math.style.fill.type == 0)
  164. {
  165. math.style.fill = null;
  166. }
  167. if (math.style.border != null && (math.style.border.color.type == -1|| math.style.border.color.type == 0))
  168. {
  169. math.style.border.color = null;
  170. }
  171. if (math.style.border != null && math.style.border.type == "none")
  172. {
  173. math.style.border = null;
  174. }
  175. return new List<Item> { math };
  176. }
  177. /// <summary>
  178. /// 处理xml 中的非ASCII编码的特殊公式字符
  179. /// </summary>
  180. /// <param name="element"></param>
  181. public void DoXml(XElement element,Dictionary<string,string> Replace, UTF32Encoding encoding )
  182. {
  183. foreach (var elm in element.Elements())
  184. {
  185. var child = elm.Elements().ToList();
  186. if (child != null && child.Count > 0)
  187. {
  188. DoXml(elm,Replace, encoding);
  189. }
  190. else
  191. {
  192. if (!string.IsNullOrEmpty(elm.Value))
  193. {
  194. //
  195. //Byte[] encodedBytes = encoding.GetBytes(a);
  196. //string ad = encoding.GetString(encodedBytes, 0, 4);
  197. string em = elm.Value;
  198. List<string> chars = new List<string>();
  199. Byte[] encodedBytes = encoding.GetBytes(em);
  200. if (encodedBytes != null) {
  201. var len = encodedBytes.Length/4;
  202. for (int i = 0; i < len; i++) {
  203. string od= encoding.GetString(encodedBytes, i * 4, 4);
  204. if (CharHelper.MathChar.TryGetValue(od, out string ne)) {
  205. em = em.Replace(od, ne);
  206. Replace[ne] = od;
  207. }
  208. }
  209. }
  210. // var keys = CharHelper.MathChar.Keys;
  211. // foreach (string key in keys)
  212. // {
  213. // em = em.Replace(key, CharHelper.MathChar[key]);
  214. // }
  215. elm.Value = em;
  216. elm.ReplaceWith(elm);
  217. }
  218. }
  219. }
  220. }/// <summary>
  221. /// 处理xml 中的非ASCII编码的特殊公式字符
  222. /// </summary>
  223. /// <param name="element"></param>
  224. public void DoMathXml(XElement element, Dictionary<string, string> Replace, UTF32Encoding encoding)
  225. {
  226. foreach (var elm in element.Elements())
  227. {
  228. var child = elm.Elements().ToList();
  229. if (child != null && child.Count > 0)
  230. {
  231. DoMathXml(elm, Replace, encoding);
  232. }
  233. else
  234. {
  235. if (!string.IsNullOrEmpty(elm.Value))
  236. {
  237. //
  238. //Byte[] encodedBytes = encoding.GetBytes(a);
  239. //string ad = encoding.GetString(encodedBytes, 0, 4);
  240. string em = elm.Value;
  241. List<string> chars = new List<string>();
  242. Byte[] encodedBytes = encoding.GetBytes(em);
  243. if (encodedBytes != null)
  244. {
  245. var len = encodedBytes.Length / 4;
  246. for (int i = 0; i < len; i++)
  247. {
  248. string od = encoding.GetString(encodedBytes, i * 4, 4);
  249. if (Replace.TryGetValue(od, out string ne))
  250. {
  251. em = em.Replace(od, ne);
  252. }
  253. }
  254. }
  255. // var keys = CharHelper.MathChar.Keys;
  256. // foreach (string key in keys)
  257. // {
  258. // em = em.Replace(key, CharHelper.MathChar[key]);
  259. // }
  260. elm.Value = em;
  261. elm.ReplaceWith(elm);
  262. }
  263. }
  264. }
  265. }
  266. public XElement ProcessOMath(XElement element)
  267. {
  268. XmlReader OMML2MML = XmlReader.Create( new StringReader(Globals.OMML2MML));
  269. XslCompiledTransform xslTransform = new XslCompiledTransform();
  270. xslTransform.Load(OMML2MML);
  271. // xslTransform.Load("F:\\OMML2MML.XSL");
  272. string mathXml = element.ToString();
  273. string officeML = string.Empty;
  274. using (TextReader tr = new StringReader(mathXml))
  275. {
  276. using (XmlReader reader = XmlReader.Create(tr))
  277. {
  278. using (MemoryStream ms = new MemoryStream())
  279. {
  280. XmlWriterSettings settings = xslTransform.OutputSettings.Clone();
  281. settings.ConformanceLevel = ConformanceLevel.Fragment;
  282. settings.OmitXmlDeclaration = true;
  283. XmlWriter xw = XmlWriter.Create(ms, settings);
  284. xslTransform.Transform(reader, xw);
  285. ms.Seek(0, SeekOrigin.Begin);
  286. using (StreamReader sr = new StreamReader(ms, Encoding.UTF8))
  287. {
  288. officeML = sr.ReadToEnd();
  289. // Console.Out.WriteLine(officeML);
  290. }
  291. }
  292. }
  293. }
  294. officeML = officeML.Replace("mml:", "");
  295. XElement officeElement = XElement.Load(new StringReader(officeML));
  296. return officeElement;
  297. }
  298. }
  299. }