fix: 修复 SmfFillType 缺少 Image 及 EnbxReader XDocument/XElement 类型错误
This commit is contained in:
400
Better-EN5/Services/Conversion/EnbxWriter.cs
Normal file
400
Better-EN5/Services/Conversion/EnbxWriter.cs
Normal file
@@ -0,0 +1,400 @@
|
||||
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 EnbxWriter
|
||||
{
|
||||
private static readonly XNamespace EN = "http://schemas.seewo.com/easinote/2016/document";
|
||||
private static readonly XNamespace DC = "http://purl.org/dc/elements/1.1/";
|
||||
|
||||
public void Export(SmfDocument doc, string enbxPath)
|
||||
{
|
||||
using var enbx = Package.Open(enbxPath, FileMode.Create, FileAccess.ReadWrite);
|
||||
Export(doc, enbx);
|
||||
}
|
||||
|
||||
public void Export(SmfDocument doc, Package enbx)
|
||||
{
|
||||
WriteContentTypes(enbx);
|
||||
WritePackageRels(enbx);
|
||||
WriteMediaFiles(doc, enbx);
|
||||
|
||||
var slideRelTargets = new List<string>();
|
||||
for (int i = 0; i < doc.Slides.Count; i++)
|
||||
{
|
||||
var slideFileName = $"slides/slide{i + 1}.xml";
|
||||
slideRelTargets.Add(slideFileName);
|
||||
|
||||
var slideDoc = BuildSlideXml(doc.Slides[i], doc, i + 1);
|
||||
var slideUri = PackUriHelper.CreatePartUri(new Uri($"/{slideFileName}", UriKind.Relative));
|
||||
var slidePart = enbx.CreatePart(slideUri, "application/vnd.seewo.easinote.slide+xml");
|
||||
using (var sw = new StreamWriter(slidePart.GetStream()))
|
||||
slideDoc.Save(sw);
|
||||
}
|
||||
|
||||
var rootDoc = BuildDocumentXml(doc, slideRelTargets);
|
||||
var docUri = PackUriHelper.CreatePartUri(new Uri("/document.xml", UriKind.Relative));
|
||||
var docPart = enbx.CreatePart(docUri, "application/vnd.seewo.easinote.document+xml");
|
||||
using (var sw = new StreamWriter(docPart.GetStream()))
|
||||
rootDoc.Save(sw);
|
||||
}
|
||||
|
||||
private XDocument BuildDocumentXml(SmfDocument doc, List<string> slideTargets)
|
||||
{
|
||||
var docElem = new XElement(EN + "Document",
|
||||
new XAttribute(XNamespace.Xmlns + "en", EN.NamespaceName),
|
||||
new XAttribute(XNamespace.Xmlns + "dc", DC.NamespaceName));
|
||||
|
||||
var props = new XElement(EN + "Properties",
|
||||
new XElement(EN + "Title", doc.Properties.Title ?? ""),
|
||||
new XElement(EN + "Author", doc.Properties.Author ?? ""),
|
||||
new XElement(EN + "Created", doc.Properties.Created?.ToString("o") ?? ""),
|
||||
new XElement(EN + "Application", doc.Properties.Application ?? "Better-Seewo"),
|
||||
new XElement(EN + "Version", "5.2.4.9855"),
|
||||
new XElement(EN + "SlideWidth", doc.Properties.SlideWidth),
|
||||
new XElement(EN + "SlideHeight", doc.Properties.SlideHeight));
|
||||
docElem.Add(props);
|
||||
|
||||
var slidesElem = new XElement(EN + "Slides");
|
||||
foreach (var target in slideTargets)
|
||||
{
|
||||
slidesElem.Add(new XElement(EN + "SlideRef", target));
|
||||
}
|
||||
docElem.Add(slidesElem);
|
||||
|
||||
return new XDocument(new XDeclaration("1.0", "utf-8", "yes"), docElem);
|
||||
}
|
||||
|
||||
private XDocument BuildSlideXml(SmfSlide slide, SmfDocument doc, int slideNum)
|
||||
{
|
||||
var slideElem = new XElement(EN + "Slide",
|
||||
new XAttribute("Id", slide.Id),
|
||||
new XAttribute("Width", doc.Properties.SlideWidth),
|
||||
new XAttribute("Height", doc.Properties.SlideHeight));
|
||||
|
||||
WriteBackground(slide, slideElem, doc, slideNum);
|
||||
|
||||
var elementsElem = new XElement(EN + "Elements");
|
||||
foreach (var element in slide.Elements)
|
||||
WriteElement(element, elementsElem, doc, slideNum);
|
||||
slideElem.Add(elementsElem);
|
||||
|
||||
return new XDocument(new XDeclaration("1.0", "utf-8", "yes"), slideElem);
|
||||
}
|
||||
|
||||
private void WriteBackground(SmfSlide slide, XElement slideElem, SmfDocument doc, int slideNum)
|
||||
{
|
||||
var bg = slide.Background;
|
||||
if (bg.Type == SmfFillType.None) return;
|
||||
|
||||
var bgElem = new XElement(EN + "Background");
|
||||
switch (bg.Type)
|
||||
{
|
||||
case SmfFillType.Solid when bg.SolidColor != null:
|
||||
bgElem.Add(new XElement(EN + "SolidFill",
|
||||
new XElement(EN + "Color", bg.SolidColor.Value)));
|
||||
break;
|
||||
case SmfFillType.Gradient when bg.Gradient != null:
|
||||
var gradElem = new XElement(EN + "GradientFill",
|
||||
new XElement(EN + "Type", bg.Gradient.Type.ToString()),
|
||||
new XElement(EN + "Angle", bg.Gradient.Angle));
|
||||
foreach (var stop in bg.Gradient.Stops)
|
||||
{
|
||||
gradElem.Add(new XElement(EN + "Stop",
|
||||
new XElement(EN + "Position", stop.Position),
|
||||
new XElement(EN + "Color", stop.Color.Value)));
|
||||
}
|
||||
bgElem.Add(gradElem);
|
||||
break;
|
||||
case SmfFillType.Image when bg.ImageRef != null:
|
||||
bgElem.Add(new XElement(EN + "ImageFill",
|
||||
new XElement(EN + "Source", bg.ImageRef)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (bgElem.HasElements)
|
||||
slideElem.Add(bgElem);
|
||||
}
|
||||
|
||||
private void WriteElement(SmfElement element, XElement elementsElem, SmfDocument doc, int slideNum)
|
||||
{
|
||||
switch (element)
|
||||
{
|
||||
case SmfTextElement te:
|
||||
WriteTextElement(te, elementsElem);
|
||||
break;
|
||||
case SmfImageElement ie:
|
||||
WriteImageElement(ie, elementsElem);
|
||||
break;
|
||||
case SmfShapeElement se:
|
||||
WriteShapeElement(se, elementsElem);
|
||||
break;
|
||||
case SmfTableElement te:
|
||||
WriteTableElement(te, elementsElem);
|
||||
break;
|
||||
case SmfInkElement ie:
|
||||
WriteInkElement(ie, elementsElem);
|
||||
break;
|
||||
case SmfGroupElement ge:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteTextElement(SmfTextElement elem, XElement parent)
|
||||
{
|
||||
var xElem = new XElement(EN + "TextElement",
|
||||
new XAttribute("Id", elem.Id));
|
||||
|
||||
AddBounds(xElem, elem.Bounds);
|
||||
if (elem.Rotation != 0)
|
||||
xElem.Add(new XElement(EN + "Rotation", elem.Rotation));
|
||||
xElem.Add(new XElement(EN + "Locked", elem.Locked));
|
||||
|
||||
var rtElem = new XElement(EN + "RichText");
|
||||
rtElem.Add(new XElement(EN + "LeftMargin", elem.RichText.LeftMargin));
|
||||
rtElem.Add(new XElement(EN + "RightMargin", elem.RichText.RightMargin));
|
||||
rtElem.Add(new XElement(EN + "TopMargin", elem.RichText.TopMargin));
|
||||
rtElem.Add(new XElement(EN + "BottomMargin", elem.RichText.BottomMargin));
|
||||
rtElem.Add(new XElement(EN + "VerticalAlignment", elem.RichText.VerticalAlignment.ToString()));
|
||||
rtElem.Add(new XElement(EN + "WordWrap", elem.RichText.WordWrap));
|
||||
|
||||
foreach (var para in elem.RichText.Paragraphs)
|
||||
{
|
||||
var pElem = new XElement(EN + "Paragraph");
|
||||
if (para.Alignment != null)
|
||||
pElem.Add(new XElement(EN + "Alignment", para.Alignment.ToString()));
|
||||
if (para.SpaceBefore != null)
|
||||
pElem.Add(new XElement(EN + "SpaceBefore", para.SpaceBefore.Value));
|
||||
if (para.SpaceAfter != null)
|
||||
pElem.Add(new XElement(EN + "SpaceAfter", para.SpaceAfter.Value));
|
||||
if (para.LineSpacing != null)
|
||||
pElem.Add(new XElement(EN + "LineSpacing", para.LineSpacing.Value));
|
||||
|
||||
foreach (var run in para.Runs)
|
||||
{
|
||||
var rElem = new XElement(EN + "Run",
|
||||
new XElement(EN + "Text", run.Text));
|
||||
if (run.Formatting != null)
|
||||
{
|
||||
var fElem = new XElement(EN + "Formatting");
|
||||
if (run.Formatting.Size != null) fElem.Add(new XElement(EN + "Size", run.Formatting.Size.Value));
|
||||
if (run.Formatting.Bold != null) fElem.Add(new XElement(EN + "Bold", run.Formatting.Bold.Value));
|
||||
if (run.Formatting.Italic != null) fElem.Add(new XElement(EN + "Italic", run.Formatting.Italic.Value));
|
||||
if (run.Formatting.Underline != null) fElem.Add(new XElement(EN + "Underline", run.Formatting.Underline.Value));
|
||||
if (run.Formatting.Strikethrough != null) fElem.Add(new XElement(EN + "Strikethrough", run.Formatting.Strikethrough.Value));
|
||||
if (run.Formatting.Color != null) fElem.Add(new XElement(EN + "Color", run.Formatting.Color.Value));
|
||||
if (run.Formatting.Font != null) fElem.Add(new XElement(EN + "Font", run.Formatting.Font));
|
||||
if (fElem.HasElements) rElem.Add(fElem);
|
||||
}
|
||||
pElem.Add(rElem);
|
||||
}
|
||||
|
||||
if (pElem.HasElements)
|
||||
rtElem.Add(pElem);
|
||||
}
|
||||
xElem.Add(rtElem);
|
||||
|
||||
parent.Add(xElem);
|
||||
}
|
||||
|
||||
private void WriteImageElement(SmfImageElement elem, XElement parent)
|
||||
{
|
||||
var xElem = new XElement(EN + "ImageElement",
|
||||
new XAttribute("Id", elem.Id));
|
||||
AddBounds(xElem, elem.Bounds);
|
||||
if (elem.Rotation != 0)
|
||||
xElem.Add(new XElement(EN + "Rotation", elem.Rotation));
|
||||
xElem.Add(new XElement(EN + "Source", elem.Source));
|
||||
|
||||
if (elem.Crop != null)
|
||||
{
|
||||
xElem.Add(new XElement(EN + "Crop",
|
||||
new XElement(EN + "Left", elem.Crop.Left),
|
||||
new XElement(EN + "Right", elem.Crop.Right),
|
||||
new XElement(EN + "Top", elem.Crop.Top),
|
||||
new XElement(EN + "Bottom", elem.Crop.Bottom)));
|
||||
}
|
||||
|
||||
parent.Add(xElem);
|
||||
}
|
||||
|
||||
private void WriteShapeElement(SmfShapeElement elem, XElement parent)
|
||||
{
|
||||
var xElem = new XElement(EN + "ShapeElement",
|
||||
new XAttribute("Id", elem.Id));
|
||||
AddBounds(xElem, elem.Bounds);
|
||||
if (elem.Rotation != 0)
|
||||
xElem.Add(new XElement(EN + "Rotation", elem.Rotation));
|
||||
xElem.Add(new XElement(EN + "ShapeType", elem.ShapeType.ToString()));
|
||||
|
||||
var fillElem = new XElement(EN + "Fill");
|
||||
fillElem.Add(new XElement(EN + "Type", elem.Fill.Type.ToString()));
|
||||
if (elem.Fill.SolidColor != null)
|
||||
fillElem.Add(new XElement(EN + "Color", elem.Fill.SolidColor.Value));
|
||||
if (fillElem.HasElements) xElem.Add(fillElem);
|
||||
|
||||
if (elem.Stroke != null)
|
||||
{
|
||||
var sElem = new XElement(EN + "Stroke");
|
||||
if (elem.Stroke.Color != null)
|
||||
sElem.Add(new XElement(EN + "Color", elem.Stroke.Color.Value));
|
||||
sElem.Add(new XElement(EN + "Width", elem.Stroke.Width));
|
||||
sElem.Add(new XElement(EN + "DashStyle", elem.Stroke.DashStyle.ToString()));
|
||||
xElem.Add(sElem);
|
||||
}
|
||||
|
||||
if (elem.TextContent != null)
|
||||
{
|
||||
var rtElem = new XElement(EN + "TextContent");
|
||||
foreach (var para in elem.TextContent.Paragraphs)
|
||||
{
|
||||
var pElem = new XElement(EN + "Paragraph");
|
||||
foreach (var run in para.Runs)
|
||||
{
|
||||
pElem.Add(new XElement(EN + "Run",
|
||||
new XElement(EN + "Text", run.Text)));
|
||||
}
|
||||
if (pElem.HasElements) rtElem.Add(pElem);
|
||||
}
|
||||
xElem.Add(rtElem);
|
||||
}
|
||||
|
||||
xElem.Add(new XElement(EN + "Locked", elem.Locked));
|
||||
|
||||
parent.Add(xElem);
|
||||
}
|
||||
|
||||
private void WriteTableElement(SmfTableElement elem, XElement parent)
|
||||
{
|
||||
var xElem = new XElement(EN + "TableElement",
|
||||
new XAttribute("Id", elem.Id));
|
||||
AddBounds(xElem, elem.Bounds);
|
||||
|
||||
var colsElem = new XElement(EN + "Columns");
|
||||
foreach (var w in elem.ColumnWidths)
|
||||
colsElem.Add(new XElement(EN + "Column", new XAttribute("Width", w)));
|
||||
xElem.Add(colsElem);
|
||||
|
||||
var rowsElem = new XElement(EN + "Rows");
|
||||
foreach (var row in elem.Rows)
|
||||
{
|
||||
var rElem = new XElement(EN + "Row", new XAttribute("Height", row.Height));
|
||||
foreach (var cell in row.Cells)
|
||||
{
|
||||
var cElem = new XElement(EN + "Cell");
|
||||
if (cell.RowSpan > 1) cElem.Add(new XAttribute("RowSpan", cell.RowSpan));
|
||||
if (cell.ColSpan > 1) cElem.Add(new XAttribute("ColSpan", cell.ColSpan));
|
||||
if (cell.Content != null)
|
||||
{
|
||||
var rtElem = new XElement(EN + "RichText");
|
||||
foreach (var para in cell.Content.Paragraphs)
|
||||
{
|
||||
var pElem = new XElement(EN + "Paragraph");
|
||||
foreach (var run in para.Runs)
|
||||
{
|
||||
pElem.Add(new XElement(EN + "Run",
|
||||
new XElement(EN + "Text", run.Text)));
|
||||
}
|
||||
if (pElem.HasElements) rtElem.Add(pElem);
|
||||
}
|
||||
if (rtElem.HasElements) cElem.Add(rtElem);
|
||||
}
|
||||
rElem.Add(cElem);
|
||||
}
|
||||
rowsElem.Add(rElem);
|
||||
}
|
||||
xElem.Add(rowsElem);
|
||||
|
||||
parent.Add(xElem);
|
||||
}
|
||||
|
||||
private void WriteInkElement(SmfInkElement elem, XElement parent)
|
||||
{
|
||||
var xElem = new XElement(EN + "InkElement",
|
||||
new XAttribute("Id", elem.Id));
|
||||
|
||||
foreach (var stroke in elem.Strokes)
|
||||
{
|
||||
var sElem = new XElement(EN + "Stroke");
|
||||
sElem.Add(new XElement(EN + "Color", stroke.Color.Value));
|
||||
sElem.Add(new XElement(EN + "Width", stroke.Width));
|
||||
sElem.Add(new XElement(EN + "Highlighter", stroke.IsHighlighter));
|
||||
sElem.Add(new XElement(EN + "Transparency", stroke.Transparency));
|
||||
|
||||
var ptsElem = new XElement(EN + "Points");
|
||||
foreach (var pt in stroke.Points)
|
||||
{
|
||||
ptsElem.Add(new XElement(EN + "Point",
|
||||
new XAttribute("X", pt.X),
|
||||
new XAttribute("Y", pt.Y),
|
||||
new XAttribute("P", pt.Pressure)));
|
||||
}
|
||||
sElem.Add(ptsElem);
|
||||
xElem.Add(sElem);
|
||||
}
|
||||
|
||||
parent.Add(xElem);
|
||||
}
|
||||
|
||||
private void AddBounds(XElement parent, SmfBounds bounds)
|
||||
{
|
||||
parent.Add(new XElement(EN + "Bounds",
|
||||
new XElement(EN + "X", bounds.X),
|
||||
new XElement(EN + "Y", bounds.Y),
|
||||
new XElement(EN + "Width", bounds.Width),
|
||||
new XElement(EN + "Height", bounds.Height)));
|
||||
}
|
||||
|
||||
private void WriteContentTypes(Package enbx)
|
||||
{
|
||||
var uri = PackUriHelper.CreatePartUri(new Uri("/[Content_Types].xml", UriKind.Relative));
|
||||
var part = enbx.CreatePart(uri, "application/xml");
|
||||
using (var sw = new StreamWriter(part.GetStream()))
|
||||
{
|
||||
sw.Write("<?xml version=\"1.0\" encoding=\"utf-8\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
|
||||
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=\"mp4\" ContentType=\"video/mp4\"/>");
|
||||
sw.Write("<Default Extension=\"mp3\" ContentType=\"audio/mpeg\"/>");
|
||||
sw.Write("<Override PartName=\"/document.xml\" ContentType=\"application/vnd.seewo.easinote.document+xml\"/>");
|
||||
for (int i = 0; i < 100; i++)
|
||||
sw.Write($"<Override PartName=\"/slides/slide{i + 1}.xml\" ContentType=\"application/vnd.seewo.easinote.slide+xml\"/>");
|
||||
sw.Write("</Types>");
|
||||
}
|
||||
}
|
||||
|
||||
private void WritePackageRels(Package enbx)
|
||||
{
|
||||
var relsUri = PackUriHelper.CreatePartUri(new Uri("/_rels/.rels", UriKind.Relative));
|
||||
var relsPart = enbx.CreatePart(relsUri, "application/vnd.openxmlformats-package.relationships+xml");
|
||||
using (var sw = new StreamWriter(relsPart.GetStream()))
|
||||
{
|
||||
sw.Write("<?xml version=\"1.0\" encoding=\"utf-8\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
|
||||
sw.Write("<Relationship Id=\"rId1\" Type=\"http://schemas.seewo.com/easinote/relationships/document\" Target=\"document.xml\"/>");
|
||||
sw.Write("</Relationships>");
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteMediaFiles(SmfDocument doc, Package enbx)
|
||||
{
|
||||
foreach (var (fileName, data) in doc.MediaFiles)
|
||||
{
|
||||
var mediaUri = PackUriHelper.CreatePartUri(new Uri($"/media/{fileName}", UriKind.Relative));
|
||||
var ct = doc.MediaContentTypes.TryGetValue(fileName, out var contentType) ? contentType : "application/octet-stream";
|
||||
var part = enbx.CreatePart(mediaUri, ct);
|
||||
using var stream = part.GetStream();
|
||||
stream.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user