Gestire i commenti della presentazione in Java

Panoramica

Questo articolo spiega come gestire i commenti di presentazione con Aspose.Slides per Java. Introduce i principali tipi relativi ai commenti e dimostra come aggiungere commenti alle diapositive, accedere ai commenti esistenti, lavorare con le risposte e i commenti moderni, e rimuovere i commenti da una presentazione.

Gli esempi coprono scenari comuni di revisione e collaborazione in PowerPoint, come assegnare commenti agli autori, leggere il testo e i metadati dei commenti, costruire catene di risposte e rimuovere commenti selezionati o tutti i commenti.

In PowerPoint, i commenti appaiono come annotazioni sulle diapositive. Selezionare un commento visualizza il suo testo e la discussione correlata.

Per richiedere che i commenti siano mostrati o nascosti all’apertura di una presentazione senza modificare i commenti stessi, vedere Mostrare o nascondere i commenti all’apertura di una presentazione.

Perché aggiungere commenti alle presentazioni?

Puoi usare i commenti per fornire feedback e collaborare con i colleghi durante la revisione delle presentazioni.

Aspose.Slides per Java fornisce le seguenti API per lavorare con i commenti:

  • La classe Presentation fornisce l’accesso agli autori dei commenti della presentazione.
  • L’interfaccia ICommentCollection rappresenta i commenti associati a un singolo autore.
  • L’interfaccia IComment fornisce informazioni su un commento, inclusi autore, data di creazione, posizione e testo.
  • La classe CommentAuthor fornisce informazioni su un autore, inclusi nome, iniziali e commenti associati.

Aggiungere commenti alle diapositive

L’esempio crea due diapositive e registra un autore di commenti con addAuthor. Usa addComment per inserire un commento su ciascuna diapositiva, poi recupera i commenti della prima diapositiva per quell’autore con getSlideComments. La console mostra il testo del primo commento due volte, dimostrando l’accesso sia tramite la diapositiva sia tramite l’autore, e la presentazione salvata contiene entrambi i commenti.

import com.aspose.slides.IComment;
import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.ISlide;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import java.awt.geom.Point2D;
import java.util.Date;

