![](/img/trans.png)
[英]Remove all unused Slide Layout from my Master Slide from Powerpoint Presentation using OpenXML SDK
[英]C# - OpenXML SDK 2.5 - Insert New Slide from Slide Masters with the layout that contains images
我用它在 OpenXML 2.5 SDK 的帮助下创建了我的新幻灯片。 我设计并使用我自己的幻灯片母版来创建一个新幻灯片。 我的幻灯片母版包括一些带图像的布局和一些不带图像的布局。
如果我从没有图像的主布局创建幻灯片,一切正常。 如果我创建一个带有布局的幻灯片,其中包含图像,我会得到正确的布局,但是在每个固定图像之上,还有另一个可移动图像与固定图像重叠,因此固定图像有不必要的重复,我不需要在我新创建的幻灯片中。
我怎么解决这个问题?
我的代码如下:
public static void InsertNewSlide(string presentationFile, int position, string layoutName)
{
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
{
InsertNewSlide(presentationDocument, position, layoutName);
}
}
public static void InsertNewSlide(PresentationDocument presentationDocument, int position, string layoutName)
{
PresentationPart presentationPart = presentationDocument.PresentationPart;
OpenXML.Slide slide = new OpenXML.Slide(new CommonSlideData(new ShapeTree()));
SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
slide.Save(slidePart);
SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.First();
SlideLayoutPart slideLayoutPart = slideMasterPart.SlideLayoutParts.SingleOrDefault(sl => sl.SlideLayout.CommonSlideData.Name.Value.Equals(layoutName, StringComparison.OrdinalIgnoreCase));
slidePart.AddPart<SlideLayoutPart>(slideLayoutPart);
slidePart.Slide.CommonSlideData = (CommonSlideData)slideMasterPart.SlideLayoutParts.SingleOrDefault(sl => sl.SlideLayout.CommonSlideData.Name.Value.Equals(layoutName)).SlideLayout.CommonSlideData.Clone();
using (Stream stream = slideLayoutPart.GetStream())
{
slidePart.SlideLayoutPart.FeedData(stream);
}
foreach (ImagePart iPart in slideLayoutPart.ImageParts)
{
ImagePart newImagePart = slidePart.AddImagePart(iPart.ContentType, slideLayoutPart.GetIdOfPart(iPart));
newImagePart.FeedData(iPart.GetStream());
}
uint maxSlideId = 1;
SlideId prevSlideId = null;
var slideIdList = presentationPart.Presentation.SlideIdList;
foreach (SlideId slideId in slideIdList.ChildElements)
{
if (slideId.Id > maxSlideId)
{
maxSlideId = slideId.Id;
}
position--;
if (position == 0)
{
prevSlideId = slideId;
}
}
maxSlideId++;
SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
newSlideId.Id = maxSlideId;
newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);
presentationPart.Presentation.Save();
}
}
多年后,但为了帮助他人 - 无需将不提供占位符功能的节点复制到基于主幻灯片模板(包括图像)的新幻灯片。
线
using (Stream stream = slideLayoutPart.GetStream())
{
slidePart.SlideLayoutPart.FeedData(stream);
显然假设您没有在 1 个工作流中添加幻灯片(即您有单独的读取和写入流),以及等效的行
slidePart.Slide.CommonSlideData = (CommonSlideData)layoutPart.SlideLayout.CommonSlideData.Clone();
这两行代码将所有主数据复制到新幻灯片上。 例如,运行上面答案中的一个代码块,在演示管理器中打开生成的 .pptx 文件并删除您看到的任何形状 - 您会注意到每个项目都位于相同副本(母版幻灯片版本),您无法删除。 因此,这种方法会不必要地使文件膨胀,并使 .pptx 的处理变得混乱,并且不像最终用户所预测的那样。
下面的代码正在工作,包括图像
public static SlidePart AppendNewSlide(PresentationPart presentationPart, SlideLayoutPart masterLayoutPart, out IEnumerable<Shape> placeholderShapes)
{
Slide clonedSlide = new Slide() {
ColorMapOverride = new ColorMapOverride {
MasterColorMapping = new Draw.MasterColorMapping()
}
};
SlidePart clonedSlidePart = presentationPart.AddNewPart<SlidePart>();
clonedSlidePart.Slide = clonedSlide;
clonedSlidePart.AddPart(masterLayoutPart);
clonedSlide.Save(clonedSlidePart);
var masterShapeTree = masterLayoutPart.SlideLayout.CommonSlideData.ShapeTree;
placeholderShapes = (from s in masterShapeTree.ChildElements<Shape>()
where s.NonVisualShapeProperties.OfType<ApplicationNonVisualDrawingProperties>().Any(anvdp=>anvdp.PlaceholderShape != null)
select new Shape()
{
NonVisualShapeProperties = (NonVisualShapeProperties)s.NonVisualShapeProperties.CloneNode(true),
TextBody = new TextBody(s.TextBody.ChildElements<Draw.Paragraph>().Select(p => p.CloneNode(true))) {
BodyProperties = new Draw.BodyProperties(),
ListStyle = new Draw.ListStyle()
},
ShapeProperties = new ShapeProperties()
}).ToList();
clonedSlide.CommonSlideData = new CommonSlideData
{
ShapeTree = new ShapeTree(placeholderShapes) {
GroupShapeProperties = (GroupShapeProperties)masterShapeTree.GroupShapeProperties.CloneNode(true),
NonVisualGroupShapeProperties = (NonVisualGroupShapeProperties)masterShapeTree.NonVisualGroupShapeProperties.CloneNode(true)
}
};
SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;
// Find the highest slide ID in the current list.
uint maxSlideId = slideIdList.Max(c=>(uint?)((SlideId)c).Id) ?? 256;
// Insert the new slide into the slide list after the previous slide.
slideIdList.Append(new SlideId() {
Id = ++maxSlideId,
RelationshipId = presentationPart.GetIdOfPart(clonedSlidePart)
});
//presentationPart.Presentation.Save();
return clonedSlidePart;
}
//helper method used above in separate static class
public static IEnumerable<T> ChildElements<T>(this OpenXmlElement el) where T: OpenXmlElement
{
if (el.HasChildren)
{
var child = el.GetFirstChild<T>();
while (child != null)
{
yield return child;
child = child.NextSibling<T>();
}
}
}
out 参数 placeholderShapes 假设在基于主模板创建新幻灯片后,开发人员希望更改某些占位符内容
我认为您应该省略复制图像部分的foreach
循环。 当我通常从幻灯片母版复制幻灯片时,我使用您正在使用的类似代码设置,但没有foreach
。 然后它从幻灯片母版部分复制给定的幻灯片,包括所有图像、布局等。
下面列出了我在我的一个项目中使用的代码( SetTitle(string)
调用是对外部方法的调用,我在 SlideMasterPart 中使用硬编码位置,而不是基于string
的布局名称。
public static void InsertNewSlideB(PresentationDocument presentationDocument, int position, string slideTitle)
{
if (presentationDocument == null)
{
throw new ArgumentNullException("presentationDocument");
}
if (slideTitle == null)
{
throw new ArgumentNullException("slideTitle");
}
PresentationPart presentationPart = presentationDocument.PresentationPart;
// Verify that the presentation is not empty.
if (presentationPart == null)
{
throw new InvalidOperationException("The presentation document is empty.");
}
// Declare and instantiate a new slide.
Slide slide = new Slide(new CommonSlideData(new ShapeTree()));
SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
slide.Save(slidePart);
SlideLayoutPart layoutPart = presentationPart.SlideMasterParts.ElementAt(0).SlideLayoutParts.ElementAt(1);
slidePart.AddPart<SlideLayoutPart>(layoutPart);
slidePart.Slide.CommonSlideData = (CommonSlideData)layoutPart.SlideLayout.CommonSlideData.Clone();
SetTitle(slidePart, slideTitle);
SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;
// Find the highest slide ID in the current list.
uint maxSlideId = 1;
SlideId prevSlideId = null;
foreach (SlideId slideId in slideIdList.ChildElements)
{
if (slideId.Id > maxSlideId)
{
maxSlideId = slideId.Id;
}
position--;
if (position == 0)
{
prevSlideId = slideId;
}
}
maxSlideId++;
// Insert the new slide into the slide list after the previous slide.
SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
newSlideId.Id = maxSlideId;
newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);
// Save the modified presentation.
presentationPart.Presentation.Save();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.