Compartilhar via


Inserir um novo slide em uma apresentação

Este tópico mostra como utilizar as classes no SDK Open XML para inserir um novo diapositivo numa 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 PresentationDocument classe 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 leitura/escrita, especifique o valor true para este parâmetro, conforme mostrado na instrução seguinte using . Neste segmento de código, o presentationFile parâmetro é uma cadeia que representa o caminho completo para o ficheiro a partir do qual pretende abrir o documento.

// Open the source document as read/write. 
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 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.

Como funciona o código de exemplo

O código de exemplo consiste em duas sobrecargas do InsertNewSlide método . O primeiro método sobrecarregado utiliza três parâmetros: o caminho completo para o ficheiro de apresentação ao qual adicionar um diapositivo, um número inteiro que representa a posição do índice de diapositivos baseado em zero na apresentação onde adicionar o diapositivo e a cadeia que representa o título do novo diapositivo. Abre o ficheiro de apresentação como leitura/escrita, obtém um PresentationDocument objeto e, em seguida, transmite esse objeto para o segundo método sobrecarregado InsertNewSlide , que executa a inserção.

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

O segundo método sobrecarregado InsertNewSlide cria um novo Slide objeto, define as respetivas propriedades e, em seguida, insere-o na ordem dos diapositivos na apresentação. A primeira secção do método cria o diapositivo e define as respetivas propriedades.

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

A secção seguinte do segundo método sobrecarregado InsertNewSlide adiciona uma forma de título ao diapositivo e define as respetivas propriedades, incluindo o respetivo texto.

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

A secção seguinte do segundo método sobrecarregado InsertNewSlide adiciona uma forma do corpo ao diapositivo e define as respetivas propriedades, incluindo o respetivo texto.

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

A secção final do segundo método sobrecarregado InsertNewSlide cria uma nova peça de diapositivo, localiza a posição de índice especificada onde inserir o diapositivo e, em seguida, insere-o e atribui o novo diapositivo à nova parte do diapositivo.

// 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ódigo de exemplo

Este é o código de exemplo completo em C# e em 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;
}

Confira também