新 HTML 导出系统 - Aspose.Slides.WebExtensions

介绍

  • 在旧的 Aspose.Slides API 版本中,当您将 PowerPoint 导出为 HTML 时,生成的 HTML 会以 SVG 标记结合 HTML 的形式呈现。每张幻灯片都会导出为一个 SVG 容器。
  • 在新的 Aspose.Slides 版本中,当您使用 WebExtensions 系统将 PowerPoint 演示文稿导出为 HTML 时,您可以自定义 HTML 导出设置,以获得最佳效果。

使用新的 WebExtensions 系统,您可以将整个演示文稿导出为带有一套 CSS 类和 JavaScript 动画(不使用 SVG)的 HTML。新的导出系统还提供了无限数量的选项和方法来定义导出过程。

在以下情况和事件中使用新的 WebExtensions 系统从演示文稿生成 HTML:

  • 使用自定义 CSS 样式或动画;覆盖某些形状类型的标记。
  • 覆盖文档结构,例如使用自定义页面之间的导航。
  • 将 .html、.css、.js 文件保存到具有自定义层次结构的文件夹中,包括将特定文件类型保存到不同的文件夹。例如,根据章节名称将幻灯片导出到相应的文件夹。
  • 默认情况下,将 CSS 和 JS 文件分别保存到独立文件夹中,然后将它们添加到 HTML 文件。图像和嵌入字体也会保存为独立文件。不过,它们也可以以 base64 格式嵌入到 HTML 文件中。您可以将部分资源保存为文件,其他资源以 base64 形式嵌入到 HTML 中。

您可以在 GitHub 上的 Aspose.Slides.WebExtensions 项目 中查看 PowerPoint 转 HTML 示例。该项目包含两个部分:Examples\SinglePageAppExamples\MultiPageApp。本文使用的其他示例也可以在该仓库中找到。

模板

为了进一步扩展 HTML 导出的功能,我们建议使用 ASP.NET Razor 模板系统。可以将 Presentation 类实例与一组模板结合使用,以获取作为导出结果的 HTML 文档。

演示

在本示例中,我们将把演示文稿中的文本导出为 HTML。首先,创建模板:

<!DOCTYPE html>
<body>
    @foreach (Slide slide in Model.Object.Slides)    
    {
        foreach (Shape shape in slide.Shapes)
        {
            if(shape is AutoShape)
            {
                ITextFrame textFrame = ((AutoShape)shape).TextFrame;
                <div class="text">@textFrame.Text</div>
            }
        }
    }
</body>
</html>

此模板以 “shape-template-hello-world.html” 保存到磁盘,在下一步中使用。

在此模板中,我们遍历演示文稿形状中的文本框以显示文本。使用 WebDocument 生成 HTML 文件,然后将 Presentation 导出到该文件:

using (Presentation pres = new Presentation())
{
    IAutoShape shape = pres.Slides[0].Shapes.AddAutoShape(ShapeType.Rectangle, 10, 10, 100, 150);
    shape.TextFrame.Text = "Hello World";
                
    WebDocumentOptions options = new WebDocumentOptions
    {
        TemplateEngine = new RazorTemplateEngine(), // 我们打算使用 Razor 模板引擎。也可以通过实现 ITemplateEngine 来使用其他模板引擎  
        OutputSaver = new FileOutputSaver() // 也可以通过实现 IOutputSaver 接口来使用其他结果保存器
    };
    WebDocument document = new WebDocument(options);

    // 添加文档 “input” - 将使用什么来源生成 HTML 文档
    document.Input
        .AddTemplate<Presentation>( // 模板将以 Presentation 作为 “model” 对象 (Model.Object) 
        "index", // 模板键 - 模板引擎需要它来将对象 (Presentation) 与磁盘上加载的模板 ("shape-template-hello-world.html") 匹配  
        @"custom-templates\shape-template-hello-world.html"); // 我们之前创建的模板
                
    // 添加输出 - 导出到磁盘时生成的 HTML 文档将如何呈现
    document.Output.Add(
        "hello-world.html", // 输出文件路径
        "index", // 将用于此文件的模板键(我们在前面的语句中设置的)  
        pres); // 实际的 Model.Object 实例 
                
    document.Save();
}

例如,我们想向导出结果添加 CSS 样式,使文本颜色变为红色。添加 CSS 模板:

.text {
    color: red;
}

随后,将其加入输入和输出:

