Compartir a través de


Insertar una nueva diapositiva en una presentación

En este tema se muestra cómo usar las clases del SDK de Open XML para insertar una nueva diapositiva en una presentación mediante programación.

Obtención de un objeto PresentationDocument

En el SDK de Open XML, la PresentationDocument clase representa un paquete de documento de presentación. Para trabajar con un documento de presentación, cree primero una instancia de la PresentationDocument clase y, a continuación, trabaje con esa instancia. Para crear la instancia de clase a partir del documento, llame al Open método que usa una ruta de acceso de archivo y a un valor booleano como segundo parámetro para especificar si un documento es editable. Para abrir un documento de lectura y escritura, especifique el valor true de este parámetro como se muestra en la instrucción siguiente using . En este segmento de código, el presentationFile parámetro es una cadena que representa la ruta de acceso completa del archivo desde el que desea abrir el documento.

// Open the source document as read/write. 
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))

Con v3.0.0+ el Close() método se ha quitado en favor de confiar en la instrucción using. Esto garantiza que se llama automáticamente al Dispose() método cuando se alcanza la llave de cierre. El bloque que sigue a la using instrucción establece un ámbito para el objeto que se crea o se denomina en la using instrucción , en este caso presentationDocument.

Estructura básica de un documento de presentación

La estructura básica de un PresentationML documento consta de varias partes, entre las que se encuentra la parte principal que contiene la definición de presentación. El siguiente texto de la especificación ISO/IEC 29500 presenta la forma general de un PresentationML paquete.

La parte principal de un PresentationML paquete comienza con un elemento raíz de presentación. Dicho elemento contiene una presentación que, a su vez, hace referencia a una lista de diapositivas, a otra de patrones de diapositivas, a otra de patrones de notas y a otra de patrones de documentos. La lista de diapositivas hace referencia a todas las diapositivas de la presentación, la de patrones de diapositivas a todos los patrones de diapositivas que se han usado en la presentación, el patrón de notas contiene información acerca del formato de las páginas de notas y el patrón de documentos describe la apariencia de los documentos.

Un documento es un conjunto impreso de diapositivas que se pueden proporcionar a un público.

Al igual que el texto y los gráficos, cada diapositiva puede incluir comentarios y notas, tener un diseño y formar parte de una o varias presentaciones personalizadas. Un comentario es una anotación dirigida a la persona que se encarga del mantenimiento de las diapositivas de la presentación. Una nota es un aviso o texto dirigido al moderador o al público.

Otras características que un PresentationML documento puede incluir son las siguientes: animación, audio, vídeo y transiciones entre diapositivas .

Un PresentationML documento no se almacena como un cuerpo grande en una sola parte. En su lugar, los elementos que implementan ciertas agrupaciones de funcionalidades se almacenan en partes independientes. Por ejemplo, todos los autores de un documento se almacenan en una parte de autores mientras que cada diapositiva tiene su propia parte.

ISO/IEC 29500: 2016

El siguiente ejemplo de código XML representa una presentación que contiene dos diapositivas denotadas por los identificadores 267 y 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>

Con el SDK de Open XML, puede crear contenido y estructura de documentos mediante clases fuertemente tipadas que corresponden a elementos PresentationML. Puede encontrar estas clases en el espacio de DocumentFormat.OpenXml.Presentation nombres. En la tabla siguiente se enumeran los nombres de clase de las clases correspondientes a los sldelementos , sldLayout, sldMastery notesMaster .

Elemento de PresentationML Open XML SDK (clase) Descripción
<sld/> Slide Diapositiva de presentación. Es el elemento raíz de SlidePart.
<sldLayout/> SlideLayout Diseño de la diapositiva. Es el elemento raíz de SlideLayoutPart.
<sldMaster/> SlideMaster Patrón de diapositivas. Es el elemento raíz de SlideMasterPart.
<notesMaster/> NotesMaster Patrón de notas (o handoutMaster). Es el elemento raíz de NotesMasterPart.

Funcionamiento del código de ejemplo

El código de ejemplo consta de dos sobrecargas del InsertNewSlide método . El primer método sobrecargado toma tres parámetros: la ruta de acceso completa del archivo de presentación al cual se debe agregar una diapositiva, un número entero que representa la posición del índice de la diapositiva con base cero en la presentación donde se debe agregar la diapositiva y la cadena que representa el título de la nueva diapositiva. Abre el archivo de presentación como de lectura y escritura, obtiene un PresentationDocument objeto y, a continuación, pasa ese objeto al segundo método sobrecargado InsertNewSlide , que realiza la inserción.

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

El segundo método sobrecargado InsertNewSlide crea un nuevo Slide objeto, establece sus propiedades y, a continuación, lo inserta en el orden de diapositivas de la presentación. La primera sección del método crea la diapositiva y establece sus propiedades.

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

La siguiente sección del segundo método sobrecargado InsertNewSlide agrega una forma de título a la diapositiva y establece sus propiedades, incluido su 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 })));

La siguiente sección del segundo método sobrecargado InsertNewSlide agrega una forma de cuerpo a la diapositiva y establece sus propiedades, incluido su 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());

La sección final del segundo método sobrecargado InsertNewSlide crea una nueva parte de diapositiva, busca la posición de índice especificada donde insertar la diapositiva y, a continuación, la inserta y asigna la nueva diapositiva a la nueva parte de diapositiva.

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

A continuación se incluye el código de ejemplo completo en C# y 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;
}

Vea también