Compartilhar via


Aplicar um tema a uma apresentação

Este tópico mostra como utilizar as classes no SDK Open XML para o Office para aplicar o tema de uma apresentação a outra apresentação programaticamente.


Obter um Objeto PresentationDocument

No SDK Open XML, a PresentationDocument classe representa um pacote de documento de apresentação. Para trabalhar com um documento de apresentação, crie primeiro uma instância da classe PresentationDocument e, em seguida, trabalhe com essa instância. Para criar a instância de classe a partir do documento, chame o Open método que utiliza um caminho de ficheiro e um valor Booleano como segundo parâmetro para especificar se um documento é editável. Para abrir um documento para acesso só de leitura, especifique o valor falso para este parâmetro. Para abrir um documento para acesso de leitura/escrita, especifique o valor verdadeiro para este parâmetro. Na instrução using seguinte, são abertos dois ficheiros de apresentação, a apresentação de destino, a qual pretende aplicar um tema e a apresentação de origem, que já tem esse tema aplicado. O ficheiro de apresentação de origem é aberto para acesso só de leitura e o ficheiro de apresentação de destino é aberto para acesso de leitura/escrita. Neste código, o parâmetro themePresentation é uma cadeia que representa o caminho para o documento de apresentação de origem e o parâmetro presentationFile é uma cadeia que representa o caminho para o documento de apresentação de destino.

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

Com a v3.0.0+ o Close() método foi removido a favor de depender da instrução using. Isto garante que o Dispose() método é chamado automaticamente quando a chaveta de fecho é atingida. O bloco que segue a using instrução estabelece um âmbito para o objeto que é criado ou nomeado na using instrução , neste caso themeDocument e presentationDocument.


Estrutura básica do documento de apresentação

A estrutura de documentos básica de um PresentationML documento consiste em várias partes, entre as quais a main parte que contém a definição da apresentação. O texto seguinte da especificação ISO/IEC 29500 apresenta a forma geral de um PresentationML pacote.

O main parte de um PresentationML pacote começa com um elemento raiz de apresentação. Esse elemento contém uma apresentação que, por sua vez, se refere a uma lista de diapositivos, a uma lista de master de diapositivos, a uma lista de notas master e a um folheto master lista. A lista de diapositivos refere-se a todos os diapositivos na apresentação; A lista de master de diapositivos refere-se a todos os modelos globais de diapositivos utilizados na apresentação; as notas master contêm informações sobre a formatação das páginas de notas; e o master de folheto descreve o aspeto de um folheto.

Um folheto é um conjunto impresso de diapositivos que podem ser fornecidos a uma audiência.

Além de texto e gráficos, cada diapositivo pode conter comentários e notas, pode ter um esquema e pode fazer parte de uma ou mais apresentações personalizadas. Um comentário é uma anotação destinada à pessoa que mantém o conjunto de diapositivos da apresentação. Uma nota é um lembrete ou texto destinado ao apresentador ou à audiência.

Outras funcionalidades que um PresentationML documento pode incluir: animação, áudio, vídeo e transições entre diapositivos.

Um PresentationML documento não é armazenado como um corpo grande numa única parte. Em vez disso, os elementos que implementam determinados agrupamentos de funcionalidades são armazenados em partes separadas. Por exemplo, todos os autores num documento são armazenados numa parte dos autores, enquanto cada diapositivo tem a sua própria parte.

ISO/IEC 29500: 2016

O seguinte exemplo de código XML representa uma apresentação que contém dois diapositivos indicados pelos IDs 267 e 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>

Com o SDK Open XML, pode criar a estrutura e o conteúdo do documento com classes com tipos fortes que correspondem a elementos PresentationML. Pode encontrar estas classes no espaço de nomes. A tabela seguinte lista os nomes das classes que correspondem aos sldelementos , sldLayout, sldMastere notesMaster .

Elemento PresentationML Abrir Classe SDK XML Descrição
<sld/> Slide Diapositivo de Apresentação. É o elemento raiz de SlidePart.
<sldLayout/> SlideLayout Esquema de Diapositivo. É o elemento raiz de SlideLayoutPart.
<sldMaster/> SlideMaster Modelo Global de Diapositivos. É o elemento raiz de SlideMasterPart.
<notesMaster/> NotesMaster Modelo Global de Notas (ou handoutMaster). É o elemento raiz de NotesMasterPart.

Estrutura do Elemento Tema

As seguintes informações da especificação ISO/IEC 29500 podem ser úteis ao trabalhar com este elemento.