using (Presentation pres = new Presentation())
{
    IAutoShape shape = pres.Slides[0].Shapes.AddAutoShape(ShapeType.Rectangle, 10, 10, 100, 150);
    shape.TextFrame.Text = "Hello World";
                
    WebDocumentOptions options = new WebDocumentOptions { TemplateEngine = new RazorTemplateEngine(), OutputSaver = new FileOutputSaver() };
    WebDocument document = new WebDocument(options);

    document.Input.AddTemplate<Presentation>("index", @"custom-templates\shape-template-hello-world.html");
    document.Input.AddTemplate<Presentation>("styles", @"custom-templates\styles\shape-template-hello-world.css");
    document.Output.Add("hello-world.html", "index", pres); 
    document.Output.Add("hello-world.css", "styles", pres);
                
    document.Save();
}

将对样式的引用添加到模板的 text 类中:

<!DOCTYPE html>
<head>
    <link rel="stylesheet" type="text/css" href="hello-world.css" />
</head>
...
</html>

默认模板

WebExtensions 提供两套基本模板,用于将演示文稿导出为 HTML:

  • 单页:所有演示文稿内容导出到一个 HTML 文件中,所有其他资源(图像、字体、样式等)导出为独立文件。
  • 多页:每张幻灯片导出为单独的 HTML 文件。资源导出的默认逻辑与单页相同。

可以使用 PresentationExtensions 类通过模板简化演示文稿导出过程。PresentationExtensions 类包含一组针对 Presentation 类的扩展方法。要将演示文稿导出为单页,只需引用 Aspose.Slides.WebExtensions 命名空间并调用两个方法。第一个方法 ToSinglePageWebDocument 创建 WebDocument 实例。第二个方法保存 HTML 文档:

using (Presentation pres = new Presentation("demo.pptx"))
{
    WebDocument document = pres.ToSinglePageWebDocument("templates\\single-page", @"single-page-output");
    document.Save();
}

ToSinglePageWebDocument 方法可以接受两个参数:模板文件夹和导出文件夹。

要将演示文稿导出为多页,使用带有相同参数的 ToMultiPageWebDocument 方法:

using (Presentation pres = new Presentation("demo.pptx"))
{
    WebDocument document = pres.ToMultiPageWebDocument("templates\\multi-page", @"mutil-page-output");
    document.Save();
}

在 WebExtensions 中,每个用于标记生成的模板都绑定到一个键。该键可在模板中使用。例如,在 @Include 指令中,您可以通过键将某个模板插入到另一个模板中。

我们可以在段落模板中使用文本段落模板的示例中演示此过程。示例位于 Aspose.Slides.WebExtensions 项目中:Templates\common\paragraph.html。要在段落中绘制各段落,我们使用 Razor Engine 的 @foreach 指令遍历它们:

@foreach (Portion portion in contextObject.Portions) 
{ 
    var subModel = Model.SubModel(portion);
    subModel.Local.Put("parentTextFrame", parentTextFrame);
    subModel.Local.Put("tableContent", tableContentFlag);
	@Raw(Include("portion", subModel).ToString().Replace(Environment.NewLine, ""));
}

段落的模板为 portion.html,为其生成了模型。该模型将被添加到输出的 paragraph.html 模板中:

@Raw(Include("portion", subModel).ToString().Replace(Environment.NewLine, ""));

对于每种形状类型,我们使用自定义模板,该模板会被添加到 Aspose.Slides.WebExtensions 项目中的通用模板集合中。ToSinglePageWebDocumentToMultiPageWebDocument 方法会将这些模板组合,以提供最终结果。这些是单页和多页共用的通用模板:

-templates
+-common
  ¦ +-scripts: 幻灯片切换动画的 JavaScript 脚本实例。
  ¦ +-styles: 通用 CSS 样式。
  +-multi-page: 多页输出的 index、menu、slide 模板。
  +-single-page: 单页输出的 index、slide 模板。

您可以在 PresentationExtensions.AddCommonInputOutput 方法中查看通用部分如何绑定到所有模板,链接如下:这里

默认模板自定义

您可以修改通用模型模板中的任何元素。例如,您可能想更改表格的格式样式,但希望单页的其他样式保持不变。

默认情况下使用 Templates\common\table.html,其外观与 PowerPoint 中的表格相同。下面使用自定义 CSS 样式更改表格格式:

