Partager via


Appliquer un thème à une présentation

Cette rubrique montre comment utiliser les classes du Kit de développement logiciel (SDK) Open XML pour Office pour appliquer le thème d’une présentation à une autre par programmation.


Obtention d’un objet PresentationDocument

Dans le Kit de développement logiciel (SDK) Open XML, la classe PresentationDocument représente un package de documents de présentation. Pour utiliser un document de présentation, créez d’abord une instance de la classe PresentationDocument, puis utilisez cette instance. Pour créer la classe instance à partir du document, appelez la méthode Open(String, Boolean) qui utilise un chemin d’accès de fichier et une valeur booléenne comme deuxième paramètre pour spécifier si un document est modifiable. Pour ouvrir un document pour un accès en lecture seule, spécifiez la valeur false pour ce paramètre. Pour ouvrir un document pour un accès en lecture-écriture, spécifiez la valeur true pour ce paramètre. Dans l’instruction using suivante, deux fichiers de présentation sont ouverts, la présentation cible, à laquelle un thème doit être appliqué, et la présentation source, à laquelle un thème est déjà appliqué. Le fichier de présentation source est ouvert pour un accès en lecture seule, et le fichier de présentation cible est ouvert pour un accès en lecture-écriture. Dans ce code, le paramètre themePresentation est une chaîne qui représente le chemin d’accès du document de présentation source, et le paramètre presentationFile est une chaîne qui représente le chemin d’accès du document de présentation cible.

using (PresentationDocument themeDocument = PresentationDocument.Open(themePresentation, false))
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
{

L'instruction using offre une alternative recommandée pour la séquence .Open, .Save, .Close standard. Elle garantit que la méthode Dispose (méthode interne utilisée par le kit de développement Open XML pour nettoyer les ressources) est automatiquement appelée lorsque l'accolade de fermeture est atteinte. Le bloc qui suit l’instruction using établit une étendue pour l’objet créé ou nommé dans l’instruction using, dans le cas présent themeDocument et presentationDocument.


Structure de document de présentation de base

La structure de document de base d’un document PresentationML est constituée d’un certain nombre de composants, parmi lesquels le composant principal qui contient la définition de la présentation. Le texte suivant de la spécification ISO/IEC 29500 présente la forme globale d’un package PresentationML .

La partie main d’un package PresentationML commence par un élément racine de présentation. Cet élément contient une présentation qui, à son tour, fait référence à une liste de diapositives, à une liste de diapositives master, à une liste de notes master et à un document master liste. La liste des diapositives référence toutes les diapositives de la présentation ; la liste de masques de diapositive référence tous les masques de diapositive utilisés dans la présentation ; le masque de pages de note contient des informations sur la mise en forme des pages de notes et le masque de document décrit comment un document se présente.

Un document à distribuer est un ensemble imprimé de diapositives qui peut être distribué aux personnes de l’audience.

En plus de textes et de graphiques, chaque diapositive peut contenir des commentaires et des notes, peut avoir une disposition et peut faire partie d’une ou plusieurs présentations personnalisées. Un commentaire est une annotation destinée à la personne qui gère le jeu de diapositives de la présentation. Une note est un rappel ou un élément de texte destiné au présentateur ou à l’audience.

Les autres fonctionnalités qu’un document PresentationML peut inclure les suivantes : animation, audio, vidéo et transitions entre les diapositives.

Un document PresentationML n’est pas stocké sous la forme d’un corps de grande taille dans un même composant. Au lieu de cela, les éléments qui implémentent certains groupes de fonctionnalités sont stockés dans des composants distincts. Par exemple, tous les commentaires d’un document sont stockés dans un même composant Commentaires, alors que chaque diapositive a son propre composant.

© ISO/IEC29500: 2008.

L’exemple de code XML suivant représente une présentation qui contient deux diapositives ayant les numéros d’identification 267 et 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>

À l’aide du Kit de développement logiciel (SDK) Open XML, vous pouvez créer une structure de document et du contenu à l’aide de classes fortement typées qui correspondent aux éléments PresentationML. Vous trouverez ces classes dans l’espace de noms DocumentFormat.OpenXml.Presentation . Le tableau suivant répertorie les noms des classes qui correspondent aux éléments sld, sldLayout, sldMaster et notesMaster.

Élément PresentationML Classe du Kit de développement logiciel (SDK) Open XML Description
Sld Slide Diapositive de présentation. Il s’agit de l’élément racine de SlidePart.
sldLayout SlideLayout Mise en page des diapositives. Il s’agit de l’élément racine de SlideLayoutPart.
sldMaster SlideMaster Masque des diapositives. Il s’agit de l’élément racine de SlideMasterPart.
Notesmaster NotesMaster Masque des pages de notes (ou handoutMaster). Il s’agit de l’élément racine de NotesMasterPart.

Structure de l’élément theme

Les informations suivantes de la spécification ISO/IEC 29500 peuvent être utiles lors de l’utilisation de cet élément.

Cet élément définit le type complexe de niveau racine associé à une feuille de style partagée (ou thème). Cet élément contient toutes les différentes options de mise en forme disponibles pour un document basé sur un thème ; en outre, il définit l’apparence globale du document lorsque des objets à thème sont utilisés dans ce dernier. [Exemple : l’image suivante illustre l’application de différents thèmes à une présentation. Dans cet exemple, vous pouvez constater qu’un thème peut affecter la police, les couleurs, les arrière-plans, les remplissages et les effets des différents objets d’une présentation. Fin de l’exemple]

Exemple de thème

Dans cet exemple, nous constatons qu’un thème peut affecter la police, les couleurs, les arrière-plans, les remplissages et les effets des différents objets d’une présentation. Fin de l’exemple]

