HtexMath.cs 13 KB

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