fix: 修复 SmfFillType 缺少 Image 及 EnbxReader XDocument/XElement 类型错误

This commit is contained in:
雾启工作室
2026-06-28 11:45:45 +08:00
parent 08bcb77eb1
commit 8c9c62fb74
16 changed files with 5754 additions and 1024 deletions

View File

@@ -0,0 +1,827 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Xml.Linq;
namespace BetterEN5.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("<?xml version=\"1.0\" encoding=\"utf-8\"?><Relationships xmlns=\"{0}\"><Relationship Id=\"rId1\" Type=\"{1}\" Target=\"ppt/presentation.xml\"/></Relationships>",
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<XDocument> 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<XDocument>();
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<XDocument> 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("<?xml version=\"1.0\" encoding=\"utf-8\"?><Types xmlns=\"{0}\">", CT.NamespaceName);
sw.Write("<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>");
sw.Write("<Default Extension=\"xml\" ContentType=\"application/xml\"/>");
sw.Write("<Default Extension=\"png\" ContentType=\"image/png\"/>");
sw.Write("<Default Extension=\"jpg\" ContentType=\"image/jpeg\"/>");
sw.Write("<Default Extension=\"jpeg\" ContentType=\"image/jpeg\"/>");
sw.Write("<Default Extension=\"gif\" ContentType=\"image/gif\"/>");
sw.Write("<Default Extension=\"bmp\" ContentType=\"image/bmp\"/>");
sw.Write("<Default Extension=\"svg\" ContentType=\"image/svg+xml\"/>");
sw.Write("<Default Extension=\"mp4\" ContentType=\"video/mp4\"/>");
sw.Write("<Default Extension=\"mp3\" ContentType=\"audio/mpeg\"/>");
sw.Write("<Default Extension=\"wav\" ContentType=\"audio/wav\"/>");
sw.Write("<Override PartName=\"/ppt/presentation.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml\"/>");
sw.Write("<Override PartName=\"/ppt/slideMasters/slideMaster1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml\"/>");
sw.Write("<Override PartName=\"/ppt/slideLayouts/slideLayout1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml\"/>");
for (int i = 0; i < slideCount; i++)
sw.Write($"<Override PartName=\"/ppt/slides/slide{i + 1}.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.presentationml.slide+xml\"/>");
sw.Write("<Override PartName=\"/ppt/presProps.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.presentationml.presProps+xml\"/>");
sw.Write("<Override PartName=\"/ppt/viewProps.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml\"/>");
sw.Write("<Override PartName=\"/ppt/theme/theme1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.theme+xml\"/>");
sw.Write("</Types>");
}
}
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("<?xml version=\"1.0\" encoding=\"utf-8\"?><a:theme xmlns:a=\"{0}\" name=\"Default\"><a:themeElements><a:clrScheme name=\"Default\"><a:dk1><a:srgbClr val=\"000000\"/></a:dk1><a:lt1><a:srgbClr val=\"FFFFFF\"/></a:lt1><a:dk2><a:srgbClr val=\"1F1F1F\"/></a:dk2><a:lt2><a:srgbClr val=\"FFFFFF\"/></a:lt2><a:accent1><a:srgbClr val=\"4472C4\"/></a:accent1><a:accent2><a:srgbClr val=\"ED7D31\"/></a:accent2><a:accent3><a:srgbClr val=\"A5A5A5\"/></a:accent3><a:accent4><a:srgbClr val=\"FFC000\"/></a:accent4><a:accent5><a:srgbClr val=\"5B9BD5\"/></a:accent5><a:accent6><a:srgbClr val=\"70AD47\"/></a:accent6><a:hlink><a:srgbClr val=\"0563C1\"/></a:hlink><a:folHlink><a:srgbClr val=\"954F72\"/></a:folHlink></a:clrScheme><a:fontScheme name=\"Default\"><a:majorFont><a:latin typeface=\"Calibri Light\"/></a:majorFont><a:minorFont><a:latin typeface=\"Calibri\"/></a:minorFont></a:fontScheme><a:fmtScheme name=\"Default\"/></a:themeElements></a:theme>",
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("<?xml version=\"1.0\" encoding=\"utf-8\"?><p:sldMaster xmlns:a=\"{0}\" xmlns:r=\"{1}\" xmlns:p=\"{2}\"><p:cSld><p:spTree><p:nvGrpSpPr><p:nvPr><p:cNvPr id=\"1\"/><p:cNvGrpSpPr/></p:nvPr></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"0\" cy=\"0\"/><a:chOff x=\"0\" y=\"0\"/><a:chExt cx=\"0\" cy=\"0\"/></a:xfrm></p:grpSpPr></p:spTree></p:cSld><p:sldLayoutIdLst><p:sldLayoutId id=\"2147483649\" r:id=\"rId1\"/></p:sldLayoutIdLst></p:sldMaster>",
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("<?xml version=\"1.0\" encoding=\"utf-8\"?><Relationships xmlns=\"{0}\"><Relationship Id=\"rId1\" Type=\"{1}\" Target=\"../slideLayouts/slideLayout1.xml\"/></Relationships>",
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("<?xml version=\"1.0\" encoding=\"utf-8\"?><p:sldLayout xmlns:a=\"{0}\" xmlns:r=\"{1}\" xmlns:p=\"{2}\" type=\"blank\"><p:cSld><p:spTree><p:nvGrpSpPr><p:nvPr><p:cNvPr id=\"1\"/><p:cNvGrpSpPr/></p:nvPr></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"0\" cy=\"0\"/><a:chOff x=\"0\" y=\"0\"/><a:chExt cx=\"0\" cy=\"0\"/></a:xfrm></p:grpSpPr></p:spTree></p:cSld></p:sldLayout>",
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("<?xml version=\"1.0\" encoding=\"utf-8\"?><p:presProps xmlns:p=\"{0}\"/>", 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("<?xml version=\"1.0\" encoding=\"utf-8\"?><p:viewProps xmlns:p=\"{0}\"/>", P.NamespaceName);
}
}
}