© ISO/IEC29500: 2008.

Le tableau suivant répertorie les types enfants possibles de la classe Theme.

Élément PresentationML Classe du Kit de développement logiciel (SDK) Open XML Description
custClrLst CustomColorList Liste de couleurs personnalisées
extLst Extensionlist Liste d’extensions
extraClrSchemeLst ExtraColorSchemeList Liste de jeux de couleurs supplémentaires
Objectdefaults Objectdefaults Valeurs par défaut des objets
Themeelements Themeelements Éléments de thème

Le fragment de schéma XML suivant définit les quatre composants de l’élément theme. L’élément themeElements contient la mise en forme principale définie dans le thème. Les autres composants fournissent les remplacements, valeurs par défaut et ajouts des informations contenues dans themeElements. Le type complexe qui définit un thème, CT_OfficeStyleSheet, est défini comme suit.

    <complexType name="CT_OfficeStyleSheet">
       <sequence>
           <element name="themeElements" type="CT_BaseStyles" minOccurs="1" maxOccurs="1"/>
           <element name="objectDefaults" type="CT_ObjectStyleDefaults" minOccurs="0" maxOccurs="1"/>
           <element name="extraClrSchemeLst" type="CT_ColorSchemeList" minOccurs="0" maxOccurs="1"/>
           <element name="custClrLst" type="CT_CustomColorList" minOccurs="0" maxOccurs="1"/>
           <element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
       </sequence>
       <attribute name="name" type="xsd:string" use="optional" default=""/>
    </complexType>

Ce type complexe contient également CT_OfficeArtExtensionList, qui est utilisé à des fins ultérieures d’extensibilité du type complexe.


Fonctionnement de l’exemple de code

L’exemple de code est constitué de deux surcharges de la méthode ApplyThemeToPresentation et de la méthode GetSlideLayoutType. Le segment de code suivant illustre la première méthode surchargée, dans laquelle deux fichiers de présentation, themePresentation et presentationFile, sont ouverts et passés à la seconde méthode surchargée en tant que paramètres.

// Apply a new theme to the presentation. 
static void ApplyThemeToPresentation(string presentationFile, string themePresentation)
{
    using (PresentationDocument themeDocument = PresentationDocument.Open(themePresentation, false))
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        ApplyThemeToPresentationDocument(presentationDocument, themeDocument);
    }
}

Dans la seconde méthode surchargée, le code commence par vérifier si l’un des fichiers de présentation est vide, auquel cas il lève une exception. Le code obtient ensuite le composant Présentation du document de présentation en déclarant un objet PresentationPart et en lui affectant la valeur du composant Présentation de l’objet PresentationDocument cible passé. Il obtient ensuite les composants Masque des diapositives à partir des composants Présentation des deux objets passés, puis obtient l’ID de relation du composant Masque des diapositives de la présentation cible.

