HtexMath.cs 13 KB

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