Presentation presentation = new Presentation();
try {
    ISlide firstSlide = presentation.getSlides().get_Item(0);
    ISlide secondSlide = presentation.getSlides().addEmptySlide(presentation.getLayoutSlides().get_Item(0));

    ICommentAuthor author = presentation.getCommentAuthors().addAuthor("Jawad", "MF");
    Point2D.Float position = new Point2D.Float(0.2f, 0.2f);
    Date createdTime = new Date();

    author.getComments().addComment("Hello Jawad, this is a slide comment", firstSlide, position, createdTime);
    author.getComments().addComment("Hello Jawad, this is the second slide comment", secondSlide, position, createdTime);

    IComment[] comments = firstSlide.getSlideComments(author);
    if (comments.length > 0) {
        IComment firstComment = comments[0];
        System.out.println(firstComment.getText());

        String commentText = firstComment.getAuthor().getComments().get_Item(0).getText();
        System.out.println(commentText);
    }

    presentation.save("Comments_out.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Trovare o creare un autore di commenti

Quando una revisione automatizzata elabora la stessa presentazione più volte, cerca nella collezione restituita da getCommentAuthors prima di aggiungere un autore. findByNameAndInitials confronta sia il nome sia le iniziali e restituisce un array di autori corrispondenti, o un array vuoto se non esistono corrispondenze. Al contrario, findByName ricerca solo per nome, indipendentemente dalle iniziali. Chiamare addAuthor con un nome e iniziali già presenti nella collezione genera un’eccezione.

L’esempio richiede un file di presentazione con almeno una diapositiva. In ciascuna delle due iterazioni, riutilizza il primo autore corrispondente, o ne crea uno solo quando il risultato è vuoto. Se ci sono più corrispondenze, seleziona il primo elemento dell’array senza unire o rimuovere gli altri autori. Poi chiama addComment per l’autore selezionato e salva la presentazione. La seconda iterazione apre l’output della prima e ripete l’operazione.

import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import java.awt.geom.Point2D;
import java.util.Date;

final String authorName = "Reviewer";
final String authorInitials = "RV";

String inputFile = "input.pptx";
Point2D.Float position = new Point2D.Float(20, 20);

for (int pass = 1; pass <= 2; pass++) {
    Presentation presentation = new Presentation(inputFile);
    try {
        ICommentAuthor[] matches = presentation.getCommentAuthors().findByNameAndInitials(authorName, authorInitials);

        ICommentAuthor author = matches.length > 0 ? matches[0] : presentation.getCommentAuthors().addAuthor(authorName, authorInitials);
        author.getComments().addComment("Please review this slide.", presentation.getSlides().get_Item(0), position, new Date());

        String outputFile = "review_pass_" + pass + ".pptx";
        presentation.save(outputFile, SaveFormat.Pptx);
        inputFile = outputFile;
    } finally {
        presentation.dispose();
    }
}

La seconda iterazione aggiunge un altro commento senza aggiungere un nuovo autore o rimuovere commenti esistenti. Il file finale, review_pass_2.pptx, contiene entrambi i nuovi commenti insieme a eventuali commenti originali. Riutilizzare un autore non deduplica i commenti: per evitare di aggiungere ripetutamente lo stesso commento, implementa un’adeguata rilevazione dei duplicati prima di aggiungerlo.

Accedere ai commenti delle diapositive

L’esempio apre una presentazione esistente e legge la collezione restituita da getCommentAuthors. Per ogni autore, itera sulla collezione restituita da getComments e stampa il numero della diapositiva, il testo del commento, il nome dell’autore e l’ora di creazione. La presentazione di input deve contenere commenti per produrre output nella console.

import com.aspose.slides.IComment;
import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.Presentation;

Presentation presentation = new Presentation("Comments1.pptx");
try {
    for (ICommentAuthor author : presentation.getCommentAuthors()) {
        for (IComment comment : author.getComments()) {
            System.out.println("Slide: " + comment.getSlide().getSlideNumber());
            System.out.println("Comment: " + comment.getText());
            System.out.println("Author: " + comment.getAuthor().getName());
            System.out.println("Posted at: " + comment.getCreatedTime());
            System.out.println();
        }
    }
} finally {
    presentation.dispose();
}

Rispondere ai commenti

Un commento principale è il commento originale in cima a una gerarchia di risposte. I metodi IComment.getParentComment e IComment.setParentComment consentono di ottenere o impostare il commento padre.

L’esempio crea commenti da due autori e usa setParentComment per costruire risposte, includendo una risposta a un’altra risposta. Passare null a getSlideComments recupera i commenti da tutti gli autori; la console indentifica ogni voce in base alla sua profondità nella gerarchia di risposte. L’esempio salva la discussione completa, chiama remove sul primo commento radice e salva una seconda presentazione con quel commento e le sue risposte rimosse.

import com.aspose.slides.IComment;
import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.ISlide;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import java.awt.geom.Point2D;
import java.util.Date;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    Point2D.Float position = new Point2D.Float(10, 10);
    Date createdTime = new Date();

    ICommentAuthor originalAuthor = presentation.getCommentAuthors().addAuthor("Author_1", "A.A.");
    IComment rootComment = originalAuthor.getComments().addComment("comment 1", slide, position, createdTime);

    ICommentAuthor reviewer = presentation.getCommentAuthors().addAuthor("Author_2", "B.B.");
    IComment firstReply = reviewer.getComments().addComment("reply 1 for comment 1", slide, position, createdTime);
    firstReply.setParentComment(rootComment);

    IComment secondReply = reviewer.getComments().addComment("reply 2 for comment 1", slide, position, createdTime);
    secondReply.setParentComment(rootComment);

    IComment subReply = originalAuthor.getComments().addComment("subreply 3 for reply 2", slide, position, createdTime);
    subReply.setParentComment(secondReply);

    reviewer.getComments().addComment("comment 2", slide, position, createdTime);
    IComment separateComment = reviewer.getComments().addComment("comment 3", slide, position, createdTime);

    IComment separateReply = originalAuthor.getComments().addComment("reply 4 for comment 3", slide, position, createdTime);
    separateReply.setParentComment(separateComment);

    IComment[] comments = slide.getSlideComments(null);
    for (int i = 0; i < comments.length; i++) {
        IComment comment = comments[i];
        while (comment.getParentComment() != null) {
            System.out.print("\t");
            comment = comment.getParentComment();
        }

        System.out.println(comments[i].getAuthor().getName() + ": " + comments[i].getText());
    }

    presentation.save("parent_comment.pptx", SaveFormat.Pptx);

    rootComment.remove();
    presentation.save("remove_comment.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Aggiungere commenti moderni

I commenti moderni possono essere associati alla diapositiva stessa, a una forma specifica o a un intervallo di testo all’interno di un’AutoShape. Il metodo ICommentCollection.addModernComment accetta un argomento IShape oltre alla diapositiva e alle coordinate del marcatore del commento.

Quando viene passato null per l’argomento shape, il commento è un commento a livello di diapositiva. Il suo marcatore è posizionato dalle coordinate fornite, ma non è associato a una forma specifica, quindi IModernComment.getShape restituisce null. Quando viene fornita una IShape, il commento è ancorato a quella forma. Le coordinate continuano a definire la posizione del marcatore del commento sulla diapositiva, mentre l’associazione alla forma può essere recuperata tramite IModernComment.getShape.

Ancorare un commento moderno a una forma

L’esempio chiama addModernComment due volte: una volta con una forma null per un commento a livello di diapositiva e una volta con un rettangolo come ancoraggio. Leggere getShape stampa true per il controllo null del commento a livello di diapositiva e Revenue title per il commento ancorato. Entrambi i commenti vengono salvati con la presentazione.

import com.aspose.slides.IAutoShape;
import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.IModernComment;
import com.aspose.slides.ISlide;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import com.aspose.slides.ShapeType;
import java.awt.geom.Point2D;
import java.util.Date;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    ICommentAuthor author = presentation.getCommentAuthors().addAuthor("Reviewer", "RV");

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 50, 50, 300, 80);
    shape.setName("Revenue title");
    shape.getTextFrame().setText("Quarterly revenue");

    Date createdTime = new Date();
    Point2D.Float slideCommentPosition = new Point2D.Float(20, 20);
    Point2D.Float shapeCommentPosition = new Point2D.Float(60, 60);
    IModernComment slideComment = author.getComments().addModernComment("Review the overall slide layout.", slide, null, slideCommentPosition, createdTime);
    IModernComment shapeComment = author.getComments().addModernComment("Check this title.", slide, shape, shapeCommentPosition, createdTime);

    System.out.println(slideComment.getShape() == null);
    System.out.println(shapeComment.getShape().getName());

    presentation.save("modern_comments.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Ancorare commenti a diversi tipi di forma

Qualsiasi oggetto della diapositiva che implementa IShape può essere usato come ancoraggio di forma. Esempi comuni includono IAutoShape, IPictureFrame, IGroupShape, IConnector e IGraphicalObject come grafici.

L’esempio utilizza addModernComment per associare un commento a ciascuno dei cinque tipi di forma: un’AutoShape, un frame immagine, un gruppo, un connettore e un grafico. L’immagine utilizza dati immagine incorporati, quindi non è necessaria un’immagine esterna. Ogni commento ha la propria posizione del marcatore, e la presentazione salvata conserva tutte e cinque le associazioni di forma.

import com.aspose.slides.ChartType;
import com.aspose.slides.IAutoShape;
import com.aspose.slides.IChart;
import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.IConnector;
import com.aspose.slides.IGroupShape;
import com.aspose.slides.IPPImage;
import com.aspose.slides.IPictureFrame;
import com.aspose.slides.ISlide;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import com.aspose.slides.ShapeType;
import java.awt.geom.Point2D;
import java.util.Base64;
import java.util.Date;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    ICommentAuthor author = presentation.getCommentAuthors().addAuthor("Reviewer", "RV");
    Date createdTime = new Date();

    IAutoShape autoShape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 20, 20, 180, 60);
    autoShape.getTextFrame().setText("AutoShape");

    Point2D.Float autoShapeCommentPosition = new Point2D.Float(30, 30);
    author.getComments().addModernComment("Comment on an AutoShape.", slide, autoShape, autoShapeCommentPosition, createdTime);

    String imageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAFklEQVR4nGP8//8/AwMDEwMDAwMDAwAkBgMB/DXemwAAAABJRU5ErkJggg==";
    byte[] imageData = Base64.getDecoder().decode(imageBase64);
    IPPImage image = presentation.getImages().addImage(imageData);
    IPictureFrame pictureFrame = slide.getShapes().addPictureFrame(ShapeType.Rectangle, 220, 20, 120, 80, image);
    Point2D.Float pictureCommentPosition = new Point2D.Float(230, 30);
    author.getComments().addModernComment("Comment on a picture.", slide, pictureFrame, pictureCommentPosition, createdTime);

    IGroupShape groupShape = slide.getShapes().addGroupShape();
    groupShape.getShapes().addAutoShape(ShapeType.Rectangle, 0, 0, 80, 40);
    groupShape.getShapes().addAutoShape(ShapeType.Ellipse, 100, 0, 80, 40);
    Point2D.Float groupCommentPosition = new Point2D.Float(40, 150);
    author.getComments().addModernComment("Comment on a group.", slide, groupShape, groupCommentPosition, createdTime);

    IConnector connector = slide.getShapes().addConnector(ShapeType.StraightConnector1, 220, 150, 140, 40);
    Point2D.Float connectorCommentPosition = new Point2D.Float(240, 150);
    author.getComments().addModernComment("Comment on a connector.", slide, connector, connectorCommentPosition, createdTime);

    IChart chart = slide.getShapes().addChart(ChartType.ClusteredColumn, 400, 20, 250, 180);
    Point2D.Float chartCommentPosition = new Point2D.Float(420, 40);
    author.getComments().addModernComment("Comment on a graphical object.", slide, chart, chartCommentPosition, createdTime);

    presentation.save("modern_comment_shape_types.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Ancorare un commento al testo e impostarne lo stato

Per un commento moderno associato a un'IAutoShape, i metodi IModernComment.getTextSelectionStart e IModernComment.setTextSelectionStart accedono alla posizione iniziale del testo selezionato nel frame di testo della forma. IModernComment.getTextSelectionLength e IModernComment.setTextSelectionLength accedono alla lunghezza della selezione. Insieme, questi valori associano il commento a uno specifico intervallo di testo all’interno dell’AutoShape.

I metodi IModernComment.getStatus e IModernComment.setStatus accedono a un valore dei costanti ModernCommentStatus:

  • NotDefined — nessuno stato specifico del commento moderno è definito.
  • Active — il commento è attivo.
  • Resolved — il commento è stato risolto.
  • Closed — il commento è chiuso.

L’esempio ancorra un commento moderno alle parole “quarterly revenue” nel testo di un rettangolo. Calcola l’indice di partenza zero‑based dal testo e lo passa a setTextSelectionStart e usa setTextSelectionLength per impostare il numero di caratteri selezionati. Dopo aver chiamato setStatus con Resolved, salva e riapre la presentazione. I quattro controlli della console dovrebbero stampare true, confermando che l’ancoraggio alla forma, l’intervallo di testo e lo stato sono stati conservati.

import com.aspose.slides.IAutoShape;
import com.aspose.slides.IComment;
import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.IModernComment;
import com.aspose.slides.ISlide;
import com.aspose.slides.ModernCommentStatus;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import com.aspose.slides.ShapeType;
import java.awt.geom.Point2D;
import java.util.Date;

String outputFile = "modern_comment_text_anchor.pptx";
String shapeText = "Review the quarterly revenue forecast.";
String selectedText = "quarterly revenue";
int expectedSelectionStart = shapeText.indexOf(selectedText);

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 50, 50, 400, 100);
    shape.setName("Forecast text");
    shape.getTextFrame().setText(shapeText);

    ICommentAuthor author = presentation.getCommentAuthors().addAuthor("Reviewer", "RV");
    Point2D.Float commentPosition = new Point2D.Float(60, 60);
    IModernComment comment = author.getComments().addModernComment("Verify this forecast wording.", slide, shape, commentPosition, new Date());
    comment.setTextSelectionStart(expectedSelectionStart);
    comment.setTextSelectionLength(selectedText.length());
    comment.setStatus(ModernCommentStatus.Resolved);

    presentation.save(outputFile, SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Presentation reopenedPresentation = new Presentation(outputFile);
try {
    ISlide reopenedSlide = reopenedPresentation.getSlides().get_Item(0);
    IComment[] reopenedComments = reopenedSlide.getSlideComments(null);

    for (IComment reopenedComment : reopenedComments) {
        if (!(reopenedComment instanceof IModernComment)) {
            continue;
        }

        IModernComment modernComment = (IModernComment) reopenedComment;
        boolean shapeMatches = modernComment.getShape() != null && "Forecast text".equals(modernComment.getShape().getName());
        boolean selectionStartMatches = modernComment.getTextSelectionStart() == expectedSelectionStart;
        boolean selectionLengthMatches = modernComment.getTextSelectionLength() == selectedText.length();
        boolean statusMatches = modernComment.getStatus() == ModernCommentStatus.Resolved;

        System.out.println("Shape anchor preserved: " + shapeMatches);
        System.out.println("Text selection start preserved: " + selectionStartMatches);
        System.out.println("Text selection length preserved: " + selectionLengthMatches);
        System.out.println("Resolved status preserved: " + statusMatches);
    }
} finally {
    reopenedPresentation.dispose();
}

Esaminare i commenti moderni esistenti

L’esempio richiede una presentazione esistente contenente commenti moderni e stampa il loro testo, lo stato e i dettagli dell’ancoraggio. Per ispezionarla, verifica quali commenti implementano IModernComment, quindi esamina IModernComment.getShape, IModernComment.getTextSelectionStart, IModernComment.getTextSelectionLength, e IModernComment.getStatus. Una forma null indica un commento a livello di diapositiva. Per un’ancora IAutoShape, i metodi di selezione del testo identificano l’intervallo associato nel frame di testo della forma.

import com.aspose.slides.IAutoShape;
import com.aspose.slides.IComment;
import com.aspose.slides.IModernComment;
import com.aspose.slides.IShape;
import com.aspose.slides.ISlide;
import com.aspose.slides.Presentation;

Presentation presentation = new Presentation("comments.pptx");
try {
    for (ISlide slide : presentation.getSlides()) {
        IComment[] comments = slide.getSlideComments(null);
        for (IComment comment : comments) {
            if (!(comment instanceof IModernComment)) {
                continue;
            }

            IModernComment modernComment = (IModernComment) comment;
            System.out.println("Slide: " + slide.getSlideNumber());
            System.out.println("Text: " + modernComment.getText());
            System.out.println("Status: " + modernComment.getStatus());

            IShape shape = modernComment.getShape();
            if (shape == null) {
                System.out.println("Anchor: slide level");
            } else {
                System.out.println("Anchor shape: " + shape.getName());
                System.out.println("Anchor type: " + shape.getClass().getSimpleName());

                if (shape instanceof IAutoShape) {
                    System.out.println("Text selection start: " + modernComment.getTextSelectionStart());
                    System.out.println("Text selection length: " + modernComment.getTextSelectionLength());
                }
            }

            System.out.println();
        }
    }
} finally {
    presentation.dispose();
}

Rimuovere i commenti

Aspose.Slides per Java consente di rimuovere tutti i commenti e i relativi autori da una presentazione o di eliminare commenti selezionati mantenendo gli altri. I seguenti esempi mostrano entrambi gli approcci e salvano la presentazione aggiornata.

Rimuovere tutti i commenti e gli autori dei commenti

L’esempio apre una presentazione esistente e chiama ICommentCollection.clear per ogni autore, quindi chiama ICommentAuthorCollection.clear per rimuovere gli stessi autori. La presentazione salvata non contiene né commenti né autori dei commenti. Usa una presentazione contenente commenti per osservare la rimozione.

import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;

Presentation presentation = new Presentation("example.pptx");
try {
    for (ICommentAuthor author : presentation.getCommentAuthors()) {
        author.getComments().clear();
    }

    presentation.getCommentAuthors().clear();

    presentation.save("example_out.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

Rimuovere commenti specifici

L’esempio crea due commenti su una diapositiva e usa getSlideComments per trovare i commenti di ciascun autore. Raccoglie i commenti il cui testo è uguale a “comment 1” prima di chiamare ICommentCollection.remove, evitando modifiche alla collezione durante la selezione. La presentazione salvata conserva solo “comment 2”.

import com.aspose.slides.IComment;
import com.aspose.slides.ICommentAuthor;
import com.aspose.slides.ISlide;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

Presentation presentation = new Presentation();
try {
    ISlide slide = presentation.getSlides().get_Item(0);

    ICommentAuthor author = presentation.getCommentAuthors().addAuthor("Author", "A");
    Date createdTime = new Date();

    Point2D.Float firstCommentPosition = new Point2D.Float(0.2f, 0.2f);
    Point2D.Float secondCommentPosition = new Point2D.Float(0.3f, 0.2f);
    author.getComments().addComment("comment 1", slide, firstCommentPosition, createdTime);
    author.getComments().addComment("comment 2", slide, secondCommentPosition, createdTime);

    for (ICommentAuthor commentAuthor : presentation.getCommentAuthors()) {
        List<IComment> commentsToRemove = new ArrayList<IComment>();
        IComment[] comments = slide.getSlideComments(commentAuthor);

        for (IComment comment : comments) {
            if ("comment 1".equals(comment.getText())) {
                commentsToRemove.add(comment);
            }
        }

        for (IComment comment : commentsToRemove) {
            commentAuthor.getComments().remove(comment);
        }
    }

    presentation.save("pres.pptx", SaveFormat.Pptx);
} finally {
    presentation.dispose();
}

FAQ

Aspose.Slides supporta uno stato risolto per i commenti moderni?

Sì. IModernComment.getStatus e IModernComment.setStatus accedono a un valore di ModernCommentStatus, incluso Resolved. Lo stato è memorizzato nella presentazione e può essere letto nuovamente dopo aver riaperto il file.

Le discussioni a thread (catene di risposte) sono supportate, e c’è un limite di nidificazione?

Sì. Ogni commento può fare riferimento al proprio parent comment, abilitando le catene di risposte. L’API non definisce un limite specifico di profondità di nidificazione.

In quale sistema di coordinate è definita la posizione del marcatore di un commento su una diapositiva?

La posizione del marcatore è definita da coordinate a virgola mobile nel sistema di coordinate della diapositiva, permettendo di posizionarlo con precisione sulla diapositiva.