fix: 修复 SmfFillType 缺少 Image 及 EnbxReader XDocument/XElement 类型错误
This commit is contained in:
573
Manager/Services/Conversion/EnbxReader.cs
Normal file
573
Manager/Services/Conversion/EnbxReader.cs
Normal file
@@ -0,0 +1,573 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Packaging;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace BetterSeewo.Manager.Services.Conversion
|
||||
{
|
||||
public class EnbxReader
|
||||
{
|
||||
private int _nextId;
|
||||
|
||||
public SmfDocument Import(string enbxPath)
|
||||
{
|
||||
using var package = Package.Open(enbxPath, FileMode.Open, FileAccess.Read);
|
||||
return Import(package);
|
||||
}
|
||||
|
||||
public SmfDocument Import(Package enbx)
|
||||
{
|
||||
_nextId = 1;
|
||||
var doc = new SmfDocument();
|
||||
|
||||
ExtractMediaFiles(enbx, doc);
|
||||
|
||||
var docPart = FindDocumentPart(enbx);
|
||||
if (docPart != null)
|
||||
{
|
||||
var docXml = XDocument.Load(docPart.GetStream());
|
||||
ParseDocumentXml(docXml.Root ?? throw new InvalidOperationException("Missing document root"), doc, enbx);
|
||||
}
|
||||
else
|
||||
{
|
||||
var mainDocPart = enbx.GetPart(
|
||||
PackUriHelper.CreatePartUri(new Uri("/document.xml", UriKind.Relative)));
|
||||
var mainDoc = XDocument.Load(mainDocPart.GetStream());
|
||||
ParseSlideBasedFormat(mainDoc, doc, enbx);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
private void ExtractMediaFiles(Package enbx, SmfDocument doc)
|
||||
{
|
||||
foreach (var part in enbx.GetParts())
|
||||
{
|
||||
var uri = part.Uri.ToString();
|
||||
if (uri.StartsWith("/media/", StringComparison.OrdinalIgnoreCase) ||
|
||||
uri.StartsWith("/ppt/media/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var fileName = Path.GetFileName(uri);
|
||||
using var stream = part.GetStream();
|
||||
var data = new byte[stream.Length];
|
||||
stream.Read(data, 0, data.Length);
|
||||
doc.MediaFiles[fileName] = data;
|
||||
doc.MediaContentTypes[fileName] = part.ContentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PackagePart? FindDocumentPart(Package enbx)
|
||||
{
|
||||
var relsUri = PackUriHelper.CreatePartUri(new Uri("/_rels/.rels", UriKind.Relative));
|
||||
if (!enbx.PartExists(relsUri)) return null;
|
||||
|
||||
var relsPart = enbx.GetPart(relsUri);
|
||||
var rels = XDocument.Load(relsPart.GetStream());
|
||||
foreach (var rel in rels.Root?.Elements("Relationship") ?? Enumerable.Empty<XElement>())
|
||||
{
|
||||
var type = (string)rel.Attribute("Type") ?? "";
|
||||
if (type.Contains("document") || type.Contains("officeDocument"))
|
||||
{
|
||||
var target = (string)rel.Attribute("Target") ?? "";
|
||||
var targetUri = PackUriHelper.CreatePartUri(new Uri(target, UriKind.Relative));
|
||||
if (enbx.PartExists(targetUri))
|
||||
return enbx.GetPart(targetUri);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ParseDocumentXml(XElement docXml, SmfDocument doc, Package enbx)
|
||||
{
|
||||
var root = docXml;
|
||||
var enNs = root.GetDefaultNamespace();
|
||||
|
||||
var props = root.Element(enNs + "Properties");
|
||||
if (props != null)
|
||||
{
|
||||
var sw = (string?)props.Element(enNs + "SlideWidth");
|
||||
var sh = (string?)props.Element(enNs + "SlideHeight");
|
||||
doc.Properties.SlideWidth = sw != null ? double.Parse(sw, CultureInfo.InvariantCulture) : 12192000;
|
||||
doc.Properties.SlideHeight = sh != null ? double.Parse(sh, CultureInfo.InvariantCulture) : 6858000;
|
||||
doc.Properties.Title = (string?)props.Element(enNs + "Title") ?? "";
|
||||
doc.Properties.Author = (string?)props.Element(enNs + "Author") ?? "";
|
||||
}
|
||||
|
||||
var board = root.Element("Board");
|
||||
if (board != null)
|
||||
{
|
||||
doc.Properties.SlideWidth = (double?)board.Element("SlideWidth") ?? 12192000;
|
||||
doc.Properties.SlideHeight = (double?)board.Element("SlideHeight") ?? 6858000;
|
||||
}
|
||||
|
||||
var slidesEl = root.Element(enNs + "Slides") ?? root.Element("Slides");
|
||||
if (slidesEl != null)
|
||||
{
|
||||
int slideNum = 0;
|
||||
foreach (var slideRef in slidesEl.Elements(enNs + "SlideRef"))
|
||||
{
|
||||
slideNum++;
|
||||
var target = (string)slideRef ?? $"slides/slide{slideNum}.xml";
|
||||
var slidePart = FindSlidePart(enbx, target, slideNum);
|
||||
if (slidePart != null)
|
||||
{
|
||||
var slideXml = XDocument.Load(slidePart.GetStream());
|
||||
ParseSlideXml(slideXml, doc, slideNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseSlideBasedFormat(XDocument mainDoc, SmfDocument doc, Package enbx)
|
||||
{
|
||||
var root = mainDoc.Root;
|
||||
if (root == null) return;
|
||||
|
||||
var board = root.Element("Board");
|
||||
if (board != null)
|
||||
{
|
||||
doc.Properties.SlideWidth = (double?)board.Element("SlideWidth") ?? 12192000;
|
||||
doc.Properties.SlideHeight = (double?)board.Element("SlideHeight") ?? 6858000;
|
||||
}
|
||||
|
||||
var slidesEl = root.Element("Slides");
|
||||
if (slidesEl != null)
|
||||
{
|
||||
int idx = 0;
|
||||
foreach (var slideEl in slidesEl.Elements("SlideSaveInfo"))
|
||||
{
|
||||
idx++;
|
||||
var slide = new SmfSlide
|
||||
{
|
||||
Id = (string)slideEl.Element("Id") ?? $"slide_{idx}",
|
||||
};
|
||||
ParseLegacyElements(slideEl, slide);
|
||||
doc.Slides.Add(slide);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseSlideXml(XDocument slideXml, SmfDocument doc, int slideNum)
|
||||
{
|
||||
var root = slideXml.Root ?? throw new InvalidOperationException("Missing slide root");
|
||||
var enNs = root.GetDefaultNamespace();
|
||||
var slide = new SmfSlide { Id = $"slide_{slideNum}" };
|
||||
|
||||
var bg = root.Element(enNs + "Background");
|
||||
if (bg != null)
|
||||
{
|
||||
var solidFill = bg.Element(enNs + "SolidFill");
|
||||
if (solidFill != null)
|
||||
{
|
||||
slide.Background.Type = SmfFillType.Solid;
|
||||
var color = (string?)solidFill.Element(enNs + "Color");
|
||||
if (color != null) slide.Background.SolidColor = new SmfColor { Value = color };
|
||||
}
|
||||
|
||||
var gradFill = bg.Element(enNs + "GradientFill");
|
||||
if (gradFill != null)
|
||||
{
|
||||
slide.Background.Type = SmfFillType.Gradient;
|
||||
slide.Background.Gradient = new SmfGradientFill
|
||||
{
|
||||
Type = Enum.TryParse<SmfGradientType>((string?)gradFill.Element(enNs + "Type"), out var gt) ? gt : SmfGradientType.Linear,
|
||||
Angle = (double?)gradFill.Element(enNs + "Angle") ?? 0,
|
||||
};
|
||||
foreach (var stop in gradFill.Elements(enNs + "Stop"))
|
||||
{
|
||||
slide.Background.Gradient.Stops.Add(new SmfGradientStop
|
||||
{
|
||||
Position = (double?)stop.Element(enNs + "Position") ?? 0,
|
||||
Color = new SmfColor { Value = (string?)stop.Element(enNs + "Color") ?? "000000" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var imgFill = bg.Element(enNs + "ImageFill");
|
||||
if (imgFill != null)
|
||||
{
|
||||
slide.Background.Type = SmfFillType.Image;
|
||||
slide.Background.ImageRef = (string?)imgFill.Element(enNs + "Source");
|
||||
}
|
||||
}
|
||||
|
||||
var elementsEl = root.Element(enNs + "Elements");
|
||||
if (elementsEl != null)
|
||||
{
|
||||
foreach (var elemEl in elementsEl.Elements())
|
||||
{
|
||||
var elem = ParseElement(elemEl, enNs);
|
||||
if (elem != null) slide.Elements.Add(elem);
|
||||
}
|
||||
}
|
||||
|
||||
doc.Slides.Add(slide);
|
||||
}
|
||||
|
||||
private SmfElement? ParseElement(XElement elemEl, XNamespace enNs)
|
||||
{
|
||||
var localName = elemEl.Name.LocalName;
|
||||
var id = (string)elemEl.Attribute("Id") ?? NextId();
|
||||
|
||||
switch (localName)
|
||||
{
|
||||
case "TextElement":
|
||||
return ParseTextElement(elemEl, enNs, id);
|
||||
case "ImageElement":
|
||||
return ParseImageElement(elemEl, enNs, id);
|
||||
case "ShapeElement":
|
||||
return ParseShapeElement(elemEl, enNs, id);
|
||||
case "TableElement":
|
||||
return ParseTableElement(elemEl, enNs, id);
|
||||
case "InkElement":
|
||||
return ParseInkElement(elemEl, enNs, id);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private SmfTextElement ParseTextElement(XElement elem, XNamespace enNs, string id)
|
||||
{
|
||||
var te = new SmfTextElement { Id = id };
|
||||
te.Bounds = ParseBounds(elem, enNs);
|
||||
te.Rotation = (double?)elem.Element(enNs + "Rotation") ?? 0;
|
||||
te.Locked = (bool?)elem.Element(enNs + "Locked") ?? false;
|
||||
|
||||
var rt = elem.Element(enNs + "RichText");
|
||||
if (rt != null)
|
||||
{
|
||||
te.RichText.LeftMargin = (double?)rt.Element(enNs + "LeftMargin") ?? 91440;
|
||||
te.RichText.RightMargin = (double?)rt.Element(enNs + "RightMargin") ?? 91440;
|
||||
te.RichText.TopMargin = (double?)rt.Element(enNs + "TopMargin") ?? 91440;
|
||||
te.RichText.BottomMargin = (double?)rt.Element(enNs + "BottomMargin") ?? 91440;
|
||||
te.RichText.WordWrap = (bool?)rt.Element(enNs + "WordWrap") ?? true;
|
||||
|
||||
var vAlign = (string?)rt.Element(enNs + "VerticalAlignment");
|
||||
if (vAlign != null && Enum.TryParse<SmfVerticalAlignment>(vAlign, out var va))
|
||||
te.RichText.VerticalAlignment = va;
|
||||
|
||||
foreach (var para in rt.Elements(enNs + "Paragraph"))
|
||||
{
|
||||
var p = new SmfParagraph();
|
||||
var algn = (string?)para.Element(enNs + "Alignment");
|
||||
if (algn != null && Enum.TryParse<SmfHorizontalAlignment>(algn, out var ha))
|
||||
p.Alignment = ha;
|
||||
p.SpaceBefore = (double?)para.Element(enNs + "SpaceBefore");
|
||||
p.SpaceAfter = (double?)para.Element(enNs + "SpaceAfter");
|
||||
p.LineSpacing = (double?)para.Element(enNs + "LineSpacing");
|
||||
|
||||
foreach (var run in para.Elements(enNs + "Run"))
|
||||
{
|
||||
var r = new SmfRun
|
||||
{
|
||||
Text = (string?)run.Element(enNs + "Text") ?? "",
|
||||
};
|
||||
var fmt = run.Element(enNs + "Formatting");
|
||||
if (fmt != null)
|
||||
{
|
||||
r.Formatting = new SmfFormatting
|
||||
{
|
||||
Size = (double?)fmt.Element(enNs + "Size"),
|
||||
Bold = (bool?)fmt.Element(enNs + "Bold"),
|
||||
Italic = (bool?)fmt.Element(enNs + "Italic"),
|
||||
Underline = (bool?)fmt.Element(enNs + "Underline"),
|
||||
Strikethrough = (bool?)fmt.Element(enNs + "Strikethrough"),
|
||||
Color = ParseSmfColor(fmt.Element(enNs + "Color")),
|
||||
Font = (string?)fmt.Element(enNs + "Font"),
|
||||
};
|
||||
}
|
||||
p.Runs.Add(r);
|
||||
}
|
||||
te.RichText.Paragraphs.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
return te;
|
||||
}
|
||||
|
||||
private SmfImageElement ParseImageElement(XElement elem, XNamespace enNs, string id)
|
||||
{
|
||||
var ie = new SmfImageElement { Id = id };
|
||||
ie.Bounds = ParseBounds(elem, enNs);
|
||||
ie.Rotation = (double?)elem.Element(enNs + "Rotation") ?? 0;
|
||||
ie.Source = (string?)elem.Element(enNs + "Source") ?? "";
|
||||
|
||||
var crop = elem.Element(enNs + "Crop");
|
||||
if (crop != null)
|
||||
{
|
||||
ie.Crop = new SmfCropInfo
|
||||
{
|
||||
Left = (double?)crop.Element(enNs + "Left") ?? 0,
|
||||
Right = (double?)crop.Element(enNs + "Right") ?? 0,
|
||||
Top = (double?)crop.Element(enNs + "Top") ?? 0,
|
||||
Bottom = (double?)crop.Element(enNs + "Bottom") ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
return ie;
|
||||
}
|
||||
|
||||
private SmfShapeElement ParseShapeElement(XElement elem, XNamespace enNs, string id)
|
||||
{
|
||||
var se = new SmfShapeElement { Id = id };
|
||||
se.Bounds = ParseBounds(elem, enNs);
|
||||
se.Rotation = (double?)elem.Element(enNs + "Rotation") ?? 0;
|
||||
se.Locked = (bool?)elem.Element(enNs + "Locked") ?? false;
|
||||
|
||||
var shapeType = (string?)elem.Element(enNs + "ShapeType");
|
||||
if (shapeType != null && Enum.TryParse<SmfShapeType>(shapeType, out var st))
|
||||
se.ShapeType = st;
|
||||
|
||||
var fill = elem.Element(enNs + "Fill");
|
||||
if (fill != null)
|
||||
{
|
||||
var fillType = (string?)fill.Element(enNs + "Type");
|
||||
if (fillType == "Solid")
|
||||
{
|
||||
se.Fill.Type = SmfFillType.Solid;
|
||||
var color = (string?)fill.Element(enNs + "Color");
|
||||
if (color != null) se.Fill.SolidColor = new SmfColor { Value = color };
|
||||
}
|
||||
}
|
||||
|
||||
var stroke = elem.Element(enNs + "Stroke");
|
||||
if (stroke != null)
|
||||
{
|
||||
se.Stroke = new SmfStroke
|
||||
{
|
||||
Color = ParseSmfColor(stroke.Element(enNs + "Color")),
|
||||
Width = (double?)stroke.Element(enNs + "Width") ?? 1,
|
||||
};
|
||||
var dash = (string?)stroke.Element(enNs + "DashStyle");
|
||||
if (dash != null && Enum.TryParse<SmfStrokeDashStyle>(dash, out var ds))
|
||||
se.Stroke.DashStyle = ds;
|
||||
}
|
||||
|
||||
var textContent = elem.Element(enNs + "TextContent");
|
||||
if (textContent != null)
|
||||
{
|
||||
var rt = new SmfRichText();
|
||||
foreach (var para in textContent.Elements(enNs + "Paragraph"))
|
||||
{
|
||||
var p = new SmfParagraph();
|
||||
foreach (var run in para.Elements(enNs + "Run"))
|
||||
{
|
||||
p.Runs.Add(new SmfRun
|
||||
{
|
||||
Text = (string?)run.Element(enNs + "Text") ?? "",
|
||||
});
|
||||
}
|
||||
rt.Paragraphs.Add(p);
|
||||
}
|
||||
se.TextContent = rt;
|
||||
}
|
||||
|
||||
return se;
|
||||
}
|
||||
|
||||
private SmfTableElement ParseTableElement(XElement elem, XNamespace enNs, string id)
|
||||
{
|
||||
var te = new SmfTableElement { Id = id };
|
||||
te.Bounds = ParseBounds(elem, enNs);
|
||||
|
||||
var cols = elem.Element(enNs + "Columns");
|
||||
if (cols != null)
|
||||
{
|
||||
foreach (var col in cols.Elements(enNs + "Column"))
|
||||
te.ColumnWidths.Add((double?)col.Attribute("Width") ?? 100000);
|
||||
}
|
||||
|
||||
var rows = elem.Element(enNs + "Rows");
|
||||
if (rows != null)
|
||||
{
|
||||
foreach (var row in rows.Elements(enNs + "Row"))
|
||||
{
|
||||
var r = new SmfTableRow
|
||||
{
|
||||
Height = (double?)row.Attribute("Height") ?? 500000,
|
||||
};
|
||||
foreach (var cell in row.Elements(enNs + "Cell"))
|
||||
{
|
||||
var c = new SmfTableCell
|
||||
{
|
||||
RowSpan = (int?)cell.Attribute("RowSpan") ?? 1,
|
||||
ColSpan = (int?)cell.Attribute("ColSpan") ?? 1,
|
||||
};
|
||||
var cellRt = cell.Element(enNs + "RichText");
|
||||
if (cellRt != null)
|
||||
{
|
||||
var ct = new SmfRichText();
|
||||
foreach (var para in cellRt.Elements(enNs + "Paragraph"))
|
||||
{
|
||||
var p = new SmfParagraph();
|
||||
foreach (var run in para.Elements(enNs + "Run"))
|
||||
{
|
||||
p.Runs.Add(new SmfRun
|
||||
{
|
||||
Text = (string?)run.Element(enNs + "Text") ?? "",
|
||||
});
|
||||
}
|
||||
ct.Paragraphs.Add(p);
|
||||
}
|
||||
c.Content = ct;
|
||||
}
|
||||
r.Cells.Add(c);
|
||||
}
|
||||
te.Rows.Add(r);
|
||||
}
|
||||
}
|
||||
|
||||
return te;
|
||||
}
|
||||
|
||||
private SmfInkElement ParseInkElement(XElement elem, XNamespace enNs, string id)
|
||||
{
|
||||
var ie = new SmfInkElement { Id = id };
|
||||
|
||||
foreach (var stroke in elem.Elements(enNs + "Stroke"))
|
||||
{
|
||||
var s = new SmfInkStroke
|
||||
{
|
||||
Color = new SmfColor { Value = (string?)stroke.Element(enNs + "Color") ?? "000000" },
|
||||
Width = (double?)stroke.Element(enNs + "Width") ?? 2,
|
||||
IsHighlighter = (bool?)stroke.Element(enNs + "Highlighter") ?? false,
|
||||
Transparency = (double?)stroke.Element(enNs + "Transparency") ?? 0,
|
||||
};
|
||||
|
||||
var pts = stroke.Element(enNs + "Points");
|
||||
if (pts != null)
|
||||
{
|
||||
foreach (var pt in pts.Elements(enNs + "Point"))
|
||||
{
|
||||
s.Points.Add(new SmfInkPoint
|
||||
{
|
||||
X = (double)pt.Attribute("X"),
|
||||
Y = (double)pt.Attribute("Y"),
|
||||
Pressure = (double?)pt.Attribute("P") ?? 0.5,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ie.Strokes.Add(s);
|
||||
}
|
||||
|
||||
return ie;
|
||||
}
|
||||
|
||||
private void ParseLegacyElements(XElement slideEl, SmfSlide slide)
|
||||
{
|
||||
var width = (double?)slideEl.Element("Width") ?? 12192000;
|
||||
var height = (double?)slideEl.Element("Height") ?? 6858000;
|
||||
|
||||
var elements = slideEl.Element("Elements");
|
||||
if (elements == null) return;
|
||||
|
||||
foreach (var elem in elements.Elements())
|
||||
{
|
||||
var localName = elem.Name.LocalName;
|
||||
if (localName == "TextSaveInfo")
|
||||
{
|
||||
var te = new SmfTextElement
|
||||
{
|
||||
Id = (string)elem.Element("Id") ?? NextId(),
|
||||
Bounds = new SmfBounds
|
||||
{
|
||||
X = (double)elem.Element("X"),
|
||||
Y = (double)elem.Element("Y"),
|
||||
Width = (double)elem.Element("Width"),
|
||||
Height = (double)elem.Element("Height"),
|
||||
},
|
||||
Rotation = (double?)elem.Element("Rotation") ?? 0,
|
||||
Locked = (bool?)elem.Element("Locked") ?? false,
|
||||
};
|
||||
|
||||
var richText = elem.Element("RichText");
|
||||
if (richText != null)
|
||||
{
|
||||
te.RichText.LeftMargin = (double?)richText.Element("LeftMargin") ?? 91440;
|
||||
te.RichText.RightMargin = (double?)richText.Element("RightMargin") ?? 91440;
|
||||
te.RichText.TopMargin = (double?)richText.Element("TopMargin") ?? 91440;
|
||||
te.RichText.BottomMargin = (double?)richText.Element("BottomMargin") ?? 91440;
|
||||
|
||||
foreach (var para in richText.Elements("Paragraph"))
|
||||
{
|
||||
var p = new SmfParagraph();
|
||||
foreach (var run in para.Elements("Run"))
|
||||
{
|
||||
var r = new SmfRun
|
||||
{
|
||||
Text = (string?)run.Element("Text") ?? "",
|
||||
};
|
||||
var fmt = run.Element("Formatting");
|
||||
if (fmt != null)
|
||||
{
|
||||
r.Formatting = new SmfFormatting
|
||||
{
|
||||
Size = (double?)fmt.Element("Size"),
|
||||
Bold = (bool?)fmt.Element("Bold"),
|
||||
Italic = (bool?)fmt.Element("Italic"),
|
||||
Color = ParseColorAttr(fmt.Element("Color")),
|
||||
Font = (string?)fmt.Element("Font"),
|
||||
};
|
||||
}
|
||||
p.Runs.Add(r);
|
||||
}
|
||||
te.RichText.Paragraphs.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
slide.Elements.Add(te);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SmfBounds ParseBounds(XElement parent, XNamespace enNs)
|
||||
{
|
||||
var b = parent.Element(enNs + "Bounds");
|
||||
if (b == null) return new SmfBounds();
|
||||
return new SmfBounds
|
||||
{
|
||||
X = (double?)b.Element(enNs + "X") ?? 0,
|
||||
Y = (double?)b.Element(enNs + "Y") ?? 0,
|
||||
Width = (double?)b.Element(enNs + "Width") ?? 0,
|
||||
Height = (double?)b.Element(enNs + "Height") ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
private SmfColor? ParseSmfColor(XElement? el)
|
||||
{
|
||||
if (el == null) return null;
|
||||
return new SmfColor { Value = el.Value };
|
||||
}
|
||||
|
||||
private SmfColor? ParseColorAttr(XElement? el)
|
||||
{
|
||||
if (el == null) return null;
|
||||
return new SmfColor { Value = el.Value };
|
||||
}
|
||||
|
||||
private PackagePart? FindSlidePart(Package enbx, string target, int slideNum)
|
||||
{
|
||||
var possiblePaths = new[]
|
||||
{
|
||||
target,
|
||||
$"/{target}",
|
||||
$"/slides/slide{slideNum}.xml",
|
||||
$"slides/slide{slideNum}.xml",
|
||||
};
|
||||
foreach (var path in possiblePaths)
|
||||
{
|
||||
var uri = PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative));
|
||||
if (enbx.PartExists(uri))
|
||||
return enbx.GetPart(uri);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string NextId() => $"elem_{_nextId++}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user