Compartilhar via


Aplicar um tema a uma apresentação

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


Obtendo um objeto PresentationDocument

No SDK do Open XML, a classe PresentationDocument representa um pacote de documento de apresentação. Para trabalhar com um documento de apresentação, primeiro crie uma instância da classe PresentationDocument e trabalhe com essa instância. Para criar a instância de classe a partir do documento, chame o método Open(String, Boolean) que usa um caminho de arquivo e um valor booliano como o segundo parâmetro para especificar se um documento é editável. Para abrir um documento para acesso somente leitura, especifique o valor false para este parâmetro. Para abrir um documento para acesso de leitura/gravação, especifique o valor verdadeiro para este parâmetro. Na instrução a seguir, dois arquivos de apresentação são abertos, a apresentação de destino, à qual aplicar um tema e a apresentação de origem, que já tem esse tema aplicado. O arquivo de apresentação de origem é aberto para acesso somente leitura e o arquivo de apresentação de destino é aberto para acesso de leitura/gravação. Neste código, o parâmetro themePresentation é uma cadeia de caracteres que representa o caminho para o documento de apresentação de origem e o parâmetro presentationFile é uma cadeia de caracteres 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))
{

A instrução using fornece uma alternativa recomendada para a sequência típica de .Open, .Save e .Close. Ela garante que o método Dispose (método interno usado pelo SDK do Open XML para limpar recursos) seja chamado automaticamente quando a chave de fechamento for atingida. O bloco que segue a instrução de uso estabelece um escopo para o objeto que é criado ou nomeado na instrução de uso , nesse caso , temaDocument e presentationDocument.


Estrutura básica do documento de apresentação

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

A main parte de um pacote PresentationML 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 slides, uma lista de master de slides, uma lista de master de anotações e uma lista de master de apostila. A lista de slides refere-se a todos os slides na apresentação; A lista de master de slides refere-se a todos os mestres de slides usados na apresentação; as anotações master contém informações sobre a formatação de páginas de anotações; e a apostila master descreve como uma apostila parece.

Uma apostila é um conjunto impresso de slides que pode ser fornecido a uma audiência.

Além de texto e gráficos, cada slide pode conter comentários e anotações, pode ter um layout e pode fazer parte de uma ou mais apresentações personalizadas. Um comentário é uma anotação destinada à pessoa que mantém o deck de slides de apresentação. Uma nota é um lembrete ou um pedaço de texto destinado ao apresentador ou ao público-alvo.

Outros recursos que um documento PresentationML pode incluir o seguinte: animação, áudio, vídeo e transições entre slides.

Um documento PresentationML não é armazenado como um corpo grande em uma única parte. Em vez disso, os elementos que implementam determinados agrupamentos de funcionalidade são armazenados em partes separadas. Por exemplo, todos os comentários em um documento são armazenados em uma parte de comentário, enquanto cada slide tem sua própria parte.

© ISO/IEC29500: 2008.

O exemplo de código XML a seguir representa uma apresentação que contém dois slides denotados pelas 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>

Usando o SDK do Open XML, você pode criar estrutura de documentos e conteúdo usando classes fortemente tipdas que correspondem a elementos PresentationML. Você pode encontrar essas classes no namespace DocumentFormat.OpenXml.Presentation . A tabela a seguir lista os nomes de classe das classes que correspondem aos elementos sld, sldLayout, sldMaster e notesMaster .

Elemento PresentationML Classe SDK Open XML Descrição
Sld Slide Slide de Apresentação. É o elemento raiz do SlidePart.
sldLayout SlideLayout Layout do Slide. É o elemento raiz do SlideLayoutPart.
sldMaster SlideMaster Mestre de Slides. É o elemento raiz do SlideMasterPart.
notesMaster NotesMaster Mestre de Anotações (ou handoutMaster). É o elemento raiz do NotesMasterPart.

Estrutura do Elemento Tema

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

Esse elemento define o tipo complexo de nível raiz associado a uma folha de estilos compartilhada (ou tema). Esse elemento contém todas as diferentes opções de formatação disponíveis para um documento por meio de um tema e define a aparência geral do documento quando objetos temáticos são usados no documento. [Exemplo: considere a imagem a seguir como um exemplo de temas diferentes em uso aplicados a uma apresentação. Neste exemplo, você pode ver como um tema pode afetar fonte, cores, planos de fundo, preenchimentos e efeitos para diferentes objetos em uma apresentação. exemplo final]

Theme sample

Neste exemplo, vemos como um tema pode afetar fonte, cores, planos de fundo, preenchimentos e efeitos para diferentes objetos em uma apresentação. exemplo final]

© ISO/IEC29500: 2008.

A tabela a seguir lista os possíveis tipos filho da classe Tema.

Elemento PresentationML Classe SDK Open XML Descrição
custClrLst CustomColorList Lista de cores personalizada
extLst ExtensionList Lista de extensões
extraClrSchemeLst ExtraColorSchemeList Lista de esquema de cores extra
objectDefaults ObjectDefaults Padrões de objeto
themeElements ThemeElements Elementos de tema

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

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

Esse tipo complexo também contém um CT_OfficeArtExtensionList, que é usado para extensibilidade futura desse tipo complexo.


Como funciona o código de exemplo

O código de exemplo consiste em duas sobrecargas do método ApplyThemeToPresentation e do método GetSlideLayoutType . O segmento de código a seguir mostra o primeiro método sobrecarregado, no qual os dois arquivos de apresentação, temaPresentação e presentationFile, são abertos e passados 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 verificando se algum dos arquivos de apresentação está vazio, nesse caso, gera uma exceção. Em seguida, o código obtém a parte de apresentação do documento de apresentação declarando um objeto PresentationPart e definindo-o igual à parte de apresentação do objeto PresentationDocument de destino passado. Em seguida, ele obtém o slide master partes das partes de apresentação de ambos os objetos passados e obtém a ID de relação do slide 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 slide master parte da apresentação de destino. Ao reutilizando a ID de relação antiga, ela adiciona o novo slide master parte da apresentação de origem à apresentação de destino. Ele 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 layout do slide no slide master parte e as adiciona à lista de novos layouts de slides. Ele especifica o tipo de layout padrão. Para este exemplo, o código para o tipo de layout padrão é "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 de slide na apresentação de destino e remove a relação de layout do slide em todos os slides. Ele usa o método GetSlideLayoutType para encontrar o tipo de layout da parte de layout do slide. Para qualquer slide com uma parte de layout de slide existente, ele adiciona uma nova parte de layout de slide do mesmo tipo que tinha anteriormente. Para qualquer slide sem uma parte de layout de slide existente, ele adiciona uma nova parte do layout do slide do tipo padrão.

// 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 do layout do slide, o código usa o método GetSlideLayoutType que usa a parte do layout do slide como parâmetro e retorna ao segundo método ApplyThemeToPresentation sobrecarregado uma cadeia de caracteres que representa o nome do tipo de layout de slide

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

    return slideData?.Name;
}

Código de exemplo

A seguir está o código de exemplo completo para copiar um tema de uma apresentação para outra. Para usar o programa, você deve criar duas apresentações, uma apresentação de origem com o tema que deseja copiar, por exemplo, Myppt9-theme.pptx e a outra é a apresentação de destino, por exemplo, Myppt9.pptx. Você pode usar a chamada a seguir em seu programa para executar a cópia.

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

Depois de executar essa chamada, você pode inspecionar o arquivo Myppt2.pptx e verá o mesmo tema do Myppt9-theme.pptx de arquivo.

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