using DocumentFormat.OpenXml.Drawing; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Presentation; using HiTeachCC.Model.PowerPoint; using HiTeachCC.Service.PowerPoint.Interface; using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using System.Xml.XPath; using TEAMModelOS.SDK.Context.Constant; using TEAMModelOS.SDK.Context.Constant.Common; using TEAMModelOS.SDK.Context.Exception; using TEAMModelOS.SDK.Helper.Common.ColorHelper; using TEAMModelOS.SDK.Helper.Common.JsonHelper; using TEAMModelOS.SDK.Helper.Common.StringHelper; using TEAMModelOS.SDK.Helper.Security.ShaHash; using TEAMModelOS.SDK.Module.AzureBlob.Container; using TEAMModelOS.SDK.Module.AzureBlob.Interfaces; using TEAMModelOS.Service.Models.PowerPoint.Inner; using ColorMap = DocumentFormat.OpenXml.Presentation.ColorMap; using Fill = HiTeachCC.Model.PowerPoint.Fill; using Media = HiTeachCC.Model.PowerPoint.Media; using Position = HiTeachCC.Model.PowerPoint.Position; namespace HiTeachCC.Service.PowerPoint.Implement { public class ShapeGenerator : IShapeGenerator { public string fileShaCode { get; set; } bool isDone = false; List MsgQueue = new List(); private Dictionary slideLayoutClrOvride { get; set; } private XmlNode themeContent { get; set; } int chartID = 0; int _order = 1; int titleFontSize = 42; int bodyFontSize = 20; int otherFontSize = 16; bool isSlideMode = false; Dictionary> styleTable = new Dictionary>(); const double px96 = 96.00, px72 = 72.00, px914400 = 914400.00, px12700 = 12700.00; const double rot60000 = 60000.00; private readonly IAzureBlobDBRepository azureBlobDBRepository; public ShapeGenerator(IAzureBlobDBRepository _azureBlobDBRepository) { azureBlobDBRepository = _azureBlobDBRepository; } public async Task> LoadPresentation(IFormFile file) { Dictionary resdict = new Dictionary(); if (FileType.GetExtention(file.FileName).ToLower().Equals("pptx")) { ConvertPPTX(file, resdict); return resdict; } else if (FileType.GetExtention(file.FileName).ToLower().Equals("pdf")) { // await ProcessPDF(file, resdict); return resdict; } else { throw new BizException("file type does not support!", 500); } } public Dictionary ConvertPPTX(IFormFile file, Dictionary resdict) { string shaCode = fileShaCode = ShaHashHelper.GetSHA1(file.OpenReadStream()); using (PresentationDocument presentationDocument = PresentationDocument.Open(file.OpenReadStream(), false)) { if (presentationDocument == null) { throw new ArgumentNullException("presentationDocument"); } XDocument xdoc = presentationDocument.ToFlatOpcDocument(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(xdoc.ToString()); var rslt_ary = ProcessPPTX(xmlDocument, shaCode); //TODO return null; } } /// /// 加载PPTX文件 /// /// /// public async Task>> ProcessPPTX(XmlDocument xdoc, string shaCode) { List> post_ary = new List>(); var dateBefore = DateTimeOffset.Now.UtcTicks; AzureBlobModel thumbnailModel = await GetThumbnailModel(xdoc, shaCode); post_ary.Add(new Dictionary { { "pptx-thumb", thumbnailModel } }); //获取全部的/ppt/slides/slide1.xml--->>/ppt/slides/slide(n).xml var slideNodes = xdoc.GetTextByPathList("//pkg:part[@pkg:contentType='application/vnd.openxmlformats-officedocument.presentationml.slide+xml']"); //获取全部的/ppt/slideLayouts/slideLayout1.xml--->>/ppt/slideLayouts/slideLayout(n).xml var slideLayoutNodes = xdoc.GetTextByPathList("//pkg:part[@pkg:contentType='application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml']"); //获取ppt的宽高 var slideSize = GetSlideSize(xdoc); post_ary.Add(new Dictionary { { "slideSize", slideSize } }); //加载当前PPT使用到的PPT节点 themeContent = LoadTheme(xdoc); //获取所有的表格样式节点 var tableStyles = xdoc.GetTextByPath("//pkg:part[@pkg:name='/ppt/tableStyles.xml']/pkg:xmlData/a:tblStyleLst"); //处理slide1---slide(n) int numOfSlides = slideNodes.Count; for (int i = 0; i < numOfSlides; i++) { string filename = slideNodes[i].GetTextByPath("@pkg:name").Value; //处理当前页的幻灯片 string slideHtml = ProcessSingleSlide(xdoc, slideNodes[i], filename, i, slideSize); post_ary.Add(new Dictionary { { "slide", slideHtml } }); post_ary.Add(new Dictionary { { "progress-update", (i + 1) * 100 / numOfSlides } }); } post_ary.Add(new Dictionary { { "globalCSS", GenGlobalCSS() } }); var dateAfter = DateTimeOffset.Now.UtcTicks; post_ary.Add(new Dictionary { { "ExecutionTime", dateAfter - dateBefore } }); return post_ary; } private Dictionary GenGlobalCSS() { Dictionary cssText = new Dictionary(); foreach (var key in styleTable.Keys) { // cssText += "div ." + styleTable[key]["name"] + "{" + styleTable[key]["text"] + "}\n"; //section > div var cssTextKey = styleTable[key]["name"]; var cssTextValue = styleTable[key]["text"]; cssText.Add(cssTextKey, cssTextValue); } return cssText; } private string ProcessSingleSlide(XmlDocument xdoc, XmlNode xnode, string sldFileName, int index, dynamic slideSize) { var resName = sldFileName.Replace("slides/slide", "slides/_rels/slide") + ".rels"; var RelationshipArray = xdoc.GetTextByPathList("//pkg:part[@pkg:name='" + resName + "']/pkg:xmlData/rel:Relationships/rel:Relationship"); Dictionary> slideResObj = new Dictionary>(); var layoutFilename = ""; foreach (XmlNode Relationship in RelationshipArray) { var RelationshipType = Relationship.GetTextByPath("@Type"); if (RelationshipType.Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout")) { layoutFilename = Relationship.GetTextByPath("@Target").Value.Replace("../", "/ppt/"); } else { //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide": //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image": //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart": //case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink": Dictionary dict = new Dictionary(); string Type = Relationship.GetTextByPath("@Type").Value.Replace("http://schemas.openxmlformats.org/officeDocument/2006/relationships/", ""); string Target = Relationship.GetTextByPath("@Target").Value.Replace("../", "/ppt/"); string Id = Relationship.GetTextByPath("@Id").Value; dict.Add("type", Type); dict.Add("target", Target); slideResObj.Add(Id, dict); } } // Open slideLayoutXX.xml var slideLayoutContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + layoutFilename + "']"); NodesTable slideLayoutTables = IndexNodes(slideLayoutContent.GetTextByPath("pkg:xmlData/p:sldLayout")); ///ppt/slides/slide5.xml 也包含a:overrideClrMapping ////ppt/slideLayouts/slideLayout13.xml 也包含a:overrideClrMapping var sldLayoutClrOvr = slideLayoutContent.GetTextByPath("pkg:xmlData/p:sldLayout/p:clrMapOvr/a:overrideClrMapping"); if (sldLayoutClrOvr != null) { //获取 overrideClrMapping所有属性节点 slideLayoutClrOvride = new Dictionary() { { "accent1", sldLayoutClrOvr.GetTextByPath("@accent1").Value}, { "accent2", sldLayoutClrOvr.GetTextByPath("@accent2").Value}, { "accent3", sldLayoutClrOvr.GetTextByPath("@accent3").Value}, { "accent4", sldLayoutClrOvr.GetTextByPath("@accent4").Value}, { "accent5", sldLayoutClrOvr.GetTextByPath("@accent5").Value}, { "accent6", sldLayoutClrOvr.GetTextByPath("@accent6").Value}, { "bg1", sldLayoutClrOvr.GetTextByPath("@bg1").Value}, { "bg2", sldLayoutClrOvr.GetTextByPath("@bg2").Value}, { "folHlink", sldLayoutClrOvr.GetTextByPath("@folHlink").Value}, { "hlink", sldLayoutClrOvr.GetTextByPath("@hlink").Value}, { "tx1", sldLayoutClrOvr.GetTextByPath("@tx1").Value}, { "tx2", sldLayoutClrOvr.GetTextByPath("@tx2").Value} }; } // =====< Step 2 >===== // Read slide master filename of the slidelayout (Get slideMasterXX.xml) // @resName: ppt/slideLayouts/slideLayout1.xml // @masterName: ppt/slideLayouts/_rels/slideLayout1.xml.rels var slideLayoutResFilename = layoutFilename.Replace("slideLayouts/slideLayout", "slideLayouts/_rels/slideLayout") + ".rels"; var slideLayoutResContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + slideLayoutResFilename + "']"); ///查看js 是替换之前 还是添加 RelationshipArray = slideLayoutResContent.GetTextByPathList("pkg:xmlData/rel:Relationships/rel:Relationship"); var masterFilename = ""; Dictionary> layoutResObj = new Dictionary>(); for (int i = 0; i < RelationshipArray.Count; i++) { if (RelationshipArray[i].GetTextByPath("@Type").Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster")) { masterFilename = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/"); } else { Dictionary dict = new Dictionary(); string Type = RelationshipArray[i].GetTextByPath("@Type").Value.Replace("http://schemas.openxmlformats.org/officeDocument/2006/relationships/", ""); string Target = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/"); string Id = RelationshipArray[i].GetTextByPath("@Id").Value; dict.Add("type", Type); dict.Add("target", Target); layoutResObj.Add(Id, dict); } } // Open slideMasterXX.xml var slideMasterContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + masterFilename + "']"); var slideMasterTextStyles = slideMasterContent.GetTextByPath("pkg:xmlData/p:sldMaster/p:txStyles"); var slideMasterTables = IndexNodes(slideMasterContent.GetTextByPath("pkg:xmlData/p:sldMaster")); /////////////////Amir///////////// //Open slideMasterXX.xml.rels var slideMasterResFilename = masterFilename.Replace("slideMasters/slideMaster", "slideMasters/_rels/slideMaster") + ".rels"; var slideMasterResContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + slideMasterResFilename + "']"); RelationshipArray = slideMasterResContent.GetTextByPathList("pkg:xmlData/rel:Relationships/rel:Relationship"); var themeFilename = ""; Dictionary> masterResObj = new Dictionary>(); for (int i = 0; i < RelationshipArray.Count; i++) { if (RelationshipArray[i].GetTextByPath("@Type").Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme")) { themeFilename = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/"); } else { Dictionary dict = new Dictionary(); string Type = RelationshipArray[i].GetTextByPath("@Type").Value.Replace("http://schemas.openxmlformats.org/officeDocument/2006/relationships/", ""); string Target = RelationshipArray[i].GetTextByPath("@Target").Value.Replace("../", "/ppt/"); string Id = RelationshipArray[i].GetTextByPath("@Id").Value; dict.Add("type", Type); dict.Add("target", Target); masterResObj.Add(Id, dict); } } //Load Theme file if (!string.IsNullOrEmpty(themeFilename)) { themeContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + themeFilename + "']"); } Console.WriteLine(sldFileName, layoutFilename, masterFilename, themeFilename); // =====< Step 3 >===== throw new NotImplementedException(); var slideContent = xdoc.GetTextByPath("//pkg:part[@pkg:name='" + sldFileName + "']"); var spTreeNode = slideContent.GetTextByPath("pkg:xmlData/p:sld/p:cSld/p:spTree"); WarpObj warpObj = new WarpObj { zip = xdoc, slideLayoutTables = slideLayoutTables, slideMasterTables = slideMasterTables, slideMasterTextStyles = slideMasterTextStyles, slideResObj = slideResObj, layoutResObj = layoutResObj, masterResObj = masterResObj }; var bgColor = GetSlideBackgroundFill(slideContent, slideLayoutContent, slideMasterContent, warpObj); var result = "
"; //result += "
"+getBackgroundShapes(slideContent, slideLayoutContent, slideMasterContent,warpObj) + "
" - TODO if (spTreeNode != null) { var nodes = spTreeNode.ChildNodes; int order = 1; foreach (XmlNode node in nodes) { result += ProcessNodesInSlide(node.Name, node , order, warpObj); order += 1; } } return ""; } private async Task ProcessNodesInSlide(string nodeKey, XmlNode node ,int order, WarpObj warpObj) { dynamic result =""; switch (nodeKey) { case "p:sp": // Shape, Text result = await ProcessSpNode(node, order, warpObj); break; case "p:cxnSp": // Shape, Text (with connection) result = ProcessCxnSpNode(node, order, warpObj); break; case "p:pic": // Picture result = await ProcessPicNode(node, order, warpObj); break; case "p:graphicFrame": // Chart, Diagram, Table result = ProcessGraphicFrameNode(node, order, warpObj); break; case "p:grpSp": result = ProcessGroupSpNode(node, order, warpObj); break; case "mc:AlternateContent": //Equations and formulas as Image var mcFallbackNode = node.GetTextByPath("mc:Fallback/p:sp"); result = await ProcessSpNode(mcFallbackNode, order, warpObj); break; default: break; } return result; } private string ProcessGroupSpNode(XmlNode node, int order, WarpObj warpObj) { var factor = 1.00 * px96 / px914400; var xfrmNode = node.GetTextByPath("p:grpSpPr/a:xfrm"); var x = int.Parse(xfrmNode.GetTextByPath("a:off/@x").Value) * factor; var y = int.Parse(xfrmNode.GetTextByPath("a:off/@y").Value) * factor; var chx = int.Parse(xfrmNode.GetTextByPath("a:chOff/@x").Value) * factor; var chy = int.Parse(xfrmNode.GetTextByPath("a:chOff/@y").Value) * factor; var cx = int.Parse(xfrmNode.GetTextByPath("a:ext/@cx").Value) * factor; var cy = int.Parse(xfrmNode.GetTextByPath("a:ext/@cy").Value) * factor; var chcx = int.Parse(xfrmNode.GetTextByPath("a:chExt/@cx").Value) * factor; var chcy = int.Parse(xfrmNode.GetTextByPath("a:chExt/@cy").Value) * factor; var result = "
"; // Procsee all child nodes var nodes = node.ChildNodes; foreach (XmlNode nd in nodes) { result += ProcessNodesInSlide(nd.Name, nd ,order, warpObj); order += 1; } result += "
"; return result; } private string ProcessGraphicFrameNode(XmlNode node, int order, WarpObj warpObj) { var result = ""; var graphicTypeUri = node.GetTextByPath("a:graphic/a:graphicData/uri"); if (graphicTypeUri != null) { switch (graphicTypeUri.Value) { case "http://schemas.openxmlformats.org/drawingml/2006/table": result = GenTable(node, warpObj); break; case "http://schemas.openxmlformats.org/drawingml/2006/chart": result = GenChart(node, warpObj); break; case "http://schemas.openxmlformats.org/drawingml/2006/diagram": result = GenDiagram(node, warpObj); break; default: break; } } return result; } private string GenDiagram(XmlNode node, WarpObj warpObj) { return ""; } private string GenChart(XmlNode node, WarpObj warpObj) { return ""; } private string GenTable(XmlNode node, WarpObj warpObj) { return ""; } private async Task ProcessPicNode(XmlNode node, int order, WarpObj warpObj) { var xfrmList = "p:spPr/a:xfrm"; var xfrmNode = node.GetTextByPath(xfrmList); Media media = new Media() { Type= "Pic" }; var id = node.GetTextByPath("p:nvPicPr/p:cNvPr/@id"); XmlNode slideLayoutSpNode = GetNodesTable(id, null, null, warpObj, "Layout"); XmlNode slideMasterSpNode = GetNodesTable(id, null, null, warpObj, "Master"); XmlNode slideLayoutXfrmNode = null; if (slideLayoutSpNode != null) { slideLayoutXfrmNode = slideLayoutSpNode.GetTextByPath(xfrmList); } XmlNode slideMasterXfrmNode = null; if (slideMasterSpNode != null) { slideMasterXfrmNode = slideMasterSpNode.GetTextByPath(xfrmList); } double rotate = 0; var rotateNode = node.GetTextByPath("p:spPr/a:xfrm/@rot"); if (rotateNode != null) { rotate = AngleToDegrees(rotateNode); } var w = int.Parse(xfrmNode.GetTextByPath("a:ext/@cx").Value) * px96 / px914400; var h = int.Parse(xfrmNode.GetTextByPath("a:ext/@cy").Value) * px96 / px914400; Fill fill = await GetShapeFill(node, warpObj); media.Fill = fill; Border border = GetBorder(node, true, "shape"); media.Border = border; Position position = GetPosition(xfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode); media.Position = position; position.Cx = w; position.Cy = h; position.Rot = rotate; var rtrnData = ""; //image var rid = node.GetTextByPath("p:blipFill/a:blip/@r:embed"); if (rid != null) { var imgName = warpObj.slideResObj[rid.Value]["target"]; if (!string.IsNullOrEmpty(imgName)) { var imgData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + imgName + "']"); var imgFileExt = imgData.GetTextByPath("@pkg:contentType"); AzureBlobModel imgModel = await SaveBase64ToBolob(imgData.InnerText, imgFileExt.Value, fileShaCode + "/imgs", ""); media.Image = imgModel.BlobUrl; media.MediaType = "image"; } } ///////////////////////////////////////Amir////////////////////////////// //video var vdoNode = node.GetTextByPath("p:nvPicPr/p:nvPr/a:videoFile/@r:link"); if (vdoNode != null) { string vdoFile = warpObj.slideResObj[vdoNode.Value]["target"]; if (!string.IsNullOrEmpty(vdoFile)) { var videoData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + vdoFile + "']"); var contentType = videoData.GetTextByPath("@pkg:contentType"); AzureBlobModel vdoModel = await SaveBase64ToBolob(videoData.InnerText, contentType.Value, fileShaCode + "/media", ""); media.Url = vdoModel.BlobUrl; media.MediaType = "video"; } /// 处理为AzureBlob 上传 // vdoMimeType = getMimeType(vdoFileExt); // blob = new Blob([uInt8Array], { // type: vdoMimeType // }); // vdoBlob = URL.createObjectURL(blob); } //audio var audioNode = node.GetTextByPath("p:nvPicPr/p:nvPr/a:audioFile/@r:link"); // var audioObjc; if (audioNode != null) { string audioFile = warpObj.slideResObj[audioNode.Value]["target"]; if (!string.IsNullOrEmpty(audioFile)) { var audioData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + audioFile + "']"); var contentType = audioData.GetTextByPath("@pkg:contentType"); AzureBlobModel adoModel = await SaveBase64ToBolob(audioData.InnerText, contentType.Value, fileShaCode + "/media", ""); media.Url = adoModel.BlobUrl; media.MediaType = "audio"; } //uInt8ArrayAudio = zip.file(audioFile).asArrayBuffer(); //blobAudio = new Blob([uInt8ArrayAudio]); //audioBlob = URL.createObjectURL(blobAudio); //var cx = parseInt(xfrmNode["a:ext"]["attrs"]["cx"]) * 20; //var cy = xfrmNode["a:ext"]["attrs"]["cy"]; //var x = parseInt(xfrmNode["a:off"]["attrs"]["x"]) / 2.5; //var y = xfrmNode["a:off"]["attrs"]["y"]; //audioObjc = { // "a:ext" : { // "attrs":{ // "cx":cx, // "cy":cy // } // }, // "a:off":{ // "attrs":{ // "x":x, // "y":y // } // } //} // mediaSupportFlag = true; } //console.log(node) ////////////////////////////////////////////////////////////////////////// //mimeType = imgFileExt; //rtrnData = "
"; //if ((vdoNode ==null && audioNode ==null) || !mediaSupportFlag) //{ // rtrnData += ""; //} //else if ((vdoNode !=null || audioNode !=null) && mediaSupportFlag) //{ // if (vdoNode !=null) // { // rtrnData += ""; // } // if (audioNode !=null) // { // rtrnData += ""; // } //} rtrnData += "This media file Not supported by HTML5"; //if ((vdoNode != null || audioNode != null) && mediaSupportFlag) //{ // //console.log("Founded supported media file but media process disabled (mediaProcess=false)"); //} rtrnData += "
"; //console.log(rtrnData) return media; } private async Task ProcessCxnSpNode(XmlNode node, int order, WarpObj warpObj) { var id = node.GetTextByPath("p:nvCxnSpPr/p:cNvPr/@id"); var name = node.GetTextByPath("p:nvCxnSpPr/p:cNvPr/@name"); return await GenShape(node, null, null, id, name, null, null, order, warpObj); } private async Task ProcessSpNode(XmlNode node, int order, WarpObj warpObj) { /* * 958 * 959 * 960 * 961 * 962 * 963 * 964 * 965 * 966 */ var id = node.GetTextByPath("p:nvSpPr/p:cNvPr/@id"); var name = node.GetTextByPath("p:nvSpPr/p:cNvPr/@name"); var idx = node.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@idx"); var type = node.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@type"); XmlNode slideLayoutSpNode = GetNodesTable(id,idx,type,warpObj, "Layout"); XmlNode slideMasterSpNode = GetNodesTable(id, idx, type, warpObj, "Master"); if (type == null) { if (slideLayoutSpNode != null) { type = slideLayoutSpNode.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@type"); } // type = slideLayoutSpNode.TryGetValue"p:nvSpPr", "p:nvPr", "p:ph", "attrs", "type"]); if (type == null) { if (slideMasterSpNode != null) { type = slideMasterSpNode.GetTextByPath("p:nvSpPr/p:nvPr/p:ph/@type"); } // type = getTextByPathList(slideMasterSpNode, ["p:nvSpPr", "p:nvPr", "p:ph", "attrs", "type"]); } } string s = await GenShape(node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, order, warpObj); return ""; } public XmlNode GetNodesTable(XmlNode id , XmlNode idx,XmlNode type , WarpObj warpObj ,string LayoutOrMaster) { XmlNode resNode = null; if (resNode == null) { if (type != null) { if (LayoutOrMaster.Equals("Layout")) { if (warpObj.slideLayoutTables.typeTable.TryGetValue(type.Value, out XmlNode LayoutNode)) { // LayoutNode.TryGetValue(type.Value, out XmlNode node); resNode = LayoutNode; }; } if (LayoutOrMaster.Equals("Master")) { if (warpObj.slideMasterTables.typeTable.TryGetValue(type.Value, out XmlNode MasterNode)) { // MasterNode.TryGetValue(type.Value, out XmlNode node); resNode = MasterNode; }; } } } if (resNode == null) { if (idx != null) { if (LayoutOrMaster.Equals("Layout")) { if (warpObj.slideLayoutTables.idxTable.TryGetValue(idx.Value, out XmlNode LayoutNode)) { //LayoutNode.TryGetValue(idx.Value, out XmlNode node); resNode = LayoutNode; }; } if (LayoutOrMaster.Equals("Master")) { if (warpObj.slideMasterTables.idxTable.TryGetValue(idx.Value, out XmlNode MasterNode)) { // LayoutNode.TryGetValue(idx.Value, out XmlNode node); resNode = MasterNode; }; } } } if (resNode == null) { if (id != null) { if (LayoutOrMaster.Equals("Layout")) { if (warpObj.slideLayoutTables.idTable.TryGetValue(id.Value,out XmlNode LayoutNode)) { // LayoutNode.TryGetValue(id.Value, out XmlNode node); resNode = LayoutNode; }; } if (LayoutOrMaster.Equals("Master")) { if (warpObj.slideMasterTables.idTable.TryGetValue(id.Value, out XmlNode MasterNode)) { // LayoutNode.TryGetValue(id.Value, out XmlNode node); resNode = MasterNode; }; } } else { resNode = null; } } return resNode; } private async Task GenShape(XmlNode node, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode, XmlNode id, XmlNode name, XmlNode idx, XmlNode type, int order, WarpObj warpObj) { var xfrmList = "p:spPr/a:xfrm"; var slideXfrmNode = node.GetTextByPath(xfrmList); XmlNode slideLayoutXfrmNode = null; if (slideLayoutSpNode != null) { slideLayoutXfrmNode = slideLayoutSpNode.GetTextByPath(xfrmList); } XmlNode slideMasterXfrmNode = null; if (slideMasterSpNode != null) { slideMasterXfrmNode = slideMasterSpNode.GetTextByPath(xfrmList); } if (slideXfrmNode == null) { slideXfrmNode = slideLayoutXfrmNode; } if (slideXfrmNode == null) { slideXfrmNode = slideMasterXfrmNode; } var result = ""; var shpId = node.GetTextByPath("/@order"); var shapType = node.GetTextByPath("p:spPr/a:prstGeom/@prst"); var custShapType = node.GetTextByPath("p:spPr/a:custGeom"); var isFlipV = 0; var isFlipH = 0; if (slideXfrmNode.GetTextByPath("@flipV") != null && slideXfrmNode.GetTextByPath("@flipV").Value == "1") {// if ( getTextByPathList(slideXfrmNode, ["attrs", "flipV"]) === "1" || getTextByPathList(slideXfrmNode, ["attrs", "flipH"]) === "1") isFlipV = 1; } if (slideXfrmNode.GetTextByPath("@flipH") != null && slideXfrmNode.GetTextByPath("@flipH").Value == "1") { isFlipH = 1; } //rotate var rotate = AngleToDegrees(slideXfrmNode.GetTextByPath("@rot")); //console.log("rotate: "+rotate); double txtRotate; var txtXframeNode = node.GetTextByPath("p:txXfrm/@rot"); if (txtXframeNode != null) { txtRotate = AngleToDegrees(txtXframeNode) + 90; } else { txtRotate = rotate; } if (shapType != null || custShapType != null) { var x = int.Parse(slideXfrmNode.GetTextByPath("a:off/@x").Value) * px96 / px914400; var y = int.Parse(slideXfrmNode.GetTextByPath("a:off/@y").Value) * px96 / px914400; var w = int.Parse(slideXfrmNode.GetTextByPath("a:ext/@cx").Value) * px96 / px914400; var h = int.Parse(slideXfrmNode.GetTextByPath("a:ext/@cy").Value) * px96 / px914400; Position position = GetPosition(slideXfrmNode, null, null); position.Cx = w; position.Cy = h; position.Rot = rotate; position.FlipH = isFlipH; position.FlipV = isFlipV; //result += ""; //result += ""; // Fill Color var Fill = await GetShapeFill(node, warpObj); var grndFillFlg = false; var imgFillFlg = false; var clrFillType = GetFillType(node.GetTextByPath("p:spPr")); ///////////////////////////////////////// if (clrFillType == "GRADIENT_FILL") { grndFillFlg = true; var color_arry = Fill.gradColor; var angl = Fill.Rot; var svgGrdnt = GetSvgGradient(w, h, angl, color_arry, shpId); //fill="url(#linGrd)" result += svgGrdnt; } else if (clrFillType == "PIC_FILL") { imgFillFlg = true; var svgBgImg = GetSvgImagePattern(Fill.Image, shpId.Value); //fill="url(#imgPtrn)" //console.log(svgBgImg) result += svgBgImg; } else { if (clrFillType != "SOLID_FILL" && clrFillType != "PATTERN_FILL" && (shapType.Value == "arc" || shapType.Value == "bracketPair" || shapType.Value == "bracePair" || shapType.Value == "leftBracket" || shapType.Value == "leftBrace" || shapType.Value == "rightBrace" || shapType.Value == "rightBracket")) { //Temp. solution - TODO Fill.HtmlText = "none"; } } // Border Color var border = GetBorder(node, true, "shape"); var headEndNodeAttrs = node.GetTextByPath("p:spPr/a:ln/a:headEnd"); var tailEndNodeAttrs = node.GetTextByPath("p:spPr/a:ln/a:tailEnd"); // type: none, triangle, stealth, diamond, oval, arrow if ((headEndNodeAttrs != null && (headEndNodeAttrs.GetTextByPath("@type").Value == "triangle" || (headEndNodeAttrs.GetTextByPath("@type").Value == "arrow")) || (tailEndNodeAttrs != null && (tailEndNodeAttrs.GetTextByPath("@type").Value == "triangle" || (tailEndNodeAttrs.GetTextByPath("@type").Value == "arrow"))))) { var triangleMarker = ""; result += triangleMarker; } result += ""; } return ""; } public Border GetBorder(XmlNode node, bool isSvgMode, string bType) { Border border = new Border(); string cssText = ""; XmlNode lineNode = null; if (bType == "shape") { cssText = "border: "; lineNode = PowerPointHelper.GetTextByPath(node, "p:spPr/a:ln");// node["p:spPr"]["a:ln"]; } else if (bType == "text") { cssText = ""; lineNode = PowerPointHelper.GetTextByPath(node, "a:rPr/a:ln");// node["a:rPr"]["a:ln"]; } if (lineNode == null) { return null; } // Border width: 1pt = 12700, default = 0.75pt var borderWidth = int.Parse(PowerPointHelper.GetTextByPath(lineNode, "@w").Value) / 12700; if (PowerPointHelper.GetTextByPath(lineNode, "@w") != null || borderWidth < 1) { cssText += "1pt "; } else { cssText += borderWidth + "pt "; } // Border type var borderType = PowerPointHelper.GetTextByPath(lineNode, "a:prstDash/@val").Value; var strokeDasharray = "0"; switch (borderType) { case "solid": cssText += "solid"; strokeDasharray = "0"; break; case "dash": cssText += "dashed"; strokeDasharray = "5"; break; case "dashDot": cssText += "dashed"; strokeDasharray = "5, 5, 1, 5"; break; case "dot": cssText += "dotted"; strokeDasharray = "1, 5"; break; case "lgDash": cssText += "dashed"; strokeDasharray = "10, 5"; break; case "lgDashDotDot": cssText += "dashed"; strokeDasharray = "10, 5, 1, 5, 1, 5"; break; case "sysDash": cssText += "dashed"; strokeDasharray = "5, 2"; break; case "sysDashDot": cssText += "dashed"; strokeDasharray = "5, 2, 1, 5"; break; case "sysDashDotDot": cssText += "dashed"; strokeDasharray = "5, 2, 1, 5, 1, 5"; break; case "sysDot": cssText += "dotted"; strokeDasharray = "2, 5"; break; case null: //console.log(borderType); default: cssText += "solid"; strokeDasharray = "0"; break; } // Border color var borderColor = PowerPointHelper.GetTextByPath(lineNode, "a:solidFill/:srgbClr/@val").Value; if (borderColor == null) { var schemeClrNode = PowerPointHelper.GetTextByPathList(lineNode, "a:solidFill/a:schemeClr"); if (schemeClrNode != null) { var schemeClr = PowerPointHelper.GetTextByPath(lineNode, "a:solidFill/a:schemeClr/@val"); borderColor = GetSchemeColorFromTheme(schemeClr.Value, null); } } // 2. drawingML namespace if (borderColor == null) { var schemeClrNode = PowerPointHelper.GetTextByPathList(node, "p:style/a:lnRef/a:schemeClr"); if (schemeClrNode != null) { var schemeClr = PowerPointHelper.GetTextByPath(node, "p:style/a:lnRef/a:schemeClr/@val"); borderColor = GetSchemeColorFromTheme(schemeClr.Value, null); } if (borderColor != null) { var shade = PowerPointHelper.GetTextByPath(node, "p:style/a:lnRef/a:schemeClr/a:shade/@val").Value; if (shade != null) { int shaded = int.Parse(shade) / 100000; var color = ColorTranslator.FromHtml("#" + borderColor); ColorHSL colorHSL = ColorHelper.RgbToHsl(new ColorRGB(color.R, color.G, color.B)); colorHSL.L = colorHSL.L * shaded; ColorRGB colorRGB = colorHSL.HslToRgb(); borderColor = ColorTranslator.ToHtml(Color.FromArgb(colorRGB.R, colorRGB.G, colorRGB.B)); // borderColor = color.hex.replace("#", ""); } } } if (borderColor == null) { if (isSvgMode) { borderColor = "none"; } else { borderColor = "#000"; } } else { borderColor = "#" + borderColor; } cssText += " " + borderColor + " "; if (isSvgMode) { return new Border { Color = borderColor, Width = borderWidth, Type = borderType, Stroke = strokeDasharray }; } else { return border; } } public string GetSvgImagePattern(string fillColor, string shpId) { var ptrn = "";// ''; ptrn += "";// ''; ptrn += "";// ''; return ptrn; } private string GetSvgGradient(double w, double h, double angl, List color_arry, XmlNode shpId) { var stopsArray = GetMiddleStops(color_arry.Count - 2); var svgAngle = ""; double svgHeight = h; double svgWidth = w; string svg = ""; List xy_ary = SVGangle(angl, svgHeight, svgWidth); double x1 = xy_ary[0]; double y1 = xy_ary[1]; double x2 = xy_ary[2]; double y2 = xy_ary[3]; var sal = stopsArray.Count; double sr = sal < 20 ? 100 : 1000; svgAngle = " gradientUnits=\"userSpaceOnUse\" x1=\"" + x1 + "%\" y1=\"" + y1 + "%\" x2=\"" + x2 + "%\" y2=\"" + y2 + "%\""; svgAngle = "\n"; svg += svgAngle; for (var i = 0; i < sal; i++) { svg += " GetMiddleStops(int s) { var sArry = new List { "0%" }; if (s == 0) { return sArry; } else { for (int i = s; i < 0; i--) { 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. var middleStopString = middleStop + "%"; sArry.Add(middleStopString); // sArry.splice(-1, 0, middleStopString); } // AM: add into stopsArray before 100% } sArry.Add("100%"); return sArry; } public async Task GetShapeFill(XmlNode node, WarpObj warpObj) { // 1. presentationML // p:spPr/ [a:noFill, solidFill, gradFill, blipFill, pattFill, grpFill] // From slide //Fill Type: //console.log("ShapeFill: ", node) var fillType = GetFillType(PowerPointHelper.GetTextByPath(node, "p:spPr")); Fill fill = new Fill(); if (fillType == "NO_FILL") { fill.SvgText = "node"; fill.Type = 0; fill.HtmlText = "background-color: initial;"; return fill; //return isSvgMode ? "none" : "background-color: initial;"; } else if (fillType == "SOLID_FILL") { XmlNode shpFill = PowerPointHelper.GetTextByPath(node, "p:spPr/a:solidFill");// node["p:spPr"]["a:solidFill"]; fill = GetSolidFill(shpFill); } else if (fillType == "GRADIENT_FILL") { var shpFill = PowerPointHelper.GetTextByPath(node, "p:spPr/a:gradFill");// node["p:spPr"]["a:gradFill"]; // fillColor = GetSolidFill(shpFill); fill = GetGradientFill(shpFill); //console.log("shpFill",shpFill,grndColor.color) } else if (fillType == "PATTERN_FILL") { var shpFill = PowerPointHelper.GetTextByPath(node, "p:spPr/a:pattFill");// node["p:spPr"]["a:pattFill"]; fill = GetPatternFill(shpFill); } else if (fillType == "PIC_FILL") { var shpFill = PowerPointHelper.GetTextByPath(node, "p:spPr/a:blipFill"); //node["p:spPr"]["a:blipFill"]; fill = await GetPicFill("slideBg", shpFill, warpObj); } // 2. drawingML namespace if (fill == null) { var clrName = PowerPointHelper.GetTextByPath(node, "p:style/a:fillRef"); fill = GetSolidFill(clrName); } if (fill != null) { if (fillType == "GRADIENT_FILL") { //if (isSvgMode) //{ // // console.log("GRADIENT_FILL color", fillColor.color[0]) // return fill; //} //else //{ var colorAry = fill.Color; var rot = fill.Rot; var bgcolor = "background: linear-gradient(" + rot + "deg,"; for (var i = 0; i < colorAry.Length; i++) { if (i == colorAry.Length - 1) { bgcolor += colorAry[i] + ");"; } else { bgcolor += colorAry[i] + ", "; } } fill.HtmlText = bgcolor; return fill; // } } else if (fillType == "PIC_FILL") { //if (isSvgMode) //{ // return fill; //} //else //{ fill.HtmlText = "background-image:url(" + fill.Image + ");"; return fill; // } } else { Console.WriteLine("#" + fill.Color); //if (isSvgMode) //{ // var color = new colz.Color(fill); // fill = color.rgb.toString(); fill.HtmlText = "background-color: #" + fill.Color + ";"; return fill; //} //else //{ // //console.log(node,"fillColor: ",fillColor,"fillType: ",fillType,"isSvgMode: ",isSvgMode) // return fill; //} } } else { //if (isSvgMode) //{ // return fill; //} //else //{ fill.SvgText = "none"; fill.HtmlText = "background-color: initial;"; return fill; // } } } private List SVGangle(double deg, double svgHeight, double svgWidth) { double w = svgWidth; double h = svgHeight; double ang = deg; double o = 2; double n = 2; double wc = w / 2; double hc = h / 2; double tx1 = 2; double ty1 = 2; double tx2 = 2; double ty2 = 2; double k = (((ang % 360) + 360) % 360); double j = (360 - k) * System.Math.PI / 180; double i = System.Math.Tan(j); double l = hc - i * wc; if (k == 0) { tx1 = w; ty1 = hc; tx2 = 0; ty2 = hc; } else if (k < 90) { n = w; o = 0; } else if (k == 90) { tx1 = wc; ty1 = 0; tx2 = wc; ty2 = h; } else if (k < 180) { n = 0; o = 0; } else if (k == 180) { tx1 = 0; ty1 = hc; tx2 = w; ty2 = hc; } else if (k < 270) { n = 0; o = h; } else if (k == 270) { tx1 = wc; ty1 = h; tx2 = wc; ty2 = 0; } else { n = w; o = h; } // AM: I could not quite figure out what m, n, and o are supposed to represent from the original code on visualcsstools.com. var m = o + (n / i); tx1 = tx1 == 2 ? i * (m - l) / (System.Math.Pow(i, 2) + 1) : tx1; ty1 = ty1 == 2 ? i * tx1 + l : ty1; tx2 = tx2 == 2 ? w - tx1 : tx2; ty2 = ty2 == 2 ? h - ty1 : ty2; double x1 = System.Math.Round(tx2 / w * 100 * 100) / 100; double y1 = System.Math.Round(ty2 / h * 100 * 100) / 100; double x2 = System.Math.Round(tx1 / w * 100 * 100) / 100; double y2 = System.Math.Round(ty1 / h * 100 * 100) / 100; return new List { x1, y1, x2, y2 }; } private Fill GetPatternFill(XmlNode node) { Fill fill = new Fill { Type = 4 }; var fgClr = PowerPointHelper.GetTextByPath(node, "a:fgClr"); fill = GetSolidFill(fgClr); return fill; } private Fill GetGradientFill(XmlNode node) { XmlNodeList gsLst = PowerPointHelper.GetTextByPathList(node, "a:gsLst/a:gs");// node["a:gsLst"]["a:gs"]; //get start color var color_ary = new List(); var tint_ary = new string[] { }; for (int i = 0; i < gsLst.Count; i++) { var lo_color = GetSolidFill(gsLst[i]); if (gsLst[i].GetTextByPath("a:srgbClr") != null) { //var mod = PowerPointHelper.GetTextByPath(gsLst[i], "a:srgbClr/a:lumMod/@val"); //var off = PowerPointHelper.GetTextByPath(gsLst[i], "a:srgbClr/a:lumOff/@val"); //double lumMod = 1.0; //double lumOff = 1.0; //if (mod!=null) //{ // lumMod = double.Parse(mod.Value) /100000; //} //if (off!=null) //{ // lumOff = double.Parse(off.Value) / 100000; //} //console.log([lumMod, lumOff]); lo_color.Color = PowerPointHelper.ColorToning(gsLst[i].OuterXml, lo_color.Color); // lo_color = ApplyLumModify(lo_color, lumMod, lumOff); } else if (gsLst[i].GetTextByPath("a:schemeClr") != null) { //a:schemeClr //var mod = PowerPointHelper.GetTextByPath(gsLst[i], "a:schemeClr/a:lumMod/@val"); //var off = PowerPointHelper.GetTextByPath(gsLst[i], "a:schemeClr/a:lumOff/@val"); //double lumMod = 1.0; //double lumOff = 1.0; //if (mod != null) //{ // lumMod = double.Parse(mod.Value) / 100000; //} //if (off != null) //{ // lumOff = double.Parse(off.Value) / 100000; //} //console.log([lumMod, lumOff]); lo_color.Color = PowerPointHelper.ColorToning(gsLst[i].OuterXml, lo_color.Color); // lo_color = ApplyLumModify(lo_color, lumMod, lumOff); } color_ary.Add(lo_color.Color); } //get rot var lin = PowerPointHelper.GetTextByPathList(node, "a:lin");// node["a:lin"]; double rot = 0; if (lin != null) { rot = AngleToDegrees(PowerPointHelper.GetTextByPath(node, "a:lin/@ang")) + 90; } return new Fill() { Type = 2, gradColor = color_ary, Rot = rot }; } //private static Fill ApplyLumModify(Fill rgbStr, double factor, double offset) //{ // Color color = ColorTranslator.FromHtml("#" + "1CADE4"); // ColorRGB RGB = new ColorRGB(color.R,color.G,color.B); // ColorHSL HSL= ColorHelper.RgbToHsl(RGB); // HSL.L= HSL.L * (1 + offset); // RGB = ColorHelper.HslToRgb(HSL); // color= Color.FromArgb(RGB.R, RGB.G, RGB.B); // rgbStr.Color=ColorTranslator.ToHtml(color).Replace("#",""); // return rgbStr; //} public Position GetPosition(XmlNode slideXfrmNode, XmlNode slideLayoutXfrmNode, XmlNode slideMasterXfrmNode) { XmlNode off = null; double x, y; if (slideXfrmNode != null) { off = PowerPointHelper.GetTextByPath(slideXfrmNode, "a:off"); } else if (slideLayoutXfrmNode != null) { off = PowerPointHelper.GetTextByPath(slideLayoutXfrmNode, "a:off"); } else if (slideMasterXfrmNode != null) { off = PowerPointHelper.GetTextByPath(slideMasterXfrmNode, "a:off"); } x = double.Parse(PowerPointHelper.GetTextByPath(off, "@x").Value) * px96 / px914400; y = double.Parse(PowerPointHelper.GetTextByPath(off, "@y").Value) * px96 / px914400; return new Position() { X = x, Y = y }; //if (off == null) //{ // return ""; //} //else //{ // // return (IsNaN(x) || IsNaN(y)) ? "" : "top:" + y + "px; left:" + x + "px;"; //} } private double AngleToDegrees(XmlNode angle) { if (angle == null) { return 0; } return double.Parse(angle.Value) / 60000.00; } private Fill GetSlideBackgroundFill(XmlNode slideContent, XmlNode slideLayoutContent, XmlNode slideMasterContent, WarpObj warpObj) { var bgPr = slideContent.GetTextByPath("p:sld/p:cSld/p:bg/p:bgPr"); var bgRef = slideContent.GetTextByPath("p:sld/p:cSld/p:bg/p:bgRef"); var bgcolor = ""; if (bgPr != null) { var bgFillTyp = GetFillType(bgPr); if (bgFillTyp == "SOLID_FILL") { var sldFill = bgPr.GetTextByPath("a:solidFill"); var bgColor = GetSolidFill(sldFill); var sldTint = GetColorOpacity(sldFill); bgcolor = "background: rgba(" + HexToRgbNew(bgColor.Color) + "," + sldTint + ");"; } else if (bgFillTyp == "GRADIENT_FILL") { bgcolor = GetBgGradientFill(bgPr, null, slideMasterContent); } else if (bgFillTyp == "PIC_FILL") { bgcolor = GetBgPicFill(bgPr, "slideBg", warpObj); } } else if (bgRef != null) { } else { } return null; } private string GetBgPicFill(XmlNode bgPr, string sorce, WarpObj warpObj) { string bgcolor; var picFillBase64 = GetPicFill(sorce, bgPr.GetTextByPath("a:blipFill"), warpObj); var ordr = bgPr["attrs"]["order"]; //a:srcRect //a:stretch => a:fillRect =>attrs (l:-17000, r:-17000) bgcolor = "background-image: url(" + picFillBase64 + "); z-index: " + ordr + ";"; return bgcolor; } private async Task GetPicFill(string type, XmlNode node, WarpObj warpObj) { //Need to test///////////////////////////////////////////// //rId //TODO - Image Properties - Tile, Stretch, or Display Portion of Image //(http://officeopenxml.com/drwPic-tile.php) // var img = ""; var rId = PowerPointHelper.GetTextByPath(node, "a:blip/@r:embed");//node["a:blip"]["attrs"]["r:embed"]; Dictionary imgPath = new Dictionary(); if (type == "slideBg") { imgPath = warpObj.slideResObj[rId.Value]; } else if (type == "layoutBg") { imgPath = warpObj.layoutResObj[rId.Value]; } else if (type == "masterBg") { imgPath = warpObj.masterResObj[rId.Value]; } if (imgPath == null) { return null; } //var imgExt = imgPath["type"]; //if (imgExt == "xml") //{ // return null; //} var imgData = warpObj.zip.GetTextByPath("//pkg:part[@pkg:name='" + imgPath["target"] + "']"); if (imgData != null) { AzureBlobModel model = await SaveBase64ToBolob(imgData.InnerText, imgData.GetTextByPath("@pkg:contentType").Value, fileShaCode + "/imgs", null); return new Fill { Type = 3, Image = model.BlobUrl }; } else { return null; } // var imgArrayBuffer = warpObj.zip.GetTextByPath(imgPath).Value.asArrayBuffer(); //var imgMimeType = GetMimeType(imgExt); //img = "data:" + imgMimeType + ";base64," + base64ArrayBuffer(imgArrayBuffer); } private string GetBgGradientFill(XmlNode bgPr, XmlNode phClr, XmlNode slideMasterContent) { var bgcolor = ""; if (bgPr != null) { var grdFill = bgPr.GetTextByPath("a:gradFill"); var gsLst = grdFill.GetTextByPathList("a:gsLst/a:gs"); // var startColorNode, endColorNode; var color_ary = new List(); var tint_ary = new List(); for (var i = 0; i < gsLst.Count; i++) { var lo_tint = ""; var lo_color = ""; if (gsLst[i]["a:srgbClr"] != null) { if (phClr == null) { lo_color = gsLst[i].GetTextByPath("a:srgbClr/@val").Value; //#... } lo_tint = gsLst[i].GetTextByPath("a:srgbClr/a:tint/@val").Value; } else if (gsLst[i]["a:schemeClr"] != null) { //a:schemeClr if (phClr == null) { var schemeClr = gsLst[i].GetTextByPath("a:schemeClr/@val"); lo_color = GetSchemeColorFromTheme("a:" + schemeClr, slideMasterContent); //#... } lo_tint = gsLst[i].GetTextByPath("a:schemeClr/a:tint/@val").Value; //console.log("schemeClr",schemeClr,slideMasterContent) } //console.log("lo_color",lo_color) color_ary[i] = lo_color; tint_ary[i] = (lo_tint != null) ? int.Parse(lo_tint) / 100000 : 1; } //get rot var lin = grdFill["a:lin"]; var rot = 90.0; if (lin != null) { rot = AngleToDegrees(lin.GetTextByPath("@ang")) + 90; } bgcolor = "background: linear-gradient(" + rot + "deg,"; for (var i = 0; i < gsLst.Count; i++) { if (i == gsLst.Count - 1) { if (phClr == null) { bgcolor += "rgba(" + HexToRgbNew(color_ary[i]) + "," + tint_ary[i] + ")" + ");"; } else { bgcolor += "rgba(" + HexToRgbNew(phClr.Value) + "," + tint_ary[i] + ")" + ");"; } } else { if (phClr == null) { bgcolor += "rgba(" + HexToRgbNew(color_ary[i]) + "," + tint_ary[i] + ")" + ", "; } else { bgcolor += "rgba(" + HexToRgbNew(phClr.Value) + "," + tint_ary[i] + ")" + ", "; } } } } else { if (phClr == null) { bgcolor = "rgba(" + HexToRgbNew(phClr.Value) + ",0);"; } } return bgcolor; } private string HexToRgbNew(string bgColor) { //var arrBuff = new ArrayBuffer(4); //var vw = new DataView(arrBuff); //vw.setUint32(0, parseInt(hex, 16), false); //var arrByte = new Uint8Array(arrBuff); int r = Convert.ToInt32("0x" + bgColor.Substring(0, 2), 16); int g = Convert.ToInt32("0x" + bgColor.Substring(2, 2), 16); int b = Convert.ToInt32("0x" + bgColor.Substring(4, 2), 16); return r + "," + g + "," + b; } private double GetColorOpacity(XmlNode solidFill) { double opcity = 1; if (solidFill == null) { return opcity; } if (solidFill.GetTextByPath("a:srgbClr") != null) { var tint = solidFill.GetTextByPath("a:srgbClr/a:tint/@val"); if (tint != null) { opcity = double.Parse(tint.Value) / 100000; } } else if (solidFill.GetTextByPath("a:schemeClr") != null) { var tint = solidFill.GetTextByPath("a:schemeClr/a:tint/@val"); if (tint != null) { opcity = double.Parse(tint.Value) / 100000; } } else if (solidFill.GetTextByPath("a:scrgbClr") != null) { var tint = solidFill.GetTextByPath("a:scrgbClr/a:tint/@val"); if (tint != null) { opcity = double.Parse(tint.Value) / 100000; } } else if (solidFill.GetTextByPath("a:prstClr") != null) { var tint = solidFill.GetTextByPath("a:prstClr/a:tint/@val"); if (tint != null) { opcity = double.Parse(tint.Value) / 100000; } } else if (solidFill.GetTextByPath("a:hslClr") != null) { var tint = solidFill.GetTextByPath("a:hslClr/a:tint/@val"); if (tint != null) { opcity = double.Parse(tint.Value) / 100000; } } else if (solidFill.GetTextByPath("a:sysClr") != null) { var tint = solidFill.GetTextByPath("a:sysClr/a:tint/@val"); if (tint != null) { opcity = double.Parse(tint.Value) / 100000; } } return opcity; } public Fill GetSolidFill(XmlNode node) { if (node == null) { return null; } Fill fill = new Fill() { Color = "FFF", Type = 1 }; if (PowerPointHelper.GetTextByPath(node, "a:srgbClr") != null) { fill.Color = PowerPointHelper.GetTextByPath(node, "a:srgbClr/@val").Value; //#... } else if (PowerPointHelper.GetTextByPath(node, "a:schemeClr") != null)//node["a:schemeClr"] != null) { //a:schemeClr var schemeClr = PowerPointHelper.GetTextByPath(node, "a:schemeClr/@val"); //console.log(schemeClr) fill.Color = GetSchemeColorFromTheme(schemeClr.Value, null); //#... } else if (PowerPointHelper.GetTextByPath(node, "a:scrgbClr") != null) { // //Need to test///////////////////////////////////////////// var defBultColorValsR = PowerPointHelper.GetTextByPath(node, "a:scrgbClr/@r"); var defBultColorValsG = PowerPointHelper.GetTextByPath(node, "a:scrgbClr/@g"); var defBultColorValsB = PowerPointHelper.GetTextByPath(node, "a:scrgbClr/@b"); var red = (defBultColorValsR.Value.IndexOf("%") != -1) ? defBultColorValsR.Value.Split("%").First() : defBultColorValsR.Value; var green = (defBultColorValsG.Value.IndexOf("%") != -1) ? defBultColorValsG.Value.Split("%").First() : defBultColorValsG.Value; var blue = (defBultColorValsB.Value.IndexOf("%") != -1) ? defBultColorValsB.Value.Split("%").First() : defBultColorValsB.Value; var scrgbClr = red + "," + green + "," + blue; fill.Color = ToHex(255 * (double.Parse(red) / 100)) + ToHex(255 * (double.Parse(green) / 100)) + ToHex(255 * (double.Parse(blue) / 100)); //console.log("scrgbClr: " + scrgbClr); } else if (PowerPointHelper.GetTextByPath(node, "a:prstClr") != null) { // //Need to test///////////////////////////////////////////// var prstClr = PowerPointHelper.GetTextByPath(node, "a:prstClr/@val");// node["a:prstClr"]["attrs"]["val"]; fill.Color = GetColorName2Hex(prstClr.Value); //console.log("prstClr: " + prstClr+" => hexClr: "+color); } else if (PowerPointHelper.GetTextByPath(node, "a:hslClr") != null) { // //Need to test///////////////////////////////////////////// var defBultColorVals = PowerPointHelper.GetTextByPath(node, "a:hslClr");//["attrs"]; var defBultColorVals_hue = PowerPointHelper.GetTextByPath(defBultColorVals, "@hue"); var defBultColorVals_sat = PowerPointHelper.GetTextByPath(defBultColorVals, "@sat"); var defBultColorVals_lum = PowerPointHelper.GetTextByPath(defBultColorVals, "@lum"); var hue = double.Parse(defBultColorVals_hue.Value) / 100000; var sat = double.Parse((defBultColorVals_sat.Value.IndexOf("%") != -1) ? defBultColorVals_sat.Value.Split("%").First() : defBultColorVals_sat.Value) / 100; var lum = double.Parse((defBultColorVals_lum.Value.IndexOf("%") != -1) ? defBultColorVals_lum.Value.Split("%").First() : defBultColorVals_lum.Value) / 100; var hslClr = defBultColorVals_hue.Value.ToString() + "," + defBultColorVals_sat.Value.ToString() + "," + defBultColorVals_lum.Value.ToString(); var hsl2rgb = HslToRgb(hue, sat, lum); fill.Color = ToHex(hsl2rgb.r) + ToHex(hsl2rgb.g) + ToHex(hsl2rgb.b); //defBultColor = cnvrtHslColor2Hex(hslClr); //TODO // console.log("hslClr: " + hslClr); } else if (PowerPointHelper.GetTextByPath(node, "a:sysClr") != null) { // //Need to test///////////////////////////////////////////// var sysClr = PowerPointHelper.GetTextByPath(node, "a:sysClr/@lastClr").Value; if (sysClr != null) { fill.Color = sysClr; } } return fill; } public string GetSchemeColorFromTheme(string schemeClr, XmlNode sldMasterNode) { // in slide master // e.g. tx2="dk2" bg2="lt2" tx1="dk1" bg1="lt1" slideLayoutClrOvride if (slideLayoutClrOvride == null || slideLayoutClrOvride.Count <= 0) { if (sldMasterNode != null) { var sldLayoutClrOvr = PowerPointHelper.GetTextByPath(sldMasterNode, "p:sldMaster/p:clrMap"); if (sldLayoutClrOvr != null) { //获取 overrideClrMapping所有属性节点 检查测试 是否slideLayoutClrOvride 需要被覆盖 slideLayoutClrOvride = new Dictionary() { { "accent1", sldLayoutClrOvr.GetTextByPath("@accent1").Value}, { "accent2", sldLayoutClrOvr.GetTextByPath("@accent2").Value}, { "accent3", sldLayoutClrOvr.GetTextByPath("@accent3").Value}, { "accent4", sldLayoutClrOvr.GetTextByPath("@accent4").Value}, { "accent5", sldLayoutClrOvr.GetTextByPath("@accent5").Value}, { "accent6", sldLayoutClrOvr.GetTextByPath("@accent6").Value}, { "bg1", sldLayoutClrOvr.GetTextByPath("@bg1").Value}, { "bg2", sldLayoutClrOvr.GetTextByPath("@bg2").Value}, { "folHlink", sldLayoutClrOvr.GetTextByPath("@folHlink").Value}, { "hlink", sldLayoutClrOvr.GetTextByPath("@hlink").Value}, { "tx1", sldLayoutClrOvr.GetTextByPath("@tx1").Value}, { "tx2", sldLayoutClrOvr.GetTextByPath("@tx2").Value} }; } } } if (!schemeClr.StartsWith("a:")) { schemeClr = "a:" + schemeClr; } //console.log(slideLayoutClrOvride); var schmClrName = schemeClr.Replace("a:", ""); if (slideLayoutClrOvride != null) { switch (schmClrName) { case "tx1": case "tx2": case "bg1": case "bg2": schemeClr = "a:" + slideLayoutClrOvride[schmClrName]; //schemeClr = "a:" + slideLayoutClrOvride[schmClrName]; //console.log(schmClrName+ "=> "+schemeClr); break; } } else { switch (schmClrName) { case "tx1": schemeClr = "a:dk1"; break; case "tx2": schemeClr = "a:dk2"; break; case "bg1": schemeClr = "a:lt1"; break; case "bg2": schemeClr = "a:lt2"; break; } } //var refNode = PowerPointHelper.GetTextByPathList(themeContent, "a:theme/a:themeElements/a:clrScheme/"+ schemeClr.Value); var color = PowerPointHelper.GetTextByPath(themeContent, "pkg:xmlData/a:theme/a:themeElements/a:clrScheme/" + schemeClr + "/a:srgbClr/@val"); if (color == null)//&& refNode != null { color = PowerPointHelper.GetTextByPath(themeContent, "pkg:xmlData/a:theme/a:themeElements/a:clrScheme/" + schemeClr + "/a:sysClr/@lastClr"); } //console.log(color) return color.Value; } private string ToHex(dynamic n) { string hex = n.toString(16); while (hex.Length < 2) { hex = "0" + hex; } return hex; } private dynamic HslToRgb(double hue, double sat, double light) { double t1, t2, r, g, b; hue /= 60; if (light <= 0.5) { t2 = light * (sat + 1); } else { t2 = light + sat - (light * sat); } t1 = light * 2 - t2; r = HueToRgb(t1, t2, hue + 2) * 255; g = HueToRgb(t1, t2, hue) * 255; b = HueToRgb(t1, t2, hue - 2) * 255; return new { r, g, b }; } private double HueToRgb(double t1, double t2, double hue) { if (hue < 0) hue += 6; if (hue >= 6) hue -= 6; if (hue < 1) return (t2 - t1) * hue + t1; else if (hue < 3) return t2; else if (hue < 4) return (t2 - t1) * (4 - hue) + t1; else return t1; } private string GetColorName2Hex(string name) { var hex = ""; var colorName = new List { "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" }; var colorHex = new List { "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" }; var findIndx = colorName.IndexOf(name); if (findIndx != -1) { hex = colorHex[findIndx]; } return hex; } public string GetFillType(XmlNode node) { //Need to test///////////////////////////////////////////// //SOLID_FILL //PIC_FILL //GRADIENT_FILL //PATTERN_FILL //NO_FILL var fillType = ""; if (node.GetTextByPath("a:noFill") != null) { fillType = "NO_FILL"; } if (node.GetTextByPath("a:solidFill") != null) { fillType = "SOLID_FILL"; } if (node.GetTextByPath("a:gradFill") != null) { fillType = "GRADIENT_FILL"; } if (node.GetTextByPath("a:pattFill") != null) { fillType = "PATTERN_FILL"; } if (node.GetTextByPath("a:blipFill") != null) { fillType = "PIC_FILL"; } return fillType; } private NodesTable IndexNodes(XmlNode content) { var idTable = new Dictionary(); var idxTable = new Dictionary(); var typeTable = new Dictionary(); var spTreeNode = content.GetTextByPath("p:cSld/p:spTree"); // Dictionary> slideResObj = new Dictionary>(); var spTreeNodeChildren = spTreeNode.ChildNodes; foreach (XmlNode child in spTreeNodeChildren) { if (child.Name.Equals("p:nvGrpSpPr") || child.Name.Equals("p:grpSpPr")) { continue; } //var targetNode = child.ChildNodes; var targetNode = child.GetTextByPath("p:nvSpPr"); // < p:cNvCxnSpPr > // < a:cxnSpLocks /> ///这个是什么意思 // if (targetNode == null) { targetNode = child.GetTextByPath("p:nvCxnSpPr"); } var id = targetNode.GetTextByPath("p:cNvPr/@id"); var idx = targetNode.GetTextByPath("p:nvPr/p:ph/@idx"); var type = targetNode.GetTextByPath("p:nvPr/p:ph/@type"); // Dictionary node = new Dictionary(); //if (child.ChildNodes != null) //{ // foreach (XmlNode xmlNode in child.ChildNodes) // { // node.TryAdd(xmlNode.Name, xmlNode); // } //} if (id != null) { idTable.Add(id.Value, child); } if (idx != null) { idxTable.Add(idx.Value, child); } if (type != null) { typeTable.Add(type.Value, child); } } return new NodesTable { idTable = idTable, idxTable = idxTable, typeTable = typeTable }; } private dynamic GetSlideSize(XmlDocument xdoc) { var sldSzNode = xdoc.GetTextByPath("//pkg:part[@pkg:name='/ppt/presentation.xml']/pkg:xmlData/p:presentation/p:sldSz"); double width = double.Parse(sldSzNode.GetTextByPath("@cx").Value) * px96 / px914400; double height = double.Parse(sldSzNode.GetTextByPath("@cy").Value) * px96 / px914400; return new { width, height }; } private async Task GetThumbnailModel(XmlDocument xdoc, string shaCode) { var thumbnailNode = xdoc.GetTextByPath("//pkg:part[@pkg:name='/docProps/thumbnail.jpeg']"); if (thumbnailNode != null) { var contentType = thumbnailNode.GetTextByPath("@pkg:contentType"); var thumbnail = thumbnailNode.InnerText; return await SaveBase64ToBolob(thumbnail, contentType.Value, shaCode + "/imgs", "thumbnail"); } return null; } private XmlNode LoadTheme(XmlDocument xdoc) { 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"); // "/ppt/theme/theme1.xml" string themeURI = "/ppt/" + themeRelationship.Value; return xdoc.GetTextByPath("//pkg:part[@pkg:name='" + themeURI + "']"); } private async Task SaveBase64ToBolob(string data, string contentType, string FolderName, string fileName) { string fileExt; if (ContentTypeDict.extdict.TryGetValue(contentType, out string ext)) { fileExt = ext; } else { //解决多种扩展名不能获取的 string[] sp = contentType.Split("/"); fileExt = sp[sp.Length - 1]; sp = fileExt.Split("+"); fileExt = "." + sp[sp.Length - 1]; } //data:image/jpeg;base64, try { if (string.IsNullOrEmpty(fileName)) { Stream stream = new MemoryStream(Convert.FromBase64String(data)); string shaCode = ShaHashHelper.GetSHA1(stream); fileName = shaCode + fileExt; } else { if (fileName.Split(".").Length == 1) { fileName += fileExt; } } Stream streamBlob = new MemoryStream(Convert.FromBase64String(data)); AzureBlobModel model = await azureBlobDBRepository.UploadFileByFolder(streamBlob, FolderName, fileName, "pptx", false); return model; } catch (Exception x) { throw new BizException(x.Message); } } } }