// Apply a new theme to the presentation. 
static void ApplyThemeToPresentationDocument(PresentationDocument presentationDocument, PresentationDocument themeDocument)
{
    // Get the presentation part of the presentation document.
    PresentationPart presentationPart = presentationDocument.PresentationPart ?? presentationDocument.AddPresentationPart();

    // Get the existing slide master part.
    SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.ElementAt(0);


    string relationshipId = presentationPart.GetIdOfPart(slideMasterPart);

    // Get the new slide master part.
    PresentationPart themeDocPresentationPart = themeDocument.PresentationPart ?? themeDocument.AddPresentationPart();
    SlideMasterPart newSlideMasterPart = themeDocPresentationPart.SlideMasterParts.ElementAt(0);

Le code supprime ensuite le composant Thème existant et le composant Masque des diapositives de la présentation cible. En réutilisant l’ancien ID de relation, il ajoute le nouveau composant Masque des diapositives de la présentation source à la présentation cible. Il ajoute également le composant Thème à la présentation cible.

if (presentationPart.ThemePart is not null)
{
    // Remove the existing theme part.
    presentationPart.DeletePart(presentationPart.ThemePart);
}

// Remove the old slide master part.
presentationPart.DeletePart(slideMasterPart);

// Import the new slide master part, and reuse the old relationship ID.
newSlideMasterPart = presentationPart.AddPart(newSlideMasterPart, relationshipId);

if (newSlideMasterPart.ThemePart is not null)
{
    // Change to the new theme part.
    presentationPart.AddPart(newSlideMasterPart.ThemePart);
}

Le code effectue une itération au sein de tous les composants Mise en page des diapositives du composant Masque des diapositives, puis les ajoute à la liste des nouvelles mises en page des diapositives. Il spécifie le type de mise en page par défaut. Pour cet exemple, le code du type de mise en page par défaut est « Title and Content ».

Dictionary<string, SlideLayoutPart> newSlideLayouts = new Dictionary<string, SlideLayoutPart>();

foreach (var slideLayoutPart in newSlideMasterPart.SlideLayoutParts)
{
    string? newLayoutType = GetSlideLayoutType(slideLayoutPart);

    if (newLayoutType is not null)
    {
        newSlideLayouts.Add(newLayoutType, slideLayoutPart);
    }
}

string? layoutType = null;
SlideLayoutPart? newLayoutPart = null;

// Insert the code for the layout for this example.
string defaultLayoutType = "Title and Content";

Le code effectue une itération au sein de tous les composants Diapositive de la présentation cible et supprime la relation à la mise en page des diapositives sur toutes les diapositives. Il utilise la méthode GetSlideLayoutType pour trouver le type de mise en page du composant Mise en page des diapositives. Pour les diapositives ayant un composant Mise en page des diapositives existant, il ajoute un nouveau composant Mise en page des diapositives du même type que précédemment. Pour les diapositives n’ayant pas de composant Mise en page des diapositives existant, il ajoute un nouveau composant Mise en page des diapositives du type par défaut.

// Remove the slide layout relationship on all slides. 
foreach (var slidePart in presentationPart.SlideParts)
{
    layoutType = null;

    if (slidePart.SlideLayoutPart is not null)
    {
        // Determine the slide layout type for each slide.
        layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart);

        // Delete the old layout part.
        slidePart.DeletePart(slidePart.SlideLayoutPart);
    }

    if (layoutType is not null && newSlideLayouts.TryGetValue(layoutType, out newLayoutPart))
    {
        // Apply the new layout part.
        slidePart.AddPart(newLayoutPart);
    }
    else
    {
        newLayoutPart = newSlideLayouts[defaultLayoutType];

        // Apply the new default layout part.
        slidePart.AddPart(newLayoutPart);
    }
}

Pour obtenir le type de mise en page des diapositives, le code utilise la méthode GetSlideLayoutType qui accepte le composant Mise en page des diapositives en tant que paramètre, puis retourne à la seconde méthode ApplyThemeToPresentation surchargée une chaîne qui représente le nom du type de mise en page des diapositives.

