ShapeGenerator.cs 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  1. using DocumentFormat.OpenXml.Packaging;
  2. using HiTeachCC.Model.PowerPoint;
  3. using HiTeachCC.Service.PowerPoint.Interface;
  4. using Microsoft.AspNetCore.Http;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Threading.Tasks;
  9. using System.Xml;
  10. using System.Xml.Linq;
  11. using TEAMModelOS.SDK.Context.Constant;
  12. using TEAMModelOS.SDK.Context.Constant.Common;
  13. using TEAMModelOS.SDK.Context.Exception;
  14. using TEAMModelOS.SDK.Helper.Security.ShaHash;
  15. using TEAMModelOS.SDK.Module.AzureBlob.Container;
  16. using TEAMModelOS.SDK.Module.AzureBlob.Interfaces;
  17. using TEAMModelOS.Service.Models.PowerPoint.Inner;
  18. using TEAMModelOS.Service.Services.PowerPoint.Implement;
  19. using Fill = HiTeachCC.Model.PowerPoint.Fill;
  20. using Media = HiTeachCC.Model.PowerPoint.Media;
  21. using Position = HiTeachCC.Model.PowerPoint.Position;
  22. namespace HiTeachCC.Service.PowerPoint.Implement
  23. {
  24. public class ShapeGenerator : IShapeGenerator
  25. {
  26. private string fileShaCode { get; set; }
  27. private bool isDone = false;
  28. private List<object> MsgQueue = new List<object>();
  29. private Dictionary<string, string> slideLayoutClrOvride { get; set; }
  30. // private XmlNode themeContent { get; set; }
  31. private int chartID = 0;
  32. private int _order = 1;
  33. private int titleFontSize = 42;
  34. private int bodyFontSize = 20;
  35. private int otherFontSize = 16;
  36. private bool isSlideMode = false;
  37. private Dictionary<string, Dictionary<string, string>> styleTable = new Dictionary<string, Dictionary<string, string>>();
  38. private const double px96 = 96.00, px72 = 72.00, px914400 = 914400.00, px12700 = 12700.00;
  39. private const double rot60000 = 60000.00;
  40. public readonly IAzureBlobDBRepository azureBlobDBRepository;
  41. public ShapeGenerator(IAzureBlobDBRepository _azureBlobDBRepository)
  42. {
  43. azureBlobDBRepository = _azureBlobDBRepository;
  44. }
  45. public async Task<Dictionary<string, object>> LoadPresentation(IFormFile file)
  46. {
  47. Dictionary<string, object> resdict = new Dictionary<string, object>();
  48. if (FileType.GetExtention(file.FileName).ToLower().Equals("pptx"))
  49. {
  50. await ConvertPPTX(file, resdict);
  51. return resdict;
  52. }
  53. else if (FileType.GetExtention(file.FileName).ToLower().Equals("pdf"))
  54. {
  55. // await ProcessPDF(file, resdict);
  56. return resdict;
  57. }
  58. else
  59. {
  60. throw new BizException("file type does not support!", 500);
  61. }
  62. }
  63. public async Task<Dictionary<string, object>> ConvertPPTX(IFormFile file, Dictionary<string, object> resdict)
  64. {
  65. string shaCode = fileShaCode = ShaHashHelper.GetSHA1(file.OpenReadStream());
  66. PresentationDocument presentationDocument = PresentationDocument.Open(file.OpenReadStream(), false);
  67. if (presentationDocument == null)
  68. {
  69. throw new ArgumentNullException("presentationDocument");
  70. }
  71. XDocument xdoc = presentationDocument.ToFlatOpcDocument();
  72. XmlDocument xmlDocument = new XmlDocument();
  73. xmlDocument.LoadXml(xdoc.ToString());
  74. var rslt_ary = await ProcessPPTX(xmlDocument, shaCode);
  75. //TODO
  76. return null;
  77. }
  78. /// <summary>
  79. /// 加载PPTX文件
  80. /// </summary>
  81. /// <param name="presentationFile"></param>
  82. /// <returns></returns>
  83. public async Task<List<Dictionary<string, object>>> ProcessPPTX(XmlDocument xdoc, string shaCode)
  84. {
  85. List<Dictionary<string, object>> post_ary = new List<Dictionary<string, object>>();
  86. var dateBefore = DateTimeOffset.Now.UtcTicks;
  87. AzureBlobModel thumbnailModel = await GetThumbnailModel(xdoc, shaCode);
  88. post_ary.Add(new Dictionary<string, object> { { "pptx-thumb", thumbnailModel } });
  89. //获取全部的/ppt/slides/slide1.xml--->>/ppt/slides/slide(n).xml
  90. var slideNodes = xdoc.GetTextByPathList("//pkg:part[@pkg:contentType='application/vnd.openxmlformats-officedocument.presentationml.slide+xml']");
  91. //获取全部的/ppt/slideLayouts/slideLayout1.xml--->>/ppt/slideLayouts/slideLayout(n).xml
  92. var slideLayoutNodes = xdoc.GetTextByPathList("//pkg:part[@pkg:contentType='application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml']");
  93. //获取ppt的宽高
  94. var slideSize = ShapeHelper.GetSlideSize(xdoc);
  95. post_ary.Add(new Dictionary<string, object> { { "slideSize", slideSize } });
  96. //加载当前PPT使用到的PPT节点
  97. var themeContent = LoadTheme(xdoc);
  98. //获取所有的表格样式节点
  99. var tableStyles = xdoc.GetTextByPath("//pkg:part[@pkg:name='/ppt/tableStyles.xml']/pkg:xmlData/a:tblStyleLst");
  100. //处理slide1---slide(n)
  101. int numOfSlides = slideNodes.Count;
  102. for (int i = 0; i < numOfSlides; i++)
  103. {
  104. string filename = slideNodes[i].GetTextByPath("@pkg:name").Value;
  105. //处理当前页的幻灯片
  106. string slideHtml = await ProcessSingleSlide(xdoc, slideNodes[i], filename, i, slideSize, themeContent);
  107. post_ary.Add(new Dictionary<string, object> { { "slide", slideHtml } });
  108. post_ary.Add(new Dictionary<string, object> { { "progress-update", (i + 1) * 100 / numOfSlides } });
  109. }
  110. post_ary.Add(new Dictionary<string, object> { { "globalCSS", GenGlobalCSS() } });
  111. var dateAfter = DateTimeOffset.Now.UtcTicks;
  112. post_ary.Add(new Dictionary<string, object> { { "ExecutionTime", dateAfter - dateBefore } });
  113. return post_ary;
  114. }
  115. public Dictionary<string, string> GenGlobalCSS()
  116. {
  117. Dictionary<string, string> cssText = new Dictionary<string, string>();
  118. foreach (var key in styleTable.Keys)
  119. {
  120. // cssText += "div ." + styleTable[key]["name"] + "{" + styleTable[key]["text"] + "}\n"; //section > div
  121. var cssTextKey = styleTable[key]["name"];
  122. var cssTextValue = styleTable[key]["text"];
  123. cssText.Add(cssTextKey, cssTextValue);
  124. }
  125. return cssText;
  126. }
  127. public async Task<string> ProcessSingleSlide(XmlDocument xdoc, XmlNode xnode, string sldFileName, int index, dynamic slideSize, XmlNode themeContent)
  128. {
  129. var resName = sldFileName.Replace("slides/slide", "slides/_rels/slide") + ".rels";
  130. var RelationshipArray = xdoc.GetTextByPathList("//pkg:part[@pkg:name='" + resName + "']/pkg:xmlData/rel:Relationships/rel:Relationship");
  131. Dictionary<string, Dictionary<string, string>> slideResObj = new Dictionary<string, Dictionary<string, string>>();
  132. var layoutFilename = "";
  133. foreach (XmlNode Relationship in RelationshipArray)
  134. {
  135. var RelationshipType = Relationship.GetTextByPath("@Type");
  136. if (RelationshipType.Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout"))
  137. {
  138. layoutFilename = Relationship.GetTextByPath("@Target").Value.Replace("../", "/ppt/");
  139. }
  140. else
  141. {
  142. //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide":
  143. //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image":
  144. //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart":
  145. //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink":
  146. Dictionary<string, string> dict = new Dictionary<string, string>();
  147. string Type = Relationship.GetTextByPath("@Type").Value.Replace("http://schemas.openxmlformats.org/officeDocument/2006/relationships/", "");
  148. string Target = Relationship.GetTextByPath("@Target").Value.Replace("../", "/ppt/");
  149. string Id = Relationship.GetTextByPath("@Id").Value;
  150. dict.Add("type", Type);
  151. dict.Add("target", Target);
  152. slideResObj.Add(Id, dict);
  153. }
  154. }
  155. // Open slideLayoutXX.xml
  156. var slideLayoutContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + layoutFilename + "']");
  157. NodesTable slideLayoutTables = ShapeHelper.IndexNodes(slideLayoutContent.GetTextByPath("pkg:xmlData/p:sldLayout"));
  158. ///ppt/slides/slide5.xml 也包含a:overrideClrMapping
  159. ////ppt/slideLayouts/slideLayout13.xml 也包含a:overrideClrMapping
  160. var sldLayoutClrOvr = slideLayoutContent.GetTextByPath("pkg:xmlData/p:sldLayout/p:clrMapOvr/a:overrideClrMapping");
  161. if (sldLayoutClrOvr != null)
  162. {
  163. //获取 overrideClrMapping所有属性节点
  164. slideLayoutClrOvride = new Dictionary<string, string>() {
  165. { "accent1", sldLayoutClrOvr.GetTextByPath("@accent1").Value},
  166. { "accent2", sldLayoutClrOvr.GetTextByPath("@accent2").Value},
  167. { "accent3", sldLayoutClrOvr.GetTextByPath("@accent3").Value},
  168. { "accent4", sldLayoutClrOvr.GetTextByPath("@accent4").Value},
  169. { "accent5", sldLayoutClrOvr.GetTextByPath("@accent5").Value},
  170. { "accent6", sldLayoutClrOvr.GetTextByPath("@accent6").Value},
  171. { "bg1", sldLayoutClrOvr.GetTextByPath("@bg1").Value},
  172. { "bg2", sldLayoutClrOvr.GetTextByPath("@bg2").Value},
  173. { "folHlink", sldLayoutClrOvr.GetTextByPath("@folHlink").Value},
  174. { "hlink", sldLayoutClrOvr.GetTextByPath("@hlink").Value},
  175. { "tx1", sldLayoutClrOvr.GetTextByPath("@tx1").Value},
  176. { "tx2", sldLayoutClrOvr.GetTextByPath("@tx2").Value}
  177. };
  178. }
  179. // =====< Step 2 >=====
  180. // Read slide master filename of the slidelayout (Get slideMasterXX.xml)
  181. // @resName: ppt/slideLayouts/slideLayout1.xml
  182. // @masterName: ppt/slideLayouts/_rels/slideLayout1.xml.rels
  183. var slideLayoutResFilename = layoutFilename.Replace("slideLayouts/slideLayout", "slideLayouts/_rels/slideLayout") + ".rels";
  184. var slideLayoutResContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + slideLayoutResFilename + "']");
  185. ///查看js 是替换之前 还是添加
  186. RelationshipArray = slideLayoutResContent.GetTextByPathList("pkg:xmlData/rel:Relationships/rel:Relationship");
  187. var masterFilename = "";
  188. Dictionary<string, Dictionary<string, string>> layoutResObj = new Dictionary<string, Dictionary<string, string>>();
  189. for (int i = 0; i < RelationshipArray.Count; i++)
  190. {
  191. if (RelationshipArray[i].GetTextByPath("@Type").Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster"))
  192. {
  193. masterFilename = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/");
  194. }
  195. else
  196. {
  197. Dictionary<string, string> dict = new Dictionary<string, string>();
  198. string Type = RelationshipArray[i].GetTextByPath("@Type").Value.Replace("http://schemas.openxmlformats.org/officeDocument/2006/relationships/", "");
  199. string Target = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/");
  200. string Id = RelationshipArray[i].GetTextByPath("@Id").Value;
  201. dict.Add("type", Type);
  202. dict.Add("target", Target);
  203. layoutResObj.Add(Id, dict);
  204. }
  205. }
  206. // Open slideMasterXX.xml
  207. var slideMasterContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + masterFilename + "']");
  208. var slideMasterTextStyles = slideMasterContent.GetTextByPath("pkg:xmlData/p:sldMaster/p:txStyles");
  209. var slideMasterTables = ShapeHelper.IndexNodes(slideMasterContent.GetTextByPath("pkg:xmlData/p:sldMaster"));
  210. /////////////////Amir/////////////
  211. //Open slideMasterXX.xml.rels
  212. var slideMasterResFilename = masterFilename.Replace("slideMasters/slideMaster", "slideMasters/_rels/slideMaster") + ".rels";
  213. var slideMasterResContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + slideMasterResFilename + "']");
  214. RelationshipArray = slideMasterResContent.GetTextByPathList("pkg:xmlData/rel:Relationships/rel:Relationship");
  215. var themeFilename = "";
  216. Dictionary<string, Dictionary<string, string>> masterResObj = new Dictionary<string, Dictionary<string, string>>();
  217. for (int i = 0; i < RelationshipArray.Count; i++)
  218. {
  219. if (RelationshipArray[i].GetTextByPath("@Type").Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"))
  220. {
  221. themeFilename = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/");
  222. }
  223. else
  224. {
  225. Dictionary<string, string> dict = new Dictionary<string, string>();
  226. string Type = RelationshipArray[i].GetTextByPath("@Type").Value.Replace("http://schemas.openxmlformats.org/officeDocument/2006/relationships/", "");
  227. string Target = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/");
  228. string Id = RelationshipArray[i].GetTextByPath("@Id").Value;
  229. dict.Add("type", Type);
  230. dict.Add("target", Target);
  231. masterResObj.Add(Id, dict);
  232. }
  233. }
  234. //Load Theme file
  235. if (!string.IsNullOrEmpty(themeFilename))
  236. {
  237. themeContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + themeFilename + "']");
  238. }
  239. // =====< Step 3 >===== throw new NotImplementedException();
  240. var slideContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + sldFileName + "']");
  241. var spTreeNode = slideContent.GetTextByPath("pkg:xmlData/p:sld/p:cSld/p:spTree");
  242. WarpObj warpObj = new WarpObj
  243. {
  244. zip = xdoc,
  245. slideLayoutTables = slideLayoutTables,
  246. slideMasterTables = slideMasterTables,
  247. slideMasterTextStyles = slideMasterTextStyles,
  248. slideResObj = slideResObj,
  249. layoutResObj = layoutResObj,
  250. masterResObj = masterResObj,
  251. slideLayoutContent = slideLayoutContent,
  252. slideMasterContent = slideMasterContent,
  253. themeContent = themeContent
  254. };
  255. var bgColor = GetSlideBackgroundFill(slideContent, index, warpObj);
  256. string result = "<div class='slide' style='width:" + slideSize.width + "px; height:" + slideSize.height + "px;" + bgColor + "'>";
  257. //result += "<div>"+getBackgroundShapes(slideContent, slideLayoutContent, slideMasterContent,warpObj) + "</div>" - TODO
  258. if (spTreeNode != null)
  259. {
  260. var nodes = spTreeNode.ChildNodes;
  261. int order = 1;
  262. foreach (XmlNode node in nodes)
  263. {
  264. result += await ProcessNodesInSlide(node.Name, node, order, warpObj);
  265. order += 1;
  266. }
  267. }
  268. return result;
  269. }
  270. public async Task<string> ProcessNodesInSlide(string nodeKey, XmlNode node, int order, WarpObj warpObj)
  271. {
  272. string result = "";
  273. switch (nodeKey)
  274. {
  275. case "p:sp": // Shape, Text
  276. result = await ProcessSpNode(node, order, warpObj);
  277. break;
  278. case "p:cxnSp": // Shape, Text (with connection)
  279. result = await ProcessCxnSpNode(node, order, warpObj);
  280. break;
  281. case "p:pic": // Picture
  282. await ProcessPicNode(node, order, warpObj);
  283. break;
  284. case "p:graphicFrame": // Chart, Diagram, Table
  285. result = ProcessGraphicFrameNode(node, order, warpObj);
  286. break;
  287. case "p:grpSp":
  288. await ProcessGroupSpNode(node, order, warpObj);
  289. break;
  290. case "mc:AlternateContent": //Equations and formulas as Image 处理公式 方程等
  291. var mcFallbackNode = node.GetTextByPath("mc:Fallback/p:sp");
  292. result = await ProcessSpNode(mcFallbackNode, order, warpObj);
  293. break;
  294. default:
  295. break;
  296. }
  297. return result;
  298. }
  299. public async Task<string> ProcessGroupSpNode(XmlNode node, int order, WarpObj warpObj)
  300. {
  301. var factor = 1.00 * px96 / px914400;
  302. var xfrmNode = node.GetTextByPath("p:grpSpPr/a:xfrm");
  303. var x = int.Parse(xfrmNode.GetTextByPath("a:off/@x").Value) * factor;
  304. var y = int.Parse(xfrmNode.GetTextByPath("a:off/@y").Value) * factor;
  305. var chx = int.Parse(xfrmNode.GetTextByPath("a:chOff/@x").Value) * factor;
  306. var chy = int.Parse(xfrmNode.GetTextByPath("a:chOff/@y").Value) * factor;
  307. var cx = int.Parse(xfrmNode.GetTextByPath("a:ext/@cx").Value) * factor;
  308. var cy = int.Parse(xfrmNode.GetTextByPath("a:ext/@cy").Value) * factor;
  309. var chcx = int.Parse(xfrmNode.GetTextByPath("a:chExt/@cx").Value) * factor;
  310. var chcy = int.Parse(xfrmNode.GetTextByPath("a:chExt/@cy").Value) * factor;
  311. string result = "<div class='block group' style='z-index: " + order + "; top: " + (y - chy) + "px; left: " + (x - chx) + "px; width: " + (cx - chcx) + "px; height: " + (cy - chcy) + "px;'>";
  312. // Procsee all child nodes
  313. var nodes = node.ChildNodes;
  314. foreach (XmlNode nd in nodes)
  315. {
  316. result += await ProcessNodesInSlide(nd.Name, nd, order, warpObj);
  317. order += 1;
  318. }
  319. result += "</div>";
  320. return result;
  321. }
  322. public string ProcessGraphicFrameNode(XmlNode node, int order, WarpObj warpObj)
  323. {
  324. var result = "";
  325. var graphicTypeUri = node.GetTextByPath("a:graphic/a:graphicData/uri");
  326. if (graphicTypeUri != null)
  327. {
  328. switch (graphicTypeUri.Value)
  329. {
  330. case "http://schemas.openxmlformats.org/drawingml/2006/table":
  331. result = GenTable(node, warpObj);
  332. break;
  333. case "http://schemas.openxmlformats.org/drawingml/2006/chart":
  334. result = GenChart(node, warpObj);
  335. break;
  336. case "http://schemas.openxmlformats.org/drawingml/2006/diagram":
  337. result = GenDiagram(node, warpObj);
  338. break;
  339. default:
  340. break;
  341. }
  342. }
  343. return result;
  344. }
  345. public string GenDiagram(XmlNode node, WarpObj warpObj)
  346. {
  347. return "";
  348. }
  349. public string GenChart(XmlNode node, WarpObj warpObj)
  350. {
  351. return "";
  352. }
  353. public string GenTable(XmlNode node, WarpObj warpObj)
  354. {
  355. return "";
  356. }
  357. public async Task<string> ProcessCxnSpNode(XmlNode node, int order, WarpObj warpObj)
  358. {
  359. var id = node.GetTextByPath("p:nvCxnSpPr/p:cNvPr/@id");
  360. var name = node.GetTextByPath("p:nvCxnSpPr/p:cNvPr/@name");
  361. return await GenShape(node, null, null, id, name, null, null, order, warpObj);
  362. }
  363. public async Task<string> ProcessSpNode(XmlNode node, int order, WarpObj warpObj)
  364. {
  365. /*
  366. * 958 <xsd:complexType name="CT_GvmlShape">
  367. * 959 <xsd:sequence>
  368. * 960 <xsd:element name="nvSpPr" type="CT_GvmlShapeNonVisual" minOccurs="1" maxOccurs="1"/>
  369. * 961 <xsd:element name="spPr" type="CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
  370. * 962 <xsd:element name="txSp" type="CT_GvmlTextShape" minOccurs="0" maxOccurs="1"/>
  371. * 963 <xsd:element name="style" type="CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
  372. * 964 <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
  373. * 965 </xsd:sequence>
  374. * 966 </xsd:complexType>
  375. */
  376. var id = node.GetTextByPath("p:nvSpPr/p:cNvPr/@id");
  377. var name = node.GetTextByPath("p:nvSpPr/p:cNvPr/@name");
  378. var idx = node.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@idx");
  379. var type = node.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@type");
  380. XmlNode slideLayoutSpNode = ShapeHelper.GetNodesTable(id, idx, type, warpObj, "Layout");
  381. XmlNode slideMasterSpNode = ShapeHelper.GetNodesTable(id, idx, type, warpObj, "Master");
  382. if (type == null)
  383. {
  384. if (slideLayoutSpNode != null)
  385. {
  386. type = slideLayoutSpNode.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@type");
  387. }
  388. // type = slideLayoutSpNode.TryGetValue"p:nvSpPr", "p:nvPr", "p:ph", "attrs", "type"]);
  389. if (type == null)
  390. {
  391. if (slideMasterSpNode != null)
  392. {
  393. type = slideMasterSpNode.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@type");
  394. }
  395. // type = getTextByPathList(slideMasterSpNode, ["p:nvSpPr", "p:nvPr", "p:ph", "attrs", "type"]);
  396. }
  397. }
  398. string s = await GenShape(node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, order, warpObj);
  399. return "";
  400. }
  401. public async Task<string> GenShape(XmlNode node, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode, XmlNode id, XmlNode name, XmlNode idx, XmlNode type, int order, WarpObj warpObj)
  402. {
  403. var xfrmList = "p:spPr/a:xfrm";
  404. var slideXfrmNode = node.GetTextByPath(xfrmList);
  405. XmlNode slideLayoutXfrmNode = null;
  406. if (slideLayoutSpNode != null)
  407. {
  408. slideLayoutXfrmNode = slideLayoutSpNode.GetTextByPath(xfrmList);
  409. }
  410. XmlNode slideMasterXfrmNode = null;
  411. if (slideMasterSpNode != null)
  412. {
  413. slideMasterXfrmNode = slideMasterSpNode.GetTextByPath(xfrmList);
  414. }
  415. if (slideXfrmNode == null)
  416. {
  417. slideXfrmNode = slideLayoutXfrmNode;
  418. }
  419. if (slideXfrmNode == null)
  420. {
  421. slideXfrmNode = slideMasterXfrmNode;
  422. }
  423. var result = "";
  424. var shapType = node.GetTextByPath("p:spPr/a:prstGeom/@prst");
  425. var custShapType = node.GetTextByPath("p:spPr/a:custGeom");
  426. var isFlipV = 0;
  427. var isFlipH = 0;
  428. if (slideXfrmNode.GetTextByPath("@flipV") != null && slideXfrmNode.GetTextByPath("@flipV").Value == "1")
  429. {// if ( getTextByPathList(slideXfrmNode, ["attrs", "flipV"]) === "1" || getTextByPathList(slideXfrmNode, ["attrs", "flipH"]) === "1")
  430. isFlipV = 1;
  431. }
  432. if (slideXfrmNode.GetTextByPath("@flipH") != null && slideXfrmNode.GetTextByPath("@flipH").Value == "1")
  433. {
  434. isFlipH = 1;
  435. }
  436. //rotate
  437. var rotate = ShapeHelper.AngleToDegrees(slideXfrmNode.GetTextByPath("@rot"));
  438. //console.log("rotate: "+rotate);
  439. double txtRotate;
  440. var txtXframeNode = node.GetTextByPath("p:txXfrm/@rot");
  441. if (txtXframeNode != null)
  442. {
  443. txtRotate = ShapeHelper.AngleToDegrees(txtXframeNode) + 90;
  444. }
  445. else
  446. {
  447. txtRotate = rotate;
  448. }
  449. if (shapType != null || custShapType != null)
  450. {
  451. Position position = ShapeHelper.GetPosition(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode);
  452. position.Rot = rotate;
  453. position.FlipH = isFlipH;
  454. position.FlipV = isFlipV;
  455. //result += "<svg class='drawing' _id='" + id + "' _idx='" + idx + "' _type='" + type + "' _name='" + name +
  456. // "' style='" +
  457. // getPosition(slideXfrmNode, null, null) +
  458. // getSize(slideXfrmNode, null, null) +
  459. // " z-index: " + order + ";" +
  460. // "transform: rotate(" + rotate + "deg);" +
  461. // "'>";
  462. //result += "<defs>";
  463. // Fill Color
  464. var Fill = await GetShapeFill(node, warpObj);
  465. var grndFillFlg = false;
  466. var imgFillFlg = false;
  467. var clrFillType = ShapeHelper.GetFillType(node.GetTextByPath("p:spPr"));
  468. /////////////////////////////////////////
  469. if (clrFillType == "GRADIENT_FILL")
  470. {
  471. grndFillFlg = true;
  472. var color_arry = Fill.gradColor;
  473. var angl = Fill.Rot;
  474. var svgGrdnt = ShapeHelper.GetSvgGradient(position.Cx, position.Cy, angl, color_arry, order, slideLayoutClrOvride, warpObj.themeContent);
  475. //fill="url(#linGrd)"
  476. result += svgGrdnt;
  477. }
  478. else if (clrFillType == "PIC_FILL")
  479. {
  480. imgFillFlg = true;
  481. var svgBgImg = ShapeHelper.GetSvgImagePattern(Fill.Image, order);
  482. //fill="url(#imgPtrn)"
  483. //console.log(svgBgImg)
  484. result += svgBgImg;
  485. }
  486. else
  487. {
  488. if (clrFillType != null && clrFillType != "SOLID_FILL" && clrFillType != "PATTERN_FILL")
  489. {
  490. Fill.HtmlText = "none";
  491. }
  492. if (shapType != null)
  493. {
  494. if (shapType.Value == "arc" ||
  495. shapType.Value == "bracketPair" ||
  496. shapType.Value == "bracePair" ||
  497. shapType.Value == "leftBracket" ||
  498. shapType.Value == "leftBrace" ||
  499. shapType.Value == "rightBrace" ||
  500. shapType.Value == "rightBracket")
  501. { //Temp. solution - TODO
  502. Fill.HtmlText = "none";
  503. }
  504. }
  505. }
  506. // Border Color
  507. var border = ShapeHelper.GetBorder(node, true, "shape", slideLayoutClrOvride, warpObj.themeContent);
  508. var headEndNodeAttrs = node.GetTextByPath("p:spPr/a:ln/a:headEnd");
  509. var tailEndNodeAttrs = node.GetTextByPath("p:spPr/a:ln/a:tailEnd");
  510. // type: none, triangle, stealth, diamond, oval, arrow
  511. if ((headEndNodeAttrs != null && (headEndNodeAttrs.GetTextByPath("@type").Value == "triangle" || (headEndNodeAttrs.GetTextByPath("@type").Value == "arrow")) ||
  512. (tailEndNodeAttrs != null && (tailEndNodeAttrs.GetTextByPath("@type").Value == "triangle" || (tailEndNodeAttrs.GetTextByPath("@type").Value == "arrow")))))
  513. {
  514. var triangleMarker = "<marker id='markerTriangle_" + order + "' viewBox='0 0 10 10' refX='1' refY='5' markerWidth='5' markerHeight='5' stroke='" + border.Color + "' fill='" + border.Color +
  515. "' orient='auto-start-reverse' markerUnits='strokeWidth'><path d='M 0 0 L 10 5 L 0 10 z' /></marker>";
  516. result += triangleMarker;
  517. }
  518. result += "</defs>";
  519. }
  520. if (shapType != null && custShapType == null) {
  521. switch (shapType.Value) {
  522. case "rect":
  523. case "flowChartProcess":
  524. case "flowChartPredefinedProcess":
  525. case "flowChartInternalStorage":
  526. case "actionButtonBlank":
  527. break;
  528. case "flowChartCollate":
  529. break;
  530. case "flowChartDocument":
  531. break;
  532. case "flowChartMultidocument":
  533. break;
  534. case "actionButtonBackPrevious":
  535. break;
  536. case "actionButtonBeginning":
  537. break;
  538. case "actionButtonDocument":
  539. break;
  540. case "actionButtonEnd":
  541. break;
  542. case "actionButtonForwardNext":
  543. break;
  544. case "actionButtonHelp":
  545. break;
  546. case "actionButtonHome":
  547. break;
  548. case "actionButtonInformation":
  549. break;
  550. case "actionButtonMovie":
  551. break;
  552. case "actionButtonReturn":
  553. break;
  554. case "actionButtonSound":
  555. break;
  556. case "irregularSeal1":
  557. case "irregularSeal2":
  558. break;
  559. case "flowChartTerminator":
  560. break;
  561. case "flowChartPunchedTape":
  562. break;
  563. case "flowChartOnlineStorage":
  564. break;
  565. case "flowChartDisplay":
  566. break;
  567. case "flowChartDelay":
  568. break;
  569. case "flowChartMagneticTape":
  570. break;
  571. case "ellipse":
  572. case "flowChartConnector":
  573. case "flowChartSummingJunction":
  574. case "flowChartOr":
  575. break;
  576. case "roundRect":
  577. case "round1Rect":
  578. case "round2DiagRect":
  579. case "round2SameRect":
  580. case "snip1Rect":
  581. case "snip2DiagRect":
  582. case "snip2SameRect":
  583. case "flowChartAlternateProcess":
  584. case "flowChartPunchedCard":
  585. break;
  586. case "snipRoundRect":
  587. break;
  588. case "bentConnector2":
  589. break;
  590. case "rtTriangle":
  591. break;
  592. case "triangle":
  593. case "flowChartExtract":
  594. case "flowChartMerge":
  595. break;
  596. case "diamond":
  597. case "flowChartDecision":
  598. case "flowChartSort":
  599. break;
  600. case "trapezoid":
  601. case "flowChartManualOperation":
  602. case "flowChartManualInput":
  603. break;
  604. case "parallelogram":
  605. case "flowChartInputOutput":
  606. break;
  607. case "pentagon":
  608. break;
  609. case "hexagon":
  610. case "flowChartPreparation":
  611. break;
  612. case "heptagon":
  613. break;
  614. case "octagon":
  615. break;
  616. case "decagon":
  617. break;
  618. case "dodecagon":
  619. break;
  620. case "star4":
  621. case "star5":
  622. case "star6":
  623. case "star7":
  624. case "star8":
  625. case "star10":
  626. case "star12":
  627. case "star16":
  628. case "star24":
  629. case "star32":
  630. break;
  631. case "pie":
  632. case "pieWedge":
  633. case "arc":
  634. break;
  635. case "chord":
  636. break;
  637. case "frame":
  638. break;
  639. case "donut":
  640. break;
  641. case "noSmoking":
  642. break;
  643. case "halfFrame":
  644. break;
  645. case "blockArc":
  646. break;
  647. case "bracePair":
  648. break;
  649. case "leftBrace":
  650. break;
  651. case "rightBrace":
  652. break;
  653. case "bracketPair":
  654. break;
  655. case "leftBracket":
  656. break;
  657. case "rightBracket":
  658. break;
  659. case "moon":
  660. break;
  661. case "corner":
  662. break;
  663. case "diagStripe":
  664. break;
  665. case "gear6":
  666. case "gear9":
  667. break;
  668. case "bentConnector3":
  669. break;
  670. case "plus":
  671. break;
  672. case "teardrop":
  673. break;
  674. case "plaque":
  675. break;
  676. case "sun":
  677. break;
  678. case "heart":
  679. break;
  680. case "lightningBolt":
  681. break;
  682. case "cube":
  683. break;
  684. case "bevel":
  685. break;
  686. case "foldedCorner":
  687. break;
  688. case "cloud":
  689. case "cloudCallout":
  690. break;
  691. case "smileyFace":
  692. break;
  693. case "verticalScroll":
  694. case "horizontalScroll":
  695. break;
  696. case "wedgeEllipseCallout":
  697. break;
  698. case "wedgeRectCallout":
  699. break;
  700. case "wedgeRoundRectCallout":
  701. break;
  702. case "accentBorderCallout1":
  703. case "accentBorderCallout2":
  704. case "accentBorderCallout3":
  705. case "borderCallout1":
  706. case "borderCallout2":
  707. case "borderCallout3":
  708. case "accentCallout1":
  709. case "accentCallout2":
  710. case "accentCallout3":
  711. case "callout1":
  712. case "callout2":
  713. case "callout3":
  714. break;
  715. case "leftRightRibbon":
  716. break;
  717. case "ribbon":
  718. case "ribbon2":
  719. break;
  720. case "doubleWave":
  721. case "wave":
  722. break;
  723. case "ellipseRibbon":
  724. case "ellipseRibbon2":
  725. break;
  726. case "line":
  727. case "straightConnector1":
  728. case "bentConnector4":
  729. case "bentConnector5":
  730. case "curvedConnector2":
  731. case "curvedConnector3":
  732. case "curvedConnector4":
  733. case "curvedConnector5":
  734. break;
  735. case "rightArrow":
  736. break;
  737. case "leftArrow":
  738. break;
  739. case "downArrow":
  740. case "flowChartOffpageConnector":
  741. break;
  742. case "upArrow":
  743. break;
  744. case "leftRightArrow":
  745. break;
  746. case "upDownArrow":
  747. break;
  748. case "quadArrow":
  749. break;
  750. case "leftRightUpArrow":
  751. break;
  752. case "leftUpArrow":
  753. break;
  754. case "bentUpArrow":
  755. break;
  756. case "bentArrow":
  757. break;
  758. case "uturnArrow":
  759. break;
  760. case "stripedRightArrow":
  761. break;
  762. case "notchedRightArrow":
  763. break;
  764. case "homePlate":
  765. break;
  766. case "chevron":
  767. break;
  768. case "rightArrowCallout":
  769. break;
  770. case "downArrowCallout":
  771. break;
  772. case "leftArrowCallout":
  773. break;
  774. case "upArrowCallout":
  775. break;
  776. case "leftRightArrowCallout":
  777. break;
  778. case "quadArrowCallout":
  779. break;
  780. case "curvedDownArrow":
  781. break;
  782. case "curvedLeftArrow":
  783. break;
  784. case "curvedRightArrow":
  785. break;
  786. case "curvedUpArrow":
  787. break;
  788. case "mathDivide":
  789. case "mathEqual":
  790. case "mathMinus":
  791. case "mathMultiply":
  792. case "mathNotEqual":
  793. case "mathPlus":
  794. break;
  795. case "can":
  796. case "flowChartMagneticDisk":
  797. case "flowChartMagneticDrum":
  798. break;
  799. case "swooshArrow":
  800. break;
  801. case "circularArrow":
  802. break;
  803. case "leftCircularArrow":
  804. break;
  805. case "leftRightCircularArrow":
  806. case "chartPlus":
  807. case "chartStar":
  808. case "chartX":
  809. case "cornerTabs":
  810. case "flowChartOfflineStorage":
  811. case "folderCorner":
  812. case "funnel":
  813. case "lineInv":
  814. case "nonIsoscelesTrapezoid":
  815. case "plaqueTabs":
  816. case "squareTabs":
  817. case "upDownArrowCallout":
  818. break;
  819. default:
  820. break;
  821. }
  822. }
  823. return result;
  824. }
  825. /// <summary>
  826. /// 幻灯片 背景色填充
  827. /// </summary>
  828. /// <param name="slideContent"></param>
  829. /// <param name="slideLayoutContent"></param>
  830. /// <param name="slideMasterContent"></param>
  831. /// <param name="index"></param>
  832. /// <param name="warpObj"></param>
  833. /// <returns></returns>
  834. public async Task<Fill> GetSlideBackgroundFill(XmlNode slideContent, int index, WarpObj warpObj)
  835. {
  836. var bgPr = slideContent.GetTextByPath("p:sld/p:cSld/p:bg/p:bgPr");
  837. var bgRef = slideContent.GetTextByPath("p:sld/p:cSld/p:bg/p:bgRef");
  838. if (bgPr != null)
  839. {
  840. var bgFillTyp = ShapeHelper.GetFillType(bgPr);
  841. if (bgFillTyp == "SOLID_FILL")
  842. {
  843. var sldFill = bgPr.GetTextByPath("a:solidFill");
  844. var bgColor = ShapeHelper.GetSolidFill(sldFill, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  845. bgColor = PowerPointHelper.ColorToning(sldFill.OuterXml, bgColor);
  846. return new Fill { Type = 1, Color = bgColor };
  847. }
  848. else if (bgFillTyp == "GRADIENT_FILL")
  849. {
  850. return ShapeHelper.GetBgGradientFill(bgPr, null, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  851. }
  852. else if (bgFillTyp == "PIC_FILL")
  853. {
  854. return await GetPicFill("slideBg", bgPr.GetTextByPath("a:blipFill"), warpObj);
  855. }
  856. }
  857. else if (bgRef != null)
  858. {
  859. string phClr = ShapeHelper.GetSolidFill(bgRef, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  860. phClr = PowerPointHelper.ColorToning(bgRef.OuterXml, phClr);
  861. var idx = bgRef.GetTextByPath("@idx");
  862. if (idx != null)
  863. {
  864. int value = int.Parse(idx.Value);
  865. if (value == 0 || value == 1000)
  866. {
  867. return new Fill { Type = 0 };
  868. //no background
  869. }
  870. else if (value > 0 && value < 1000)
  871. {
  872. //fillStyleLst in themeContent
  873. //themeContent["a:fmtScheme"]["a:fillStyleLst"]
  874. //bgcolor = "background: red;";
  875. }
  876. else if (value > 1000)
  877. {
  878. var trueIdx = value - 1000;
  879. var bgFillLst = warpObj.themeContent.GetTextByPath("a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst");
  880. if (bgFillLst != null) {
  881. XmlNodeList nodeList = bgFillLst.ChildNodes;
  882. if (trueIdx < nodeList.Count) {
  883. string type= ShapeHelper.GetFillType(nodeList[trueIdx - 1]);
  884. if (type.Equals("SOLID_FILL"))
  885. {
  886. if (string.IsNullOrEmpty(phClr))
  887. {
  888. phClr = ShapeHelper.GetSolidFill(nodeList[trueIdx - 1], slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  889. }
  890. phClr = PowerPointHelper.ColorToning(nodeList[trueIdx - 1].Value, phClr);
  891. return new Fill { Type = 1, Color = phClr };
  892. }
  893. else if (type.Equals("GRADIENT_FILL"))
  894. {
  895. return ShapeHelper.GetBgGradientFill(nodeList[trueIdx - 1], phClr, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  896. }
  897. else if (type.Equals("PIC_FILL"))
  898. {
  899. return await GetPicFill("slideBg", nodeList[trueIdx - 1].GetTextByPath("a:blipFill"), warpObj);
  900. }
  901. else {
  902. return new Fill { Type = 0 };
  903. }
  904. }
  905. }
  906. }
  907. }
  908. //var node = bgRef.GetTextByPath("");
  909. //if (bgRef["a:srgbClr"] !== undefined)
  910. //{
  911. // phClr = getTextByPathList(bgRef,["a:srgbClr", "attrs", "val"]); //#...
  912. //}
  913. //else if (bgRef["a:schemeClr"] !== undefined)
  914. //{ //a:schemeClr
  915. // var schemeClr = getTextByPathList(bgRef,["a:schemeClr", "attrs", "val"]);
  916. // phClr = getSchemeColorFromTheme("a:" + schemeClr, slideMasterContent); //#...
  917. // //console.log("schemeClr",schemeClr,"phClr=",phClr)
  918. //}
  919. }
  920. else
  921. {
  922. bgPr =warpObj. slideLayoutContent.GetTextByPath("p:sldLayout/p:cSld/p:bg/p:bgPr");
  923. bgRef = warpObj. slideLayoutContent.GetTextByPath("p:sldLayout/p:cSld/p:bg/p:bgRef");
  924. if (bgPr != null)
  925. {
  926. var bgFillTyp = ShapeHelper.GetFillType(bgPr);
  927. if (bgFillTyp == "SOLID_FILL")
  928. {
  929. var sldFill = bgPr.GetTextByPath("a:solidFill");
  930. var bgColor = ShapeHelper.GetSolidFill(sldFill, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  931. bgColor = PowerPointHelper.ColorToning(sldFill.OuterXml, bgColor);
  932. return new Fill { Type = 1, Color = bgColor };
  933. }
  934. else if (bgFillTyp == "GRADIENT_FILL")
  935. {
  936. return ShapeHelper.GetBgGradientFill(bgPr, null, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  937. }
  938. else if (bgFillTyp == "PIC_FILL")
  939. {
  940. return await GetPicFill("slideBg", bgPr.GetTextByPath("a:blipFill"), warpObj);
  941. }
  942. }
  943. else if (bgRef != null)
  944. {
  945. string phClr = ShapeHelper.GetSolidFill(bgRef, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  946. phClr = PowerPointHelper.ColorToning(bgRef.OuterXml, phClr);
  947. var idx = bgRef.GetTextByPath("@idx");
  948. if (idx != null)
  949. {
  950. int value = int.Parse(idx.Value);
  951. if (value == 0 || value == 1000)
  952. {
  953. return new Fill { Type = 0 };
  954. //no background
  955. }
  956. else if (value > 0 && value < 1000)
  957. {
  958. //fillStyleLst in themeContent
  959. //themeContent["a:fmtScheme"]["a:fillStyleLst"]
  960. //bgcolor = "background: red;";
  961. }
  962. else if (value > 1000)
  963. {
  964. var trueIdx = value - 1000;
  965. var bgFillLst = warpObj.themeContent.GetTextByPath("a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst");
  966. if (bgFillLst != null)
  967. {
  968. XmlNodeList nodeList = bgFillLst.ChildNodes;
  969. if (trueIdx < nodeList.Count)
  970. {
  971. string type = ShapeHelper.GetFillType(nodeList[trueIdx - 1]);
  972. if (type.Equals("SOLID_FILL"))
  973. {
  974. if (string.IsNullOrEmpty(phClr))
  975. {
  976. phClr = ShapeHelper.GetSolidFill(nodeList[trueIdx - 1], slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  977. }
  978. phClr = PowerPointHelper.ColorToning(nodeList[trueIdx - 1].Value, phClr);
  979. return new Fill { Type = 1, Color = phClr };
  980. }
  981. else if (type.Equals("GRADIENT_FILL"))
  982. {
  983. return ShapeHelper.GetBgGradientFill(nodeList[trueIdx - 1], phClr, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  984. }
  985. else if (type.Equals("PIC_FILL"))
  986. {
  987. return await GetPicFill("slideBg", nodeList[trueIdx - 1].GetTextByPath("a:blipFill"), warpObj);
  988. }
  989. else
  990. {
  991. return new Fill { Type = 0 };
  992. }
  993. }
  994. }
  995. }
  996. }
  997. }
  998. }
  999. return null;
  1000. }
  1001. public async Task<Fill> GetPicFill(string type, XmlNode node, WarpObj warpObj)
  1002. {
  1003. //Need to test/////////////////////////////////////////////
  1004. //rId
  1005. //TODO - Image Properties - Tile, Stretch, or Display Portion of Image
  1006. //(http://officeopenxml.com/drwPic-tile.php)
  1007. // var img = "";
  1008. var rId = node.GetTextByPath("a:blip/@r:embed");//node["a:blip"]["attrs"]["r:embed"];
  1009. Dictionary<string, string> imgPath = new Dictionary<string, string>();
  1010. if (type == "slideBg")
  1011. {
  1012. imgPath = warpObj.slideResObj[rId.Value];
  1013. }
  1014. else if (type == "layoutBg")
  1015. {
  1016. imgPath = warpObj.layoutResObj[rId.Value];
  1017. }
  1018. else if (type == "masterBg")
  1019. {
  1020. imgPath = warpObj.masterResObj[rId.Value];
  1021. }
  1022. if (imgPath == null)
  1023. {
  1024. return null;
  1025. }
  1026. //var imgExt = imgPath["type"];
  1027. //if (imgExt == "xml")
  1028. //{
  1029. // return null;
  1030. //}
  1031. var imgData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + imgPath["target"] + "']");
  1032. if (imgData != null)
  1033. {
  1034. AzureBlobModel model = await SaveBase64ToBolob(imgData.InnerText, imgData.GetTextByPath("@pkg:contentType").Value,
  1035. fileShaCode + "/imgs", null);
  1036. return new Fill { Type = 3, Image = model.BlobUrl };
  1037. }
  1038. else { return null; }
  1039. // var imgArrayBuffer = warpObj.zip.GetTextByPath(imgPath).Value.asArrayBuffer();
  1040. //var imgMimeType = GetMimeType(imgExt);
  1041. //img = "data:" + imgMimeType + ";base64," + base64ArrayBuffer(imgArrayBuffer);
  1042. }
  1043. public async Task<Fill> GetShapeFill(XmlNode node, WarpObj warpObj)
  1044. {
  1045. // 1. presentationML
  1046. // p:spPr/ [a:noFill, solidFill, gradFill, blipFill, pattFill, grpFill]
  1047. // From slide
  1048. //Fill Type:
  1049. //console.log("ShapeFill: ", node)
  1050. var fillType = ShapeHelper.GetFillType(node.GetTextByPath("p:spPr"));
  1051. Fill fill = new Fill();
  1052. //0
  1053. if (fillType == "NO_FILL")
  1054. {
  1055. fill.SvgText = "node";
  1056. fill.Type = 0;
  1057. fill.HtmlText = "background-color: initial;";
  1058. return fill;
  1059. //return isSvgMode ? "none" : "background-color: initial;";
  1060. }
  1061. //1纯色填充
  1062. else if (fillType == "SOLID_FILL")
  1063. {
  1064. XmlNode shpFill = node.GetTextByPath("p:spPr/a:solidFill");// node["p:spPr"]["a:solidFill"];
  1065. string color = ShapeHelper.GetSolidFill(shpFill, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  1066. return new Fill { Type = 1, Color = color };
  1067. }
  1068. //2渐变色填充
  1069. else if (fillType == "GRADIENT_FILL")
  1070. {
  1071. var shpFill = node.GetTextByPath("p:spPr/a:gradFill");// node["p:spPr"]["a:gradFill"];
  1072. // fillColor = GetSolidFill(shpFill);
  1073. fill = ShapeHelper.GetGradientFill(shpFill, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  1074. //console.log("shpFill",shpFill,grndColor.color)
  1075. }//3图片 纹理填充
  1076. else if (fillType == "PIC_FILL")
  1077. {
  1078. var shpFill = node.GetTextByPath("p:spPr/a:blipFill"); //node["p:spPr"]["a:blipFill"];
  1079. fill = await GetPicFill("slideBg", shpFill, warpObj);
  1080. }//4 图案填充
  1081. else if (fillType == "PATTERN_FILL")
  1082. {
  1083. /*
  1084. *
  1085. *<a:pattFill prst="ltDnDiag">
  1086. <a:fgClr>
  1087. <a:schemeClr val="dk1">
  1088. <a:lumMod val="15000"/>
  1089. <a:lumOff val="85000"/>
  1090. </a:schemeClr>
  1091. </a:fgClr>
  1092. <a:bgClr>
  1093. <a:schemeClr val="lt1"/>
  1094. </a:bgClr>
  1095. </a:pattFill>
  1096. */
  1097. var shpFill = node.GetTextByPath("p:spPr/a:pattFill");// node["p:spPr"]["a:pattFill"];
  1098. fill = ShapeHelper.GetPatternFill(shpFill, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  1099. }
  1100. // 2. drawingML namespace
  1101. if (fill == null)
  1102. {
  1103. var clrName = node.GetTextByPath("p:style/a:fillRef");
  1104. string color = ShapeHelper.GetSolidFill(clrName, slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
  1105. }
  1106. if (fill != null)
  1107. {
  1108. if (fillType == "GRADIENT_FILL")
  1109. {
  1110. //if (isSvgMode)
  1111. //{
  1112. // // console.log("GRADIENT_FILL color", fillColor.color[0])
  1113. // return fill;
  1114. //}
  1115. //else
  1116. //{
  1117. var colorAry = fill.gradColor;
  1118. var rot = fill.Rot;
  1119. var bgcolor = "background: linear-gradient(" + rot + "deg,";
  1120. for (var i = 0; i < colorAry.Count; i++)
  1121. {
  1122. if (i == colorAry.Count - 1)
  1123. {
  1124. bgcolor += colorAry[i] + ");";
  1125. }
  1126. else
  1127. {
  1128. bgcolor += colorAry[i] + ", ";
  1129. }
  1130. }
  1131. fill.HtmlText = bgcolor;
  1132. return fill;
  1133. // }
  1134. }
  1135. else if (fillType == "PIC_FILL")
  1136. {
  1137. //if (isSvgMode)
  1138. //{
  1139. // return fill;
  1140. //}
  1141. //else
  1142. //{
  1143. fill.HtmlText = "background-image:url(" + fill.Image + ");";
  1144. return fill;
  1145. // }
  1146. }
  1147. else
  1148. {
  1149. Console.WriteLine("#" + fill.Color);
  1150. //if (isSvgMode)
  1151. //{
  1152. // var color = new colz.Color(fill);
  1153. // fill = color.rgb.toString();
  1154. fill.HtmlText = "background-color: #" + fill.Color + ";";
  1155. return fill;
  1156. //}
  1157. //else
  1158. //{
  1159. // //console.log(node,"fillColor: ",fillColor,"fillType: ",fillType,"isSvgMode: ",isSvgMode)
  1160. // return fill;
  1161. //}
  1162. }
  1163. }
  1164. else
  1165. {
  1166. //if (isSvgMode)
  1167. //{
  1168. // return fill;
  1169. //}
  1170. //else
  1171. //{
  1172. fill.SvgText = "none";
  1173. fill.HtmlText = "background-color: initial;";
  1174. return fill;
  1175. // }
  1176. }
  1177. }
  1178. public async Task<AzureBlobModel> GetThumbnailModel(XmlDocument xdoc, string shaCode)
  1179. {
  1180. var thumbnailNode = xdoc.GetTextByPath("//pkg:part[@pkg:name='/docProps/thumbnail.jpeg']");
  1181. if (thumbnailNode != null)
  1182. {
  1183. var contentType = thumbnailNode.GetTextByPath("@pkg:contentType");
  1184. var thumbnail = thumbnailNode.InnerText;
  1185. return await SaveBase64ToBolob(thumbnail, contentType.Value, shaCode + "/imgs", "thumbnail");
  1186. }
  1187. return null;
  1188. }
  1189. public XmlNode LoadTheme(XmlDocument xdoc)
  1190. {
  1191. var themeRelationship = xdoc.GetTextByPath("//pkg:part[@pkg:name='/ppt/_rels/presentation.xml.rels']/pkg:xmlData/rel:Relationships/rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme']/@Target");
  1192. // "/ppt/theme/theme1.xml"
  1193. string themeURI = "/ppt/" + themeRelationship.Value;
  1194. return xdoc.GetTextByPath("//pkg:part[@pkg:name='" + themeURI + "']");
  1195. }
  1196. public async Task<AzureBlobModel> SaveBase64ToBolob(string data, string contentType, string FolderName, string fileName)
  1197. {
  1198. string fileExt;
  1199. if (ContentTypeDict.extdict.TryGetValue(contentType, out string ext))
  1200. {
  1201. fileExt = ext;
  1202. }
  1203. else
  1204. {
  1205. //解决多种扩展名不能获取的
  1206. string[] sp = contentType.Split("/");
  1207. fileExt = sp[sp.Length - 1];
  1208. sp = fileExt.Split("+");
  1209. fileExt = "." + sp[sp.Length - 1];
  1210. }
  1211. //data:image/jpeg;base64,
  1212. if (string.IsNullOrEmpty(fileName))
  1213. {
  1214. Stream stream = new MemoryStream(Convert.FromBase64String(data));
  1215. string shaCode = ShaHashHelper.GetSHA1(stream);
  1216. fileName = shaCode + fileExt;
  1217. }
  1218. else
  1219. {
  1220. if (fileName.Split(".").Length == 1)
  1221. {
  1222. fileName += fileExt;
  1223. }
  1224. }
  1225. Stream streamBlob = new MemoryStream(Convert.FromBase64String(data));
  1226. AzureBlobModel model = await azureBlobDBRepository.UploadFileByFolder(streamBlob, FolderName, fileName, "pptx", false);
  1227. return model;
  1228. }
  1229. public async Task<Media> ProcessPicNode(XmlNode node, int order, WarpObj warpObj)
  1230. {
  1231. var xfrmList = "p:spPr/a:xfrm";
  1232. var xfrmNode = node.GetTextByPath(xfrmList);
  1233. Media media = new Media() { Type = "Pic" };
  1234. var id = node.GetTextByPath("p:nvPicPr/p:cNvPr/@id");
  1235. XmlNode slideLayoutSpNode = ShapeHelper.GetNodesTable(id, null, null, warpObj, "Layout");
  1236. XmlNode slideMasterSpNode = ShapeHelper.GetNodesTable(id, null, null, warpObj, "Master");
  1237. XmlNode slideLayoutXfrmNode = null;
  1238. if (slideLayoutSpNode != null)
  1239. {
  1240. slideLayoutXfrmNode = slideLayoutSpNode.GetTextByPath(xfrmList);
  1241. }
  1242. XmlNode slideMasterXfrmNode = null;
  1243. if (slideMasterSpNode != null)
  1244. {
  1245. slideMasterXfrmNode = slideMasterSpNode.GetTextByPath(xfrmList);
  1246. }
  1247. double rotate = 0;
  1248. var rotateNode = node.GetTextByPath("p:spPr/a:xfrm/@rot");
  1249. if (rotateNode != null)
  1250. {
  1251. rotate = ShapeHelper.AngleToDegrees(rotateNode);
  1252. }
  1253. Fill fill = await GetShapeFill(node, warpObj);
  1254. media.Fill = fill;
  1255. Border border = ShapeHelper.GetBorder(node, true, "shape", slideLayoutClrOvride, warpObj.themeContent);
  1256. media.Border = border;
  1257. Position position = ShapeHelper.GetPosition(xfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode);
  1258. media.Position = position;
  1259. position.Rot = rotate;
  1260. var rtrnData = "";
  1261. //image
  1262. var rid = node.GetTextByPath("p:blipFill/a:blip/@r:embed");
  1263. if (rid != null)
  1264. {
  1265. var imgName = warpObj.slideResObj[rid.Value]["target"];
  1266. Console.WriteLine(imgName);
  1267. if (!string.IsNullOrEmpty(imgName))
  1268. {
  1269. var imgData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + imgName + "']");
  1270. var imgFileExt = imgData.GetTextByPath("@pkg:contentType");
  1271. AzureBlobModel imgModel = await SaveBase64ToBolob(imgData.InnerText, imgFileExt.Value, fileShaCode + "/imgs", "");
  1272. media.Image = imgModel.BlobUrl;
  1273. media.MediaType = "image";
  1274. }
  1275. }
  1276. ///////////////////////////////////////Amir//////////////////////////////
  1277. //video
  1278. var vdoNode = node.GetTextByPath("p:nvPicPr/p:nvPr/a:videoFile/@r:link");
  1279. if (vdoNode != null)
  1280. {
  1281. string vdoFile = warpObj.slideResObj[vdoNode.Value]["target"];
  1282. if (!string.IsNullOrEmpty(vdoFile))
  1283. {
  1284. var videoData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + vdoFile + "']");
  1285. var contentType = videoData.GetTextByPath("@pkg:contentType");
  1286. AzureBlobModel vdoModel = await SaveBase64ToBolob(videoData.InnerText, contentType.Value, fileShaCode + "/media", "");
  1287. media.Url = vdoModel.BlobUrl;
  1288. media.MediaType = "video";
  1289. }
  1290. /// 处理为AzureBlob 上传
  1291. // vdoMimeType = getMimeType(vdoFileExt);
  1292. // blob = new Blob([uInt8Array], {
  1293. // type: vdoMimeType
  1294. // });
  1295. // vdoBlob = URL.createObjectURL(blob);
  1296. }
  1297. //audio
  1298. var audioNode = node.GetTextByPath("p:nvPicPr/p:nvPr/a:audioFile/@r:link");
  1299. // var audioObjc;
  1300. if (audioNode != null)
  1301. {
  1302. string audioFile = warpObj.slideResObj[audioNode.Value]["target"];
  1303. if (!string.IsNullOrEmpty(audioFile))
  1304. {
  1305. var audioData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + audioFile + "']");
  1306. var contentType = audioData.GetTextByPath("@pkg:contentType");
  1307. AzureBlobModel adoModel = await SaveBase64ToBolob(audioData.InnerText, contentType.Value, fileShaCode + "/media", "");
  1308. media.Url = adoModel.BlobUrl;
  1309. media.MediaType = "audio";
  1310. }
  1311. //uInt8ArrayAudio = zip.file(audioFile).asArrayBuffer();
  1312. //blobAudio = new Blob([uInt8ArrayAudio]);
  1313. //audioBlob = URL.createObjectURL(blobAudio);
  1314. //var cx = parseInt(xfrmNode["a:ext"]["attrs"]["cx"]) * 20;
  1315. //var cy = xfrmNode["a:ext"]["attrs"]["cy"];
  1316. //var x = parseInt(xfrmNode["a:off"]["attrs"]["x"]) / 2.5;
  1317. //var y = xfrmNode["a:off"]["attrs"]["y"];
  1318. //audioObjc = {
  1319. // "a:ext" : {
  1320. // "attrs":{
  1321. // "cx":cx,
  1322. // "cy":cy
  1323. // }
  1324. // },
  1325. // "a:off":{
  1326. // "attrs":{
  1327. // "x":x,
  1328. // "y":y
  1329. // }
  1330. // }
  1331. //}
  1332. // mediaSupportFlag = true;
  1333. }
  1334. //console.log(node)
  1335. //////////////////////////////////////////////////////////////////////////
  1336. //mimeType = imgFileExt;
  1337. //rtrnData = "<div class='block content' style='" +
  1338. // (( audioPlayerFlag) ? GetPosition(audioObjc, null, null) : GetPosition(xfrmNode, null, null)) +
  1339. // (( audioPlayerFlag) ? GetSize(audioObjc, null, null) :GetSize(xfrmNode, null, null)) +
  1340. // " z-index: " + order + ";" +
  1341. // "transform: rotate(" + rotate + "deg);'>";
  1342. //if ((vdoNode ==null && audioNode ==null) || !mediaSupportFlag)
  1343. //{
  1344. // rtrnData += "<img src='data:" + mimeType + ";base64," + base64ArrayBuffer(imgArrayBuffer) + "' style='width: 100%; height: 100%'/>";
  1345. //}
  1346. //else if ((vdoNode !=null || audioNode !=null) && mediaSupportFlag)
  1347. //{
  1348. // if (vdoNode !=null)
  1349. // {
  1350. // rtrnData += "<video src='" + vdoBlob + "' controls style='width: 100%; height: 100%'>Your browser does not support the video tag.</video>";
  1351. // }
  1352. // if (audioNode !=null)
  1353. // {
  1354. // rtrnData += "<audio id='audio_player' controls ><source src='" + audioBlob + "'></audio>";
  1355. // }
  1356. //}
  1357. rtrnData += "<span style='color:red;font-size:40px;position: absolute;'>This media file Not supported by HTML5</span>";
  1358. //if ((vdoNode != null || audioNode != null) && mediaSupportFlag)
  1359. //{
  1360. // //console.log("Founded supported media file but media process disabled (mediaProcess=false)");
  1361. //}
  1362. rtrnData += "</div>";
  1363. //console.log(rtrnData)
  1364. return media;
  1365. }
  1366. }
  1367. }