ShapeHelper.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. using System.Collections.Generic;
  2. using System.Drawing;
  3. using System.Linq;
  4. using System.Xml;
  5. using System.Runtime;
  6. using System.Xml.Linq;
  7. using System.Xml.XPath;
  8. using DocumentFormat.OpenXml;
  9. using DocumentFormat.OpenXml.Drawing;
  10. namespace HTEXLib
  11. {
  12. public static class ShapeHelper
  13. {
  14. private const int degree = 4;
  15. private const double px96 = 96.00, px72 = 72.00, px914400 = 914400.00, px12700 = 12700.00;
  16. private const double rot60000 = 60000.00;
  17. public static XmlNamespaceManager xmlnsManager;
  18. public static XmlNode GetTextByPath(this XmlDocument document, string expression)
  19. {
  20. return document.SelectSingleNode(expression, xmlnsManager);
  21. }
  22. public static XmlNode GetTextByPath(this XmlNode node, string expression)
  23. {
  24. return node.SelectSingleNode(expression, xmlnsManager);
  25. }
  26. public static XmlNodeList GetTextByPathList(this XmlDocument document, string expression)
  27. {
  28. return document.SelectNodes(expression, xmlnsManager);
  29. }
  30. public static XmlNodeList GetTextByPathList(this XmlNode node, string expression)
  31. {
  32. return node.SelectNodes(expression, xmlnsManager);
  33. }
  34. public static IEnumerable<XElement> GetTextByPathList(this XElement xElement, string expression)
  35. {
  36. return xElement.XPathSelectElements(expression, xmlnsManager);
  37. }
  38. public static XElement GetTextByPath(this XElement xElement, string expression)
  39. {
  40. return xElement.XPathSelectElement(expression, xmlnsManager);
  41. }
  42. public static IEnumerable<XElement> GetTextByPathList(this OpenXmlElement node, string expression)
  43. {
  44. return XElement.Parse(node.OuterXml).XPathSelectElements(expression, xmlnsManager);
  45. }
  46. public static XElement GetTextByPath(this OpenXmlElement node, string expression)
  47. {
  48. return XElement.Parse(node.OuterXml).XPathSelectElement(expression, xmlnsManager);
  49. }
  50. static ShapeHelper()
  51. {
  52. xmlnsManager = new XmlNamespaceManager(new NameTable());
  53. xmlnsManager.AddNamespace("p", "http://schemas.openxmlformats.org/presentationml/2006/main");
  54. xmlnsManager.AddNamespace("a", "http://schemas.openxmlformats.org/drawingml/2006/main");
  55. xmlnsManager.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
  56. xmlnsManager.AddNamespace("fo", "http://www.w3.org/1999/XSL/Format");
  57. xmlnsManager.AddNamespace("app", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
  58. xmlnsManager.AddNamespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
  59. xmlnsManager.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");
  60. xmlnsManager.AddNamespace("dcterms", "http://purl.org/dc/terms/");
  61. xmlnsManager.AddNamespace("dcmitype", "http://purl.org/dc/dcmitype/");
  62. xmlnsManager.AddNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships");
  63. xmlnsManager.AddNamespace("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
  64. xmlnsManager.AddNamespace("cus", "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties");
  65. xmlnsManager.AddNamespace("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
  66. xmlnsManager.AddNamespace("pic", "http://schemas.openxmlformats.org/drawingml/2006/picture");
  67. xmlnsManager.AddNamespace("dsp", "http://schemas.microsoft.com/office/drawing/2008/diagram");
  68. xmlnsManager.AddNamespace("dgm", "http://schemas.openxmlformats.org/drawingml/2006/diagram");
  69. xmlnsManager.AddNamespace("a14", "http://schemas.microsoft.com/office/drawing/2010/main");
  70. xmlnsManager.AddNamespace("m", "http://schemas.openxmlformats.org/officeDocument/2006/math");
  71. xmlnsManager.AddNamespace("mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
  72. xmlnsManager.AddNamespace("p14", "http://schemas.microsoft.com/office/powerpoint/2010/main");
  73. xmlnsManager.AddNamespace("pkg", "http://schemas.microsoft.com/office/2006/xmlPackage");
  74. xmlnsManager.AddNamespace("p15", "http://schemas.microsoft.com/office/powerpoint/2012/main");
  75. xmlnsManager.AddNamespace("a16", "http://schemas.microsoft.com/office/drawing/2014/main");
  76. xmlnsManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
  77. xmlnsManager.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart");
  78. xmlnsManager.AddNamespace("c14", "http://schemas.microsoft.com/office/drawing/2007/8/2/chart");
  79. xmlnsManager.AddNamespace("c16", "http://schemas.microsoft.com/office/drawing/2014/chart");
  80. xmlnsManager.AddNamespace("cs", "http://schemas.microsoft.com/office/drawing/2012/chartStyle");
  81. xmlnsManager.AddNamespace("thm15", "http://schemas.microsoft.com/office/thememl/2012/main");
  82. xmlnsManager.AddNamespace("fn", "http://www.w3.org/2005/xpath-functions");
  83. }
  84. /// <summary>
  85. /// 调色补充 Shade Tint LumMod LumOff 等
  86. /// </summary>
  87. /// <param name="xml"></param>
  88. /// <param name="color"></param>
  89. /// <returns></returns>
  90. public static string ColorToning(string nodeXml, string colorHex)
  91. {
  92. //ColorTransform
  93. //PercentageType percentageType = new PercentageType();
  94. if (string.IsNullOrEmpty(colorHex)) { return null; }
  95. ColorConverter converter = new ColorConverter();
  96. XmlDocument doc = new XmlDocument();
  97. doc.LoadXml(nodeXml);
  98. XmlNode tint = doc.SelectSingleNode("//a:tint/@val", xmlnsManager);
  99. if (tint != null)
  100. {
  101. colorHex = converter.SetTint(colorHex, double.Parse(tint.Value));
  102. }
  103. XmlNode hueMod = doc.SelectSingleNode("//a:hueMod/@val", xmlnsManager);
  104. if (hueMod != null)
  105. {
  106. colorHex = converter.SetHueMod(colorHex, double.Parse(hueMod.Value));
  107. }
  108. XmlNode satMod = doc.SelectSingleNode("//a:satMod/@val", xmlnsManager);
  109. if (satMod != null)
  110. {
  111. colorHex = converter.SetSaturationMod(colorHex, double.Parse(satMod.Value));
  112. }
  113. XmlNode satOff = doc.SelectSingleNode("//a:satOff/@val", xmlnsManager);
  114. if (satOff != null)
  115. {
  116. colorHex = converter.SetSaturationOff(colorHex, double.Parse(satOff.Value));
  117. }
  118. XmlNode lumMod = doc.SelectSingleNode("//a:lumMod/@val", xmlnsManager);
  119. if (lumMod != null)
  120. {
  121. colorHex = converter.SetLuminanceMod(colorHex, double.Parse(lumMod.Value));
  122. }
  123. XmlNode lumOff = doc.SelectSingleNode("//a:lumOff/@val", xmlnsManager);
  124. if (lumOff != null)
  125. {
  126. colorHex = converter.SetLuminanceOff(colorHex, double.Parse(lumOff.Value));
  127. }
  128. XmlNode hueOff = doc.SelectSingleNode("//a:hueOff/@val", xmlnsManager);
  129. if (hueOff != null)
  130. {
  131. colorHex = converter.SetHueOff(colorHex, double.Parse(hueOff.Value));
  132. }
  133. XmlNode alphaOff = doc.SelectSingleNode("//a:alphaOff/@val", xmlnsManager);
  134. if (alphaOff != null)
  135. {
  136. Color color = ColorTranslator.FromHtml("#" + colorHex);
  137. //color.A * (int.Parse(alpha.Value) / 100000);
  138. color = Color.FromArgb(color.A- color.A * (int.Parse(alphaOff.Value) / 100000), color.R, color.G, color.B);
  139. colorHex= color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2");
  140. }
  141. XmlNode shade = doc.SelectSingleNode("//a:shade/@val", xmlnsManager);
  142. if (shade != null)
  143. {
  144. colorHex = converter.SetShade(colorHex, double.Parse(shade.Value));
  145. }
  146. XmlNode alpha = doc.SelectSingleNode("//a:alpha/@val", xmlnsManager);
  147. if (alpha != null)
  148. {
  149. Color color= ColorTranslator.FromHtml("#" + colorHex);
  150. //color.A * (int.Parse(alpha.Value) / 100000);
  151. //TODO是用255计算 还是颜色本身的A alpha计算
  152. color = Color.FromArgb(color.A * (int.Parse(alpha.Value) / 100000), color.R,color.G,color.B);
  153. colorHex = color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2");
  154. }
  155. //TODO //颜色调和 说明网站 https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_comp_topic_ID0EATEJB.html
  156. XmlNode comp = doc.SelectSingleNode("//a:comp", xmlnsManager);
  157. if (comp != null) {
  158. colorHex = converter.SetComp(colorHex);
  159. }
  160. //反色
  161. XmlNode inv = doc.SelectSingleNode("//a:inv", xmlnsManager);
  162. if (inv != null) {
  163. Color color = ColorTranslator.FromHtml("#" + colorHex);
  164. colorHex = (255- color.R).ToString("X2") + (255 - color.G).ToString("X2") + (255 - color.B).ToString("X2");
  165. }
  166. XmlNode alphaMod = doc.SelectSingleNode("//a:alphaMod/@val", xmlnsManager);
  167. if (alphaMod != null) {
  168. }
  169. XmlNode gray = doc.SelectSingleNode("//a:gray/@val", xmlnsManager);
  170. XmlNode hue = doc.SelectSingleNode("//a:hue/@val", xmlnsManager);
  171. XmlNode sat = doc.SelectSingleNode("//a:sat/@val", xmlnsManager);
  172. XmlNode lum = doc.SelectSingleNode("//a:lum/@val", xmlnsManager);
  173. XmlNode red = doc.SelectSingleNode("//a:red/@val", xmlnsManager);
  174. XmlNode redOff = doc.SelectSingleNode("//a:redOff/@val", xmlnsManager);
  175. XmlNode redMod = doc.SelectSingleNode("//a:redMod/@val", xmlnsManager);
  176. XmlNode green = doc.SelectSingleNode("//a:green/@val", xmlnsManager);
  177. XmlNode greenOff = doc.SelectSingleNode("//a:greenOff/@val", xmlnsManager);
  178. XmlNode greenMod = doc.SelectSingleNode("//a:greenMod/@val", xmlnsManager);
  179. XmlNode blue = doc.SelectSingleNode("//a:blue/@val", xmlnsManager);
  180. XmlNode blueOff = doc.SelectSingleNode("//a:blueOff/@val", xmlnsManager);
  181. XmlNode blueMod = doc.SelectSingleNode("//a:blueMod/@val", xmlnsManager);
  182. XmlNode gamma = doc.SelectSingleNode("//a:gamma/@val", xmlnsManager);
  183. XmlNode invGamma = doc.SelectSingleNode("//a:invGamma/@val", xmlnsManager);
  184. return colorHex;
  185. }
  186. public static string GetSchemeColorFromTheme(string schemeClr, XmlNode sldMasterNode, Dictionary<string, string> slideLayoutClrOvride, XmlNode themeContent)
  187. {
  188. //<p:clrMap ...> in slide master
  189. // e.g. tx2="dk2" bg2="lt2" tx1="dk1" bg1="lt1" slideLayoutClrOvride
  190. if (slideLayoutClrOvride == null || slideLayoutClrOvride.Count <= 0)
  191. {
  192. if (sldMasterNode != null)
  193. {
  194. var sldLayoutClrOvr = ShapeHelper.GetTextByPath(sldMasterNode, "p:sldMaster/p:clrMap");
  195. if (sldLayoutClrOvr != null)
  196. {
  197. //获取 overrideClrMapping所有属性节点 检查测试 是否slideLayoutClrOvride 需要被覆盖
  198. slideLayoutClrOvride = new Dictionary<string, string>() {
  199. { "accent1", sldLayoutClrOvr.GetTextByPath("@accent1").Value},
  200. { "accent2", sldLayoutClrOvr.GetTextByPath("@accent2").Value},
  201. { "accent3", sldLayoutClrOvr.GetTextByPath("@accent3").Value},
  202. { "accent4", sldLayoutClrOvr.GetTextByPath("@accent4").Value},
  203. { "accent5", sldLayoutClrOvr.GetTextByPath("@accent5").Value},
  204. { "accent6", sldLayoutClrOvr.GetTextByPath("@accent6").Value},
  205. { "bg1", sldLayoutClrOvr.GetTextByPath("@bg1").Value},
  206. { "bg2", sldLayoutClrOvr.GetTextByPath("@bg2").Value},
  207. { "folHlink", sldLayoutClrOvr.GetTextByPath("@folHlink").Value},
  208. { "hlink", sldLayoutClrOvr.GetTextByPath("@hlink").Value},
  209. { "tx1", sldLayoutClrOvr.GetTextByPath("@tx1").Value},
  210. { "tx2", sldLayoutClrOvr.GetTextByPath("@tx2").Value}
  211. };
  212. }
  213. }
  214. }
  215. if (!schemeClr.StartsWith("a:"))
  216. {
  217. schemeClr = "a:" + schemeClr;
  218. }
  219. //console.log(slideLayoutClrOvride);
  220. var schmClrName = schemeClr.Replace("a:", "");
  221. if (slideLayoutClrOvride != null)
  222. {
  223. switch (schmClrName)
  224. {
  225. case "tx1":
  226. case "tx2":
  227. case "bg1":
  228. case "bg2":
  229. schemeClr = "a:" + slideLayoutClrOvride[schmClrName];
  230. //schemeClr = "a:" + slideLayoutClrOvride[schmClrName];
  231. //console.log(schmClrName+ "=> "+schemeClr);
  232. break;
  233. }
  234. }
  235. else
  236. {
  237. switch (schmClrName)
  238. {
  239. case "tx1":
  240. schemeClr = "a:dk1";
  241. break;
  242. case "tx2":
  243. schemeClr = "a:dk2";
  244. break;
  245. case "bg1":
  246. schemeClr = "a:lt1";
  247. break;
  248. case "bg2":
  249. schemeClr = "a:lt2";
  250. break;
  251. }
  252. }
  253. //var refNode = ShapeHelper.GetTextByPathList(themeContent, "a:theme/a:themeElements/a:clrScheme/"+ schemeClr.Value);
  254. var color = ShapeHelper.GetTextByPath(themeContent, "pkg:xmlData/a:theme/a:themeElements/a:clrScheme/" + schemeClr + "/a:srgbClr/@val");
  255. if (color == null)//&& refNode != null
  256. {
  257. color = ShapeHelper.GetTextByPath(themeContent, "pkg:xmlData/a:theme/a:themeElements/a:clrScheme/" + schemeClr + "/a:sysClr/@lastClr");
  258. }
  259. //console.log(color)
  260. return color.Value;
  261. }
  262. public static string GetSvgImagePattern(string fillColor, int shpId)
  263. {
  264. var ptrn = "<pattern id=\"imgPtrn_" + shpId + "\"patternContentUnits=\"objectBoundingBox\" width=\"1\" height=\"1\">";// '<pattern id="imgPtrn_' + shpId + '" patternContentUnits="objectBoundingBox" width="1" height="1">';
  265. ptrn += "<image xlink:href=\"" + fillColor + "\"preserveAspectRatio=\"none\" width=\"1\" height=\"1\"></image>";// '<image xlink:href="' + fillColor + '" preserveAspectRatio="none" width="1" height="1"></image>';
  266. ptrn += "</pattern>";// '';
  267. return ptrn;
  268. }
  269. public static string GetSvgGradient(double w, double h, double angl, List<string> color_arry, int shpId, Dictionary<string, string> slideLayoutClrOvride, XmlNode themeContent)
  270. {
  271. var stopsArray = GetMiddleStops(color_arry.Count - 2);
  272. var svgAngle = "";
  273. double svgHeight = h;
  274. double svgWidth = w;
  275. string svg = "";
  276. List<double> xy_ary = SVGangle(angl, svgHeight, svgWidth, slideLayoutClrOvride, themeContent);
  277. double x1 = xy_ary[0];
  278. double y1 = xy_ary[1];
  279. double x2 = xy_ary[2];
  280. double y2 = xy_ary[3];
  281. var sal = stopsArray.Count;
  282. double sr = sal < 20 ? 100 : 1000;
  283. svgAngle = " gradientUnits=\"userSpaceOnUse\" x1=\"" + x1 + "%\" y1=\"" + y1 + "%\" x2=\"" + x2 + "%\" y2=\"" + y2 + "%\"";
  284. svgAngle = "<linearGradient id=\"linGrd_" + shpId + "\"" + svgAngle + ">\n";
  285. svg += svgAngle;
  286. for (var i = 0; i < sal; i++)
  287. {
  288. svg += "<stop offset=\"" + (System.Math.Round(double.Parse(stopsArray[i].Replace("%", ""))) / 100 * sr) / sr + "\" stop-color=\"" + color_arry[i] + "\"";
  289. svg += "/>\n";
  290. }
  291. svg += "</linearGradient>\n" + "";
  292. return svg;
  293. }
  294. public static List<string> GetMiddleStops(int s)
  295. {
  296. var sArry = new List<string> { "0%" };
  297. if (s == 0)
  298. {
  299. return sArry;
  300. }
  301. else
  302. {
  303. for (int i = s; i < 0; i--)
  304. {
  305. var middleStop = 100 - ((100 / (s + 1)) * (i + 1)); // AM: Ex - For 3 middle stops, progression will be 25%, 50%, and 75%, plus 0% and 100% at the ends.
  306. var middleStopString = middleStop + "%";
  307. sArry.Add(middleStopString);
  308. // sArry.splice(-1, 0, middleStopString);
  309. }
  310. // AM: add into stopsArray before 100%
  311. }
  312. sArry.Add("100%");
  313. return sArry;
  314. }
  315. public static List<double> SVGangle(double deg, double svgHeight, double svgWidth, Dictionary<string, string> slideLayoutClrOvride, XmlNode themeContent)
  316. {
  317. double w = svgWidth;
  318. double h = svgHeight;
  319. double ang = deg;
  320. double o = 2;
  321. double n = 2;
  322. double wc = w / 2;
  323. double hc = h / 2;
  324. double tx1 = 2;
  325. double ty1 = 2;
  326. double tx2 = 2;
  327. double ty2 = 2;
  328. double k = (((ang % 360) + 360) % 360);
  329. double j = (360 - k) * System.Math.PI / 180;
  330. double i = System.Math.Tan(j);
  331. double l = hc - i * wc;
  332. if (k == 0)
  333. {
  334. tx1 = w;
  335. ty1 = hc;
  336. tx2 = 0;
  337. ty2 = hc;
  338. }
  339. else if (k < 90)
  340. {
  341. n = w;
  342. o = 0;
  343. }
  344. else if (k == 90)
  345. {
  346. tx1 = wc;
  347. ty1 = 0;
  348. tx2 = wc;
  349. ty2 = h;
  350. }
  351. else if (k < 180)
  352. {
  353. n = 0;
  354. o = 0;
  355. }
  356. else if (k == 180)
  357. {
  358. tx1 = 0;
  359. ty1 = hc;
  360. tx2 = w;
  361. ty2 = hc;
  362. }
  363. else if (k < 270)
  364. {
  365. n = 0;
  366. o = h;
  367. }
  368. else if (k == 270)
  369. {
  370. tx1 = wc;
  371. ty1 = h;
  372. tx2 = wc;
  373. ty2 = 0;
  374. }
  375. else
  376. {
  377. n = w;
  378. o = h;
  379. }
  380. // AM: I could not quite figure out what m, n, and o are supposed to represent from the original code on visualcsstools.com.
  381. var m = o + (n / i);
  382. tx1 = tx1 == 2 ? i * (m - l) / (System.Math.Pow(i, 2) + 1) : tx1;
  383. ty1 = ty1 == 2 ? i * tx1 + l : ty1;
  384. tx2 = tx2 == 2 ? w - tx1 : tx2;
  385. ty2 = ty2 == 2 ? h - ty1 : ty2;
  386. double x1 = System.Math.Round(tx2 / w * 100 * 100) / 100.0;
  387. double y1 = System.Math.Round(ty2 / h * 100 * 100) / 100.0;
  388. double x2 = System.Math.Round(tx1 / w * 100 * 100) / 100.0;
  389. double y2 = System.Math.Round(ty1 / h * 100 * 100) / 100.0;
  390. return new List<double> { x1, y1, x2, y2 };
  391. }
  392. public static dynamic GetSlideSize(XmlDocument xdoc)
  393. {
  394. var sldSzNode = xdoc.GetTextByPath("//pkg:part[@pkg:name='/ppt/presentation.xml']/pkg:xmlData/p:presentation/p:sldSz");
  395. double width = double.Parse(sldSzNode.GetTextByPath("@cx").Value) * px96 / px914400;
  396. double height = double.Parse(sldSzNode.GetTextByPath("@cy").Value) * px96 / px914400;
  397. return new { width, height };
  398. }
  399. public static Position GetPosition(XmlNode slideXfrmNode, XmlNode slideLayoutXfrmNode, XmlNode slideMasterXfrmNode)
  400. {
  401. XmlNode off = null;
  402. XmlNode ext = null;
  403. double x, y, w, h;
  404. //ext
  405. if (slideXfrmNode != null)
  406. {
  407. ext = ShapeHelper.GetTextByPath(slideXfrmNode, "a:ext");
  408. }
  409. else if (slideLayoutXfrmNode != null && ext == null)
  410. {
  411. ext = ShapeHelper.GetTextByPath(slideLayoutXfrmNode, "a:ext");
  412. }
  413. else if (slideMasterXfrmNode != null && ext == null)
  414. {
  415. ext = ShapeHelper.GetTextByPath(slideMasterXfrmNode, "a:ext");
  416. }
  417. //off
  418. if (slideXfrmNode != null)
  419. {
  420. off = ShapeHelper.GetTextByPath(slideXfrmNode, "a:off");
  421. }
  422. else if (slideLayoutXfrmNode != null && off == null)
  423. {
  424. off = ShapeHelper.GetTextByPath(slideLayoutXfrmNode, "a:off");
  425. }
  426. else if (slideMasterXfrmNode != null && off == null)
  427. {
  428. off = ShapeHelper.GetTextByPath(slideMasterXfrmNode, "a:off");
  429. }
  430. x = System.Math.Round(double.Parse(off.GetTextByPath("@x").Value) * px96 / px914400, degree);
  431. y = System.Math.Round(double.Parse(off.GetTextByPath("@y").Value) * px96 / px914400, degree);
  432. w = System.Math.Round(double.Parse(ext.GetTextByPath("@cx").Value) * px96 / px914400, degree);
  433. h = System.Math.Round(double.Parse(ext.GetTextByPath("@cy").Value) * px96 / px914400, degree);
  434. return new Position()
  435. {
  436. cx = w,
  437. cy = h,
  438. x = x,
  439. y = y
  440. };
  441. }
  442. public static NodesTable IndexNodes(XmlNode content)
  443. {
  444. var idTable = new Dictionary<string, XmlNode>();
  445. var idxTable = new Dictionary<string, XmlNode>();
  446. var typeTable = new Dictionary<string, XmlNode>();
  447. var spTreeNode = content.GetTextByPath("p:cSld/p:spTree");
  448. // Dictionary<string, Dictionary<string, string>> slideResObj = new Dictionary<string, Dictionary<string, string>>();
  449. var spTreeNodeChildren = spTreeNode.ChildNodes;
  450. foreach (XmlNode child in spTreeNodeChildren)
  451. {
  452. if (child.Name.Equals("p:nvGrpSpPr") || child.Name.Equals("p:grpSpPr"))
  453. {
  454. continue;
  455. }
  456. //var targetNode = child.ChildNodes;
  457. var targetNode = child.GetTextByPath("p:nvSpPr");
  458. // < p:cNvCxnSpPr >
  459. // < a:cxnSpLocks /> ///这个是什么意思
  460. // </ p:cNvCxnSpPr >
  461. if (targetNode == null)
  462. {
  463. targetNode = child.GetTextByPath("p:nvCxnSpPr");
  464. }
  465. XmlNode id = null, idx = null, type = null;
  466. if (targetNode != null)
  467. {
  468. id = targetNode.GetTextByPath("p:cNvPr/@id");
  469. idx = targetNode.GetTextByPath("p:nvPr/p:ph/@idx");
  470. type = targetNode.GetTextByPath("p:nvPr/p:ph/@type");
  471. }
  472. // Dictionary<string, XmlNode> node = new Dictionary<string, XmlNode>();
  473. //if (child.ChildNodes != null)
  474. //{
  475. // foreach (XmlNode xmlNode in child.ChildNodes)
  476. // {
  477. // node.TryAdd(xmlNode.Name, xmlNode);
  478. // }
  479. //}
  480. if (id != null)
  481. {
  482. idTable[id.Value] = child;
  483. }
  484. if (idx != null)
  485. {
  486. idxTable[idx.Value] = child;
  487. }
  488. if (type != null)
  489. {
  490. ///会出现相同Key
  491. typeTable[type.Value] = child;
  492. }
  493. }
  494. return new NodesTable { idTable = idTable, idxTable = idxTable, typeTable = typeTable };
  495. }
  496. public static double AngleToDegrees(XmlNode angle)
  497. {
  498. if (angle == null)
  499. {
  500. return 0;
  501. }
  502. return double.Parse(angle.Value) / rot60000;
  503. }
  504. public static double AngleToDegrees(string angle)
  505. {
  506. if (angle == null)
  507. {
  508. return 0;
  509. }
  510. return double.Parse(angle) / rot60000;
  511. }
  512. public static XmlNode GetNodesTable(XmlNode id, XmlNode idx, XmlNode type, WarpObj warpObj, string LayoutOrMaster)
  513. {
  514. XmlNode resNode = null;
  515. if (resNode == null)
  516. {
  517. if (id != null)
  518. {
  519. if (LayoutOrMaster.Equals("Layout"))
  520. {
  521. if (warpObj.slideLayoutTables.idTable.TryGetValue(id.Value, out XmlNode LayoutNode))
  522. {
  523. // LayoutNode.TryGetValue(id.Value, out XmlNode node);
  524. resNode = LayoutNode;
  525. };
  526. }
  527. if (LayoutOrMaster.Equals("Master"))
  528. {
  529. if (warpObj.slideMasterTables.idTable.TryGetValue(id.Value, out XmlNode MasterNode))
  530. {
  531. // LayoutNode.TryGetValue(id.Value, out XmlNode node);
  532. resNode = MasterNode;
  533. };
  534. }
  535. }
  536. }
  537. if (resNode == null)
  538. {
  539. if (idx != null)
  540. {
  541. if (LayoutOrMaster.Equals("Layout"))
  542. {
  543. if (warpObj.slideLayoutTables.idxTable.TryGetValue(idx.Value, out XmlNode LayoutNode))
  544. {
  545. //LayoutNode.TryGetValue(idx.Value, out XmlNode node);
  546. resNode = LayoutNode;
  547. };
  548. }
  549. if (LayoutOrMaster.Equals("Master"))
  550. {
  551. if (warpObj.slideMasterTables.idxTable.TryGetValue(idx.Value, out XmlNode MasterNode))
  552. {
  553. // LayoutNode.TryGetValue(idx.Value, out XmlNode node);
  554. resNode = MasterNode;
  555. };
  556. }
  557. }
  558. }
  559. if (resNode == null)
  560. {
  561. if (type != null)
  562. {
  563. if (LayoutOrMaster.Equals("Layout"))
  564. {
  565. if (warpObj.slideLayoutTables.typeTable.TryGetValue(type.Value, out XmlNode LayoutNode))
  566. {
  567. // LayoutNode.TryGetValue(type.Value, out XmlNode node);
  568. resNode = LayoutNode;
  569. };
  570. }
  571. if (LayoutOrMaster.Equals("Master"))
  572. {
  573. if (warpObj.slideMasterTables.typeTable.TryGetValue(type.Value, out XmlNode MasterNode))
  574. {
  575. // MasterNode.TryGetValue(type.Value, out XmlNode node);
  576. resNode = MasterNode;
  577. };
  578. }
  579. }
  580. }
  581. return resNode;
  582. }
  583. public static string HexToRgbNew(string bgColor)
  584. {
  585. //var arrBuff = new ArrayBuffer(4);
  586. //var vw = new DataView(arrBuff);
  587. //vw.setUint32(0, parseInt(hex, 16), false);
  588. //var arrByte = new Uint8Array(arrBuff);
  589. int r = System.Convert.ToInt32("0x" + bgColor.Substring(0, 2), 16);
  590. int g = System.Convert.ToInt32("0x" + bgColor.Substring(2, 2), 16);
  591. int b = System.Convert.ToInt32("0x" + bgColor.Substring(4, 2), 16);
  592. return r + "," + g + "," + b;
  593. }
  594. public static double GetColorOpacity(XmlNode solidFill)
  595. {
  596. double opcity = 1;
  597. if (solidFill == null)
  598. {
  599. return opcity;
  600. }
  601. if (solidFill.GetTextByPath("a:srgbClr") != null)
  602. {
  603. var tint = solidFill.GetTextByPath("a:srgbClr/a:tint/@val");
  604. if (tint != null)
  605. {
  606. opcity = double.Parse(tint.Value) / 100000.0;
  607. }
  608. }
  609. else if (solidFill.GetTextByPath("a:schemeClr") != null)
  610. {
  611. var tint = solidFill.GetTextByPath("a:schemeClr/a:tint/@val");
  612. if (tint != null)
  613. {
  614. opcity = double.Parse(tint.Value) / 100000.0;
  615. }
  616. }
  617. else if (solidFill.GetTextByPath("a:scrgbClr") != null)
  618. {
  619. var tint = solidFill.GetTextByPath("a:scrgbClr/a:tint/@val");
  620. if (tint != null)
  621. {
  622. opcity = double.Parse(tint.Value) / 100000.0;
  623. }
  624. }
  625. else if (solidFill.GetTextByPath("a:prstClr") != null)
  626. {
  627. var tint = solidFill.GetTextByPath("a:prstClr/a:tint/@val");
  628. if (tint != null)
  629. {
  630. opcity = double.Parse(tint.Value) / 100000.0;
  631. }
  632. }
  633. else if (solidFill.GetTextByPath("a:hslClr") != null)
  634. {
  635. var tint = solidFill.GetTextByPath("a:hslClr/a:tint/@val");
  636. if (tint != null)
  637. {
  638. opcity = double.Parse(tint.Value) / 100000.0;
  639. }
  640. }
  641. else if (solidFill.GetTextByPath("a:sysClr") != null)
  642. {
  643. var tint = solidFill.GetTextByPath("a:sysClr/a:tint/@val");
  644. if (tint != null)
  645. {
  646. opcity = double.Parse(tint.Value) / 100000.0;
  647. }
  648. }
  649. return opcity;
  650. }
  651. public static string GetSolidFill(XmlNode node, Dictionary<string, string> slideLayoutClrOvride, XmlNode slideMasterContent, XmlNode themeContent)
  652. {
  653. if (node == null)
  654. {
  655. return null;
  656. }
  657. string Color = null;
  658. // Fill fill = new Fill() { Color = "FFF", Type = 1 };
  659. var srgbClrval = node.GetTextByPath("a:srgbClr/@val");
  660. var schemeClrval = node.GetTextByPath("a:schemeClr/@val");
  661. if (srgbClrval != null)
  662. {
  663. Color = srgbClrval.Value; //#...
  664. }
  665. else if (schemeClrval != null)//node["a:schemeClr"] != null)
  666. {
  667. //a:schemeClr
  668. // var schemeClr = ShapeHelper.GetTextByPath(node, "a:schemeClr/@val");
  669. //console.log(schemeClr)
  670. Color = ShapeHelper.GetSchemeColorFromTheme(schemeClrval.Value, slideMasterContent, slideLayoutClrOvride, themeContent); //#...
  671. }
  672. else if (ShapeHelper.GetTextByPath(node, "a:scrgbClr") != null)
  673. {
  674. //<a:scrgbClr r="50%" g="50%" b="50%"/> //Need to test/////////////////////////////////////////////
  675. var defBultColorValsR = ShapeHelper.GetTextByPath(node, "a:scrgbClr/@r");
  676. var defBultColorValsG = ShapeHelper.GetTextByPath(node, "a:scrgbClr/@g");
  677. var defBultColorValsB = ShapeHelper.GetTextByPath(node, "a:scrgbClr/@b");
  678. var red = (defBultColorValsR.Value.IndexOf("%") != -1) ? defBultColorValsR.Value.Split('%').First() : defBultColorValsR.Value;
  679. var green = (defBultColorValsG.Value.IndexOf("%") != -1) ? defBultColorValsG.Value.Split('%').First() : defBultColorValsG.Value;
  680. var blue = (defBultColorValsB.Value.IndexOf("%") != -1) ? defBultColorValsB.Value.Split('%').First() : defBultColorValsB.Value;
  681. var scrgbClr = red + "," + green + "," + blue;
  682. Color = ToHex(255 * (int.Parse(red) / 100)) + ToHex(255 * (int.Parse(green) / 100)) + ToHex(255 * (int.Parse(blue) / 100));
  683. //console.log("scrgbClr: " + scrgbClr);
  684. }
  685. else if (ShapeHelper.GetTextByPath(node, "a:prstClr") != null)
  686. {
  687. //<a:prstClr val="black"/> //Need to test/////////////////////////////////////////////
  688. var prstClr = ShapeHelper.GetTextByPath(node, "a:prstClr/@val");// node["a:prstClr"]["attrs"]["val"];
  689. Color = GetColorName2Hex(prstClr.Value);
  690. //console.log("prstClr: " + prstClr+" => hexClr: "+color);
  691. }
  692. else if (ShapeHelper.GetTextByPath(node, "a:hslClr") != null)
  693. {
  694. //<a:hslClr hue="14400000" sat="100%" lum="50%"/> //Need to test/////////////////////////////////////////////
  695. var defBultColorVals = ShapeHelper.GetTextByPath(node, "a:hslClr");//["attrs"];
  696. var defBultColorVals_hue = ShapeHelper.GetTextByPath(defBultColorVals, "@hue");
  697. var defBultColorVals_sat = ShapeHelper.GetTextByPath(defBultColorVals, "@sat");
  698. var defBultColorVals_lum = ShapeHelper.GetTextByPath(defBultColorVals, "@lum");
  699. var hue = int.Parse(defBultColorVals_hue.Value) / 100000;
  700. var sat = int.Parse((defBultColorVals_sat.Value.IndexOf("%") != -1) ? defBultColorVals_sat.Value.Split('%').First() : defBultColorVals_sat.Value) / 100;
  701. var lum = int.Parse((defBultColorVals_lum.Value.IndexOf("%") != -1) ? defBultColorVals_lum.Value.Split('%').First() : defBultColorVals_lum.Value) / 100;
  702. var hslClr = defBultColorVals_hue.Value.ToString() + "," + defBultColorVals_sat.Value.ToString() + "," + defBultColorVals_lum.Value.ToString();
  703. var hsl2rgb = HslToRgb(hue, sat, lum);
  704. Color = ToHex(hsl2rgb.r) + ToHex(hsl2rgb.g) + ToHex(hsl2rgb.b);
  705. //defBultColor = cnvrtHslColor2Hex(hslClr); //TODO
  706. // console.log("hslClr: " + hslClr);
  707. }
  708. else if (ShapeHelper.GetTextByPath(node, "a:sysClr") != null)
  709. {
  710. //<a:sysClr val="windowText" lastClr="000000"/> //Need to test/////////////////////////////////////////////
  711. var sysClr = ShapeHelper.GetTextByPath(node, "a:sysClr/@lastClr").Value;
  712. if (sysClr != null)
  713. {
  714. Color = sysClr;
  715. }
  716. }
  717. return Color;
  718. }
  719. public static string ToHex(int n)
  720. {
  721. string hex = System.Convert.ToString(n, 16);
  722. while (hex.Length < 2) { hex = "0" + hex; }
  723. return hex;
  724. }
  725. public static dynamic HslToRgb(int hue, int sat, int light)
  726. {
  727. int t1, t2, r, g, b;
  728. hue /= 60;
  729. if (light <= 0.5)
  730. {
  731. t2 = light * (sat + 1);
  732. }
  733. else
  734. {
  735. t2 = light + sat - (light * sat);
  736. }
  737. t1 = light * 2 - t2;
  738. r = HueToRgb(t1, t2, hue + 2) * 255;
  739. g = HueToRgb(t1, t2, hue) * 255;
  740. b = HueToRgb(t1, t2, hue - 2) * 255;
  741. return new { r, g, b };
  742. }
  743. public static int HueToRgb(int t1, int t2, int hue)
  744. {
  745. if (hue < 0) hue += 6;
  746. if (hue >= 6) hue -= 6;
  747. if (hue < 1) return (t2 - t1) * hue + t1;
  748. else if (hue < 3) return t2;
  749. else if (hue < 4) return (t2 - t1) * (4 - hue) + t1;
  750. else return t1;
  751. }
  752. public static string GetColorName2Hex(string name)
  753. {
  754. var hex = "";
  755. var colorName = new List<string> { "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGrey", "DarkGreen", "DarkKhaki", "DarkMagenta", "DarkOliveGreen", "DarkOrange", "DarkOrchid", "DarkRed", "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", "DarkSlateGrey", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", "DimGray", "DimGrey", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Grey", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGray", "LightGrey", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", "LightSkyBlue", "LightSlateGray", "LightSlateGrey", "LightSteelBlue", "LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple", "RebeccaPurple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", "SlateGray", "SlateGrey", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow", "YellowGreen" };
  756. var colorHex = new List<string> { "f0f8ff", "faebd7", "00ffff", "7fffd4", "f0ffff", "f5f5dc", "ffe4c4", "000000", "ffebcd", "0000ff", "8a2be2", "a52a2a", "deb887", "5f9ea0", "7fff00", "d2691e", "ff7f50", "6495ed", "fff8dc", "dc143c", "00ffff", "00008b", "008b8b", "b8860b", "a9a9a9", "a9a9a9", "006400", "bdb76b", "8b008b", "556b2f", "ff8c00", "9932cc", "8b0000", "e9967a", "8fbc8f", "483d8b", "2f4f4f", "2f4f4f", "00ced1", "9400d3", "ff1493", "00bfff", "696969", "696969", "1e90ff", "b22222", "fffaf0", "228b22", "ff00ff", "dcdcdc", "f8f8ff", "ffd700", "daa520", "808080", "808080", "008000", "adff2f", "f0fff0", "ff69b4", "cd5c5c", "4b0082", "fffff0", "f0e68c", "e6e6fa", "fff0f5", "7cfc00", "fffacd", "add8e6", "f08080", "e0ffff", "fafad2", "d3d3d3", "d3d3d3", "90ee90", "ffb6c1", "ffa07a", "20b2aa", "87cefa", "778899", "778899", "b0c4de", "ffffe0", "00ff00", "32cd32", "faf0e6", "ff00ff", "800000", "66cdaa", "0000cd", "ba55d3", "9370db", "3cb371", "7b68ee", "00fa9a", "48d1cc", "c71585", "191970", "f5fffa", "ffe4e1", "ffe4b5", "ffdead", "000080", "fdf5e6", "808000", "6b8e23", "ffa500", "ff4500", "da70d6", "eee8aa", "98fb98", "afeeee", "db7093", "ffefd5", "ffdab9", "cd853f", "ffc0cb", "dda0dd", "b0e0e6", "800080", "663399", "ff0000", "bc8f8f", "4169e1", "8b4513", "fa8072", "f4a460", "2e8b57", "fff5ee", "a0522d", "c0c0c0", "87ceeb", "6a5acd", "708090", "708090", "fffafa", "00ff7f", "4682b4", "d2b48c", "008080", "d8bfd8", "ff6347", "40e0d0", "ee82ee", "f5deb3", "ffffff", "f5f5f5", "ffff00", "9acd32" };
  757. var findIndx = colorName.IndexOf(name);
  758. if (findIndx != -1)
  759. {
  760. hex = colorHex[findIndx];
  761. }
  762. return hex;
  763. }
  764. public static string GetFillType(XmlNode node)
  765. {
  766. //Need to test/////////////////////////////////////////////
  767. //SOLID_FILL
  768. //PIC_FILL
  769. //GRADIENT_FILL
  770. //PATTERN_FILL
  771. //NO_FILL
  772. var fillType = "";
  773. if (node.GetTextByPath("a:noFill") != null)
  774. {
  775. fillType = "NO_FILL";
  776. }
  777. if (node.GetTextByPath("a:solidFill") != null)
  778. {
  779. fillType = "SOLID_FILL";
  780. }
  781. if (node.GetTextByPath("a:gradFill") != null)
  782. {
  783. fillType = "GRADIENT_FILL";
  784. }
  785. if (node.GetTextByPath("a:pattFill") != null)
  786. {
  787. fillType = "PATTERN_FILL";
  788. }
  789. if (node.GetTextByPath("a:blipFill") != null)
  790. {
  791. fillType = "PIC_FILL";
  792. }
  793. if (fillType == "")
  794. {
  795. var clrName = node.GetTextByPath("p:style/a:fillRef");
  796. if (clrName != null)
  797. {
  798. fillType = "SOLID_FILL";
  799. }
  800. }
  801. return fillType;
  802. }
  803. }
  804. }