// Get the slide layout type.
static string? GetSlideLayoutType(SlideLayoutPart slideLayoutPart)
{
    CommonSlideData? slideData = slideLayoutPart.SlideLayout?.CommonSlideData;

    return slideData?.Name;
}

Exemple de code

Voici l’exemple de code complet pour copier un thème d’une présentation à une autre. Pour utiliser le programme, vous devez créer deux présentations, une présentation source avec le thème que vous voulez copier, par exemple Myppt9-theme.pptx, et une présentation cible, par exemple Myppt9.pptx. Vous pouvez utiliser l’appel suivant dans votre programme pour effectuer la copie.

ApplyThemeToPresentation(args[0], args[1]);

Une fois l’appel effectué, examinez le contenu du fichier Myppt2.pptx et vous constaterez que le thème est identique à celui du fichier Myppt9-theme.pptx.

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using System.Collections.Generic;
using System.Linq;
ApplyThemeToPresentation(args[0], args[1]);
// Apply a new theme to the presentation. 
static void ApplyThemeToPresentation(string presentationFile, string themePresentation)
{
    using (PresentationDocument themeDocument = PresentationDocument.Open(themePresentation, false))
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        ApplyThemeToPresentationDocument(presentationDocument, themeDocument);
    }
}
// Apply a new theme to the presentation. 
static void ApplyThemeToPresentationDocument(PresentationDocument presentationDocument, PresentationDocument themeDocument)
{
    // Get the presentation part of the presentation document.
    PresentationPart presentationPart = presentationDocument.PresentationPart ?? presentationDocument.AddPresentationPart();

    // Get the existing slide master part.
    SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.ElementAt(0);


    string relationshipId = presentationPart.GetIdOfPart(slideMasterPart);

    // Get the new slide master part.
    PresentationPart themeDocPresentationPart = themeDocument.PresentationPart ?? themeDocument.AddPresentationPart();
    SlideMasterPart newSlideMasterPart = themeDocPresentationPart.SlideMasterParts.ElementAt(0);
    if (presentationPart.ThemePart is not null)
    {
        // Remove the existing theme part.
        presentationPart.DeletePart(presentationPart.ThemePart);
    }

    // Remove the old slide master part.
    presentationPart.DeletePart(slideMasterPart);

    // Import the new slide master part, and reuse the old relationship ID.
    newSlideMasterPart = presentationPart.AddPart(newSlideMasterPart, relationshipId);

    if (newSlideMasterPart.ThemePart is not null)
    {
        // Change to the new theme part.
        presentationPart.AddPart(newSlideMasterPart.ThemePart);
    }
    Dictionary<string, SlideLayoutPart> newSlideLayouts = new Dictionary<string, SlideLayoutPart>();

    foreach (var slideLayoutPart in newSlideMasterPart.SlideLayoutParts)
    {
        string? newLayoutType = GetSlideLayoutType(slideLayoutPart);

        if (newLayoutType is not null)
        {
            newSlideLayouts.Add(newLayoutType, slideLayoutPart);
        }
    }

    string? layoutType = null;
    SlideLayoutPart? newLayoutPart = null;

    // Insert the code for the layout for this example.
    string defaultLayoutType = "Title and Content";
    // Remove the slide layout relationship on all slides. 
    foreach (var slidePart in presentationPart.SlideParts)
    {
        layoutType = null;

        if (slidePart.SlideLayoutPart is not null)
        {
            // Determine the slide layout type for each slide.
            layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart);

            // Delete the old layout part.
            slidePart.DeletePart(slidePart.SlideLayoutPart);
        }

        if (layoutType is not null && newSlideLayouts.TryGetValue(layoutType, out newLayoutPart))
        {
            // Apply the new layout part.
            slidePart.AddPart(newLayoutPart);
        }
        else
        {
            newLayoutPart = newSlideLayouts[defaultLayoutType];

            // Apply the new default layout part.
            slidePart.AddPart(newLayoutPart);
        }
    }
}
// Get the slide layout type.
static string? GetSlideLayoutType(SlideLayoutPart slideLayoutPart)
{
    CommonSlideData? slideData = slideLayoutPart.SlideLayout?.CommonSlideData;

    return slideData?.Name;
}

Voir aussi