Объединение нескольких презентаций PowerPoint
Я хочу предупредить вас, друзья, что в настоящее время мы работаем над устранением ряда неполадок на сервере, и поэтому в некоторых предыдущих записях могут не отображаться изображения или ссылки на исходный код. Надеюсь, эти неполадки будут скоро исправлены.
В своей предыдущей записи я показал вам простой способ объединения нескольких документов Word. Сегодня я расскажу, как можно объединить несколько презентаций PowerPoint.
Решение
Для объединения двух презентаций — исходной и целевой — потребуется выполнить следующие действия:
- Открыть целевую презентацию с помощью пакета Open XML SDK и получить доступ к главному разделу презентации.
- Открыть исходную презентацию и получить доступ к ее главному разделу.
- Добавить все слайды исходной презентации в целевую презентацию, сохранив их порядок.
- Проверить наличие отношения между главным разделом целевой презентации и разделом макета образца слайдов для каждого добавленного слайда.
- Проверить наличие в главном разделе целевой презентации ссылки на каждый добавленный раздел макета образца слайдов.
- Проверить наличие в главном разделе целевой презентации ссылки на каждый добавленный раздел слайдов.
- Выполнить операцию очистки, чтобы обеспечить присвоение всем ссылкам на разделы макета слайдов уникальных идентификаторов.
- Сохранить изменения целевой презентации.
В моей демонстрации будет использоваться пакет SDK версии 2.
Чтобы более наглядно представить изложенный здесь материал, начнем работать со следующими двумя презентациями, в каждой из которых содержится по три слайда:
Destination Deck |
Source Deck |
Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить здесь.
Код
Как указывалось в разделе "Решение" выше, для выполнения первых трех шагов необходимо открыть целевую и исходную презентации, чтобы добавить каждый слайд исходной презентации в целевую презентацию. Взгляните на фрагмент кода, в котором реализуется выполнение этих задач:
static void MergeDecks(string sourceDeck, string destDeck) { int id = 1; //Open up the destination deck using (PresentationDocument myDestDeck = PresentationDocument.Open(destDeck, true)) { PresentationPart destPresPart = myDestDeck.PresentationPart; //Open up the source deck using (PresentationDocument mySourceDeck = PresentationDocument.Open(sourceDeck, true)) { PresentationPart sourcePresPart = mySourceDeck.PresentationPart; //Need to get a unique ids for slide master and slide lists //(will use these later) uniqueId = GetMaxIdFromChild(destPresPart.Presentation.SlideMasterIdList); uint maxSlideId = GetMaxIdFromChild(destPresPart.Presentation.SlideIdList); //Copy each slide in my source deck in order to my destination deck foreach (SlideId slideId in sourcePresPart.Presentation.SlideIdList) { SlidePart sp; SlidePart destSp; SlideMasterPart destMasterPart; string relId; SlideMasterId newSlideMasterId; SlideId newSlideId; //come up with a unique relationship id id++; sp = (SlidePart)sourcePresPart .GetPartById(slideId.RelationshipId); relId = sourceDeck.Remove(sourceDeck.IndexOf('.')) + id; destSp = destPresPart.AddPart<SlidePart>(sp, relId); //Add the slide part to the destination deck SlidePart destSp = destPresPart.AddPart<SlidePart>(sp, relId); ... } ... } ... } } |
Для проверки того, что все слайды исходной презентации добавлены в правильном порядке, необходимо перебрать список идентификаторов слайдов. Кроме того, обратите внимание, что нам потребовалось использовать преимущества метода AddPart, который позволяет добавлять не только раздел слайдов, но и все разделы, на которые в нем имеются ссылки.
На данном этапе мы лишь выполнили импорт раздела слайдов в целевую презентацию. Нашей следующей задачей будет установление отношения между главным разделом целевой презентации и добавленным разделом образцов слайдов. И здесь мы воспользуемся возможностями метода AddPart для добавления этого отношения с помощью следующего кода (метод AddPart устанавливает отношения, если раздел уже существует в пакете):
//Master part was added, but now we need to make sure the relationship is in place destMasterPart = destSp.SlideLayoutPart.SlideMasterPart; destPresPart.AddPart(destMasterPart); |
Наш следующий шаг заключается в добавлении списка идентификаторов разделов образцов слайдов и идентификаторов слайдов в соответствующие списки главного раздела целевой презентации. Идентификаторы, указанные в каждом из этих списков, должны быть уникальными. Кроме того, существует дополнительное ограничение, которое состоит в том, что списки идентификаторов образцов слайдов и идентификаторов макетов слайдов должны содержать только уникальные значения, которые больше или равны 2147483684. Для выполнения этих требований уникальности необходим метод, который позволяет извлекать текущее максимальное значение идентификатора в списке. В таком случае при каждом добавлении нового элемента в список нам будет достаточно прибавить единицу к максимальному значению идентификатора. Ниже показан универсальный метод извлечения максимального значения из набора дочерних элементов.
static uint GetMaxIdFromChild(OpenXmlElement el) { uint max = 1; //Get max id value from set of children foreach (OpenXmlElement child in el.ChildElements) { OpenXmlAttribute attribute = child.GetAttribute("id", ""); uint id = uint.Parse(attribute.Value); if (id > max) max = id; } return max; } |
Этот метод вызывается перед первым проходом цикла, чтобы получить соответствующие уникальные идентификаторы для списков идентификаторов разделов образцов слайдов и идентификаторов слайдов. После получения уникальных идентификаторов можно добавить идентификаторы раздела образцов слайдов и идентификаторы слайдов в соответствующие списки главного раздела целевой презентации. Ниже показан код, необходимый для добавления идентификаторов в эти два списка.
//Add slide master to slide master list uniqueId++; newSlideMasterId = new SlideMasterId(); newSlideMasterId.RelationshipId = destPresPart.GetIdOfPart(destMasterPart); newSlideMasterId.Id = uniqueId; //Add slide to slide list maxSlideId++; newSlideId = new SlideId(); newSlideId.RelationshipId = relId; newSlideId.Id = maxSlideId; destPresPart.Presentation.SlideMasterIdList.Append(newSlideMasterId); destPresPart.Presentation.SlideIdList.Append(newSlideId); |
Мы почти закончили! Теперь нам осталось только проверить уникальность всех идентификаторов макетов слайдов. Как уже упоминалось, значения этих идентификаторов не должны совпадать со значениями списка идентификаторов разделов образцов слайдов. Кроме того, необходимо убедиться, что эти идентификаторы больше или равны 2147483684. Ниже показан метод, который перебирает все разделы образцов слайдов и устанавливает идентификаторы всех макетов слайдов, на которые имеются ссылки, простым увеличением значений идентификаторов на основе максимального значения uint, определенного на данный момент.
static void FixSlideLayoutIds(PresentationPart presPart) { //Need to make sure all slide layouts have unique ids foreach (SlideMasterPart slideMasterPart in presPart.SlideMasterParts) { foreach (SlideLayoutId slideLayoutId in slideMasterPart.SlideMaster.SlideLayoutIdList) { uniqueId++; slideLayoutId.Id = (uint)uniqueId; } slideMasterPart.SlideMaster.Save(); } } |
Заключение
Собрав вместе все показанные фрагменты и запустив итоговый код, мы получим презентацию, содержащую шесть слайдов в правильном порядке.
Взгляните на снимок экрана, на котором показана окончательная презентация:
Зияд Раджаби (Zeyad Rajabi)
Это локализованная запись блога. Исходную статью можно найти по адресу https://blogs.msdn.com/brian_jones/archive/2009/03/05/how-to-assemble-multiple-powerpoint-decks.