Este elemento define o tipo complexo de nível de raiz associado a uma folha de estilos partilhada (ou tema). Este elemento contém todas as diferentes opções de formatação disponíveis para um documento através de um tema e define o aspeto e funcionalidade gerais do documento quando os objetos temáticos são utilizados no documento. [Exemplo: considere a imagem seguinte como um exemplo de temas diferentes em utilização aplicados a uma apresentação. Neste exemplo, pode ver como um tema pode afetar o tipo de letra, as cores, os fundos, os preenchimentos e os efeitos de diferentes objetos numa apresentação. exemplo final]

Theme sample

Neste exemplo, vemos como um tema pode afetar o tipo de letra, as cores, os fundos, os preenchimentos e os efeitos de diferentes objetos numa apresentação. exemplo final]

© ISO/IEC 29500: 2016

A tabela seguinte lista os possíveis tipos subordinados da classe Tema.

Elemento PresentationML Abrir Classe SDK XML Descrição
custClrLst CustomColorList Lista de Cores Personalizada
extLst ExtensionList Lista de Extensões
extraClrSchemeLst ExtraColorSchemeList Lista de Esquemas de Cores Adicionais
objectDefaults ObjectDefaults Predefinições de Objeto
themeElements ThemeElements Elementos do Tema

O fragmento de Esquema XML seguinte define as quatro partes do elemento de tema. O elemento themeElements é a peça que contém o main formatação definida no tema. As outras partes fornecem substituições, predefinições e adições às informações contidas em themeElements. O tipo complexo que define um tema, CT_OfficeStyleSheet, é definido da seguinte forma.

    <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>

Este tipo complexo também contém um CT_OfficeArtExtensionList, que é utilizado para extensibilidade futura deste tipo complexo.


Como funciona o código de exemplo

O código de exemplo consiste em duas sobrecargas do método ApplyThemeToPresentation e no método GetSlideLayoutType . O segmento de código seguinte mostra o primeiro método sobrecarregado, no qual os dois ficheiros de apresentação, themePresentation e presentationFile, são abertos e transmitidos para o segundo método sobrecarregado como parâmetros.

// 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);
    }
}

No segundo método sobrecarregado, o código começa por verificar se algum dos ficheiros de apresentação está vazio, caso em que gera uma exceção. Em seguida, o código obtém a parte da apresentação do documento de apresentação ao declarar um objeto PresentationPart e defini-lo como igual à parte da apresentação do objeto PresentationDocument de destino transmitido. Em seguida, obtém o diapositivo master partes das partes da apresentação de ambos os objetos transmitidos e obtém o ID de relação do diapositivo master parte da apresentação de destino.

// 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);

Em seguida, o código remove a parte do tema existente e o diapositivo master parte da apresentação de destino. Ao reutilizar o ID da relação antiga, adiciona o novo diapositivo master parte da apresentação de origem à apresentação de destino. Também adiciona a parte do tema à apresentação de destino.

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);
}

O código itera todas as partes do esquema de diapositivo no diapositivo master parte e adiciona-as à lista de novos esquemas de diapositivos. Especifica o tipo de esquema predefinido. Para este exemplo, o código para o tipo de esquema predefinido é "Título e Conteúdo".

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";

O código itera todas as partes do diapositivo na apresentação de destino e remove a relação de esquema de diapositivo em todos os diapositivos. Utiliza o método GetSlideLayoutType para encontrar o tipo de esquema da peça de esquema de diapositivo. Para qualquer diapositivo com uma peça de esquema de diapositivo existente, adiciona uma nova parte do esquema de diapositivo do mesmo tipo que tinha anteriormente. Para qualquer diapositivo sem uma peça de esquema de diapositivo existente, adiciona uma nova parte do esquema de diapositivo do tipo predefinido.

// 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);
    }
}

Para obter o tipo de esquema de diapositivo, o código utiliza o método GetSlideLayoutType que utiliza a parte do esquema do diapositivo como um parâmetro e devolve ao segundo método ApplyThemeToPresentation sobrecarregado uma cadeia que representa o nome do tipo de esquema de diapositivo

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

    return slideData?.Name;
}

Código de exemplo

Segue-se o código de exemplo completo para copiar um tema de uma apresentação para outra. Para utilizar o programa, tem de criar duas apresentações, uma apresentação de origem com o tema que pretende copiar, por exemplo, Myppt9-theme.pptx e a outra é a apresentação de destino, por exemplo, Myppt9.pptx. Pode utilizar a seguinte chamada no programa para efetuar a cópia.

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

Depois de efetuar essa chamada, pode inspecionar o ficheiro Myppt2.pptx e verá o mesmo tema do ficheiro 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;
}

Confira também