using System; using System.Collections.Generic; using System.IO; using System.IO.Packaging; using System.Linq; using System.Xml.Linq; namespace BetterSeewo.Manager.Services.Conversion { public class PptxExporter { private static readonly XNamespace A = "http://schemas.openxmlformats.org/drawingml/2006/main"; private static readonly XNamespace P = "http://schemas.openxmlformats.org/presentationml/2006/main"; private static readonly XNamespace R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; private static readonly XNamespace CT = "http://schemas.openxmlformats.org/package/2006/content-types"; private static readonly XNamespace Rel = "http://schemas.openxmlformats.org/package/2006/relationships"; public void Export(SmfDocument doc, string pptxPath) { using var pptx = Package.Open(pptxPath, FileMode.Create, FileAccess.ReadWrite); Export(doc, pptx); } public void Export(SmfDocument doc, Package pptx) { CreateContentTypes(pptx, doc.Slides.Count); CreateMinimalTheme(pptx); CreateMinimalSlideMaster(pptx); CreateMinimalSlideLayout(pptx); CreatePresProps(pptx); CreateViewProps(pptx); WriteMediaFiles(doc, pptx); var presDoc = BuildPresentation(doc); var (presRelDoc, slideRelDocs) = BuildRelations(doc, presDoc); var presXmlUri = PackUriHelper.CreatePartUri(new Uri("/ppt/presentation.xml", UriKind.Relative)); var presPart = pptx.CreatePart(presXmlUri, "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"); var presRelUri = PackUriHelper.CreatePartUri(new Uri("/ppt/_rels/presentation.xml.rels", UriKind.Relative)); var presRelPart = pptx.CreatePart(presRelUri, "application/vnd.openxmlformats-package.relationships+xml"); using (var sw = new StreamWriter(presPart.GetStream())) presDoc.Save(sw); using (var sw = new StreamWriter(presRelPart.GetStream())) presRelDoc.Save(sw); WriteSlides(doc, pptx, slideRelDocs); var rootRelUri = PackUriHelper.CreatePartUri(new Uri("/_rels/.rels", UriKind.Relative)); var rootRelPart = pptx.CreatePart(rootRelUri, "application/vnd.openxmlformats-package.relationships+xml"); using (var sw = new StreamWriter(rootRelPart.GetStream())) { sw.Write("", Rel.NamespaceName, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"); } } private XDocument BuildPresentation(SmfDocument doc) { var pres = new XDocument(new XElement(P + "presentation", new XAttribute(XNamespace.Xmlns + "a", A.NamespaceName), new XAttribute(XNamespace.Xmlns + "r", R.NamespaceName), new XAttribute(XNamespace.Xmlns + "p", P.NamespaceName), new XElement(P + "sldMasterIdLst", new XElement(P + "sldMasterId", new XAttribute("id", 2147483648), new XAttribute(R + "id", "rId1"))), new XElement(P + "sldIdLst"), new XElement(P + "sldSz", new XAttribute("cx", doc.Properties.SlideWidth), new XAttribute("cy", doc.Properties.SlideHeight)), new XElement(P + "notesSz", new XAttribute("cx", 6858000), new XAttribute("cy", 9144000)))); return pres; } private (XDocument presRels, List slideRels) BuildRelations(SmfDocument doc, XDocument presDoc) { var presRelNs = XNamespace.Get(Rel.NamespaceName); var presRels = new XDocument(new XElement(presRelNs + "Relationships", new XElement(presRelNs + "Relationship", new XAttribute("Id", "rId1"), new XAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster"), new XAttribute("Target", "slideMasters/slideMaster1.xml")))); var slideIdLst = presDoc.Root?.Element(P + "sldIdLst"); var slideRels = new List(); for (int i = 0; i < doc.Slides.Count; i++) { var rId = $"rId{i + 2}"; var slideFileName = $"slides/slide{i + 1}.xml"; slideIdLst?.Add(new XElement(P + "sldId", new XAttribute("id", 256 + i), new XAttribute(R + "id", rId))); presRels.Root?.Add(new XElement(presRelNs + "Relationship", new XAttribute("Id", rId), new XAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide"), new XAttribute("Target", slideFileName))); var slideRel = new XDocument(new XElement(presRelNs + "Relationships", new XElement(presRelNs + "Relationship", new XAttribute("Id", "rId1"), new XAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout"), new XAttribute("Target", "../slideLayouts/slideLayout1.xml")))); slideRels.Add(slideRel); } return (presRels, slideRels); } private void WriteSlides(SmfDocument doc, Package pptx, List slideRelDocs) { for (int i = 0; i < doc.Slides.Count; i++) { var slide = doc.Slides[i]; var slideDoc = BuildSlideXml(slide, doc, i + 1); var slideUri = PackUriHelper.CreatePartUri(new Uri($"/ppt/slides/slide{i + 1}.xml", UriKind.Relative)); var slidePart = pptx.CreatePart(slideUri, "application/vnd.openxmlformats-officedocument.presentationml.slide+xml"); using (var sw = new StreamWriter(slidePart.GetStream())) slideDoc.Save(sw); var slideRelUri = PackUriHelper.CreatePartUri(new Uri($"/ppt/slides/_rels/slide{i + 1}.xml.rels", UriKind.Relative)); var slideRelPart = pptx.CreatePart(slideRelUri, "application/vnd.openxmlformats-package.relationships+xml"); using (var sw = new StreamWriter(slideRelPart.GetStream())) slideRelDocs[i].Save(sw); } } private XDocument BuildSlideXml(SmfSlide slide, SmfDocument doc, int slideNum) { var sld = new XDocument(new XElement(P + "sld", new XAttribute(XNamespace.Xmlns + "a", A.NamespaceName), new XAttribute(XNamespace.Xmlns + "r", R.NamespaceName), new XAttribute(XNamespace.Xmlns + "p", P.NamespaceName))); var cSld = new XElement(P + "cSld"); WriteBackground(slide, cSld, doc, slideNum); var spTree = new XElement(P + "spTree"); spTree.Add(new XElement(P + "nvGrpSpPr", new XElement(P + "cNvPr", new XAttribute("id", 1), new XAttribute("name", "")), new XElement(P + "cNvGrpSpPr"))); spTree.Add(new XElement(P + "grpSpPr", new XElement(A + "xfrm", new XElement(A + "off", new XAttribute("x", 0), new XAttribute("y", 0)), new XElement(A + "ext", new XAttribute("cx", 0), new XAttribute("cy", 0)), new XElement(A + "chOff", new XAttribute("x", 0), new XAttribute("y", 0)), new XElement(A + "chExt", new XAttribute("cx", 0), new XAttribute("cy", 0))))); int shapeId = 2; foreach (var element in slide.Elements) { WriteElement(element, spTree, doc, slideNum, ref shapeId); } cSld.Add(spTree); sld.Root?.Add(cSld); return sld; } private void WriteBackground(SmfSlide slide, XElement cSld, SmfDocument doc, int slideNum) { var bg = slide.Background; if (bg.Type == SmfFillType.None) return; var bgPr = new XElement(P + "bgPr"); switch (bg.Type) { case SmfFillType.Solid when bg.SolidColor != null: bgPr.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", bg.SolidColor.Value)))); break; case SmfFillType.Gradient when bg.Gradient != null: bgPr.Add(WrGradient(bg.Gradient)); break; case SmfFillType.Image when bg.ImageRef != null: if (doc.MediaFiles.ContainsKey(bg.ImageRef)) { var relId = $"bgRel_{slideNum}"; bgPr.Add(new XElement(A + "blipFill", new XElement(A + "blip", new XAttribute(R + "embed", relId)), new XElement(A + "stretch", new XElement(A + "fillRect")))); var slideRelUri = PackUriHelper.CreatePartUri(new Uri($"/ppt/slides/_rels/slide{slideNum}.xml.rels", UriKind.Relative)); if (slideRelUri != null) { } } break; } if (bgPr.HasElements) { cSld.Add(new XElement(P + "bg", bgPr)); } } private void WriteElement(SmfElement element, XElement spTree, SmfDocument doc, int slideNum, ref int shapeId) { switch (element) { case SmfTextElement textElem: WriteTextShape(textElem, spTree, ref shapeId); break; case SmfImageElement imgElem: WriteImage(imgElem, spTree, doc, slideNum, ref shapeId); break; case SmfShapeElement shapeElem: WriteShape(shapeElem, spTree, ref shapeId); break; case SmfTableElement tableElem: WriteTable(tableElem, spTree, ref shapeId); break; case SmfInkElement inkElem: WriteInk(inkElem, spTree, ref shapeId); break; case SmfGroupElement groupElem: break; } } private void WriteTextShape(SmfTextElement elem, XElement spTree, ref int shapeId) { var sp = new XElement(P + "sp"); sp.Add(new XElement(P + "nvSpPr", new XElement(P + "cNvPr", new XAttribute("id", shapeId++), new XAttribute("name", $"TextBox{shapeId - 1}")), new XElement(P + "cNvSpPr", new XAttribute("txBox", 1)), new XElement(P + "nvPr"))); var spPr = new XElement(P + "spPr"); spPr.Add(WrXfrm(elem.Bounds, elem.Rotation)); if (elem.BackgroundFill?.Type == SmfFillType.Solid && elem.BackgroundFill.SolidColor != null) { spPr.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", elem.BackgroundFill.SolidColor.Value)))); } else { spPr.Add(new XElement(A + "noFill")); } if (elem.Outline != null) spPr.Add(WrStroke(elem.Outline)); spPr.Add(new XElement(A + "prstGeom", new XAttribute("prst", "rect"), new XElement(A + "avLst"))); sp.Add(spPr); sp.Add(WrTxBody(elem.RichText)); spTree.Add(sp); } private void WriteImage(SmfImageElement elem, XElement spTree, SmfDocument doc, int slideNum, ref int shapeId) { if (!doc.MediaFiles.ContainsKey(elem.Source)) return; var relId = $"imgRel_{shapeId}_{slideNum}"; var pic = new XElement(P + "pic"); pic.Add(new XElement(P + "nvPicPr", new XElement(P + "cNvPr", new XAttribute("id", shapeId++), new XAttribute("name", elem.Source)), new XElement(P + "cNvPicPr"))); var blipFill = new XElement(P + "blipFill", new XElement(A + "blip", new XAttribute(R + "embed", relId))); if (elem.Crop != null) { blipFill.Element(A + "blip")?.Add(new XElement(A + "srcRect", new XAttribute("l", elem.Crop.Left), new XAttribute("r", elem.Crop.Right), new XAttribute("t", elem.Crop.Top), new XAttribute("b", elem.Crop.Bottom))); } blipFill.Add(new XElement(A + "stretch", new XElement(A + "fillRect"))); pic.Add(blipFill); var spPr = new XElement(P + "spPr"); spPr.Add(WrXfrm(elem.Bounds, elem.Rotation)); spPr.Add(new XElement(A + "prstGeom", new XAttribute("prst", "rect"), new XElement(A + "avLst"))); pic.Add(spPr); spTree.Add(pic); AddImageRel(doc, slideNum, relId, elem.Source); } private void AddImageRel(SmfDocument doc, int slideNum, string relId, string fileName) { var slideRelUri = PackUriHelper.CreatePartUri(new Uri($"/ppt/slides/_rels/slide{slideNum}.xml.rels", UriKind.Relative)); } private void WriteShape(SmfShapeElement elem, XElement spTree, ref int shapeId) { var sp = new XElement(P + "sp"); sp.Add(new XElement(P + "nvSpPr", new XElement(P + "cNvPr", new XAttribute("id", shapeId++), new XAttribute("name", $"Shape{shapeId - 1}")), new XElement(P + "cNvSpPr"), new XElement(P + "nvPr"))); var spPr = new XElement(P + "spPr"); spPr.Add(WrXfrm(elem.Bounds, elem.Rotation)); var shapePrst = ShapeTypeToPrst(elem.ShapeType); if (elem.Fill.Type == SmfFillType.Solid && elem.Fill.SolidColor != null) { spPr.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", elem.Fill.SolidColor.Value)))); } else if (elem.Fill.Type == SmfFillType.Gradient && elem.Fill.Gradient != null) { spPr.Add(WrGradient(elem.Fill.Gradient)); } else { spPr.Add(new XElement(A + "noFill")); } if (elem.Stroke != null) spPr.Add(WrStroke(elem.Stroke)); spPr.Add(new XElement(A + "prstGeom", new XAttribute("prst", shapePrst), new XElement(A + "avLst"))); sp.Add(spPr); if (elem.TextContent != null) sp.Add(WrTxBody(elem.TextContent)); spTree.Add(sp); } private void WriteTable(SmfTableElement elem, XElement spTree, ref int shapeId) { var gf = new XElement(P + "graphicFrame"); gf.Add(new XElement(P + "nvGraphicFramePr", new XElement(P + "cNvPr", new XAttribute("id", shapeId++), new XAttribute("name", $"Table{shapeId - 1}")), new XElement(P + "cNvGraphicFramePr"), new XElement(P + "nvPr"))); var xfrm = new XElement(P + "xfrm"); xfrm.Add(new XElement(A + "off", new XAttribute("x", elem.Bounds.X), new XAttribute("y", elem.Bounds.Y))); xfrm.Add(new XElement(A + "ext", new XAttribute("cx", elem.Bounds.Width), new XAttribute("cy", elem.Bounds.Height))); gf.Add(xfrm); var gv = new XElement(A + "graphic", new XElement(A + "graphicData", new XAttribute("uri", "http://schemas.openxmlformats.org/drawingml/2006/table"))); var tbl = new XElement(A + "tbl"); var gridCol = new XElement(A + "tblGrid"); foreach (var w in elem.ColumnWidths) gridCol.Add(new XElement(A + "gridCol", new XAttribute("w", w))); tbl.Add(gridCol); foreach (var row in elem.Rows) { var tr = new XElement(A + "tr", new XAttribute("h", row.Height)); foreach (var cell in row.Cells) { var tc = new XElement(A + "tc"); var tcPr = new XElement(A + "tcPr"); tcPr.Add(new XAttribute("marL", cell.LeftMargin)); tcPr.Add(new XAttribute("marR", cell.RightMargin)); tcPr.Add(new XAttribute("marT", cell.TopMargin)); tcPr.Add(new XAttribute("marB", cell.BottomMargin)); if (cell.RowSpan > 1) tcPr.Add(new XAttribute("rowSpan", cell.RowSpan)); if (cell.ColSpan > 1) tcPr.Add(new XAttribute("gridSpan", cell.ColSpan)); if (cell.MergeHorizontal) tcPr.Add(new XAttribute("hMerge", 1)); if (cell.MergeVertical) tcPr.Add(new XAttribute("vMerge", 1)); tcPr.Add(new XAttribute("anchor", cell.VerticalAlign switch { SmfVerticalAlignment.Top => "t", SmfVerticalAlignment.Middle => "m", SmfVerticalAlignment.Bottom => "b", _ => "t", })); if (cell.Background?.Type == SmfFillType.Solid && cell.Background.SolidColor != null) { tcPr.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", cell.Background.SolidColor.Value)))); } tcPr.Add(WrTblBorder("lnL", cell.LeftBorder)); tcPr.Add(WrTblBorder("lnR", cell.RightBorder)); tcPr.Add(WrTblBorder("lnT", cell.TopBorder)); tcPr.Add(WrTblBorder("lnB", cell.BottomBorder)); tc.Add(tcPr); if (cell.Content != null) tc.Add(WrCellTxBody(cell.Content)); else tc.Add(new XElement(A + "txBody", new XElement(A + "bodyPr"), new XElement(A + "p"))); tr.Add(tc); } tbl.Add(tr); } gv.Element(A + "graphicData")?.Add(tbl); gf.Add(gv); spTree.Add(gf); } private void WriteInk(SmfInkElement elem, XElement spTree, ref int shapeId) { foreach (var stroke in elem.Strokes) { var sp = new XElement(P + "sp"); sp.Add(new XElement(P + "nvSpPr", new XElement(P + "cNvPr", new XAttribute("id", shapeId++), new XAttribute("name", $"Ink{shapeId - 1}")), new XElement(P + "cNvSpPr"), new XElement(P + "nvPr"))); var minX = stroke.Points.Min(p => p.X); var minY = stroke.Points.Min(p => p.Y); var maxX = stroke.Points.Max(p => p.X); var maxY = stroke.Points.Max(p => p.Y); var spPr = new XElement(P + "spPr"); spPr.Add(new XElement(A + "xfrm", new XElement(A + "off", new XAttribute("x", minX), new XAttribute("y", minY)), new XElement(A + "ext", new XAttribute("cx", maxX - minX), new XAttribute("cy", maxY - minY)))); spPr.Add(new XElement(A + "prstGeom", new XAttribute("prst", "rect"), new XElement(A + "avLst"))); var ln = new XElement(A + "ln", new XAttribute("w", stroke.Width * 12700)); ln.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", stroke.Color.Value)))); if (stroke.IsHighlighter) { ln.Add(new XElement(A + "round")); } spPr.Add(ln); sp.Add(spPr); var txBody = new XElement(P + "txBody", new XElement(A + "bodyPr"), new XElement(A + "p")); sp.Add(txBody); spTree.Add(sp); } } private XElement WrXfrm(SmfBounds bounds, double rotation) { var xfrm = new XElement(A + "xfrm"); if (rotation != 0) xfrm.Add(new XAttribute("rot", (int)(rotation * 60000))); xfrm.Add(new XElement(A + "off", new XAttribute("x", bounds.X), new XAttribute("y", bounds.Y))); xfrm.Add(new XElement(A + "ext", new XAttribute("cx", bounds.Width), new XAttribute("cy", bounds.Height))); return xfrm; } private XElement WrTxBody(SmfRichText rt) { var txBody = new XElement(P + "txBody"); var bodyPr = new XElement(A + "bodyPr"); bodyPr.Add(new XAttribute("lIns", rt.LeftMargin)); bodyPr.Add(new XAttribute("rIns", rt.RightMargin)); bodyPr.Add(new XAttribute("tIns", rt.TopMargin)); bodyPr.Add(new XAttribute("bIns", rt.BottomMargin)); bodyPr.Add(new XAttribute("wrap", rt.WordWrap ? "square" : "none")); bodyPr.Add(new XAttribute("anchor", rt.VerticalAlignment switch { SmfVerticalAlignment.Top => "t", SmfVerticalAlignment.Middle => "m", SmfVerticalAlignment.Bottom => "b", _ => "t", })); if (rt.AutoFit) bodyPr.Add(new XElement(A + "normAutofit")); txBody.Add(bodyPr); if (rt.Paragraphs.Count == 0) { txBody.Add(new XElement(A + "p")); return txBody; } foreach (var para in rt.Paragraphs) { var pElem = new XElement(A + "p"); if (para.Alignment != null || para.SpaceBefore != null || para.SpaceAfter != null || para.LineSpacing != null) { var pPr = new XElement(A + "pPr"); if (para.Alignment != null) { pPr.Add(new XAttribute("algn", para.Alignment switch { SmfHorizontalAlignment.Left => "l", SmfHorizontalAlignment.Center => "ctr", SmfHorizontalAlignment.Right => "r", SmfHorizontalAlignment.Justify => "just", _ => "l", })); } if (para.SpaceBefore != null) pPr.Add(new XAttribute("spcBef", para.SpaceBefore.Value)); if (para.SpaceAfter != null) pPr.Add(new XAttribute("spcAft", para.SpaceAfter.Value)); if (para.LineSpacing != null) { pPr.Add(new XElement(A + "lnSpc", new XElement(A + "spcPct", new XAttribute("val", (int)(para.LineSpacing.Value * 100000))))); } pElem.Add(pPr); } if (para.Runs.Count == 0) { pElem.Add(new XElement(A + "endParaRPr")); } else { foreach (var run in para.Runs) { var rElem = new XElement(A + "r"); if (run.Formatting != null) { var rPr = new XElement(A + "rPr"); if (run.Formatting.Size != null) rPr.Add(new XAttribute("sz", (int)(run.Formatting.Size.Value * 100))); if (run.Formatting.Bold == true) rPr.Add(new XAttribute("b", 1)); if (run.Formatting.Italic == true) rPr.Add(new XAttribute("i", 1)); if (run.Formatting.Underline == true) rPr.Add(new XAttribute("u", "sng")); if (run.Formatting.Strikethrough == true) rPr.Add(new XAttribute("strike", "sngStrike")); if (run.Formatting.Color != null) rPr.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", run.Formatting.Color.Value)))); if (run.Formatting.Font != null) rPr.Add(new XElement(A + "latin", new XAttribute("typeface", run.Formatting.Font))); if (rPr.HasAttributes || rPr.HasElements) rElem.Add(rPr); } rElem.Add(new XElement(A + "t", new XText(run.Text))); pElem.Add(rElem); } } txBody.Add(pElem); } return txBody; } private XElement WrCellTxBody(SmfRichText rt) { var txBody = new XElement(A + "txBody"); var bodyPr = new XElement(A + "bodyPr"); bodyPr.Add(new XAttribute("anchor", rt.VerticalAlignment switch { SmfVerticalAlignment.Top => "t", SmfVerticalAlignment.Middle => "m", SmfVerticalAlignment.Bottom => "b", _ => "t", })); txBody.Add(bodyPr); if (rt.Paragraphs.Count == 0) { txBody.Add(new XElement(A + "p")); } else { foreach (var para in rt.Paragraphs) { var pElem = new XElement(A + "p"); if (para.Runs.Count == 0) { pElem.Add(new XElement(A + "endParaRPr")); } else { foreach (var run in para.Runs) { var rElem = new XElement(A + "r"); if (run.Formatting != null) { var rPr = new XElement(A + "rPr"); if (run.Formatting.Size != null) rPr.Add(new XAttribute("sz", (int)(run.Formatting.Size.Value * 100))); if (run.Formatting.Bold == true) rPr.Add(new XAttribute("b", 1)); if (run.Formatting.Italic == true) rPr.Add(new XAttribute("i", 1)); if (run.Formatting.Color != null) rPr.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", run.Formatting.Color.Value)))); if (run.Formatting.Font != null) rPr.Add(new XElement(A + "latin", new XAttribute("typeface", run.Formatting.Font))); if (rPr.HasAttributes || rPr.HasElements) rElem.Add(rPr); } rElem.Add(new XElement(A + "t", new XText(run.Text))); pElem.Add(rElem); } } txBody.Add(pElem); } } return txBody; } private XElement WrGradient(SmfGradientFill grad) { var gradFill = new XElement(A + "gradFill"); var gsLst = new XElement(A + "gsLst"); foreach (var stop in grad.Stops) { var gs = new XElement(A + "gs", new XAttribute("pos", (int)(stop.Position * 1000))); gs.Add(new XElement(A + "srgbClr", new XAttribute("val", stop.Color.Value))); gsLst.Add(gs); } gradFill.Add(gsLst); if (grad.Type == SmfGradientType.Linear) { gradFill.Add(new XElement(A + "lin", new XAttribute("ang", (int)(grad.Angle * 60000)), new XAttribute("scaled", 1))); } else { gradFill.Add(new XElement(A + "path", new XAttribute("path", grad.Type switch { SmfGradientType.Radial => "circle", SmfGradientType.Rectangular => "rect", SmfGradientType.Path => "shape", _ => "circle", }))); } return gradFill; } private XElement WrStroke(SmfStroke stroke) { var ln = new XElement(A + "ln", new XAttribute("w", stroke.Width)); if (stroke.Color != null) { ln.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", stroke.Color.Value)))); } if (stroke.DashStyle != SmfStrokeDashStyle.Solid) { ln.Add(new XElement(A + "prstDash", new XAttribute("val", stroke.DashStyle switch { SmfStrokeDashStyle.Dash => "dash", SmfStrokeDashStyle.Dot => "dot", SmfStrokeDashStyle.DashDot => "dashDot", SmfStrokeDashStyle.LongDash => "lgDash", SmfStrokeDashStyle.LongDashDot => "lgDashDot", SmfStrokeDashStyle.DashDotDot => "dashDotDot", _ => "solid", }))); } return ln; } private XElement WrTblBorder(string name, SmfTableBorder border) { var ln = new XElement(A + name, new XAttribute("w", border.Width)); if (border.Style != SmfTableBorderStyle.None) { ln.Add(new XAttribute("cmpd", "sng")); var dashVal = border.Style switch { SmfTableBorderStyle.Dashed => "dash", SmfTableBorderStyle.Dotted => "dot", _ => "solid", }; ln.Add(new XElement(A + "prstDash", new XAttribute("val", dashVal))); } ln.Add(new XElement(A + "solidFill", new XElement(A + "srgbClr", new XAttribute("val", border.Color)))); return ln; } private void WriteMediaFiles(SmfDocument doc, Package pptx) { foreach (var (fileName, data) in doc.MediaFiles) { var mediaUri = PackUriHelper.CreatePartUri(new Uri($"/ppt/media/{fileName}", UriKind.Relative)); var contentType = doc.MediaContentTypes.TryGetValue(fileName, out var ct) ? ct : "application/octet-stream"; var part = pptx.CreatePart(mediaUri, contentType); using var stream = part.GetStream(); stream.Write(data, 0, data.Length); } } private static string ShapeTypeToPrst(SmfShapeType type) { return type switch { SmfShapeType.Rectangle => "rect", SmfShapeType.Ellipse => "ellipse", SmfShapeType.Triangle => "triangle", SmfShapeType.RoundedRectangle => "roundRect", SmfShapeType.Diamond => "diamond", SmfShapeType.Parallelogram => "parallelogram", SmfShapeType.Trapezoid => "trapezoid", SmfShapeType.Pentagon => "pentagon", SmfShapeType.Hexagon => "hexagon", SmfShapeType.Octagon => "octagon", SmfShapeType.Star => "star5", SmfShapeType.ArrowRight => "arrow", SmfShapeType.ArrowLeft => "leftArrow", SmfShapeType.ArrowUp => "upArrow", SmfShapeType.ArrowDown => "downArrow", SmfShapeType.Line => "line", SmfShapeType.LineArrow => "straightConnector1", SmfShapeType.Cloud => "cloud", SmfShapeType.Heart => "heart", SmfShapeType.Cross => "cross", SmfShapeType.Chevron => "chevron", SmfShapeType.Pie => "pie", SmfShapeType.BlockArc => "blockArc", SmfShapeType.RightTriangle => "rtTriangle", SmfShapeType.RegularPentagon => "pentagon", _ => "rect", }; } private void CreateContentTypes(Package pptx, int slideCount) { var uri = PackUriHelper.CreatePartUri(new Uri("/[Content_Types].xml", UriKind.Relative)); var part = pptx.CreatePart(uri, "application/xml"); using (var sw = new StreamWriter(part.GetStream())) { sw.Write("", CT.NamespaceName); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); for (int i = 0; i < slideCount; i++) sw.Write($""); sw.Write(""); sw.Write(""); sw.Write(""); sw.Write(""); } } private void CreateMinimalTheme(Package pptx) { var themeUri = PackUriHelper.CreatePartUri(new Uri("/ppt/theme/theme1.xml", UriKind.Relative)); var themePart = pptx.CreatePart(themeUri, "application/vnd.openxmlformats-officedocument.theme+xml"); using (var sw = new StreamWriter(themePart.GetStream())) { sw.Write("", A.NamespaceName); } } private void CreateMinimalSlideMaster(Package pptx) { var masterUri = PackUriHelper.CreatePartUri(new Uri("/ppt/slideMasters/slideMaster1.xml", UriKind.Relative)); var masterPart = pptx.CreatePart(masterUri, "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"); using (var sw = new StreamWriter(masterPart.GetStream())) { sw.Write("", A.NamespaceName, R.NamespaceName, P.NamespaceName); } var masterRelUri = PackUriHelper.CreatePartUri(new Uri("/ppt/slideMasters/_rels/slideMaster1.xml.rels", UriKind.Relative)); var masterRelPart = pptx.CreatePart(masterRelUri, "application/vnd.openxmlformats-package.relationships+xml"); using (var sw = new StreamWriter(masterRelPart.GetStream())) { sw.Write("", Rel.NamespaceName, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout"); } } private void CreateMinimalSlideLayout(Package pptx) { var layoutUri = PackUriHelper.CreatePartUri(new Uri("/ppt/slideLayouts/slideLayout1.xml", UriKind.Relative)); var layoutPart = pptx.CreatePart(layoutUri, "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"); using (var sw = new StreamWriter(layoutPart.GetStream())) { sw.Write("", A.NamespaceName, R.NamespaceName, P.NamespaceName); } } private void CreatePresProps(Package pptx) { var uri = PackUriHelper.CreatePartUri(new Uri("/ppt/presProps.xml", UriKind.Relative)); var part = pptx.CreatePart(uri, "application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"); using (var sw = new StreamWriter(part.GetStream())) sw.Write("", P.NamespaceName); } private void CreateViewProps(Package pptx) { var uri = PackUriHelper.CreatePartUri(new Uri("/ppt/viewProps.xml", UriKind.Relative)); var part = pptx.CreatePart(uri, "application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml"); using (var sw = new StreamWriter(part.GetStream())) sw.Write("", P.NamespaceName); } } }