.custom-table {
    border: 1px solid black;
}
.custom-table tr:nth-child(even) {background: #CCC}
.custom-table tr:nth-child(odd) {background: #ffb380}

我们可以在调用 PresentationExtensions.ToSinglePageWebDocument 方法时,创建相同的输入模板结构和输出文件(如生成的那样)。为此添加 ExportCustomTableStyles_AddCommonStructure 方法。该方法与 ToSinglePageWebDocument 的区别在于——我们无需添加标准表格模板和主索引页面(它们将被替换为对自定义表格样式的引用):

private static void ExportCustomTableStyles_AddCommonStructure(
    Presentation pres, 
    WebDocument document,
    string templatesPath, 
    string outputPath, 
    bool embedImages)
{
    AddCommonStylesTemplates(document, templatesPath);
            
    document.Input.AddTemplate<Slide>("slide", Path.Combine(templatesPath, "slide.html"));
    document.Input.AddTemplate<AutoShape>("autoshape", Path.Combine(templatesPath, "autoshape.html"));
    document.Input.AddTemplate<TextFrame>("textframe", Path.Combine(templatesPath, "textframe.html"));
    document.Input.AddTemplate<Paragraph>("paragraph", Path.Combine(templatesPath, "paragraph.html"));
    document.Input.AddTemplate<Paragraph>("bullet", Path.Combine(templatesPath, "bullet.html"));
    document.Input.AddTemplate<Portion>("portion", Path.Combine(templatesPath, "portion.html"));
    document.Input.AddTemplate<VideoFrame>("videoframe", Path.Combine(templatesPath, "videoframe.html"));
    document.Input.AddTemplate<PictureFrame>("pictureframe", Path.Combine(templatesPath, "pictureframe.html")); ;
    document.Input.AddTemplate<Shape>("shape", Path.Combine(templatesPath, "shape.html"));

    AddSinglePageCommonOutput(pres, document, outputPath);
            
    AddResourcesOutput(pres, document, embedImages);
            
    AddScriptsOutput(document, templatesPath);
}

改为添加自定义模板:

using (Presentation pres = new Presentation("table.pptx"))
{
    const string templatesPath = "templates\\single-page";
    const string outputPath = "custom-table-styles";
                
    var options = new WebDocumentOptions
    {
        TemplateEngine = new RazorTemplateEngine(),
        OutputSaver = new FileOutputSaver(),
        EmbedImages = false
    };

    // 设置全局文档值
    WebDocument document = new WebDocument(options);
    SetupGlobals(document, options, outputPath);

    // 添加公共结构(不包括表格模板)
    ExportCustomTableStyles_AddCommonStructure(pres, document, templatesPath, outputPath, options.EmbedImages);
                
    // 添加自定义表格模板
    document.Input.AddTemplate<Table>("table", @"custom-templates\table-custom-style.html");
                
    // 添加自定义表格样式
    document.Input.AddTemplate<Presentation>("table-custom-style", @"custom-templates\styles\table-custom-style.css");
    document.Output.Add(Path.Combine(outputPath, "table-custom-style.css"), "table-custom-style", pres);
                
    // 添加自定义索引 - 这只是标准 "index.html" 的副本,但
    // 包含对 "table-custom-style.css" 的引用
    document.Input.AddTemplate<Presentation>("index", @"custom-templates\index-table-custom-style.html");
                
    document.Save();
}
@model TemplateContext<Table>

@{
	Table contextObject = Model.Object;
	
	var origin = Model.Local.Get<Point>("origin");
	var positionStyle = string.Format("left: {0}px; top: {1}px; width: {2}px; height: {3}px;",
										(int)contextObject.X + origin.X,
										(int)contextObject.Y + origin.Y,
										(int)contextObject.Width,
										(int)contextObject.Height);
}

	<table class="table custom-table" style="@positionStyle">
	@for (int i = 0; i < contextObject.Rows.Count; i++)
	{
		var rowHeight = string.Format("height: {0}px", contextObject.Rows[i].Height);
		<tr style="@rowHeight">
		@for (int j = 0; j < contextObject.Columns.Count; j++)
		{
			var cell = contextObject[j, i];
			if (cell.FirstRowIndex ==  i && cell.FirstColumnIndex == j)
			{
				var spans = cell.IsMergedCell ? string.Format("rowspan=\"{0}\" colspan=\"{1}\"", cell.RowSpan, cell.ColSpan) : "";
				<td width="@cell.Width px" @Raw(spans)>
					@{
						for(int k = 0; k < cell.TextFrame.Paragraphs.Count; k++)
						{
							var para = (Paragraph)cell.TextFrame.Paragraphs[k];
						
							var subModel = Model.SubModel(para);
							double[] margins = new double[] { cell.MarginLeft, cell.MarginTop, cell.MarginRight, cell.MarginBottom };
							subModel.Local.Put("margins", margins);
							subModel.Local.Put("parent", cell.TextFrame);
							subModel.Local.Put("parentContainerSize", new SizeF((float)cell.Width, (float)cell.Height));
                            subModel.Local.Put("tableContent", true);
							
							@Include("paragraph", subModel)
						}
					}
				</td>
			}
		}
		</tr>
	}
</table>

注意,自定义表格模板使用了与标准表格相同的 “table” 键。因此,您可以在不重新编写的情况下替换特定的默认模板。您也可以使用默认结构中的模板,只要键相同。例如,您可以在表格模板中使用标准段落模板,或用相同键替换它。

您还可以使用 index.html 将对自定义表格 CSS 样式的引用包含进去:

<!DOCTYPE html>    
    
<html     
    xmlns="http://www.w3.org/1999/xhtml"    
    xmlns:svg="http://www.w3.org/2000/svg"    
    xmlns:xlink="http://www.w3.org/1999/xlink">    
<head>    
     ...
    <link rel="stylesheet" type="text/css" href="table-custom-style.css" />
    ...
</head>    
<body>    
    ...
</body>
</html>

从头创建项目:动画幻灯片切换

WebExtensions 允许您导出带有动画幻灯片切换的演示文稿——只需在 WebDocumentOptions 中将 AnimateTransitions 属性设为 true

WebDocumentOptions options = new WebDocumentOptions
{
    // ... 其他选项
    AnimateTransitions = true
};

让我们创建一个新项目,使用 Aspose.Slides 和 Aspose.Slides.WebExtensions 为 PDF 创建带平滑动画页面切换的 HTML 查看器。这里需要使用 Aspose.Slides 的 PDF 导入功能。

创建 PdfToPresentationToHtml 项目并添加 Aspose.Slides.WebExtensions NuGet 包(Aspose.Slides 包也会作为依赖项添加): NuGet Package

首先导入 PDF 文档,该文档将被动画化并导出为 HTML 演示文稿:

using (Presentation pres = new Presentation())
{
    pres.Slides.RemoveAt(0);
    pres.Slides.AddFromPdf("sample.pdf");
}

现在,我们可以设置动画幻灯片切换(每张幻灯片对应导入的 PDF 页面)。示例 PDF 文档中使用了 9 张幻灯片。为它们每一张添加幻灯片切换(在浏览 HTML 时演示):

pres.Slides[0].SlideShowTransition.Type = TransitionType.Fade;
pres.Slides[1].SlideShowTransition.Type = TransitionType.RandomBar;
pres.Slides[2].SlideShowTransition.Type = TransitionType.Cover;
pres.Slides[3].SlideShowTransition.Type = TransitionType.Dissolve;
pres.Slides[4].SlideShowTransition.Type = TransitionType.Switch;
pres.Slides[5].SlideShowTransition.Type = TransitionType.Pan;
pres.Slides[6].SlideShowTransition.Type = TransitionType.Ferris;
pres.Slides[7].SlideShowTransition.Type = TransitionType.Pull;
pres.Slides[8].SlideShowTransition.Type = TransitionType.Plus;

最后,使用 WebDocumentAnimateTransitions 属性设为 true,将其导出为 HTML:

WebDocumentOptions options = new WebDocumentOptions
{
    TemplateEngine = new RazorTemplateEngine(),
    OutputSaver = new FileOutputSaver(),
    AnimateTransitions = true
};

WebDocument document = pres.ToSinglePageWebDocument(options, "templates\\single-page", "animated-pdf");
document.Save();

完整源码示例:

using (Presentation pres = new Presentation())
{
    pres.Slides.RemoveAt(0);
    pres.Slides.AddFromPdf("sample.pdf");

    pres.Slides[0].SlideShowTransition.Type = TransitionType.Fade;
    pres.Slides[1].SlideShowTransition.Type = TransitionType.RandomBar;
    pres.Slides[2].SlideShowTransition.Type = TransitionType.Cover;
    pres.Slides[3].SlideShowTransition.Type = TransitionType.Dissolve;
    pres.Slides[4].SlideShowTransition.Type = TransitionType.Switch;
    pres.Slides[5].SlideShowTransition.Type = TransitionType.Pan;
    pres.Slides[6].SlideShowTransition.Type = TransitionType.Ferris;
    pres.Slides[7].SlideShowTransition.Type = TransitionType.Pull;
    pres.Slides[8].SlideShowTransition.Type = TransitionType.Plus;

    WebDocumentOptions options = new WebDocumentOptions
    {
        TemplateEngine = new RazorTemplateEngine(),
        OutputSaver = new FileOutputSaver(),
        AnimateTransitions = true
    };

    WebDocument document = pres.ToSinglePageWebDocument(options, "templates\\single-page", "animated-pdf");
    document.Save();
}

以上即为从 PDF 文档生成带动画页面切换的 HTML 所需的全部内容。