Вставьте новый слайд в презентацию
В этом разделе показано, как использовать классы в пакете SDK для Open XML для программной вставки нового слайда в презентацию.
Получение объекта PresentationDocument
В пакете SDK Open PresentationDocument XML класс представляет пакет документов презентации. Чтобы работать с документом презентации, сначала создайте экземпляр PresentationDocument
класса , а затем работайте с этим экземпляром. Чтобы создать экземпляр класса из документа, вызовите Open метод, использующий путь к файлу, и логическое значение в качестве второго параметра, чтобы указать, доступен ли документ для редактирования. Чтобы открыть документ для чтения и записи, укажите значение true
для этого параметра, как показано в следующей using
инструкции.
В этом сегменте presentationFile
кода параметр представляет собой строку, представляющую полный путь к файлу, из которого требуется открыть документ.
// Open the source document as read/write.
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
В версии 3.0.0+ Close() метод был удален в пользу использования инструкции using.
Это гарантирует автоматический Dispose() вызов метода при достижении закрывающей фигурной скобки. Блок, следующий за using
оператором , устанавливает область для объекта, созданного или именованного в инструкцииusing
, в данном случае presentationDocument
.
Базовая структура документа презентации
Базовая структура PresentationML
документа состоит из нескольких частей, среди которых есть main часть, содержащая определение презентации. В следующем тексте из спецификации ISO/IEC 29500 представлена общая форма PresentationML
пакета.
Main часть
PresentationML
пакета начинается с корневого элемента презентации. Этот элемент содержит презентацию, которая, в свою очередь, ссылается на список слайдов, список образцов слайдов, список образцов заметок и список образцов раздаточных материалов. Список слайдов ссылается на все слайды в презентации; список образцов слайдов ссылается на все образцы слайдов, используемые в презентации; в списке образцов заметок содержатся данные о форматировании страниц заметок, а в списке образцов раздаточных материалов описан внешний вид раздаточных материалов.Раздаточные материалы представляют собой набор распечатанных слайдов, которые можно раздать слушателям для последующего использования.
Наряду с текстом и изображениями слайды могут содержать комментарии, заметки и разметку, а также могут входить в одну или несколько пользовательских презентаций. Комментарий представляет собой примечание, которое адресовано сотруднику, ответственному за обслуживание набора слайдов. Заметка представляет собой напоминание или отрывок текста, предназначенный для докладчика или для слушателей.
Другие функции документа
PresentationML
могут включать следующие: анимацию, звук, видео и переходы между слайдами.Документ
PresentationML
не хранится в виде одного большого текста в одной части. Элементы с определенной группировкой функций хранятся в различных частях. Например, все авторы в документе хранятся в одной части авторов, а каждый слайд имеет свою собственную часть.ISO/IEC 29500: 2016
Указанный ниже пример кода XML описывает презентацию, содержащую 2 слайда с идентификаторами 267 и 256.
<p:presentation xmlns:p="…" … >
<p:sldMasterIdLst>
<p:sldMasterId
xmlns:rel="https://…/relationships" rel:id="rId1"/>
</p:sldMasterIdLst>
<p:notesMasterIdLst>
<p:notesMasterId
xmlns:rel="https://…/relationships" rel:id="rId4"/>
</p:notesMasterIdLst>
<p:handoutMasterIdLst>
<p:handoutMasterId
xmlns:rel="https://…/relationships" rel:id="rId5"/>
</p:handoutMasterIdLst>
<p:sldIdLst>
<p:sldId id="267"
xmlns:rel="https://…/relationships" rel:id="rId2"/>
<p:sldId id="256"
xmlns:rel="https://…/relationships" rel:id="rId3"/>
</p:sldIdLst>
<p:sldSz cx="9144000" cy="6858000"/>
<p:notesSz cx="6858000" cy="9144000"/>
</p:presentation>
С помощью пакета SDK Open XML можно создавать структуру документа и содержимое с помощью строго типизированных классов, соответствующих элементам PresentationML. Эти классы можно найти в пространстве имен. В следующей таблице перечислены имена классов, которые соответствуют sld
элементам , sldLayout
, sldMaster
и notesMaster
.
Элемент PresentationML | Класс пакета SDK Open XML | Описание |
---|---|---|
<sld/> |
Slide | Слайд презентации. Это корневой элемент части SlidePart. |
<sldLayout/> |
SlideLayout | Разметка слайда. Это корневой элемент части SlideLayoutPart. |
<sldMaster/> |
SlideMaster | Образец слайда. Это корневой элемент части SlideMasterPart. |
<notesMaster/> |
NotesMaster | Образец заметок (или handoutMaster). Это корневой элемент части NotesMasterPart. |
Механизм работы примера кода
Пример кода состоит из двух перегрузок InsertNewSlide
метода . Первый перегруженный метод принимает три параметра: полный путь к файлу презентации, в который нужно вставить слайд, целое число, представляющее значение индекса в презентации (начиная с нуля), куда нужно добавить слайд, а также строку, представляющую заголовок нового слайда. Он открывает файл презентации для чтения и записи, получает PresentationDocument
объект, а затем передает этот объект во второй перегруженный InsertNewSlide
метод, который выполняет вставку.
// Insert a slide into the specified presentation.
public static void InsertNewSlide(string presentationFile, int position, string slideTitle)
{
// Open the source document as read/write.
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
{
// Pass the source document and the position and title of the slide to be inserted to the next method.
InsertNewSlide(presentationDocument, position, slideTitle);
}
}
Второй перегруженный InsertNewSlide
метод создает новый Slide
объект, задает его свойства, а затем вставляет его в порядок слайдов в презентации. В первой части данного метода создается слайд и задаются его свойства.
// Insert the specified slide into the presentation at the specified position.
public static SlidePart InsertNewSlide(PresentationDocument presentationDocument, int position, string slideTitle)
{
PresentationPart? presentationPart = presentationDocument.PresentationPart;
// Verify that the presentation is not empty.
if (presentationPart is null)
{
throw new InvalidOperationException("The presentation document is empty.");
}
// Declare and instantiate a new slide.
Slide slide = new Slide(new CommonSlideData(new ShapeTree()));
uint drawingObjectId = 1;
// Construct the slide content.
// Specify the non-visual properties of the new slide.
CommonSlideData commonSlideData = slide.CommonSlideData ?? slide.AppendChild(new CommonSlideData());
ShapeTree shapeTree = commonSlideData.ShapeTree ?? commonSlideData.AppendChild(new ShapeTree());
NonVisualGroupShapeProperties nonVisualProperties = shapeTree.AppendChild(new NonVisualGroupShapeProperties());
nonVisualProperties.NonVisualDrawingProperties = new NonVisualDrawingProperties() { Id = 1, Name = "" };
nonVisualProperties.NonVisualGroupShapeDrawingProperties = new NonVisualGroupShapeDrawingProperties();
nonVisualProperties.ApplicationNonVisualDrawingProperties = new ApplicationNonVisualDrawingProperties();
// Specify the group shape properties of the new slide.
shapeTree.AppendChild(new GroupShapeProperties());
Следующий раздел второго перегруженного InsertNewSlide
метода добавляет фигуру заголовка на слайд и задает его свойства, включая его текст.
// Declare and instantiate the title shape of the new slide.
Shape titleShape = shapeTree.AppendChild(new Shape());
drawingObjectId++;
// Specify the required shape properties for the title shape.
titleShape.NonVisualShapeProperties = new NonVisualShapeProperties
(new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Title" },
new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Type = PlaceholderValues.Title }));
titleShape.ShapeProperties = new ShapeProperties();
// Specify the text of the title shape.
titleShape.TextBody = new TextBody(new Drawing.BodyProperties(),
new Drawing.ListStyle(),
new Drawing.Paragraph(new Drawing.Run(new Drawing.Text() { Text = slideTitle })));
Следующий раздел второго перегруженного InsertNewSlide
метода добавляет фигуру тела на слайд и задает его свойства, включая его текст.
// Declare and instantiate the body shape of the new slide.
Shape bodyShape = shapeTree.AppendChild(new Shape());
drawingObjectId++;
// Specify the required shape properties for the body shape.
bodyShape.NonVisualShapeProperties = new NonVisualShapeProperties(new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Content Placeholder" },
new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Index = 1 }));
bodyShape.ShapeProperties = new ShapeProperties();
// Specify the text of the body shape.
bodyShape.TextBody = new TextBody(new Drawing.BodyProperties(),
new Drawing.ListStyle(),
new Drawing.Paragraph());
Последний раздел второго перегруженного InsertNewSlide
метода создает новую часть слайда, находит указанную позицию индекса, в которой нужно вставить слайд, а затем вставляет его и назначает новый слайд новой части слайда.
// Create the slide part for the new slide.
SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
// Assign the new slide to the new slide part
slidePart.Slide = slide;
// Modify the slide ID list in the presentation part.
// The slide ID list should not be null.
SlideIdList? slideIdList = presentationPart.Presentation.SlideIdList;
// Find the highest slide ID in the current list.
uint maxSlideId = 1;
SlideId? prevSlideId = null;
OpenXmlElementList slideIds = slideIdList?.ChildElements ?? default;
foreach (SlideId slideId in slideIds)
{
if (slideId.Id is not null && slideId.Id > maxSlideId)
{
maxSlideId = slideId.Id;
}
position--;
if (position == 0)
{
prevSlideId = slideId;
}
}
maxSlideId++;
// Get the ID of the previous slide.
SlidePart lastSlidePart;
if (prevSlideId is not null && prevSlideId.RelationshipId is not null)
{
lastSlidePart = (SlidePart)presentationPart.GetPartById(prevSlideId.RelationshipId!);
}
else
{
string? firstRelId = ((SlideId)slideIds[0]).RelationshipId;
// If the first slide does not contain a relationship ID, throw an exception.
if (firstRelId is null)
{
throw new ArgumentNullException(nameof(firstRelId));
}
lastSlidePart = (SlidePart)presentationPart.GetPartById(firstRelId);
}
// Use the same slide layout as that of the previous slide.
if (lastSlidePart.SlideLayoutPart is not null)
{
slidePart.AddPart(lastSlidePart.SlideLayoutPart);
}
// 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);
Пример кода
Далее представлен полный пример кода на языках C# и Visual Basic.
// Insert a slide into the specified presentation.
public static void InsertNewSlide(string presentationFile, int position, string slideTitle)
{
// Open the source document as read/write.
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
{
// Pass the source document and the position and title of the slide to be inserted to the next method.
InsertNewSlide(presentationDocument, position, slideTitle);
}
}
// Insert the specified slide into the presentation at the specified position.
public static SlidePart InsertNewSlide(PresentationDocument presentationDocument, int position, string slideTitle)
{
PresentationPart? presentationPart = presentationDocument.PresentationPart;
// Verify that the presentation is not empty.
if (presentationPart is null)
{
throw new InvalidOperationException("The presentation document is empty.");
}
// Declare and instantiate a new slide.
Slide slide = new Slide(new CommonSlideData(new ShapeTree()));
uint drawingObjectId = 1;
// Construct the slide content.
// Specify the non-visual properties of the new slide.
CommonSlideData commonSlideData = slide.CommonSlideData ?? slide.AppendChild(new CommonSlideData());
ShapeTree shapeTree = commonSlideData.ShapeTree ?? commonSlideData.AppendChild(new ShapeTree());
NonVisualGroupShapeProperties nonVisualProperties = shapeTree.AppendChild(new NonVisualGroupShapeProperties());
nonVisualProperties.NonVisualDrawingProperties = new NonVisualDrawingProperties() { Id = 1, Name = "" };
nonVisualProperties.NonVisualGroupShapeDrawingProperties = new NonVisualGroupShapeDrawingProperties();
nonVisualProperties.ApplicationNonVisualDrawingProperties = new ApplicationNonVisualDrawingProperties();
// Specify the group shape properties of the new slide.
shapeTree.AppendChild(new GroupShapeProperties());
// Declare and instantiate the title shape of the new slide.
Shape titleShape = shapeTree.AppendChild(new Shape());
drawingObjectId++;
// Specify the required shape properties for the title shape.
titleShape.NonVisualShapeProperties = new NonVisualShapeProperties
(new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Title" },
new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Type = PlaceholderValues.Title }));
titleShape.ShapeProperties = new ShapeProperties();
// Specify the text of the title shape.
titleShape.TextBody = new TextBody(new Drawing.BodyProperties(),
new Drawing.ListStyle(),
new Drawing.Paragraph(new Drawing.Run(new Drawing.Text() { Text = slideTitle })));
// Declare and instantiate the body shape of the new slide.
Shape bodyShape = shapeTree.AppendChild(new Shape());
drawingObjectId++;
// Specify the required shape properties for the body shape.
bodyShape.NonVisualShapeProperties = new NonVisualShapeProperties(new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Content Placeholder" },
new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Index = 1 }));
bodyShape.ShapeProperties = new ShapeProperties();
// Specify the text of the body shape.
bodyShape.TextBody = new TextBody(new Drawing.BodyProperties(),
new Drawing.ListStyle(),
new Drawing.Paragraph());
// Create the slide part for the new slide.
SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
// Assign the new slide to the new slide part
slidePart.Slide = slide;
// Modify the slide ID list in the presentation part.
// The slide ID list should not be null.
SlideIdList? slideIdList = presentationPart.Presentation.SlideIdList;
// Find the highest slide ID in the current list.
uint maxSlideId = 1;
SlideId? prevSlideId = null;
OpenXmlElementList slideIds = slideIdList?.ChildElements ?? default;
foreach (SlideId slideId in slideIds)
{
if (slideId.Id is not null && slideId.Id > maxSlideId)
{
maxSlideId = slideId.Id;
}
position--;
if (position == 0)
{
prevSlideId = slideId;
}
}
maxSlideId++;
// Get the ID of the previous slide.
SlidePart lastSlidePart;
if (prevSlideId is not null && prevSlideId.RelationshipId is not null)
{
lastSlidePart = (SlidePart)presentationPart.GetPartById(prevSlideId.RelationshipId!);
}
else
{
string? firstRelId = ((SlideId)slideIds[0]).RelationshipId;
// If the first slide does not contain a relationship ID, throw an exception.
if (firstRelId is null)
{
throw new ArgumentNullException(nameof(firstRelId));
}
lastSlidePart = (SlidePart)presentationPart.GetPartById(firstRelId);
}
// Use the same slide layout as that of the previous slide.
if (lastSlidePart.SlideLayoutPart is not null)
{
slidePart.AddPart(lastSlidePart.SlideLayoutPart);
}
// 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);
return slidePart;
}